Source index
scripts/build-license-page.mjs
import {readFile, writeFile, mkdir} from 'node:fs/promises'
import {fileURLToPath} from 'node:url'
import path from 'node:path'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const markdown = await readFile(path.join(root, 'THIRD_PARTY_NOTICES.md'), 'utf8')
const escape = value => value.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"')
const inline = value => escape(value)
.replace(/\[([^\]]+)\]\((https:\/\/[^\s)]+)\)/g, '<a href="$2">$1</a>')
.replace(/`([^`]+)`/g, '<code>$1</code>')
let listOpen = false
const pieces = []
for (const line of markdown.split(/\r?\n/)) {
if (!line.trim()) { if (listOpen) {pieces.push('</ul>'); listOpen = false} continue }
if (line.startsWith('- ')) { if (!listOpen) {pieces.push('<ul>'); listOpen = true} pieces.push(`<li>${inline(line.slice(2))}</li>`); continue }
if (listOpen) {pieces.push('</ul>'); listOpen = false}
const heading = line.match(/^(#{1,3}) (.+)$/)
pieces.push(heading ? `<h${heading[1].length}>${inline(heading[2])}</h${heading[1].length}>` : `<p>${inline(line)}</p>`)
}
if (listOpen) pieces.push('</ul>')
const html = `<!doctype html>\n<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Access Atlas — licenses and sources</title><style>body{font:18px/1.65 system-ui,sans-serif;color:#15251f;background:#f7faf8;margin:0}main{max-width:78ch;margin:auto;padding:2rem 1.25rem}h1,h2,h3{line-height:1.2}h2{margin-top:2.5rem}a{color:#075d49;overflow-wrap:anywhere}a:focus-visible{outline:3px solid #9a4400;outline-offset:4px}code{background:#e5eee9;padding:.1em .25em}li{margin-bottom:.5rem}</style></head><body><main><nav aria-label="Page"><a href="/">Return to Access Atlas</a></nav>\n${pieces.join('\n')}\n</main></body></html>\n`
await mkdir(path.join(root, 'public'), {recursive: true})
await writeFile(path.join(root, 'public/licenses.html'), html)
console.log('Generated public/licenses.html from THIRD_PARTY_NOTICES.md')