From 4d008ca9fe377315ed26cb093efcaddfaf67a5af Mon Sep 17 00:00:00 2001 From: devlimits Date: Thu, 2 Jul 2026 10:36:19 +0900 Subject: [PATCH] fix(convert): pass through
in markdown so table cells can have line breaks markdown-it runs with html:false, so raw
was escaped to <br> and cells could not contain a line break. Add br to the inline-HTML passthrough allow-list;
,
,
now survive, while
in code spans stays escaped. --- lib/macro-converter.js | 2 +- tests/macro-converter.test.js | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/macro-converter.js b/lib/macro-converter.js index 2dc2a25..e2def3e 100644 --- a/lib/macro-converter.js +++ b/lib/macro-converter.js @@ -21,7 +21,7 @@ const STASH_DELIM = '\uE000'; // The body alternation `"[^"]*"|'[^']*'|[^>]` makes the match quote-aware // so a literal `>` inside a quoted attribute value (e.g. // ``) does not terminate the tag prematurely. -const PASSTHROUGH_TAG_RE = /<\/?(?:u|sub|sup|mark|details|summary)(?=[\s/>])(?:"[^"]*"|'[^']*'|[^>])*>/gi; +const PASSTHROUGH_TAG_RE = /<\/?(?:br|u|sub|sup|mark|details|summary)(?=[\s/>])(?:"[^"]*"|'[^']*'|[^>])*>/gi; // Block-level HTML elements that should pass through WITHOUT markdown processing of their content. const PASSTHROUGH_BLOCK_RE = /<(svg|div)(?:\s[^>]*)?>[\s\S]*?<\/\1>/gi; // Single-backtick inline code spans. Block-level code (fenced + indented) is diff --git a/tests/macro-converter.test.js b/tests/macro-converter.test.js index 29c860a..e7649e2 100644 --- a/tests/macro-converter.test.js +++ b/tests/macro-converter.test.js @@ -1048,6 +1048,31 @@ describe('MacroConverter /// passthrough', () => { }); }); +describe('MacroConverter
passthrough', () => { + // `
` is the practical way to get a line break inside a table cell via + // markdown, since markdown table grammar allows only inline text per cell. + const converter = new MacroConverter({ isCloud: true }); + + test('
in a table cell passes through instead of being escaped', () => { + const md = '| 버전 | 변경 |\n| --- | --- |\n| v1 | 가

다 |'; + const result = converter.markdownToStorage(md); + expect(result).toContain('



'); + expect(result).not.toContain('<br>'); + }); + + test('
and
variants pass through', () => { + const result = converter.markdownToStorage('a
b and c
d'); + expect(result).toContain('a
b and c
d'); + expect(result).not.toContain('<br'); + }); + + test('literal
inside inline code stays escaped, not passed through', () => { + const result = converter.markdownToStorage('`
`'); + expect(result).toContain('<br>'); + expect(result).not.toMatch(/
/); + }); +}); + describe('MacroConverter storageToMarkdown panel formatting', () => { const converter = new MacroConverter({ isCloud: true });