#!/usr/bin/env nu
# Linkify site conventions in blog markdown source:
#
# ontoref / Ontoref → … (brand mention, case-preserving)
# ADR-NNN → ADR-NNN (decision deep-link)
#
# Operates on the MARKDOWN SOURCE (not the generated HTML) so the change survives
# every `just content` regeneration. Both rewrites are idempotent via lookarounds:
# an already-wrapped mention (preceded by `>` / followed by ``) is left as-is.
#
# Skipped, so code and metadata never get a stray link:
# - YAML frontmatter (between the leading --- delimiters)
# - fenced code blocks (``` … ```)
# - inline code spans (`…`)
# - headings (lines beginning with #)
# - compound identifiers: ontoref-daemon, ontoref/dist, .ontoref, /adr/038 (lookarounds)
#
# Usage (from outreach/site):
# nu scripts/build/linkify-site.nu # default glob
# nu scripts/build/linkify-site.nu site/content/blog/**/*.md
# nu scripts/build/linkify-site.nu --check # CI gate, no writes
const LINK = '${n}'
const WORD = '(?\w./-])(?[Oo]ntoref)(?![<\w./-])'
const ADR_LINK = 'ADR-${num}'
const ADR_WORD = '(?/\w-])ADR-(?\d+)(?!)'
# Apply both site rewrites outside inline-code spans on a single line.
def linkify-line [line: string]: nothing -> string {
$line
| split row '`'
| enumerate
| each {|it|
if ($it.index mod 2) == 0 {
$it.item
| str replace --all --regex $WORD $LINK
| str replace --all --regex $ADR_WORD $ADR_LINK
} else {
$it.item
}
}
| str join '`'
}
def main [
pattern: string = "site/content/blog/**/*.md"
--check # report posts that WOULD change and exit non-zero; never writes
] {
let files = (glob $pattern | sort)
mut changed = 0
for f in $files {
let lines = (open --raw $f | lines)
mut out = []
mut in_front = false
mut in_fence = false
mut idx = 0
for line in $lines {
let trimmed = ($line | str trim)
# Frontmatter: a leading --- opens it, the next --- closes it.
if $trimmed == "---" and not $in_fence {
if $idx == 0 {
$in_front = true
} else if $in_front {
$in_front = false
}
$out = ($out | append $line)
$idx = ($idx + 1)
continue
}
if ($trimmed | str starts-with '```') {
$in_fence = (not $in_fence)
$out = ($out | append $line)
$idx = ($idx + 1)
continue
}
if $in_front or $in_fence or ($trimmed | str starts-with '#') {
$out = ($out | append $line)
$idx = ($idx + 1)
continue
}
$out = ($out | append (linkify-line $line))
$idx = ($idx + 1)
}
let result = ($out | str join "\n")
let original = (open --raw $f)
# Preserve a trailing newline if the source had one.
let final = if ($original | str ends-with "\n") { $result + "\n" } else { $result }
if $final != $original {
if $check {
print $" ($f | path basename): unlinked site mentions pending"
} else {
$final | save -f $f
print $" ($f | path basename): linked"
}
$changed = ($changed + 1)
}
}
if $check {
if $changed > 0 {
error make { msg: $"linkify-site --check: ($changed) post\(s\) have unlinked site mentions — run `just content`" }
}
print "linkify-site --check: all posts clean"
} else {
print $"linkify-site: ($changed) file\(s\) updated"
}
}