Skip to content

Commit 40f2e04

Browse files
Repair release bundle guide links and explain VS Code installation
1 parent 8b6df5d commit 40f2e04

2 files changed

Lines changed: 177 additions & 14 deletions

File tree

‎VS Code Extension/README.md‎

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,25 @@ Start with the
3030
or run `serhelp start` on a server to locate the active script directory and
3131
see the first-run workflow.
3232

33-
This extension is maintained together with the main SER repository. SER's build
34-
regenerates the reflection-backed language manifest. The shared tooling build
35-
then produces the extension, visual-editor webview and standalone editor from
36-
that same manifest and shared language core.
33+
## Install
3734

38-
The maintainable extension source is in `src`. Files in `out` are synchronized
39-
build artifacts used by VS Code.
35+
If you downloaded a SER release, install the extension from its `.vsix` file:
36+
37+
1. Find `ser-<version>.vsix` in the release files. The Complete zip also has it
38+
in its `VS Code Extension` folder.
39+
2. In VS Code, open **Extensions**, select the **...** menu, choose
40+
**Install from VSIX...**, and pick the file. You can also run
41+
`code --install-extension ser-<version>.vsix` in a terminal.
42+
3. Reload VS Code if it asks.
43+
44+
## Build from source
45+
46+
This extension is maintained together with the main SER repository. The
47+
extension, its Blocks editor and the standalone Blocks editor are all built
48+
from the same SER language data that the plugin's build creates.
49+
50+
The editable source is in `src`. Files in `out` are generated from it and are
51+
what VS Code loads, so do not edit them by hand.
4052

4153
From the repository's `Tooling` directory:
4254

@@ -45,10 +57,25 @@ npm install
4557
npm run verify
4658
```
4759

48-
If the tooling dependencies are installed, the normal SER build runs this
49-
synchronization automatically before copying the extension to
50-
`%USERPROFILE%\\.vscode\\extensions\\ser`.
60+
Once these dependencies are installed, each SER build also refreshes the
61+
extension files in this folder.
62+
63+
### Building does not install the extension
64+
65+
A normal SER build only refreshes the extension files in this folder. It does
66+
not change the extension your VS Code uses.
67+
68+
To also copy the extension into VS Code during the build, add
69+
`/p:InstallSerExtensionAfterBuild=true`:
70+
71+
```powershell
72+
dotnet build SER.csproj -c Release --no-restore /p:InstallSerExtensionAfterBuild=true
73+
```
74+
75+
This copies the extension to `%USERPROFILE%\.vscode\extensions\ser`. Reload
76+
VS Code afterwards to use the new version.
5177

52-
To use a different installed-extension path, pass
53-
`/p:SerExtensionInstallDirectory="C:\\path\\to\\.vscode\\extensions\\ser"`
54-
to MSBuild.
78+
To copy it somewhere else, such as a VS Code Insiders profile, also pass
79+
`/p:SerExtensionInstallDirectory="C:\path\to\.vscode\extensions\ser"`. This
80+
setting only changes the destination. On its own, without
81+
`/p:InstallSerExtensionAfterBuild=true`, it copies nothing.

‎tools/package-release.ps1‎

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,145 @@ function Invoke-CheckedCommand {
3535
}
3636
}
3737

38+
# Online fallbacks for links whose target is not shipped in a bundle.
39+
$onlineDocsBaseUrl = 'https://scriptedevents.github.io/ScriptedEventsReloaded/'
40+
$repositoryWebUrl = 'https://github.com/ScriptedEvents/ScriptedEventsReloaded'
41+
$repositoryRawUrl = 'https://raw.githubusercontent.com/ScriptedEvents/ScriptedEventsReloaded/main'
42+
$markdownLinkPattern = '(?<prefix>\]\(|\bsrc=")(?<target>[^)"\s]+)(?<suffix>[)"])'
43+
44+
function ConvertTo-UrlPath {
45+
param([Parameter(Mandatory)] [AllowEmptyString()] [string]$RelativePath)
46+
47+
(($RelativePath -split '[\\/]') | ForEach-Object { [System.Uri]::EscapeDataString($_) }) -join '/'
48+
}
49+
50+
function Test-IsRelativeLinkTarget {
51+
param([Parameter(Mandatory)] [string]$Target)
52+
53+
# Skip web/mail links, in-page anchors and site-root paths.
54+
return -not ($Target -match '^(?:[a-zA-Z][a-zA-Z0-9+.-]*:|#|/)')
55+
}
56+
57+
function Split-LinkTarget {
58+
param([Parameter(Mandatory)] [string]$Target)
59+
60+
$hashIndex = $Target.IndexOf('#')
61+
if ($hashIndex -lt 0) {
62+
return @([System.Uri]::UnescapeDataString($Target), '')
63+
}
64+
return @([System.Uri]::UnescapeDataString($Target.Substring(0, $hashIndex)), $Target.Substring($hashIndex))
65+
}
66+
67+
function Get-OnlineLinkTarget {
68+
param(
69+
[Parameter(Mandatory)] [string]$RepositoryRelativePath,
70+
[switch]$RawFile
71+
)
72+
73+
$path = $RepositoryRelativePath -replace '\\', '/'
74+
if ($path -match '^docs/(?<page>.+)\.md$') {
75+
$page = $Matches['page']
76+
if ($page -eq 'README') {
77+
return $onlineDocsBaseUrl
78+
}
79+
if ($page.EndsWith('/README')) {
80+
$page = $page.Substring(0, $page.Length - 'README'.Length)
81+
}
82+
return $onlineDocsBaseUrl + (ConvertTo-UrlPath $page)
83+
}
84+
if ($RawFile) {
85+
return "$repositoryRawUrl/$(ConvertTo-UrlPath $path)"
86+
}
87+
$kind = if (Test-Path -LiteralPath (Join-Path $repositoryDirectory $path) -PathType Container) { 'tree' } else { 'blob' }
88+
return "$repositoryWebUrl/$kind/main/$(ConvertTo-UrlPath $path)"
89+
}
90+
91+
# Copies a repository Markdown file to the root of a bundle. Relative links are
92+
# pointed at the matching file inside that bundle when it is shipped there, and
93+
# at the online documentation or GitHub repository when it is not.
94+
function Copy-MarkdownToBundleRoot {
95+
param(
96+
[Parameter(Mandatory)] [string]$RepositoryRelativePath,
97+
[Parameter(Mandatory)] [string]$BundleRoot
98+
)
99+
100+
$sourceFile = Join-Path $repositoryDirectory $RepositoryRelativePath
101+
$sourceDirectory = Split-Path -Parent $sourceFile
102+
$repositoryPrefix = $repositoryDirectory.TrimEnd('\', '/') + [System.IO.Path]::DirectorySeparatorChar
103+
$content = [System.IO.File]::ReadAllText($sourceFile)
104+
$output = New-Object System.Text.StringBuilder
105+
$position = 0
106+
107+
foreach ($match in [regex]::Matches($content, $markdownLinkPattern)) {
108+
$target = $match.Groups['target'].Value
109+
$newTarget = $target
110+
if (Test-IsRelativeLinkTarget $target) {
111+
$pathPart, $anchor = Split-LinkTarget $target
112+
$fullPath = [System.IO.Path]::GetFullPath((Join-Path $sourceDirectory $pathPart))
113+
if (-not $fullPath.StartsWith($repositoryPrefix, [System.StringComparison]::OrdinalIgnoreCase)) {
114+
throw "$RepositoryRelativePath links outside the repository: $target"
115+
}
116+
$relativeTarget = $fullPath.Substring($repositoryPrefix.Length).TrimEnd('\', '/')
117+
if (Test-Path -LiteralPath (Join-Path $BundleRoot $relativeTarget)) {
118+
$newTarget = (ConvertTo-UrlPath $relativeTarget) + $anchor
119+
}
120+
else {
121+
$isImage = $match.Groups['prefix'].Value -ne ']('
122+
$newTarget = (Get-OnlineLinkTarget -RepositoryRelativePath $relativeTarget -RawFile:$isImage) + $anchor
123+
}
124+
}
125+
126+
$targetGroup = $match.Groups['target']
127+
[void]$output.Append($content, $position, $targetGroup.Index - $position)
128+
[void]$output.Append($newTarget)
129+
$position = $targetGroup.Index + $targetGroup.Length
130+
}
131+
[void]$output.Append($content, $position, $content.Length - $position)
132+
133+
$destination = Join-Path $BundleRoot (Split-Path -Leaf $sourceFile)
134+
[System.IO.File]::WriteAllText($destination, $output.ToString(), (New-Object System.Text.UTF8Encoding($false)))
135+
}
136+
137+
# Fails the release if any Markdown file in a bundle links to a local file that
138+
# is missing from that bundle.
139+
function Assert-BundleMarkdownLinks {
140+
param([Parameter(Mandatory)] [string]$BundleRoot)
141+
142+
$bundlePrefix = [System.IO.Path]::GetFullPath($BundleRoot).TrimEnd('\', '/') + [System.IO.Path]::DirectorySeparatorChar
143+
$brokenLinks = New-Object System.Collections.Generic.List[string]
144+
foreach ($file in Get-ChildItem -LiteralPath $BundleRoot -Filter '*.md' -File -Recurse) {
145+
$content = [System.IO.File]::ReadAllText($file.FullName)
146+
foreach ($match in [regex]::Matches($content, $markdownLinkPattern)) {
147+
$target = $match.Groups['target'].Value
148+
if (-not (Test-IsRelativeLinkTarget $target)) {
149+
continue
150+
}
151+
$pathPart = (Split-LinkTarget $target)[0]
152+
if ($pathPart.Length -eq 0) {
153+
continue
154+
}
155+
$fullPath = [System.IO.Path]::GetFullPath((Join-Path $file.DirectoryName $pathPart))
156+
if (-not $fullPath.StartsWith($bundlePrefix, [System.StringComparison]::OrdinalIgnoreCase) -or
157+
-not (Test-Path -LiteralPath $fullPath)) {
158+
$brokenLinks.Add("$($file.FullName.Substring($bundlePrefix.Length)): $target")
159+
}
160+
}
161+
}
162+
163+
if ($brokenLinks.Count -gt 0) {
164+
throw "Bundle $BundleRoot has links to files it does not contain:`n$($brokenLinks -join "`n")"
165+
}
166+
}
167+
38168
function Copy-ReleaseNotices {
39169
param([Parameter(Mandatory)] [string]$Destination)
40170

41171
Copy-Item -LiteralPath (Join-Path $repositoryDirectory 'LICENSE') -Destination $Destination
42172
Copy-Item -LiteralPath (Join-Path $repositoryDirectory 'THIRD_PARTY_LICENSES.txt') -Destination $Destination
43-
Copy-Item -LiteralPath (Join-Path $repositoryDirectory 'README.md') -Destination $Destination
44-
Copy-Item -LiteralPath (Join-Path $repositoryDirectory 'docs\getting-started\installation.md') -Destination $Destination
173+
# Copy these last, after the bundle's other content, so their links can be
174+
# pointed at files that are actually in the bundle.
175+
Copy-MarkdownToBundleRoot -RepositoryRelativePath 'README.md' -BundleRoot $Destination
176+
Copy-MarkdownToBundleRoot -RepositoryRelativePath 'docs\getting-started\installation.md' -BundleRoot $Destination
45177
}
46178

47179
function Compress-ReleaseDirectory {
@@ -123,6 +255,10 @@ $vsixPath = Join-Path $releaseDirectory "ser-$extensionVersion.vsix"
123255
Invoke-CheckedCommand -FilePath 'npm' -Arguments @('run', 'package', '--', '--out', $vsixPath) -WorkingDirectory $extensionDirectory
124256
Copy-Item -LiteralPath $vsixPath -Destination (Join-Path $completeStage 'VS Code Extension')
125257

258+
foreach ($stage in @($learningStage, $editorStage, $completeStage)) {
259+
Assert-BundleMarkdownLinks -BundleRoot $stage
260+
}
261+
126262
Compress-ReleaseDirectory -Source $learningStage -Destination (Join-Path $releaseDirectory "SER-$coreVersion-Examples-and-Documentation.zip")
127263
Compress-ReleaseDirectory -Source $editorStage -Destination (Join-Path $releaseDirectory "SER-Visual-Editor-$coreVersion.zip")
128264
Compress-ReleaseDirectory -Source $completeStage -Destination (Join-Path $releaseDirectory "SER-$coreVersion-Complete.zip")

0 commit comments

Comments
 (0)