UNPKG

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)

499 lines 24.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParseTabular = exports.separateByColumns = void 0; var tslib_1 = require("tslib"); var tabular_td_1 = require("./tabular-td"); var common_1 = require("./common"); var sub_math_1 = require("./sub-math"); var sub_tabular_1 = require("./sub-tabular"); var multi_column_row_1 = require("./multi-column-row"); var sub_cell_1 = require("./sub-cell"); var utils_1 = require("../../utils"); var consts_1 = require("../../common/consts"); // Column spec letters that carry explicit vertical alignment. var EXPLICIT_V_COL_SPEC = 'mpb'; // Frozen: shared by all td_open in a tabular — extend via spread, not in-place. var TD_META_BY_BRACKET = { t: Object.freeze({ parentBracket: 't' }), c: Object.freeze({ parentBracket: 'c' }), b: Object.freeze({ parentBracket: 'b' }), }; /** * Splits a tabular row into columns by unescaped '&' characters. * Escaped '\&' is treated as a literal '&' and does not split columns. */ var separateByColumns = function (str) { // Fast path: no column separators at all if (str.indexOf('&') === -1) { return [str]; } var columns = []; var index = 0; for (var i = 0; i < str.length; i++) { var pos = str.indexOf('&', i); // No more separators found if (pos === -1) { break; } // Skip escaped '&' (e.g. '\&') if ((0, utils_1.isEscapedAt)(str, pos)) { i = pos; continue; } // Unescaped '&' splits the column columns.push(str.slice(index, pos)); index = pos + 1; i = pos; } // Always push the remaining tail (may be empty if string ends with '&') columns.push(str.slice(index)); return columns; }; exports.separateByColumns = separateByColumns; var getNumCol = function (cells) { var res = 0; for (var i = 0; i < cells.length; i++) { var columns = (0, exports.separateByColumns)(cells[i]); var col = columns.length; for (var j = 0; j < columns.length; j++) { col += (0, multi_column_row_1.getMC)(columns[j]); } res = col > res ? col : res; } return res; }; var getRows = function (str) { str = (0, sub_math_1.getSubMath)(str); str = (0, sub_cell_1.getSubDiagbox)(str); return str.split('\\\\'); }; /** * Marks a table column as requiring fixed width if the cell content * contains an inline list environment. */ var markColIfHasList = function (colsToFixWidth, colIndex, content) { if (!content) { return; } if (!(0, common_1.detectLocalBlock)(content)) { return; } colsToFixWidth.add(colIndex); }; var setTokensTabular = function (str, _a) { var _b, _c, _d; var _e = _a === void 0 ? {} : _a, _f = _e.align, align = _f === void 0 ? '' : _f, _g = _e.options, options = _g === void 0 ? {} : _g, _h = _e.isSubTabular, isSubTabular = _h === void 0 ? false : _h, bracket = _e.bracket; var res = []; var rows = getRows(str); var cellsAll = (0, common_1.getCellsAll)(rows); var numCol = getNumCol(cellsAll); var data = (0, common_1.getRowLines)(rows, numCol); var CellsHLines = data.cLines; var CellsHLSpaces = data.cSpaces; var colsToFixWidth = new Set(); var optionBracket = (0, common_1.normalizeDefaultCellVerticalAlign)(options === null || options === void 0 ? void 0 : options.defaultCellVerticalAlign); // For HTML rendering: source bracket OR option (incl. 'c'). var effectiveBracket = bracket !== null && bracket !== void 0 ? bracket : optionBracket; var dataAlign = (0, common_1.getVerticallyColumnAlign)(align, numCol, effectiveBracket); var cLines = (0, common_1.getColumnLines)(align, numCol); var cAlign = dataAlign.cAlign, vAlign = dataAlign.vAlign, cWidth = dataAlign.cWidth, colSpec = dataAlign.colSpec; var decimal = (0, common_1.getDecimal)(cAlign, cellsAll); var _j = options.forLatex, forLatex = _j === void 0 ? false : _j, _k = options.outMath, outMath = _k === void 0 ? {} : _k; var skipVisual = !!(options === null || options === void 0 ? void 0 : options.forMD) || !!forLatex; // Option fallback only at top level — nested keeps source bracket (round-trip). var latexBracket = bracket !== null && bracket !== void 0 ? bracket : (isSubTabular ? undefined : (optionBracket === 'c' ? undefined : optionBracket)); // Parent bracket attached to every td_open under forLatex. var tdMeta = forLatex && latexBracket ? TD_META_BY_BRACKET[latexBracket] : undefined; res.push({ token: 'table_open', type: 'table_open', tag: 'table', n: 1, attrs: (0, tabular_td_1.getSharedTableOpenAttrs)(undefined, skipVisual), latex: forLatex ? align : outMath.include_table_markdown ? cAlign.join('|') : '' }); var tableOpen = res[0]; if (options === null || options === void 0 ? void 0 : options.forPptx) { res.push({ token: 'tbody_open', type: 'tbody_open', tag: 'tbody', n: 1, attrs: (0, tabular_td_1.getSharedTbodyOpenAttrs)(numCol) }); } else { res.push({ token: 'tbody_open', type: 'tbody_open', tag: 'tbody', n: 1 }); } var MR = new Array(numCol).fill(0); var _loop_1 = function (i) { var e_1, _l; if (!cellsAll[i] || cellsAll[i].length === 0) { if (i < cellsAll.length - 1) { res.push({ token: 'tr_open', type: 'tr_open', tag: 'tr', n: 1, attrs: (0, tabular_td_1.getSharedTrOpenAttrs)(skipVisual), latex: forLatex && data && data.sLines && data.sLines.length > i ? data.sLines[i] : '' }); for (var k = 0; k < numCol; k++) { if ((options === null || options === void 0 ? void 0 : options.forPptx) && MR[k] && MR[k] > 0) { MR[k] = MR[k] > 0 ? MR[k] - 1 : 0; continue; } var cRight = k === numCol - 1 ? cLines[cLines.length - 1] : cLines[k + 1]; var cLeft = k === 0 ? cLines[0] : ''; var data_1 = (0, tabular_td_1.AddTd)('', { h: cAlign[k], v: vAlign[k], w: cWidth[k] }, { left: cLeft, right: cRight, bottom: CellsHLines[i + 1] ? CellsHLines[i + 1][k] : 'none', top: i === 0 ? CellsHLines[i] ? CellsHLines[i][k] : 'none' : '' }, CellsHLSpaces[i + 1][k], null, skipVisual, tdMeta); markColIfHasList(colsToFixWidth, k, data_1.content); try { for (var _m = (e_1 = void 0, tslib_1.__values(data_1.res)), _o = _m.next(); !_o.done; _o = _m.next()) { var t = _o.value; res.push(t); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_o && !_o.done && (_l = _m.return)) _l.call(_m); } finally { if (e_1) throw e_1.error; } } } res.push(tabular_td_1.SHARED_TR_CLOSE); } return "continue"; } res.push({ token: 'tr_open', type: 'tr_open', tag: 'tr', n: 1, attrs: (0, tabular_td_1.getSharedTrOpenAttrs)(skipVisual), latex: forLatex && data && data.sLines && data.sLines.length > i ? data.sLines[i] : '' }); var cells = (0, exports.separateByColumns)(cellsAll[i]); var _loop_2 = function (j) { var e_2, _p, e_3, _q, e_4, _r, e_5, _s, e_6, _t; var ic = (0, multi_column_row_1.getCurrentMC)(cells, j); if (ic >= numCol) { return "break"; } if (j >= (cells.length) && ic < numCol) { for (var k = ic; k < numCol; k++) { if (MR[k] && MR[k] > 0) { MR[k] = MR[k] > 0 ? MR[k] - 1 : 0; continue; } var cRight_1 = k === numCol - 1 ? cLines[cLines.length - 1] : cLines[k + 1]; var cLeft_1 = k === 0 ? cLines[0] : ''; var data_2 = (0, tabular_td_1.AddTd)('', { h: cAlign[k], v: vAlign[k], w: cWidth[k] }, { left: cLeft_1, right: cRight_1, bottom: CellsHLines[i + 1] ? CellsHLines[i + 1][k] : 'none', top: i === 0 ? CellsHLines[i] ? CellsHLines[i][k] : 'none' : '' }, CellsHLSpaces[i + 1][k], null, skipVisual, tdMeta); markColIfHasList(colsToFixWidth, k, data_2.content); try { for (var _u = (e_2 = void 0, tslib_1.__values(data_2.res)), _v = _u.next(); !_v.done; _v = _u.next()) { var t = _v.value; res.push(t); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_v && !_v.done && (_p = _u.return)) _p.call(_u); } finally { if (e_2) throw e_2.error; } } } return "break"; } var cRight = ic === numCol - 1 ? cLines[cLines.length - 1] : cLines[ic + 1]; var cLeft = ic === 0 ? cLines[0] : ''; if (cells[j] && cells[j].trim().length > 0) { // Multicol inherits only non-default brackets (option 'middle' stays no-op). var multi = (0, multi_column_row_1.getMultiColumnMultiRow)(cells[j], { lLines: cLines[ic], align: cAlign[ic], rLines: cRight, bracketDefault: latexBracket }, forLatex, options === null || options === void 0 ? void 0 : options.forPptx, skipVisual); if (multi) { var mr = multi.mr > rows.length ? rows.length : multi.mr; var mc = multi.mc > numCol ? numCol : multi.mc; if (mc && mc > 1) { var d = ic - mc + 1; if (MR[d] && MR[d] > 0) { var maxK = mc; for (var k = 0; k < maxK; k++) { MR[d + k] = MR[d + k] > 0 ? MR[d + k] - 1 : 0; if (MR[d + k] > 0) { mc -= 1; } } if (mc < 1) { if (forLatex && multi.latex) { res.push({ token: 'td_skip', type: 'td_skip', tag: 'td', n: -1, latex: multi.latex }); } return "continue"; } } else { MR[ic] = MR[ic] > 0 ? MR[ic] - 1 : 0; } } else { MR[ic] = MR[ic] > 0 ? MR[ic] - 1 : 0; if (MR[ic] && MR[ic] > 0) { if (forLatex) { res.push({ token: 'td_skip', type: 'td_skip', tag: 'td', n: -1, latex: multi && multi.latex ? multi.latex : '' }); } return "continue"; } } MR[ic] = MR[ic] > 0 ? MR[ic] - 1 : 0; if (mr && mr > 0) { if (mc && mc > 1) { var d = ic - mc + 1; for (var k = 0; k < mc; k++) { MR[d + k] = mr; } } else { MR[ic] = mr; } if (mr + i >= rows.length - 1 && !skipVisual) { multi.attrs = (0, tabular_td_1.addHLineIntoStyle)(multi.attrs, CellsHLines[mr + i] ? CellsHLines[mr + i][ic] : 'none'); } } else { if (mc && mc > 1) { var d = ic - mc + 1; for (var k = 0; k < mc; k++) { MR[d + k] = MR[d + k] > 0 ? MR[d + k] - 1 : 0; } ic = d; } else { MR[ic] = MR[ic] > 0 ? MR[ic] - 1 : 0; } if (MR[ic] && MR[ic] > 0) { if (forLatex) { res.push({ token: 'td_skip', type: 'td_skip', tag: 'td', n: -1, latex: multi && multi.latex ? multi.latex : '' }); } return "continue"; } } if (!skipVisual) { if (i === 0) { multi.attrs = (0, tabular_td_1.addHLineIntoStyle)(multi.attrs, CellsHLines[i] ? CellsHLines[i][ic] : 'none', 'top'); } if (mr && mr > 0) { multi.attrs = (0, tabular_td_1.addHLineIntoStyle)(multi.attrs, CellsHLines[mr + i] ? CellsHLines[mr + i][ic] : 'none'); } else { multi.attrs = (0, tabular_td_1.addHLineIntoStyle)(multi.attrs, CellsHLines[i + 1] ? CellsHLines[i + 1][ic] : 'none'); } } var tdOpen = { token: 'td_open', type: 'td_open', tag: 'td', n: 1, attrs: multi.attrs, latex: forLatex && multi && multi.latex ? multi.latex : '' }; res.push(tdOpen); if (forLatex) { tdOpen.meta = tslib_1.__assign(tslib_1.__assign({}, tdMeta), { multi: multi.multi, colCount: numCol, colSpecs: colSpec, currentColIndex: ic, isSubTabular: isSubTabular }); } if (multi.subTable) { if (multi.subTable.some(function (item) { return (0, common_1.detectLocalBlock)(item.content); })) { colsToFixWidth.add(ic); if (forLatex) { tdOpen.meta.forceMultiFixedWidth = true; } } try { for (var _w = (e_3 = void 0, tslib_1.__values(multi.subTable)), _x = _w.next(); !_x.done; _x = _w.next()) { var t = _x.value; res.push(t); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_x && !_x.done && (_q = _w.return)) _q.call(_w); } finally { if (e_3) throw e_3.error; } } } else { if (multi.content) { if ((0, common_1.detectLocalBlock)(multi.content)) { colsToFixWidth.add(ic); if (forLatex) { tdOpen.meta.forceMultiFixedWidth = true; } } res.push({ token: 'inline', type: 'inline', tag: '', n: 0, content: multi.content }); } } res.push(tabular_td_1.SHARED_TD_CLOSE); return "continue"; } MR[ic] = MR[ic] > 0 ? MR[ic] - 1 : 0; if (MR[ic] && MR[ic] > 0) { if (forLatex) { res.push({ token: 'td_skip', type: 'td_skip', tag: 'td', n: -1, latex: multi && multi.latex ? multi.latex : '' }); } return "continue"; } var parseMath = (0, sub_math_1.getMathTableContent)(cells[j], 0); var content = parseMath || (0, common_1.getContent)(cells[j]); var handleSubTable = function (subTable, vOverride) { if (!colsToFixWidth.has(ic) && subTable.some(function (item) { return (0, common_1.detectLocalBlock)(item.content); })) { colsToFixWidth.add(ic); } return (0, tabular_td_1.AddTdSubTable)(subTable, { h: cAlign[ic], v: vOverride, w: cWidth[ic] }, { left: cLeft, right: cRight, bottom: CellsHLines[i + 1] ? CellsHLines[i + 1][ic] : 'none', top: i === 0 ? (CellsHLines[i] ? CellsHLines[i][ic] : 'none') : '' }, skipVisual, tdMeta); }; var parseSub = (0, sub_tabular_1.getSubTabular)(content, 0, true, forLatex); if (parseSub && parseSub.length > 0) { var cellV = vAlign[ic]; // Diagbox always centers, ignoring outer bracket. // getSubTabular returns a single wrapper; hasDiagbox is OR'd across all placeholders. if ((_b = parseSub[0]) === null || _b === void 0 ? void 0 : _b.hasDiagbox) { cellV = 'middle'; // colSpec may be 'p{2cm}'. } else if (!EXPLICIT_V_COL_SPEC.includes(((_c = colSpec[ic]) === null || _c === void 0 ? void 0 : _c[0]) || '')) { // First nested tabular wins if a cell contains several. var placeholder = (_d = content.match(consts_1.doubleAngleBracketUuidPattern)) === null || _d === void 0 ? void 0 : _d[0]; var cellBracket = placeholder ? (0, sub_tabular_1.getSubTabularBracket)(placeholder) : undefined; if (cellBracket) cellV = (0, common_1.bracketToVAlign)(cellBracket); } try { for (var _y = (e_4 = void 0, tslib_1.__values(handleSubTable(parseSub, cellV))), _z = _y.next(); !_z.done; _z = _y.next()) { var t = _z.value; res.push(t); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (_z && !_z.done && (_r = _y.return)) _r.call(_y); } finally { if (e_4) throw e_4.error; } } return "continue"; } var data_3 = (0, tabular_td_1.AddTd)(content, { h: cAlign[ic], v: vAlign[ic], w: cWidth[ic] }, { left: cLeft, right: cRight, bottom: CellsHLines[i + 1] ? CellsHLines[i + 1][ic] : 'none', top: i === 0 ? CellsHLines[i] ? CellsHLines[i][ic] : 'none' : '' }, CellsHLSpaces[i + 1][ic], decimal[ic], skipVisual, tdMeta); markColIfHasList(colsToFixWidth, ic, data_3.content); try { for (var _0 = (e_5 = void 0, tslib_1.__values(data_3.res)), _1 = _0.next(); !_1.done; _1 = _0.next()) { var t = _1.value; res.push(t); } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (_1 && !_1.done && (_s = _0.return)) _s.call(_0); } finally { if (e_5) throw e_5.error; } } } else { MR[ic] = MR[ic] > 0 ? MR[ic] - 1 : 0; if (MR[ic] && MR[ic] > 0) { if (forLatex) { res.push({ token: 'td_skip', type: 'td_skip', tag: 'td', n: -1 }); } return "continue"; } var data_4 = (0, tabular_td_1.AddTd)('', { h: cAlign[ic], v: vAlign[ic], w: cWidth[ic] }, { left: cLeft, right: cRight, bottom: CellsHLines[i + 1] ? CellsHLines[i + 1][ic] : 'none', top: i === 0 ? CellsHLines[i] ? CellsHLines[i][ic] : 'none' : '' }, CellsHLSpaces[i + 1][ic], null, skipVisual, tdMeta); markColIfHasList(colsToFixWidth, ic, data_4.content); try { for (var _2 = (e_6 = void 0, tslib_1.__values(data_4.res)), _3 = _2.next(); !_3.done; _3 = _2.next()) { var t = _3.value; res.push(t); } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (_3 && !_3.done && (_t = _2.return)) _t.call(_2); } finally { if (e_6) throw e_6.error; } } } }; for (var j = 0; j < numCol; j++) { var state_1 = _loop_2(j); if (state_1 === "break") break; } res.push(tabular_td_1.SHARED_TR_CLOSE); }; for (var i = 0; i < rows.length; i++) { _loop_1(i); } if (forLatex) { res.push({ token: 'tbody_close', type: 'tbody_close', tag: 'tbody', n: -1, latex: data && data.sLines && data.sLines.length ? data.sLines[data.sLines.length - 1] : '' }); } else { res.push(tabular_td_1.SHARED_TBODY_CLOSE); } res.push(tabular_td_1.SHARED_TABLE_CLOSE); if (forLatex) { var colsToFixWidthArr = Array.from(colsToFixWidth); tableOpen.meta = { colsToFixWidth: colsToFixWidthArr, colSpecs: colSpec, colCount: numCol, isSubTabular: isSubTabular, vLineSpec: cLines }; if (latexBracket) { tableOpen.meta.bracket = latexBracket; } if (colsToFixWidthArr.length) { tableOpen.meta.shouldRewriteColSpec = (0, common_1.shouldRewriteColSpec)(colsToFixWidthArr, colSpec); } } return res; }; var ParseTabular = function (str, i, align, options, isSubTabular, bracket) { if (align === void 0) { align = ''; } if (options === void 0) { options = {}; } if (isSubTabular === void 0) { isSubTabular = false; } var res = []; var posEnd = str.indexOf('\\end{tabular}'); if (posEnd > 0) { var posBegin = str.slice(i, posEnd).lastIndexOf('\\begin{tabular}'); if (posBegin >= 0) { var params = (0, common_1.getParams)(str, posBegin + '\\begin{tabular}'.length); if (params) { var subT = str.slice(posBegin, posEnd + '\\end{tabular}'.length); str = (0, sub_tabular_1.pushSubTabular)(str, subT, [], posBegin, posEnd, i, 0, params.bracket); res = (0, exports.ParseTabular)(str, 0, align, options, isSubTabular, bracket); } else { var match = str .slice(posBegin) .match(consts_1.BEGIN_TABULAR_BRACKET_RE); var subT = str.slice(posBegin, posEnd + '\\end{tabular}'.length); str = (0, sub_tabular_1.pushSubTabular)(str, subT, [], posBegin + match.index, posEnd, i, 0, (0, common_1.parseTabularPos)(match === null || match === void 0 ? void 0 : match[1])); res = (0, exports.ParseTabular)(str, 0, align, options, isSubTabular, bracket); } } else { var subT = str.slice(i, posEnd); var subRes = setTokensTabular(subT, { align: align, options: options, isSubTabular: false, bracket: bracket }); str = (0, sub_tabular_1.pushSubTabular)(str, subT, subRes, 0, posEnd); res = (0, exports.ParseTabular)(str, 0, align, options, isSubTabular, bracket); } } else { res = setTokensTabular(str, { align: align, options: options, isSubTabular: isSubTabular, bracket: bracket }); } return res; }; exports.ParseTabular = ParseTabular; //# sourceMappingURL=parse-tabular.js.map