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)
179 lines • 7.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSubMath = exports.getMathTableContent = exports.mathTablePush = exports.ClearSubMathLists = void 0;
var common_1 = require("./common");
var mdPluginRaw_1 = require("../../mdPluginRaw");
var utils_1 = require("../../utils");
var sub_code_1 = require("./sub-code");
var consts_1 = require("../../common/consts");
var RE_MATH_OPEN = /\\\\\[|\\\[|\\\\\(|\\\(|\$\$|\$|\\begin\{([^}]*)\}|eqref\{([^}]*)\}|ref\{([^}]*)\}/;
// Shared `/g`-flag scanner reused across calls — getSubMath is not reentrant
// (no recursion, no callbacks out), so we just reset lastIndex on entry.
var RE_MATH_OPEN_G = new RegExp(RE_MATH_OPEN.source, 'g');
var mathTable = new Map();
var ClearSubMathLists = function () {
mathTable.clear();
};
exports.ClearSubMathLists = ClearSubMathLists;
var mathTablePush = function (idOrItem, content) {
if (typeof idOrItem === 'string') {
mathTable.set(idOrItem, content);
}
else {
mathTable.set(idOrItem.id, idOrItem.content);
}
};
exports.mathTablePush = mathTablePush;
/** Replace UUID placeholders with original math content.
* Uses trimmed string for regex matching (consistent with getSubMath),
* but untrimmed sub for slicing to preserve original whitespace. */
var getMathTableContent = function (sub, i) {
var tail = sub.trim().slice(i);
var cellM = tail.match(consts_1.doubleCurlyBracketUuidPattern);
cellM = cellM ? cellM : tail.match(consts_1.singleCurlyBracketPattern);
if (!cellM) {
return '';
}
var parts = [];
var lastIdx = 0;
for (var j = 0; j < cellM.length; j++) {
var id = cellM[j].replace(/\{/g, '').replace(/\}/g, '');
var mathContent = mathTable.get(id);
if (mathContent !== undefined) {
var iB = sub.indexOf(cellM[j], lastIdx);
if (iB >= 0) {
parts.push(sub.slice(lastIdx, iB));
parts.push(mathContent);
lastIdx = iB + cellM[j].length;
}
}
}
if (parts.length === 0) {
return (0, common_1.getContent)(sub);
}
parts.push(sub.slice(lastIdx));
return (0, common_1.getContent)(parts.join(''));
};
exports.getMathTableContent = getMathTableContent;
/**
* Returns the end marker for a matched opening marker.
* - string: end marker to search for (e.g. "\\]", "$")
* - null: self-closing match (eqref/ref) — no end marker needed, content = match itself
* - undefined: \begin{env} — caller must resolve via balanced tag search
*/
var getEndMarker = function (matchStr, envGroup, eqrefGroup, refGroup) {
if (matchStr === "\\\\[")
return "\\\\]";
if (matchStr === "\\[")
return "\\]";
if (matchStr === "\\\\(")
return "\\\\)";
if (matchStr === "\\(")
return "\\)";
if (eqrefGroup !== undefined || refGroup !== undefined)
return null;
if (matchStr === "$$")
return "$$";
if (matchStr === "$")
return "$";
return undefined;
};
var shouldSkipDollar = function (str, marker, beginMarkerPos, endMarkerPos) {
var beforeEnd = str.charCodeAt(endMarkerPos - 1);
if (beforeEnd === 0x5c ||
(beginMarkerPos > 0 && str.charCodeAt(beginMarkerPos - 1) === 0x5c)) {
return true;
}
if (marker === "$") {
var afterStart = str.charCodeAt(beginMarkerPos + 1);
if (beforeEnd === 0x20 || beforeEnd === 0x09 || beforeEnd === 0x0a ||
afterStart === 0x20 || afterStart === 0x09 || afterStart === 0x0a) {
return true;
}
}
var suffix = str.charCodeAt(endMarkerPos + 1);
if (suffix >= 0x30 && suffix < 0x3a) {
return true;
}
return false;
};
/**
* Extract math expressions from a string, replacing them with placeholders.
* Iterative single-pass: scans the original string once, collects non-math
* segments and placeholders into an array, joins at the end.
*
* `startPos` is a seek offset applied via `re.lastIndex` before scanning.
*/
var getSubMath = function (str, startPos) {
var _a;
if (startPos === void 0) { startPos = 0; }
var re = RE_MATH_OPEN_G;
re.lastIndex = startPos > 0 ? startPos : 0;
var parts = [];
var lastCopied = 0;
var match;
while ((match = re.exec(str)) !== null) {
var beginMarkerPos = match.index;
var startMathPos = beginMarkerPos + match[0].length;
var envGroup = match[1];
var endMarker = getEndMarker(match[0], envGroup, match[2], match[3]);
var endMarkerPos = -1;
if (endMarker === null) {
endMarkerPos = startMathPos;
endMarker = '';
}
else if (endMarker === undefined) {
if (envGroup && envGroup !== 'abstract' && envGroup !== 'tabular') {
var environment = envGroup.trim();
var openTag = (0, utils_1.beginTag)(environment, true);
var closeTag = (0, utils_1.endTag)(environment, true);
if (closeTag && openTag) {
var data = (0, utils_1.findOpenCloseTagsMathEnvironment)(str.slice(beginMarkerPos), openTag, closeTag);
var lastClose = ((_a = data === null || data === void 0 ? void 0 : data.arrClose) === null || _a === void 0 ? void 0 : _a.length) ? data.arrClose[data.arrClose.length - 1] : null;
if (lastClose && typeof lastClose.posStart === 'number') {
endMarkerPos = beginMarkerPos + lastClose.posStart;
}
endMarker = "\\end{".concat(envGroup, "}");
}
}
if (endMarker === undefined) {
continue;
}
}
if (endMarkerPos === -1) {
endMarkerPos = (0, mdPluginRaw_1.findEndMarkerPos)(str, endMarker, startMathPos);
}
if (endMarkerPos === -1) {
re.lastIndex = startMathPos;
continue;
}
if (match[0] === "$" || match[0] === "$$") {
if (shouldSkipDollar(str, match[0], beginMarkerPos, endMarkerPos)) {
re.lastIndex = startMathPos;
continue;
}
}
var nextPos = endMarkerPos + endMarker.length;
var content = str.slice(beginMarkerPos, nextPos);
var id = (0, common_1.generateUniqueId)();
var isCodeEnv = !!(envGroup && consts_1.LATEX_BLOCK_ENV.has(envGroup));
if (isCodeEnv) {
(0, sub_code_1.addExtractedCodeBlock)({ id: id, content: content });
}
else {
(0, exports.mathTablePush)(id, content);
}
var placeholder = isCodeEnv ? "<<".concat(id, ">>") : "{".concat(id, "}");
parts.push(str.slice(lastCopied, beginMarkerPos));
parts.push(placeholder);
lastCopied = nextPos;
re.lastIndex = nextPos;
}
if (parts.length === 0) {
return str;
}
parts.push(str.slice(lastCopied));
return parts.join('');
};
exports.getSubMath = getSubMath;
//# sourceMappingURL=sub-math.js.map