117 lines
3.1 KiB
JavaScript
117 lines
3.1 KiB
JavaScript
const fs = require('fs/promises')
|
|
const path = require('path')
|
|
const marked = require('marked')
|
|
const fm = require('front-matter')
|
|
const { highlight, highlightAuto } = require('highlight.js')
|
|
|
|
marked.use({
|
|
highlight: (code, lang) => {
|
|
if (!lang) {
|
|
return highlightAuto(code).value
|
|
}
|
|
return highlight(lang, code).value
|
|
}
|
|
})
|
|
|
|
function tocHTML (toc) {
|
|
let html = '<ul>\n'
|
|
for (const li of toc) {
|
|
html += '<li>\n'
|
|
html += `<div>\n<a href="#${li.slug}">${li.text}</a>\n</div>\n`
|
|
if (li.children && li.children.length > 0) {
|
|
html += tocHTML(li.children)
|
|
}
|
|
html += '</li>\n'
|
|
}
|
|
html += '</ul>\n'
|
|
|
|
return html
|
|
}
|
|
|
|
function markdownTOC (markdown) {
|
|
const tokens = marked.lexer(markdown)
|
|
const slugger = new marked.Slugger()
|
|
const toc = []
|
|
let currentHeading
|
|
let ignoreFirst = true
|
|
for (const token of tokens) {
|
|
if (token.type === 'heading') {
|
|
if (token.depth === 1) {
|
|
if (ignoreFirst) {
|
|
ignoreFirst = false
|
|
continue
|
|
}
|
|
currentHeading = {
|
|
text: token.text,
|
|
slug: slugger.slug(token.text),
|
|
children: []
|
|
}
|
|
toc.push(currentHeading)
|
|
} else if (token.depth === 2) {
|
|
if (!currentHeading) {
|
|
continue
|
|
}
|
|
currentHeading.children.push({
|
|
text: token.text,
|
|
slug: slugger.slug(token.text)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
toc: tocHTML(toc),
|
|
html: marked.parser(tokens)
|
|
}
|
|
}
|
|
|
|
function createHTML (header, footer, text) {
|
|
const { attributes, body } = fm(text)
|
|
for (const prop in attributes) {
|
|
header = header.replace(new RegExp(`%\\(${prop}\\)s`, 'ig'), attributes[prop])
|
|
footer = footer.replace(new RegExp(`%\\(${prop}\\)s`, 'ig'), attributes[prop])
|
|
}
|
|
|
|
const { toc, html } = markdownTOC(body)
|
|
|
|
header = header.replace(/%\(toc_html\)s/ig, toc)
|
|
|
|
return header + html + footer
|
|
}
|
|
|
|
async function createDocs () {
|
|
const docs = path.resolve(__dirname, '..', 'docs')
|
|
const dist = path.resolve(__dirname, '..', 'public')
|
|
const branding = path.join(docs, 'branding')
|
|
|
|
await fs.rmdir(dist, { recursive: true })
|
|
await fs.mkdir(dist)
|
|
|
|
const header = await fs.readFile(path.join(branding, 'header.html.in'), { encoding: 'utf8' })
|
|
const footer = await fs.readFile(path.join(branding, 'footer.html.in'), { encoding: 'utf8' })
|
|
const files = await fs.readdir(docs)
|
|
for (const file of files) {
|
|
if (!file.endsWith('.md')) {
|
|
continue
|
|
}
|
|
const text = await fs.readFile(path.join(docs, file), { encoding: 'utf8' })
|
|
const html = createHTML(header, footer, text)
|
|
|
|
await fs.writeFile(path.join(dist, file.replace(/md$/, 'html')), html)
|
|
}
|
|
|
|
const dest = path.join(dist, 'media')
|
|
const src = path.join(branding, 'media')
|
|
await fs.mkdir(dest)
|
|
await fs.mkdir(path.join(dest, 'css'))
|
|
await fs.mkdir(path.join(dest, 'img'))
|
|
await fs.copyFile(path.join(src, 'css', 'style.css'), path.join(dest, 'css', 'style.css'))
|
|
await fs.copyFile(path.join(src, 'img', 'logo.svg'), path.join(dest, 'img', 'logo.svg'))
|
|
await fs.copyFile(path.join(branding, 'CNAME'), path.join(dist, 'CNAME'))
|
|
}
|
|
|
|
createDocs().catch(ex => {
|
|
console.error(ex)
|
|
process.exit(1)
|
|
})
|