-
Notifications
You must be signed in to change notification settings - Fork 0
⚙️ [Maintenance]: Minor docs-site switch to Zensical #403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
d05fec9
a088cea
75912ac
6f6c4f4
2b5cc1c
528fed2
d5deb4d
214dfb3
5e8c7ff
9388dde
a69daa5
3edbe44
8dedc1a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| name: Build-ZensicalSite | ||
| description: Build Zensical site output and normalize output folder. | ||
|
|
||
| inputs: | ||
| WorkingDirectory: | ||
| description: Working directory for the repository build. | ||
| required: true | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Build documentation site | ||
| shell: pwsh | ||
| run: '& "${{ github.action_path }}/src/build-zensical-site.ps1" -WorkingDirectory "${{ inputs.WorkingDirectory }}"' | ||
Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ github.action_path } Error loading related location Loading Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ inputs.WorkingDirectory } Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [string]$WorkingDirectory | ||
| ) | ||
|
|
||
| $ErrorActionPreference = 'Stop' | ||
|
|
||
| $resolvedWorkingDirectory = Resolve-Path -Path $WorkingDirectory | Select-Object -ExpandProperty Path | ||
| $siteWorkingDirectory = Join-Path -Path $resolvedWorkingDirectory -ChildPath 'outputs/site' | ||
| $outputSitePath = Join-Path -Path $resolvedWorkingDirectory -ChildPath '_site' | ||
|
|
||
| Set-Location -Path $siteWorkingDirectory | ||
|
|
||
| if (-not (Test-Path -Path 'zensical.toml')) { | ||
| throw "No documentation config file found in outputs/site. Expected zensical.toml." | ||
| } | ||
|
|
||
| zensical build --config-file 'zensical.toml' | ||
|
|
||
| if (Test-Path -Path '_site') { | ||
| if (Test-Path -Path $outputSitePath) { | ||
| Remove-Item -Path $outputSitePath -Recurse -Force | ||
| } | ||
| Move-Item -Path '_site' -Destination $outputSitePath -Force | ||
| } | ||
|
|
||
| if (-not (Test-Path -Path $outputSitePath)) { | ||
| throw "Expected Zensical output at $outputSitePath but it was not created." | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| name: Inject-SiteScripts | ||
| description: Inject shared JavaScript snippets into generated site HTML files. | ||
|
|
||
| inputs: | ||
| SitePath: | ||
| description: Path to the generated site output directory. | ||
| required: true | ||
| WorkflowPath: | ||
| description: Path to the checked out workflow repository root. | ||
| required: false | ||
| default: _wf | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Inject site scripts | ||
| shell: pwsh | ||
| run: '& "${{ github.action_path }}/src/inject-site-scripts.ps1" -SitePath "${{ inputs.SitePath }}" -WorkflowPath "${{ inputs.WorkflowPath }}"' | ||
Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ github.action_path } Error loading related location Loading Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ inputs.SitePath } Error loading related location Loading Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ inputs.WorkflowPath } Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [string]$SitePath, | ||
|
|
||
| [Parameter(Mandatory)] | ||
| [string]$WorkflowPath | ||
| ) | ||
|
|
||
| $resolvedSitePath = Resolve-Path -Path $SitePath -ErrorAction Stop | Select-Object -ExpandProperty Path | ||
| $injectorsPath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "$WorkflowPath/.github/scripts/site-injectors" | ||
|
|
||
| if (-not (Test-Path -Path $injectorsPath)) { | ||
| throw "Expected site injector folder at $injectorsPath but it was not found." | ||
| } | ||
|
|
||
| $injectorScripts = Get-ChildItem -Path $injectorsPath -File -Filter '*.js' | Sort-Object -Property Name | ||
| if (-not $injectorScripts) { | ||
| Write-Host "No site injector scripts found under $injectorsPath." | ||
| exit 0 | ||
| } | ||
|
|
||
| Get-ChildItem -Path $resolvedSitePath -Filter '*.html' -Recurse | ForEach-Object { | ||
| $html = Get-Content -Path $_.FullName -Raw | ||
| $modified = $false | ||
|
|
||
| foreach ($injectorScript in $injectorScripts) { | ||
| $marker = "data-psmodule-site-injector=""$($injectorScript.Name)""" | ||
| if ($html -match [Regex]::Escape($marker)) { | ||
| continue | ||
| } | ||
|
|
||
| $scriptContent = Get-Content -Path $injectorScript.FullName -Raw | ||
| $injectedScript = "<script $marker>$scriptContent</script>" | ||
| $html = $html -replace '</body>', "$injectedScript`n</body>" | ||
| $modified = $true | ||
| } | ||
|
|
||
| if ($modified) { | ||
| Set-Content -Path $_.FullName -Value $html -NoNewline | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| name: Install-Zensical | ||
| description: Install Zensical CLI used for documentation site generation. | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Install Zensical CLI | ||
| shell: pwsh | ||
| run: '& "${{ github.action_path }}/src/install-zensical.ps1"' | ||
Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ github.action_path } Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| $ErrorActionPreference = 'Stop' | ||
|
|
||
| pip install zensical |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| name: Structure-Site | ||
| description: Structure generated docs and create site config for Zensical. | ||
|
|
||
| inputs: | ||
| WorkingDirectory: | ||
| description: Working directory for the repository build. | ||
| required: true | ||
| Name: | ||
| description: Optional module name override. | ||
| required: false | ||
| default: '' | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Structure site content and config | ||
| shell: pwsh | ||
| run: '& "${{ github.action_path }}/src/structure-site.ps1" -WorkingDirectory "${{ inputs.WorkingDirectory }}" -Name "${{ inputs.Name }}"' | ||
Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ github.action_path } Error loading related location Loading Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ inputs.WorkingDirectory } Error loading related location Loading Check warningCode scanning / CodeQL Code injection Medium
Potential code injection in
${ inputs.Name } Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [string]$WorkingDirectory, | ||
|
|
||
| [Parameter()] | ||
| [string]$Name | ||
| ) | ||
|
|
||
| $ErrorActionPreference = 'Stop' | ||
|
|
||
| $resolvedWorkingDirectory = Resolve-Path -Path $WorkingDirectory | Select-Object -ExpandProperty Path | ||
| $siteOutputPath = Join-Path -Path $resolvedWorkingDirectory -ChildPath 'outputs/site' | ||
| $docsOutputPath = Join-Path -Path $resolvedWorkingDirectory -ChildPath 'outputs/docs' | ||
| $moduleSourcePath = Join-Path -Path $resolvedWorkingDirectory -ChildPath 'src' | ||
| $moduleName = if ([string]::IsNullOrEmpty($Name)) { $env:GITHUB_REPOSITORY_NAME } else { $Name } | ||
|
|
||
| $functionDocsFolder = New-Item -Path (Join-Path -Path $siteOutputPath -ChildPath 'docs/Functions') -ItemType Directory -Force | ||
| Copy-Item -Path (Join-Path -Path $docsOutputPath -ChildPath '*') -Destination $functionDocsFolder.FullName -Recurse -Force | ||
|
|
||
| Write-Host "Function Docs Folder: $($functionDocsFolder.FullName)" | ||
| Write-Host "Module Name: $moduleName" | ||
| Write-Host "Module Source Path: $moduleSourcePath" | ||
| Write-Host "Site Output Path: $siteOutputPath" | ||
|
|
||
| $aboutDocsFolder = New-Item -Path (Join-Path -Path $siteOutputPath -ChildPath 'docs/About') -ItemType Directory -Force | ||
| $aboutSourceFolder = Join-Path -Path $moduleSourcePath -ChildPath 'en-US' | ||
| if (Test-Path -Path $aboutSourceFolder) { | ||
| Get-ChildItem -Path $aboutSourceFolder -Filter '*.txt' | Copy-Item -Destination $aboutDocsFolder.FullName -Force -PassThru | | ||
| Rename-Item -NewName { $_.Name -replace '\.txt$', '.md' } | ||
| } | ||
|
|
||
| $assetsFolder = New-Item -Path (Join-Path -Path $siteOutputPath -ChildPath 'docs/Assets') -ItemType Directory -Force | ||
| $iconPath = Join-Path -Path $resolvedWorkingDirectory -ChildPath 'icon/icon.png' | ||
| if (Test-Path -Path $iconPath) { | ||
| Copy-Item -Path $iconPath -Destination $assetsFolder.FullName -Force | ||
| } | ||
|
|
||
| $readmePath = Join-Path -Path $resolvedWorkingDirectory -ChildPath 'README.md' | ||
| $readmeTargetPath = Join-Path -Path $siteOutputPath -ChildPath 'docs/README.md' | ||
| Copy-Item -Path $readmePath -Destination $readmeTargetPath -Force | ||
|
|
||
| $possiblePaths = @( | ||
| '.github/zensical.toml', | ||
| 'docs/zensical.toml', | ||
| 'zensical.toml' | ||
| ) | ||
|
|
||
| $docsConfigSourcePath = $null | ||
| foreach ($relativePath in $possiblePaths) { | ||
| $candidatePath = Join-Path -Path $resolvedWorkingDirectory -ChildPath $relativePath | ||
| if (Test-Path -Path $candidatePath) { | ||
| $docsConfigSourcePath = $candidatePath | ||
| break | ||
| } | ||
| } | ||
|
|
||
| if (-not $docsConfigSourcePath) { | ||
| throw "Documentation config file not found. Expected one of: $($possiblePaths -join ', ')" | ||
| } | ||
|
|
||
| $docsConfigFileName = [System.IO.Path]::GetFileName($docsConfigSourcePath) | ||
| $docsConfigTargetPath = Join-Path -Path $siteOutputPath -ChildPath $docsConfigFileName | ||
|
|
||
| $docsConfigContent = Get-Content -Path $docsConfigSourcePath -Raw | ||
| $docsConfigContent = $docsConfigContent.Replace('-{{ REPO_NAME }}-', $moduleName) | ||
| $docsConfigContent = $docsConfigContent.Replace('-{{ REPO_OWNER }}-', $env:GITHUB_REPOSITORY_OWNER) | ||
|
|
||
| if ($docsConfigFileName -eq 'zensical.toml') { | ||
| if ($docsConfigContent -match '(?m)^\s*site_dir\s*=') { | ||
| $docsConfigContent = $docsConfigContent -replace '(?m)^\s*site_dir\s*=.*$', 'site_dir = "_site"' | ||
| } else { | ||
| $docsConfigContent = $docsConfigContent -replace '(?m)^\[project\]\s*$', "[project]`nsite_dir = ""_site""" | ||
| } | ||
| } | ||
|
|
||
| Set-Content -Path $docsConfigTargetPath -Value $docsConfigContent -Force | ||
| Write-Host "Build Config Type: $docsConfigFileName" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| (() => { | ||
| const storageKey = "zensical-nav-state-v1"; | ||
| let lastSignature = ""; | ||
|
|
||
| const getToggles = () => | ||
| Array.from(document.querySelectorAll("input.md-nav__toggle.md-toggle[id]")); | ||
|
|
||
| const getPrimaryList = () => | ||
| document.querySelector("nav.md-nav--primary > ul.md-nav__list"); | ||
|
|
||
| const applyDefaultTopLevelState = (toggles) => { | ||
| const primaryList = getPrimaryList(); | ||
| if (!primaryList) { | ||
| return; | ||
| } | ||
|
|
||
| const topLevelToggles = Array.from( | ||
| primaryList.querySelectorAll( | ||
| ":scope > li > input.md-nav__toggle.md-toggle[id]" | ||
| ) | ||
| ); | ||
| const topLevelIds = new Set(topLevelToggles.map((toggle) => toggle.id)); | ||
|
|
||
| for (const toggle of toggles) { | ||
| toggle.checked = topLevelIds.has(toggle.id); | ||
| } | ||
| }; | ||
|
|
||
| const restoreState = (toggles) => { | ||
| const raw = localStorage.getItem(storageKey); | ||
| if (!raw) { | ||
| applyDefaultTopLevelState(toggles); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| const state = JSON.parse(raw); | ||
| for (const toggle of toggles) { | ||
| if (Object.prototype.hasOwnProperty.call(state, toggle.id)) { | ||
| toggle.checked = !!state[toggle.id]; | ||
| } | ||
| } | ||
| } catch { | ||
| applyDefaultTopLevelState(toggles); | ||
| } | ||
| }; | ||
|
|
||
| const persistState = (toggles) => { | ||
| const state = {}; | ||
| for (const toggle of toggles) { | ||
| state[toggle.id] = !!toggle.checked; | ||
| } | ||
| localStorage.setItem(storageKey, JSON.stringify(state)); | ||
| }; | ||
|
|
||
| const initialize = () => { | ||
| const toggles = getToggles(); | ||
| if (toggles.length === 0) { | ||
| return; | ||
| } | ||
|
|
||
| const signature = toggles.map((toggle) => toggle.id).join("|"); | ||
| if (signature === lastSignature) { | ||
| return; | ||
| } | ||
|
|
||
| lastSignature = signature; | ||
| restoreState(toggles); | ||
| for (const toggle of toggles) { | ||
| if (toggle.dataset.navStateBound === "true") { | ||
| continue; | ||
| } | ||
|
|
||
| toggle.dataset.navStateBound = "true"; | ||
| toggle.addEventListener("change", () => persistState(getToggles())); | ||
| } | ||
| }; | ||
|
|
||
| if (document.readyState === "loading") { | ||
| document.addEventListener("DOMContentLoaded", initialize, { once: true }); | ||
| } else { | ||
| initialize(); | ||
| } | ||
|
|
||
| setInterval(initialize, 500); | ||
| })(); |
Uh oh!
There was an error while loading. Please reload this page.