import { readFileSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
const src = readFileSync(process.argv[2], 'utf8')
const out = process.argv[3]
const esc = (s) => s.replace(/&/g, '&').replace(//g, '>')
const inline = (s) =>
esc(s)
.replace(/`([^`]+)`/g, '$1')
.replace(/\*\*([^*]+)\*\*/g, '$1')
.replace(/\*([^*]+)\*/g, '$1')
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1')
.replace(/→/g, '→')
const slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '')
const lines = src.split('\n')
let html = []
const toc = []
let i = 0
let para = []
const flushPara = () => {
if (para.length) {
html.push(`
${inline(para.join(' '))}
`)
para = []
}
}
let titleLine = null
let subtitle = null
let meta = null
while (i < lines.length) {
const line = lines[i]
if (line.startsWith('```')) {
flushPara()
const lang = line.slice(3).trim()
const buf = []
i++
while (i < lines.length && !lines[i].startsWith('```')) buf.push(lines[i++])
i++
if (lang === 'mermaid') html.push(`
${esc(buf.join('\n'))}
`)
else html.push(`
${esc(buf.join('\n'))}
`)
continue
}
if (/^#{1,3} /.test(line)) {
flushPara()
const level = line.match(/^#+/)[0].length
const text = line.replace(/^#+ /, '')
if (level === 1 && titleLine === null) { titleLine = text; i++; continue }
const id = slug(text)
if (level === 2) toc.push({ id, text })
html.push(`${inline(text)}`)
i++
continue
}
if (line.startsWith('|')) {
flushPara()
const rows = []
while (i < lines.length && lines[i].startsWith('|')) rows.push(lines[i++])
const cells = (r) => r.replace(/^\|/, '').replace(/\|$/, '').split('|').map((c) => c.trim())
const head = cells(rows[0])
const body = rows.slice(2).map(cells)
let t = '
' + head.map((h) => `
${inline(h)}
`).join('') + '
'
for (const r of body) t += '
' + r.map((c) => `
${inline(c)}
`).join('') + '
'
t += '
'
html.push(t)
continue
}
if (/^[-*] /.test(line) || /^\d+\. /.test(line)) {
flushPara()
const ordered = /^\d+\. /.test(line)
const items = []
while (i < lines.length && (/^[-*] /.test(lines[i]) || /^\d+\. /.test(lines[i]))) {
let item = lines[i].replace(/^([-*]|\d+\.) /, '')
i++
while (i < lines.length && /^\s{2,}\S/.test(lines[i])) item += ' ' + lines[i++].trim()
items.push(item)
}
const tag = ordered ? 'ol' : 'ul'
html.push(`<${tag}>` + items.map((it) => `
${inline(it)}
`).join('') + `${tag}>`)
continue
}
if (/^!\[[^\]]*\]\([^)]+\)$/.test(line.trim())) {
flushPara()
const m = line.trim().match(/^!\[([^\]]*)\]\(([^)]+)\)$/)
const data = readFileSync(join(dirname(process.argv[2]), m[2])).toString('base64')
html.push(``)
i++
continue
}
if (line.trim() === '---') { flushPara(); html.push(''); i++; continue }
if (line.trim() === '') { flushPara(); i++; continue }
if (titleLine !== null && subtitle === null && line.startsWith('**')) { subtitle = line.replace(/\*\*/g, ''); i++; continue }
if (subtitle !== null && meta === null && line.startsWith('*')) { meta = line.replace(/^\*|\*$/g, ''); i++; continue }
para.push(line.trim())
i++
}
flushPara()
// drop the first hr (after meta)
const firstHr = html.indexOf('')
if (firstHr === 0) html.splice(0, 1)
const metaParts = (meta || '').split('·').map((s) => s.trim())
const page = `${process.env.PAGE_LANG ? `` : ''}${process.env.PAGE_TITLE || 'VPP AI Platform Architecture'}