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)
300 lines • 13.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AddTdSubTable = exports.AddTd = exports.addHLineIntoStyle = exports.addStyle = exports.setColumnLines = exports.SHARED_TBODY_CLOSE = exports.SHARED_TABLE_CLOSE = exports.SHARED_TR_CLOSE = exports.SHARED_TD_CLOSE = exports.getSharedTrOpenAttrs = exports.getSharedTbodyOpenAttrs = exports.getSharedTableOpenAttrs = exports.clearColumnStyleCache = void 0;
var tslib_1 = require("tslib");
var utils_1 = require("../../utils");
var sub_code_1 = require("./sub-code");
var consts_1 = require("../../common/consts");
// Pre-interned border styles — only ~8 unique values per orientation,
// share one instance across every <td> instead of reallocating per call.
var V_LEFT_NONE = 'border-left: none !important; ';
var V_LEFT_SOLID = 'border-left-style: solid !important; border-left-width: 1px !important; ';
var V_LEFT_DOUBLE = 'border-left-style: double !important; border-left-width: 3px !important; ';
var V_LEFT_DASHED = 'border-left-style: dashed !important; border-left-width: 1px !important; ';
var V_RIGHT_NONE = 'border-right: none !important; ';
var V_RIGHT_SOLID = 'border-right-style: solid !important; border-right-width: 1px !important; ';
var V_RIGHT_DOUBLE = 'border-right-style: double !important; border-right-width: 3px !important; ';
var V_RIGHT_DASHED = 'border-right-style: dashed !important; border-right-width: 1px !important; ';
var H_TOP_NONE = 'border-top: none !important; ';
var H_TOP_SOLID = 'border-top-style: solid !important; border-top-width: 1px !important; ';
var H_TOP_DOUBLE = 'border-top-style: double !important; border-top-width: 3px !important; ';
var H_TOP_DASHED = 'border-top-style: dashed !important; border-top-width: 1px !important; ';
var H_BOTTOM_NONE = 'border-bottom: none !important; ';
var H_BOTTOM_SOLID = 'border-bottom-style: solid !important; border-bottom-width: 1px !important; ';
var H_BOTTOM_DOUBLE = 'border-bottom-style: double !important; border-bottom-width: 3px !important; ';
var H_BOTTOM_DASHED = 'border-bottom-style: dashed !important; border-bottom-width: 1px !important; ';
var verticalCellLine = function (line, pos) {
if (pos === void 0) { pos = 'left'; }
var lines = line.split(' ');
var isLeft = pos === 'left';
if (lines.length > 1) {
return isLeft ? V_LEFT_DOUBLE : V_RIGHT_DOUBLE;
}
switch (lines[0]) {
case '':
return '';
case 'none':
return isLeft ? V_LEFT_NONE : V_RIGHT_NONE;
case 'solid':
return isLeft ? V_LEFT_SOLID : V_RIGHT_SOLID;
case 'double':
return isLeft ? V_LEFT_DOUBLE : V_RIGHT_DOUBLE;
case 'dashed':
return isLeft ? V_LEFT_DASHED : V_RIGHT_DASHED;
default:
return isLeft ? V_LEFT_SOLID : V_RIGHT_SOLID;
}
};
var horizontalCellLine = function (line, pos) {
if (pos === void 0) { pos = 'bottom'; }
var lines = line.split(' ');
var isTop = pos === 'top';
if (lines.length > 1) {
return isTop ? H_TOP_DOUBLE : H_BOTTOM_DOUBLE;
}
switch (lines[0]) {
case 'none':
return isTop ? H_TOP_NONE : H_BOTTOM_NONE;
case 'hline':
return isTop ? H_TOP_SOLID : H_BOTTOM_SOLID;
case 'hhline':
return isTop ? H_TOP_DOUBLE : H_BOTTOM_DOUBLE;
case 'hdashline':
return isTop ? H_TOP_DASHED : H_BOTTOM_DASHED;
default:
return isTop ? H_TOP_NONE : H_BOTTOM_NONE;
}
};
// Per-parse dedup caches for style strings and <td> attrs arrays. Shared attrs
// are read-only; mutators clone via `attrsSharedMarker` (see tokenAttrSet).
var columnStyleCache = new Map();
var cellAttrsCache = new Map();
var markAttrsShared = function (attrs) {
Object.defineProperty(attrs, consts_1.attrsSharedMarker, {
value: true, enumerable: false, configurable: true, writable: true,
});
return attrs;
};
var clearColumnStyleCache = function () {
columnStyleCache.clear();
cellAttrsCache.clear();
TABLE_OPEN_ATTRS_CACHE.clear();
TBODY_OPEN_ATTRS_CACHE.clear();
TR_OPEN_ATTRS_SHARED = null;
};
exports.clearColumnStyleCache = clearColumnStyleCache;
var internStyle = function (style) {
var cached = columnStyleCache.get(style);
if (cached !== undefined)
return cached;
columnStyleCache.set(style, style);
return style;
};
var composeCellStyle = function (aligns, lines, space) {
var _a = lines.left, left = _a === void 0 ? '' : _a, _b = lines.right, right = _b === void 0 ? '' : _b, _c = lines.bottom, bottom = _c === void 0 ? '' : _c, _d = lines.top, top = _d === void 0 ? '' : _d;
if (!aligns)
aligns = { h: '', v: '', w: '' };
var _e = aligns.h, h = _e === void 0 ? '' : _e, _f = aligns.v, v = _f === void 0 ? '' : _f, _g = aligns.w, w = _g === void 0 ? '' : _g;
var borderLeft = verticalCellLine(left, 'left');
var borderRight = verticalCellLine(right, 'right');
var borderBottom = horizontalCellLine(bottom, 'bottom');
var borderTop = horizontalCellLine(top, 'top');
var textAlign = "text-align: ".concat(h
? h === 'decimal' ? 'center' : h
: 'center', "; ");
var width = '';
if (w) {
width = (0, utils_1.getLatexTextWidth)(w, 1200);
if (!width)
width = "width: ".concat(w, "; ");
}
var vAlign = v ? "vertical-align: ".concat(v, "; ") : '';
var padding = space && space !== 'none' ? "padding-bottom: ".concat(space, " !important;") : '';
var style = textAlign + borderLeft + borderRight + borderBottom + borderTop + width + vAlign + padding;
return internStyle(style);
};
/** Read-only shared attrs keyed by (style, isEmpty). Mutators must clone. */
var getSharedCellAttrs = function (style, isEmpty, skipVisual) {
if (skipVisual === void 0) { skipVisual = false; }
// Style and `_empty` class are HTML/CSS-only. XLSX reads style too but
// doesn't set skipVisual, so that path is unaffected.
if (skipVisual)
return undefined;
var key = isEmpty ? style + '\0E' : style;
var cached = cellAttrsCache.get(key);
if (cached)
return cached;
var attrs = isEmpty
? [['style', style], ['class', '_empty']]
: [['style', style]];
markAttrsShared(attrs);
cellAttrsCache.set(key, attrs);
return attrs;
};
// Shared attrs for structural tabular tokens — same values repeat thousands
// of times per doc.
var TABLE_OPEN_ATTRS_CACHE = new Map();
var TBODY_OPEN_ATTRS_CACHE = new Map();
var TR_OPEN_ATTRS_SHARED = null;
var TR_OPEN_STYLE = 'border-top: none !important; border-bottom: none !important;';
var getSharedTableOpenAttrs = function (extraClass, skipVisual) {
if (skipVisual === void 0) { skipVisual = false; }
// class='tabular' is HTML-only (used for table detection by DOCX/PPTX builders).
// Under skipVisual, keep only data-type (non-visual subtable marker).
if (skipVisual && !extraClass)
return undefined;
var key = (skipVisual ? 'v:' : '') + (extraClass || '');
var cached = TABLE_OPEN_ATTRS_CACHE.get(key);
if (cached)
return cached;
var attrs = skipVisual
? [['data-type', extraClass]]
: (extraClass
? [['class', 'tabular'], ['data-type', extraClass]]
: [['class', 'tabular']]);
markAttrsShared(attrs);
TABLE_OPEN_ATTRS_CACHE.set(key, attrs);
return attrs;
};
exports.getSharedTableOpenAttrs = getSharedTableOpenAttrs;
var getSharedTbodyOpenAttrs = function (numCol) {
var key = numCol.toString();
var cached = TBODY_OPEN_ATTRS_CACHE.get(key);
if (cached)
return cached;
var attrs = [['data_num_col', key]];
markAttrsShared(attrs);
TBODY_OPEN_ATTRS_CACHE.set(key, attrs);
return attrs;
};
exports.getSharedTbodyOpenAttrs = getSharedTbodyOpenAttrs;
var getSharedTrOpenAttrs = function (skipVisual) {
if (skipVisual === void 0) { skipVisual = false; }
// tr_open.style is the HTML border-reset — no MD/LaTeX/XLSX consumer.
if (skipVisual)
return undefined;
if (TR_OPEN_ATTRS_SHARED)
return TR_OPEN_ATTRS_SHARED;
var attrs = [['style', TR_OPEN_STYLE]];
markAttrsShared(attrs);
TR_OPEN_ATTRS_SHARED = attrs;
return attrs;
};
exports.getSharedTrOpenAttrs = getSharedTrOpenAttrs;
// Frozen shared close-tokens. SHARED_TBODY_CLOSE only when !forLatex (forLatex carries per-table `latex` payload).
exports.SHARED_TD_CLOSE = Object.freeze({
token: 'td_close', type: 'td_close', tag: 'td', n: -1,
});
exports.SHARED_TR_CLOSE = Object.freeze({
token: 'tr_close', type: 'tr_close', tag: 'tr', n: -1,
});
exports.SHARED_TABLE_CLOSE = Object.freeze({
token: 'table_close', type: 'table_close', tag: 'table', n: -1,
});
exports.SHARED_TBODY_CLOSE = Object.freeze({
token: 'tbody_close', type: 'tbody_close', tag: 'tbody', n: -1,
});
// Legacy entry point: callers that build their own attrs array (AddTdSubTable,
// multi-column paths) still use this — hot <td> path uses getSharedCellAttrs.
var setColumnLines = function (aligns, lines) {
var style = composeCellStyle(aligns, lines, '');
return ['style', style];
};
exports.setColumnLines = setColumnLines;
var addStyle = function (attrs, style) {
// Clone-on-write: shared attrs (from the per-parse cache) are read-only.
// Clone the outer array AND each inner [name, value] tuple, because
// `attrs[i][1] += style` below would otherwise mutate the cached tuple.
// Array.isArray guard: legacy callers may pass mixed-shape attrs; preserve non-tuple items as-is.
if (attrs && attrs[consts_1.attrsSharedMarker]) {
attrs = attrs.map(function (pair) { return Array.isArray(pair) ? [pair[0], pair[1]] : pair; });
}
var index = attrs.findIndex(function (item) { return item[0] === 'style'; });
if (index >= 0) {
attrs[index][1] += style;
}
else {
attrs.push(['style', style]);
}
return attrs;
};
exports.addStyle = addStyle;
var addHLineIntoStyle = function (attrs, line, pos) {
if (line === void 0) { line = ''; }
if (pos === void 0) { pos = 'bottom'; }
var style = horizontalCellLine(line, pos);
return (0, exports.addStyle)(attrs, style);
};
exports.addHLineIntoStyle = addHLineIntoStyle;
var AddTd = function (content, aligns, lines, space, decimal, skipVisual, meta) {
if (decimal === void 0) { decimal = null; }
if (skipVisual === void 0) { skipVisual = false; }
var res = [];
var style = skipVisual ? '' : composeCellStyle(aligns, lines, space);
content = content.replace(consts_1.preserveNewlineUnlessDoubleAngleUuidRegex, ' ');
content = (0, sub_code_1.getExtractedCodeBlockContent)(content, 0);
var attrs = getSharedCellAttrs(style, !content, skipVisual);
var tdOpen = { token: 'td_open', type: 'td_open', tag: 'td', n: 1, attrs: attrs };
if (meta)
tdOpen.meta = meta;
res.push(tdOpen);
if (content) {
if (decimal && parseFloat(content)) {
var arr = content.split('.');
var fr = (arr[1] ? new Array(decimal.r - arr[1].length).fill(0) : new Array(decimal.r).fill(0)).join('');
var fl = (arr[0] ? new Array(decimal.l - arr[0].length).fill(0) : new Array(decimal.l).fill(0)).join('');
if (arr[1]) {
res.push({ token: 'inline_decimal', type: 'inline_decimal', tag: '', n: 0, content: "".concat(fl, ";").concat(content, ";").concat(fr),
ascii: content,
ascii_tsv: content,
ascii_csv: content,
ascii_md: content,
latex: content });
}
else {
res.push({ token: 'inline_decimal', type: 'inline_decimal', tag: '', n: 0, content: "".concat(fl, ";").concat(content, ";.").concat(fr),
ascii: content,
ascii_tsv: content,
ascii_csv: content,
ascii_md: content,
latex: content });
}
}
else {
res.push({ token: 'inline', type: 'inline', tag: '', n: 0, content: content });
}
}
res.push(exports.SHARED_TD_CLOSE);
return { res: res, content: content };
};
exports.AddTd = AddTd;
var AddTdSubTable = function (subTable, aligns, lines, skipVisual, meta) {
var e_1, _a;
if (skipVisual === void 0) { skipVisual = false; }
var res = [];
var attrs;
if (!skipVisual) {
attrs = [(0, exports.setColumnLines)(aligns, lines)];
}
var tdOpen = { token: 'td_open', type: 'td_open', tag: 'td', n: 1, attrs: attrs };
if (meta)
tdOpen.meta = meta;
res.push(tdOpen);
try {
for (var subTable_1 = tslib_1.__values(subTable), subTable_1_1 = subTable_1.next(); !subTable_1_1.done; subTable_1_1 = subTable_1.next()) {
var t = subTable_1_1.value;
res.push(t);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (subTable_1_1 && !subTable_1_1.done && (_a = subTable_1.return)) _a.call(subTable_1);
}
finally { if (e_1) throw e_1.error; }
}
res.push(exports.SHARED_TD_CLOSE);
return res;
};
exports.AddTdSubTable = AddTdSubTable;
//# sourceMappingURL=tabular-td.js.map