Verify wikilink heading anchors
This commit is contained in:
parent
1e3257369c
commit
d2f514cf16
2 changed files with 46 additions and 7 deletions
|
|
@ -38,13 +38,20 @@ foreach ($note in $notes) {
|
|||
$text = Get-Content -Raw -LiteralPath $note.FullName -Encoding utf8
|
||||
foreach ($match in [regex]::Matches($text, '!??\[\[(?<target>[^\]]+)\]\]')) {
|
||||
$linkCount += 1
|
||||
$target = ($match.Groups['target'].Value -split '\|', 2)[0]
|
||||
$target = ($target -split '#', 2)[0].Trim()
|
||||
if (-not $target) { continue }
|
||||
$linkBody = ($match.Groups['target'].Value -split '\|', 2)[0]
|
||||
$targetParts = $linkBody -split '#', 2
|
||||
$target = $targetParts[0].Trim()
|
||||
$anchor = if ($targetParts.Count -gt 1) { [uri]::UnescapeDataString($targetParts[1].Trim()) } else { $null }
|
||||
$target = $target -replace '\\', '/'
|
||||
$resolved = @()
|
||||
$extension = [System.IO.Path]::GetExtension($target)
|
||||
if ($extension -and $extension.ToLowerInvariant() -ne '.md') {
|
||||
if (-not $target -and $anchor) {
|
||||
$resolved = @($note.FullName)
|
||||
}
|
||||
elseif (-not $target) {
|
||||
continue
|
||||
}
|
||||
elseif ($extension -and $extension.ToLowerInvariant() -ne '.md') {
|
||||
$relativeAsset = [System.IO.Path]::GetFullPath((Join-Path $note.DirectoryName $target))
|
||||
$rootAsset = [System.IO.Path]::GetFullPath((Join-Path $contentFull $target))
|
||||
if (Test-Path -LiteralPath $relativeAsset -PathType Leaf) { $resolved += $relativeAsset }
|
||||
|
|
@ -71,6 +78,24 @@ foreach ($note in $notes) {
|
|||
elseif ($resolved.Count -gt 1 -and $target -notmatch '[/\\]') {
|
||||
$errors += "$sourceRelative -> [[$($match.Groups['target'].Value)]] is ambiguous across $($resolved.Count) files"
|
||||
}
|
||||
elseif ($anchor -and $resolved.Count -eq 1 -and [System.IO.Path]::GetExtension($resolved[0]).ToLowerInvariant() -eq '.md') {
|
||||
$destinationText = Get-Content -Raw -LiteralPath $resolved[0] -Encoding utf8
|
||||
if ($anchor.StartsWith('^')) {
|
||||
$blockId = [regex]::Escape($anchor.Substring(1))
|
||||
if ($destinationText -notmatch "(?m)\\^$blockId\\s*$") {
|
||||
$errors += "$sourceRelative -> [[$($match.Groups['target'].Value)]] has no matching block anchor"
|
||||
}
|
||||
}
|
||||
else {
|
||||
$wantedHeading = ($anchor -replace '\s+', ' ').Trim().ToLowerInvariant()
|
||||
$headings = @([regex]::Matches($destinationText, '(?m)^#{1,6}\s+(?<heading>.+?)\s*#*\s*$') | ForEach-Object {
|
||||
(($_.Groups['heading'].Value -replace '\s+', ' ').Trim()).ToLowerInvariant()
|
||||
})
|
||||
if ($headings -notcontains $wantedHeading) {
|
||||
$errors += "$sourceRelative -> [[$($match.Groups['target'].Value)]] has no matching heading anchor"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ if (-not $fixtureFull.StartsWith($tempBase + [System.IO.Path]::DirectorySeparato
|
|||
try {
|
||||
$content = Join-Path $fixtureFull "Kalsa"
|
||||
New-Item -ItemType Directory -Path $content | Out-Null
|
||||
Set-Content -LiteralPath (Join-Path $content "index.md") -Encoding utf8 -Value "# Fixture`n`nSee [[Institution]]."
|
||||
Set-Content -LiteralPath (Join-Path $content "Institution.md") -Encoding utf8 -Value "# Institution`n`nA bounded test note."
|
||||
Set-Content -LiteralPath (Join-Path $content "index.md") -Encoding utf8 -Value "# Fixture`n`nSee [[Institution#Bounded authority]]."
|
||||
Set-Content -LiteralPath (Join-Path $content "Institution.md") -Encoding utf8 -Value "# Institution`n`n## Bounded authority`n`nA bounded test note."
|
||||
|
||||
& (Join-Path $PSScriptRoot "verify-seed.ps1")
|
||||
& (Join-Path $PSScriptRoot "check-wikilinks.ps1") -ContentRoot $content
|
||||
|
|
@ -34,6 +34,20 @@ try {
|
|||
}
|
||||
Remove-Item -LiteralPath $broken -Force
|
||||
|
||||
$brokenAnchor = Join-Path $content "Broken Anchor.md"
|
||||
Set-Content -LiteralPath $brokenAnchor -Encoding utf8 -Value "# Broken Anchor`n`nSee [[Institution#No such heading]]."
|
||||
$caughtBrokenAnchor = $false
|
||||
try {
|
||||
& (Join-Path $PSScriptRoot "check-wikilinks.ps1") -ContentRoot $content | Out-Null
|
||||
}
|
||||
catch {
|
||||
$caughtBrokenAnchor = $true
|
||||
}
|
||||
if (-not $caughtBrokenAnchor) {
|
||||
throw "Wikilink checker failed to reject a missing heading anchor"
|
||||
}
|
||||
Remove-Item -LiteralPath $brokenAnchor -Force
|
||||
|
||||
$forbidden = Join-Path $content "workshop"
|
||||
New-Item -ItemType Directory -Path $forbidden | Out-Null
|
||||
$caughtBoundary = $false
|
||||
|
|
@ -47,7 +61,7 @@ try {
|
|||
throw "Publication checker failed to reject a nested workshop directory"
|
||||
}
|
||||
|
||||
Write-Output "Lore tool tests passed, including broken-link and publication-boundary negative checks."
|
||||
Write-Output "Lore tool tests passed, including broken-link, broken-anchor, and publication-boundary negative checks."
|
||||
}
|
||||
finally {
|
||||
$resolvedFixture = [System.IO.Path]::GetFullPath($fixtureFull)
|
||||
|
|
|
|||
Loading…
Reference in a new issue