`)
}
const seenIDs = Object.create(null)
function anchor(token) {
let id = token.hashID
if (!id || id in seenIDs) return ""
seenIDs[id] = true
return ` `
}
function attrs(token) {
return token.attrs ? token.attrs.map(([name, val]) => ` ${name}="${escape(String(val))}"`).join("") : ""
}
let linkedChapter = null
let renderer = {
fence(token) {
let config = /\S/.test(token.info) ? PJSON.parse(token.info) : {}
if (config.hidden) return "";
let lang = config.lang || "javascript"
return `\n\n${anchor(token)}${highlight(lang, token.content.trimRight())} `
},
hardbreak() { return ` ` },
softbreak() { return " " },
text(token) {
let {content} = token
if (linkedChapter != null) content = content.replace(/\?/g, linkedChapter)
return escape(content)
},
paragraph_open(token) { return `\n\n${anchor(token)}` },
paragraph_close() { return "
" },
heading_open(token) { return `\n\n<${token.tag}${attrs(token)}>${anchor(token)}` },
heading_close(token) { return `${token.tag}>` },
bullet_list_open(token) { return `\n\n` },
bullet_list_close() { return ` ` },
ordered_list_open(token) { return `\n\n` },
ordered_list_close() { return `\n\n ` },
list_item_open() { return "\n\n" },
list_item_close() { return " " },
table_open() { return "\n\n" },
table_close() { return "\n\n
" },
tbody_open() { return "" },
tbody_close() { return "" },
tr_open() { return "\n\n" },
tr_close() { return "\n\n " },
td_open() { return "" },
td_close() { return " " },
html_block(token) { return token.content },
code_inline(token) { return `${maybeSplitInlineCode(escape(token.content))}` },
strong_open() { return "" },
strong_close() { return " " },
em_open() { return "" },
em_close() { return " " },
sub_open() { return "" },
sub_close() { return " " },
sup_open() { return "" },
sup_close() { return " " },
link_open(token) {
let alt = token.attrGet("alt"), href= token.attrGet("href")
let maybeChapter = /^(\w+)(#.*)?$/.exec(href)
if (maybeChapter && chapters.includes(maybeChapter[1])) {
let number = ""
if (maybeChapter[1] != "hints") {
linkedChapter = chapters.indexOf(maybeChapter[1])
number = pad(linkedChapter) + "_"
}
href = number + maybeChapter[1] + (epub ? ".xhtml" : ".html") + (maybeChapter[2] || "")
}
return ``
},
link_close() { linkedChapter = null; return " " },
inline(token) { return renderArray(token.children) },
meta_figure(token) {
let {url, alt, chapter} = token.args[0]
let className = !chapter ? null : "chapter" + (chapter == "true" ? "" : " " + chapter)
return ` `
},
meta_quote_open() { return "\n\n" },
meta_quote_close(token) {
let {author, title} = token.args[0] || {}
return (author ? `\n\n${escape(author)}${title ? `, ${escape(title)} ` : ""} ` : "") +
"\n\n "
},
meta_keyname_open() { return "" },
meta_keyname_close() { return " " },
meta_hint_open() { return "\n\n" },
meta_hint_close() { return "\n\n
" }
}
function renderArray(tokens) {
let result = ""
for (let i = 0; i < tokens.length; i++) {
let token = tokens[i], f = renderer[token.type]
if (!f) throw new Error("No render function for " + token.type)
result += f(token)
}
return result
}
function pad(n) {
return (n < 10 ? "0" : "") + n
}
metadata.content = renderArray(tokens)
let index
if (chapter && (index = chapters.indexOf(chapter[1])) > -1) {
metadata.chap_num = index
if (index > 0) metadata.prev_link = `${pad(index - 1)}_${chapters[index - 1]}`
if (index < chapters.length - 1) metadata.next_link = `${pad(index + 1)}_${chapters[index + 1]}`
}
let template = mold.bake("chapter", fs.readFileSync(__dirname + `/${epub ? "epub_" : ""}chapter.html`, "utf8"))
console.log(template(metadata))