mirror of
https://github.com/clearlinux/official-images.git
synced 2026-08-19 02:57:13 +00:00
190775c582
Most notably, this allows emoji in headers to generate the correct anchors. See https://gist.github.com/tianon/75e267d9137b1c2978031b66b3a98987 for a bunch of test cases I worked through this with (and found bugs in GitHub's implementation while reverse engineering it, which is fun, and quirks of the library I was copying that aren't correct for the GitHub implementation). I've also verified that this causes no changes to the TOC here or over in the docs repo (as expected).
86 lines
2.8 KiB
Bash
Executable File
86 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
self="$(basename "$0")"
|
|
usage() {
|
|
cat <<-EOU
|
|
usage: $self path/to/markdown.md
|
|
eg: $self README.md
|
|
|
|
WARNING: this will *always* clobber any path/to/markdown.md.{toc,bak} while processing; use with caution!
|
|
EOU
|
|
}
|
|
|
|
markdown="${1:-}"
|
|
if ! shift || [ ! -s "$markdown" ]; then usage >&2; exit 1; fi
|
|
|
|
# see https://gist.github.com/tianon/75e267d9137b1c2978031b66b3a98987 for an insane test case for this (with several rough edges)
|
|
|
|
jq --raw-input --null-input --raw-output '
|
|
reduce inputs as $line ({ toc: "" };
|
|
if $line | test("^```") then
|
|
.ignore |= not
|
|
else . end
|
|
| if .ignore then . else
|
|
(
|
|
$line
|
|
| capture("^(?<hash>#+)[[:space:]]*(?<heading>.*?)[[:space:]]*$")
|
|
// null
|
|
) as $cap
|
|
| if $cap then
|
|
($cap.hash | length) as $level
|
|
| .levels[$level] += 1
|
|
| .levels |= (.[range($level+1; length)] = 0)
|
|
| (
|
|
$cap.heading
|
|
| ascii_downcase
|
|
# https://github.com/thlorenz/anchor-markdown-header/blob/6b9bc1c902e48942666859fb6f795d91cbfd48e7/anchor-markdown-header.js#L33-L48
|
|
| gsub(" "; "-")
|
|
# escape codes (commented out because this is not something GitHub strips, although it *does* strip % which is not included below, so that is added here)
|
|
#| gsub("%[abcdef0-9]{2}"; ""; "i")
|
|
| gsub("%"; "")
|
|
# single chars that are removed
|
|
| gsub("[\\\\/?!:\\[\\]`.,()*\"'"'"';{}+=<>~$|#@&–—]"; "")
|
|
# CJK punctuations that are removed
|
|
| gsub("[。?!,、;:“”【】()〔〕[]﹃﹄“ ”‘’﹁﹂—…-~《》〈〉「」]"; "")
|
|
# Strip emojis (*technically* this is way too aggressive and will strip out *all* UTF-8, but 🤷)
|
|
| (split("") | map(select(utf8bytelength == 1)) | join(""))
|
|
# TODO Strip embedded markdown formatting
|
|
) as $anchor
|
|
# handle repetition (same end anchor)
|
|
| (
|
|
(.seen // []) as $seen
|
|
| first(
|
|
# this 1000 limits how many repeated headings we can have, but 1000 of the exact same header text seems pretty generous 🙊
|
|
$anchor + (range(1000) | if . > 0 then "-\(.)" else "" end)
|
|
| select(IN($seen[]) | not)
|
|
)
|
|
// error("repetition level too deep on #\($anchor) (\($line)) at line \(input_line_number)")
|
|
) as $finalAnchor
|
|
| .toc += "\("\t" * ($level-1) // "")\(.levels[$level]).\t[\($cap.heading)](#\($finalAnchor))\n"
|
|
| .seen += [ $finalAnchor ]
|
|
else . end
|
|
end
|
|
)
|
|
| .toc
|
|
' "$markdown" > "$markdown.toc"
|
|
|
|
gawk -v tocFile="$markdown.toc" '
|
|
/^<!-- AUTOGENERATED TOC -->$/ {
|
|
inToc = !inToc
|
|
seenToc = 1
|
|
if (inToc) {
|
|
print
|
|
print ""
|
|
system("cat " tocFile)
|
|
# no need for another newline because tocFile should already end with one
|
|
print
|
|
}
|
|
next
|
|
}
|
|
!inToc { print }
|
|
' "$markdown" > "$markdown.bak"
|
|
|
|
mv -f "$markdown.bak" "$markdown"
|
|
rm -f "$markdown.toc"
|