mathpix-markdown-it
Version:
Mathpix-markdown-it is an open source implementation of the mathpix-markdown spec written in Typescript. It relies on the following open source libraries: MathJax v3 (to render math with SVGs), markdown-it (for standard Markdown parsing)
165 lines • 7.95 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeLatexLstlistingEnvRendererWithMd = void 0;
var tslib_1 = require("tslib");
var escapeHtml = require('markdown-it/lib/common/utils').escapeHtml;
var NEWLINE_RE = /\r?\n/g;
/**
* Render a code token (block or inline) with optional syntax highlighting and math-aware children.
*
* Behavior:
* - If the token has `children`, iterates through them:
* - `text` children are highlighted with `md.options.highlight(langName)` when available,
* otherwise HTML-escaped.
* - non-`text` children are rendered via `md.renderer.renderInline` (e.g., math spans),
* while their plain-text projections are taken from `child.ascii*` fields.
* - If the token has no `children`, highlights/escapes `token.content` as a single chunk.
* - Builds plain-text TSV/CSV strings from the rendered pieces (newlines are replaced with spaces)
* and stores them into `token.tsv` / `token.csv` (arrays with a single string).
*
* Notes:
* - The function mutates `token.tsv` and `token.csv`.
* - If the highlighter throws or returns a falsy value, the raw text is HTML-escaped.
*
* @param token Markdown-It token representing the code fragment.
* @param md Markdown-It instance (used for highlighting and rendering).
* @param langName Language name passed to the highlighter (may be empty).
* @param options Renderer options forwarded to `renderInline` for non-text children.
* @param env Rendering environment forwarded to `renderInline`.
* @returns HTML string produced from the token content (children-aware).
*/
var renderCodeWithMathHighlighted = function (token, md, langName, options, env) {
var e_1, _a;
var _b, _c, _d, _e, _f, _g, _h, _j, _k;
if (options === void 0) { options = {}; }
if (env === void 0) { env = {}; }
var children = (_b = token.children) !== null && _b !== void 0 ? _b : [];
var partsHtml = [];
var partsTsv = [];
var partsCsv = [];
if (children.length > 0) {
try {
for (var children_1 = tslib_1.__values(children), children_1_1 = children_1.next(); !children_1_1.done; children_1_1 = children_1.next()) {
var child = children_1_1.value;
if (child.type === 'text') {
var raw = (_c = child.content) !== null && _c !== void 0 ? _c : '';
try {
var highlighted = (((_d = md.options) === null || _d === void 0 ? void 0 : _d.highlight) && typeof md.options.highlight === 'function')
? (md.options.highlight(raw, langName) || escapeHtml(raw)) // <-- raw code в highlight
: escapeHtml(raw);
partsHtml.push(highlighted);
}
catch (_l) {
partsHtml.push(escapeHtml(raw));
}
partsTsv.push(raw);
partsCsv.push(raw);
}
else {
var mathHtml = md.renderer.renderInline([child], options, env);
if ((options === null || options === void 0 ? void 0 : options.forDocx) && mathHtml) {
mathHtml = mathHtml
.split(/\r?\n/)
.map(function (line) { return line.trim(); })
.join('');
}
partsHtml.push(mathHtml);
partsTsv.push((_f = (_e = child.ascii_tsv) !== null && _e !== void 0 ? _e : child.ascii) !== null && _f !== void 0 ? _f : '');
partsCsv.push((_h = (_g = child.ascii_csv) !== null && _g !== void 0 ? _g : child.ascii) !== null && _h !== void 0 ? _h : '');
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
}
finally { if (e_1) throw e_1.error; }
}
}
else {
var raw = (_j = token.content) !== null && _j !== void 0 ? _j : '';
var highlighted = (((_k = md.options) === null || _k === void 0 ? void 0 : _k.highlight) && typeof md.options.highlight === 'function')
? (md.options.highlight(raw, langName) || escapeHtml(raw)) // <-- raw code в highlight
: escapeHtml(raw);
partsHtml.push(highlighted);
partsTsv.push(raw);
partsCsv.push(raw);
}
var tsv = partsTsv.join('').replace(NEWLINE_RE, ' ');
var csv = partsCsv.join('').replace(NEWLINE_RE, ' ');
token.tsv = [tsv];
token.csv = [csv];
var html = partsHtml.join('');
if (options.forPptx) {
return html.replace(NEWLINE_RE, '<br><span class="br-break"></span>');
}
return html;
};
/**
* Create a Markdown-It renderer for LaTeX `lstlisting` environments.
*
* Behavior:
* - Always delegates rendering of the token content to `renderCodeWithMathHighlighted`
* (handles both plain code and tokens with math-aware children; also builds TSV/CSV).
* - If the returned HTML starts with a full `<pre...>` block (e.g. provided by an external highlighter),
* it is returned as-is with a trailing newline.
* - Otherwise, the result is wrapped into `<pre><code ...>` and a language class
* `options.langPrefix + langName` is gently injected by cloning token attrs (the original token is not mutated).
*
* @param md Markdown-It instance (used for highlighting and rendering).
* @returns A renderer function `(tokens, idx, options, env, slf) => string` for `latex_lstlisting_env`.
*/
var makeLatexLstlistingEnvRendererWithMd = function (md) {
return function (tokens, idx, options, env, slf) {
var _a, _b, _c;
if (options === void 0) { options = {}; }
if (env === void 0) { env = {}; }
var token = tokens[idx];
var langName = (_c = (_b = (_a = token.meta) === null || _a === void 0 ? void 0 : _a.language) === null || _b === void 0 ? void 0 : _b.hlName) !== null && _c !== void 0 ? _c : '';
var highlighted = renderCodeWithMathHighlighted(token, md, langName, options, env);
if (highlighted.indexOf('<pre') === 0) {
return highlighted + '\n';
}
var styleValue = 'text-align: left;';
// If language exists, inject class gently, without modifying original token.
// May be, one day we will add .clone() for token and simplify this part, but
// now we prefer to keep things local.
var classes = ['lstlisting-code'];
if (langName) {
classes.push(options.langPrefix + langName);
}
var attrs = token.attrs ? token.attrs.map(function (_a) {
var _b = tslib_1.__read(_a, 2), k = _b[0], v = _b[1];
return [k, v];
}) : [];
// handle `class` attribute
var classIndex = token.attrIndex('class');
var className = classes.join(' ');
if (classIndex < 0) {
attrs.push(['class', className]);
}
else {
attrs[classIndex][1] += ' ' + className;
}
// handle `style` attribute (if provided as value)
if (styleValue) {
var styleIndex = token.attrIndex('style');
if (styleIndex < 0) {
attrs.push(['style', styleValue]);
}
else {
attrs[styleIndex][1] += '; ' + styleValue;
}
}
// Fake token just to render attributes
var fakeToken = { attrs: attrs };
return '<pre class="lstlisting"><code'
+ slf.renderAttrs(fakeToken)
+ '>'
+ highlighted
+ '</code></pre>\n';
};
};
exports.makeLatexLstlistingEnvRendererWithMd = makeLatexLstlistingEnvRendererWithMd;
//# sourceMappingURL=render-latex-lstlisting-env.js.map