perf: validate mobile review table delimiters by cell (#20317)

This commit is contained in:
Neil
2026-09-12 01:29:11 -07:00
committed by GitHub
parent cd8e98fdf9
commit 3bc631dad3
2 changed files with 41 additions and 3 deletions
@@ -30,8 +30,6 @@ const HEADING = /^(#{1,6})\s+(.*)$/
const FENCE = /^```/
// Captures the fence info string (language) on the opening fence, e.g. ```mermaid.
const FENCE_OPEN = /^```\s*([^\s`]*)/
// A GFM table delimiter row: cells of dashes with optional leading/trailing colons.
const TABLE_DELIM = /^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/
const QUOTE = /^>\s?(.*)$/
const HR = /^(?:---+|\*\*\*+|___+)\s*$/
const UNORDERED = /^\s*[-*+]\s+(.*)$/
@@ -114,7 +112,7 @@ function parseLines(content: string): MarkdownBlock[] {
// GFM pipe table: a header row immediately followed by a delimiter row.
// Requires the delimiter row so plain prose with a stray `|` isn't captured.
if (line.includes('|') && i + 1 < lines.length && TABLE_DELIM.test(lines[i + 1])) {
if (line.includes('|') && i + 1 < lines.length && isTableDelimiter(lines[i + 1])) {
flushParagraph()
const headers = splitTableRow(line)
const align = parseAlignRow(lines[i + 1])
@@ -217,6 +215,10 @@ function splitTableRow(line: string): string[] {
return cells
}
function isTableDelimiter(line: string): boolean {
return splitTableRow(line).every((cell) => /^:?-+:?$/.test(cell))
}
// Reads alignment from a delimiter row's colons: `:--` left, `:-:` center, `--:` right.
function parseAlignRow(line: string): CellAlign[] {
return splitTableRow(line).map((spec) => {
@@ -0,0 +1,36 @@
import { runInNewContext } from 'node:vm'
import { describe, expect, it } from 'vitest'
import { parseMarkdownBlocks } from './markdown-blocks'
const ORIGINAL_DELIMITER = /^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/
function isParsedTable(delimiter: string): boolean {
return parseMarkdownBlocks(`a|b\n${delimiter}`)[0]?.kind === 'table'
}
describe('review Markdown table delimiter cost', () => {
it.each([
{ name: 'leading whitespace', delimiter: ' '.repeat(60_000) + 'x' },
{ name: 'trailing cell whitespace', delimiter: '-|-' + ' '.repeat(60_000) + 'x' }
])('rejects $name without backtracking', ({ delimiter }) => {
// Interrupt synchronous regex regressions instead of hanging the test worker.
const blocks = runInNewContext(
'parse(input)',
{ parse: parseMarkdownBlocks, input: `a|b\n${delimiter}` },
{ timeout: 250 }
)
expect(blocks).toEqual([{ kind: 'paragraph', text: `a|b\n${delimiter}` }])
})
it('preserves the original delimiter grammar over generated rows', () => {
const parts = ['', '-', '--', ':', ':-:', ':--', '--:', '|', ' ', '\t', '\r', '\\|', 'x']
for (const left of parts) {
for (const middle of parts) {
for (const right of parts) {
const row = left + middle + right
expect(isParsedTable(row), JSON.stringify(row)).toBe(ORIGINAL_DELIMITER.test(row))
}
}
}
})
})