| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- #!/usr/bin/env bash
- set -Eeuo pipefail
- self="$(basename "$0")"
- usage() {
- cat <<-EOU
- usage: $self path/to/README.md
- eg: $self README.md
- WARNING: if README.md has the TOC-replacement comments,
- README.md.bak will be clobbered and the TOC will be inserted
- EOU
- }
- readme="${1:-}"
- if ! shift || [ ! -f "$readme" ]; then usage >&2; exit 1; fi
- toc="$(
- gawk '
- # ignore comments in code blocks, which are not headers but look like them
- /^```/ { ignore = !ignore }
- /^#/ && !ignore {
- level = length($1)
- $1 = ""
- gsub(/^[[:space:]]|[[:space:]]$/, "")
- ++levelCounter[level]
- for (i in levelCounter) {
- if (i > level) {
- levelCounter[i] = 0
- }
- }
- prefix = levelCounter[level] ".\t"
- for (i = 1; i < level; ++i) {
- prefix = "\t" prefix
- }
- hash = tolower($0)
- gsub(/['"'"'./`]/, "", hash)
- gsub(/[^a-z0-9]+/, "-", hash)
- gsub(/^-|-$/, "", hash)
- printf "%s[%s](#%s)\n", prefix, $0, hash
- }
- ' "$readme"
- )"
- toFile="${readme}.bak"
- gawk -v toFile="$toFile" -v toc="$toc" '
- BEGIN { printf "" > toFile }
- /^<!-- AUTOGENERATED TOC -->$/ {
- inToc = !inToc
- seenToc = 1
- if (inToc) {
- print >> toFile
- print "" >> toFile
- print toc >> toFile
- print "" >> toFile
- print >> toFile
- }
- next
- }
- !inToc { print >> toFile }
- END { if (!seenToc) { close(toFile); printf "" > toFile } }
- ' "$readme"
- if [ -s "$toFile" ]; then
- mv "$toFile" "$readme"
- else
- rm "$toFile"
- echo "$toc"
- fi
|