markdown-to-standalone-html
Version:
Markdown to standalone HTML converter. It generates a standalone HTML with all CSS and images embedded, browsable responsible TOC, math support (KATEX), code syntax highlighting (highlight.js), and rendering of lyrics with chords
121 lines • 6.39 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const markdown_it_1 = __importDefault(require("markdown-it"));
const markdown_it_implicit_figures_1 = __importDefault(require("markdown-it-implicit-figures"));
const html_minifier_1 = require("html-minifier");
const highlight_js_1 = __importDefault(require("highlight.js"));
const markdown_it_anchor_1 = __importDefault(require("markdown-it-anchor"));
const uslug_1 = __importDefault(require("uslug"));
const markdown_toc_1 = __importDefault(require("markdown-toc"));
const markdown_it_embedded_images_1 = __importDefault(require("./plugins/markdown-it-embedded-images"));
const markdown_it_katex_1 = __importDefault(require("@traptitech/markdown-it-katex"));
const markdown_it_code_chords_1 = __importDefault(require("./plugins/markdown-it-code-chords"));
const markdown_it_chordsong_1 = __importDefault(require("./plugins/markdown-it-chordsong"));
async function markdownToStandAloneHtml(mdContents, { basePath = '.', template = path_1.default.resolve(__dirname, '..', 'templates', 'template.html'), plugins = [] }) {
const mdItOptions = {
html: true,
xhtmlOut: false,
breaks: false,
langPrefix: 'language-',
linkify: false,
typographer: false,
quotes: '“”‘’'
};
const cssArr = [];
const scriptArr = [];
let plugin = plugins.find(plugin => plugin.name === 'highlightjs');
if (plugin !== undefined) {
mdItOptions.highlight = function (str, language) {
if (language !== undefined && highlight_js_1.default.getLanguage(language) !== undefined) {
try {
return '<pre><code class="hljs">' +
highlight_js_1.default.highlight(str, { language, ignoreIllegals: true }).value +
'</code></pre>';
}
catch (__) { }
}
return '<pre><code class="hljs">' + md.utils.escapeHtml(str) + '</code></pre>';
};
cssArr.push(fs_1.default.readFileSync(require.resolve(`highlight.js/styles/${plugin.options.theme}.css`), 'utf8'));
}
const md = (0, markdown_it_1.default)(mdItOptions);
md.use(markdown_it_implicit_figures_1.default, {
dataType: false,
figcaption: false,
tabindex: false,
link: false
});
let templateStr;
if (template.length > 8 && template.slice(-9) === '.toc.html') {
template = template.slice(0, template.length - 9) + '.html';
}
plugin = plugins.find(plugin => plugin.name === 'toc');
if (plugin !== undefined) {
const templateFileWithToc = path_1.default.join(path_1.default.dirname(template), `${path_1.default.basename(template, '.html')}.toc.html`);
if (!fs_1.default.existsSync(templateFileWithToc)) {
throw new Error(`Can't find template file '${templateFileWithToc}'`);
}
templateStr = fs_1.default.readFileSync(templateFileWithToc, 'utf8');
md.use(markdown_it_anchor_1.default, { level: 2, slugify: uslug_1.default });
const tocContents = md.render((0, markdown_toc_1.default)(mdContents, { firsth1: false, slugify: uslug_1.default, maxdepth: plugin.options.tocMaxDepth }).content);
templateStr = templateStr.replace('<!-- {{TOC_TITLE}} -->', plugin.options.tocTitle)
.replace('<!-- {{TOC}} -->', tocContents);
}
else {
if (!fs_1.default.existsSync(template)) {
throw new Error(`Can't find template file '${template}'`);
}
templateStr = fs_1.default.readFileSync(template, 'utf8');
}
md.use(markdown_it_embedded_images_1.default, basePath);
plugin = plugins.find(plugin => plugin.name === 'katex');
if (plugin !== undefined) {
md.use(markdown_it_katex_1.default, { throwOnError: true });
const cssRegex = /url\((.+?)\) format\(['"](.+?)['"]\)/g;
const cssContents = fs_1.default.readFileSync(require.resolve('katex/dist/katex.css'), 'utf8').replace(cssRegex, (match, p1, p2) => {
const fontFileBuf = fs_1.default.readFileSync(require.resolve(`katex/dist/${p1}`));
return `url(data:font/${p2};base64,${fontFileBuf.toString('base64')})`;
});
cssArr.push(cssContents);
}
plugin = plugins.find(plugin => plugin.name === 'code-chords');
if (plugin !== undefined) {
md.use(markdown_it_code_chords_1.default);
cssArr.push(fs_1.default.readFileSync(require.resolve('markdown-it-chords/markdown-it-chords.css'), 'utf-8'));
}
plugin = plugins.find(plugin => plugin.name === 'chordsong');
if (plugin !== undefined) {
md.use(markdown_it_chordsong_1.default, cssArr);
}
plugin = plugins.find(plugin => plugin.name === 'bootstrapCss');
if (plugin !== undefined) {
cssArr.push(fs_1.default.readFileSync(require.resolve('bootstrap/dist/css/bootstrap.css'), 'utf8'));
}
plugin = plugins.find(plugin => plugin.name === 'bootstrapJs');
if (plugin !== undefined) {
const removeMapRegEx = /\/{2}# sourceMappingURL=\S*/g;
scriptArr.push(fs_1.default.readFileSync(require.resolve('jquery/dist/jquery.slim.min.js'), 'utf8').replace(removeMapRegEx, ''));
scriptArr.push(fs_1.default.readFileSync(require.resolve('bootstrap/dist/js/bootstrap.bundle.min.js'), 'utf8').replace(removeMapRegEx, ''));
}
const main = md.render(mdContents);
const titleRegex = /<h1>(.+?)<\/h1>/s;
const titleMatch = main.match(titleRegex);
const title = (titleMatch !== null) ? titleMatch[1] : 'Readme';
const css = `<style type="text/css">${cssArr.join('\n')}</style>`;
const script = `<script>\n${scriptArr.join('\n</script>\n<script>\n')}\n</script>`;
templateStr = templateStr.replace('<!-- {{CSS}} -->', css)
.replace('<!-- {{MAIN}} -->', main)
.replace('<!-- {{TITLE}} -->', title)
.replace('<!-- {{SCRIPT}} -->', script);
const output = (0, html_minifier_1.minify)(templateStr, {
minifyCSS: true
});
return output;
}
exports.default = markdownToStandAloneHtml;
//# sourceMappingURL=index.js.map