103 lines
2.7 KiB
JavaScript
Raw Normal View History

2025-02-28 19:43:11 +08:00
'use strict';
function markedHighlight(options) {
if (typeof options === 'function') {
options = {
highlight: options,
};
}
if (!options || typeof options.highlight !== 'function') {
throw new Error('Must provide highlight function');
}
if (typeof options.langPrefix !== 'string') {
options.langPrefix = 'language-';
}
if (typeof options.emptyLangClass !== 'string') {
options.emptyLangClass = '';
}
return {
async: !!options.async,
walkTokens(token) {
if (token.type !== 'code') {
return;
}
const lang = getLang(token.lang);
if (options.async) {
return Promise.resolve(options.highlight(token.text, lang, token.lang || '')).then(updateToken(token));
}
const code = options.highlight(token.text, lang, token.lang || '');
if (code instanceof Promise) {
throw new Error('markedHighlight is not set to async but the highlight function is async. Set the async option to true on markedHighlight to await the async highlight function.');
}
updateToken(token)(code);
},
useNewRenderer: true,
renderer: {
code(code, infoString, escaped) {
// istanbul ignore next
if (typeof code === 'object') {
escaped = code.escaped;
infoString = code.lang;
code = code.text;
}
const lang = getLang(infoString);
const classValue = lang ? options.langPrefix + escape(lang) : options.emptyLangClass;
const classAttr = classValue
? ` class="${classValue}"`
: '';
code = code.replace(/\n$/, '');
return `<pre><code${classAttr}>${escaped ? code : escape(code, true)}\n</code></pre>`;
},
},
};
}
function getLang(lang) {
return (lang || '').match(/\S*/)[0];
}
function updateToken(token) {
return (code) => {
if (typeof code === 'string' && code !== token.text) {
token.escaped = true;
token.text = code;
}
};
}
// copied from marked helpers
const escapeTest = /[&<>"']/;
const escapeReplace = new RegExp(escapeTest.source, 'g');
const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');
const escapeReplacements = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
};
const getEscapeReplacement = (ch) => escapeReplacements[ch];
function escape(html, encode) {
if (encode) {
if (escapeTest.test(html)) {
return html.replace(escapeReplace, getEscapeReplacement);
}
} else {
if (escapeTestNoEncode.test(html)) {
return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
}
}
return html;
}
exports.markedHighlight = markedHighlight;