From 9ea068bf647afea9f1d1dfb7711ec7d21feca1fa Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 7 Aug 2021 00:48:59 -0400 Subject: [PATCH] Fix catastrophic backtracking and trim starting pipes --- shared/naturalcrit/markdown.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 2a6f0e3b9..01abc33a7 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -240,7 +240,7 @@ const spanTable = { start(src) { return src.match(/^\n *([^\n ].*\|.*)\n/)?.index; }, // Hint to Marked.js to stop and check for a match tokenizer(src, tokens) { //const regex = this.tokenizer.rules.block.table; - const regex = new RegExp('^ *([^\\n ].*\\|.*\\n(?:.*?[^\\s].*\\n)*?)' // Header + const regex = new RegExp('^ *([^\\n ].*\\|.*\\n(?: *[^\\s].*\\n)*?)' // Header + ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)\\|?' // Align + '(?:\\n *((?:(?!\\n| {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})' // Cells + '(?:\\n+|$)| {0,3}#{1,6} | {0,3}>| {4}[^\\n]| {0,3}(?:`{3,}' @@ -369,9 +369,9 @@ const getTableCell = (text, cell, type, align)=>{ }; const splitCells = (tableRow, count, prevRow = [])=>{ - // ensure that every cell-delimiting pipe has a space - // before it to distinguish it from an escaped pipe - const row = tableRow.replace(/(\|+)/g, (match, p1, offset, str)=>{ + // trim any excessive pipes at start of row + tableRow = tableRow.replace(/^\|+(?=\|)/, '') + .replace(/(\|+)/g, (match, p1, offset, str)=>{ let escaped = false, curr = offset; while (--curr >= 0 && str[curr] === '\\') escaped = !escaped; @@ -380,12 +380,12 @@ const splitCells = (tableRow, count, prevRow = [])=>{ // so we leave it and the slashes alone return p1; } else { - // add space before unescaped | + // add space before unescaped | to distinguish it from an escaped pipe return ` ${p1}`; } }); - const cells = row.split(/(?: \||(?<=\|)\|)(?=[^\|]|$)/g); + const cells = tableRow.split(/(?: \||(?<=\|)\|)(?=[^\|]|$)/g); let i = 0; // First/last cell in a row cannot be empty if it has no leading/trailing pipe @@ -400,7 +400,7 @@ const splitCells = (tableRow, count, prevRow = [])=>{ rowspan : 1, colspan : Math.max(cells[i].length - trimmedCell.length, 1), text : trimmedCell.trim().replace(/\\\|/g, '|') - // leading or trailing whitespace is ignored per the gfm spec + // trim whitespace and display escaped pipes as normal character }; // Handle Rowspan @@ -411,6 +411,7 @@ const splitCells = (tableRow, count, prevRow = [])=>{ for (j = 0; j < prevRow.length; j++) { prevCell = prevRow[j]; if((prevCols == numCols) && (prevCell.colspan == cells[i].colspan)) { + // merge into matching cell in previous row (the "target") cells[i].rowSpanTarget = prevCell.rowSpanTarget ?? prevCell; cells[i].rowSpanTarget.text += ` ${cells[i].text.slice(0, -1)}`; cells[i].rowSpanTarget.rowspan += 1;