UNPKG

@vivliostyle/vfm

Version:

Custom Markdown syntax specialized in book authoring.

96 lines (95 loc) 2.98 kB
import { select, selectAll } from 'hast-util-select'; import footnotes from 'remark-footnotes'; /** * Replace the footnote link with Pandoc format. * @param tree Tree of Hypertext AST. */ const replaceFootnoteLinks = (tree) => { const sups = selectAll('sup[id^="fnref-"]', tree).filter((node) => node.children.length === 1 && node.children[0].tagName === 'a'); for (let i = 0; i < sups.length; ++i) { const parent = sups[i]; const refIndex = i + 1; parent.tagName = 'a'; parent.properties = { id: `fnref${refIndex}`, href: `#fn${refIndex}`, className: ['footnote-ref'], role: 'doc-noteref', }; const child = parent.children[0]; child.tagName = 'sup'; child.properties = {}; child.children = [{ type: 'text', value: `${refIndex}` }]; } }; /** * Check if it has a class name as a back reference. * @param className Array of class names. * @returns `true` for back reference, `false` otherwise. */ const hasBackReferenceClass = (className) => { if (Array.isArray(className)) { for (const name of className) { if (name === 'footnote-backref') { return true; } } } return false; }; /** * Replace back reference with Pandoc format. * @param elements Children elements of footnote. * @param index Index of footnote. */ const replaceBackReference = (elements, index) => { for (const element of elements) { if (element.type === 'element' && element.tagName === 'a' && element.properties && hasBackReferenceClass(element.properties.className)) { element.properties.href = `#fnref${index}`; element.properties.className = ['footnote-back']; element.properties.role = 'doc-backlink'; // Back reference is only one break; } } }; /** * Replace the footnote with Pandoc format. * @param tree Tree of Hypertext AST. */ const replaceFootnotes = (tree) => { const area = select('div.footnotes', tree); if (area && area.properties) { area.tagName = 'section'; area.properties.role = 'doc-endnotes'; } else { return; } const items = selectAll('section.footnotes ol li', tree); for (let i = 0; i < items.length; ++i) { const item = items[i]; if (!item.properties) { continue; } const refIndex = i + 1; item.properties.id = `fn${refIndex}`; item.properties.role = 'doc-endnote'; replaceBackReference(item.children, refIndex); } }; /** * Process Markdown AST. */ export const mdast = [footnotes, { inlineNotes: true }]; /** * Process math related Hypertext AST. * Resolves HTML diffs between `remark-footnotes` and Pandoc footnotes. */ export const hast = () => (tree) => { replaceFootnoteLinks(tree); replaceFootnotes(tree); };