mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-09-28 13:15:34 +00:00
fix(markdown-editor): normalize CRLF in escapeTablePipes so tables keep cells
The pre-lex pipe protection split on '\n', leaving a trailing '\r' on every line. The '$'-anchored TABLE_DELIMITER_LINE then failed to match '| --- |\r', so the whole module no-op'd on CRLF input and marked dropped cells whose code spans / templates / URLs held a pipe — silently losing data on the first load of Windows- or API-authored content. Normalize '\r\n' and lone '\r' to '\n' up front (marked re-normalizes the returned string anyway). Original bytes are preserved when nothing is escaped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b015f3ba98
commit
81e448cf05
@@ -143,6 +143,27 @@ describe('table cell with a pipe inside a URL — content survives load and conv
|
||||
});
|
||||
});
|
||||
|
||||
describe('CRLF line endings — tables still protected', () => {
|
||||
it('escapes a code-span pipe in a CRLF table row', () => {
|
||||
expect(escapeTablePipes('| a | b |\r\n| --- | --- |\r\n| `x | y` | z |\r\n')).toBe(
|
||||
'| a | b |\n| --- | --- |\n| `x \\| y` | z |\n',
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps the trailing cell of a CRLF table on round-trip', () => {
|
||||
const out = roundTrip('| a | b |\r\n| --- | --- |\r\n| `x | y` | z |\r\n');
|
||||
|
||||
expect(out).toContain('z');
|
||||
expect(out).toContain('`x \\| y`');
|
||||
});
|
||||
|
||||
it('leaves CRLF bytes untouched when there is no table to escape', () => {
|
||||
const doc = 'line one\r\nline `a | b` two\r\n';
|
||||
|
||||
expect(escapeTablePipes(doc)).toBe(doc);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TABLE_DELIMITER_LINE is linear (ReDoS guard)', () => {
|
||||
it('scans a crafted delimiter-looking line with a long trailing space run in linear time', () => {
|
||||
// A `|`-line followed by "dashes + many spaces + non-matching tail" was O(n²) on the old regex
|
||||
|
||||
@@ -137,7 +137,11 @@ export const escapeTablePipes = (markdown: string): string => {
|
||||
return markdown;
|
||||
}
|
||||
|
||||
const lines = markdown.split('\n');
|
||||
// marked normalizes CRLF itself, but this pre-pass runs BEFORE it: a trailing `\r` left by split('\n')
|
||||
// defeats the `$`-anchored TABLE_DELIMITER_LINE, so a CRLF document's tables would go unprotected here and
|
||||
// lose cells. Normalize first; the return below keeps the original bytes when nothing was escaped.
|
||||
const source = markdown.includes('\r') ? markdown.replace(/\r\n?/g, '\n') : markdown;
|
||||
const lines = source.split('\n');
|
||||
let openFence: null | string = null;
|
||||
let isChanged = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user