From f9328cccd56002e00736c457963afdedc2231715 Mon Sep 17 00:00:00 2001 From: Evan Jacobs Date: Thu, 11 Apr 2024 14:54:42 -0400 Subject: [PATCH] fix: adjusted block html regex to avoid perf issues Closes #546 Thank you @devbrains-com for contributing the basis of this fix! --- .changeset/quiet-boxes-flow.md | 5 ++ index.compiler.spec.tsx | 148 +++++++++++++++++++++++++++++++++ index.tsx | 2 +- 3 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 .changeset/quiet-boxes-flow.md diff --git a/.changeset/quiet-boxes-flow.md b/.changeset/quiet-boxes-flow.md new file mode 100644 index 00000000..965975cd --- /dev/null +++ b/.changeset/quiet-boxes-flow.md @@ -0,0 +1,5 @@ +--- +"markdown-to-jsx": patch +--- + +Improved block html detection regex to handle certain edge cases that cause extreme slowness. Thank you @devbrains-com for the basis for this fix 🤝 diff --git a/index.compiler.spec.tsx b/index.compiler.spec.tsx index 53950e80..9626aaa6 100644 --- a/index.compiler.spec.tsx +++ b/index.compiler.spec.tsx @@ -3442,6 +3442,154 @@ Item detail

`) }) + + it('#546 perf regression test, self-closing block + block HTML causes exponential degradation', () => { + render( + compiler( + ` + +You can have anything here. But it's best if the self-closing tag also appears in the document as a pair tag multiple times. We have found it when compiling a table with spans that had a self-closing span at the top. + +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no +no + +Each span you copy above increases the time it takes by 2. Also, writing text here increases the time.`.trim() + ) + ) + + expect(root.innerHTML).toMatchInlineSnapshot(` +
+ + +

+ You can have anything here. But it's best if the self-closing tag also appears in the document as a pair tag multiple times. We have found it when compiling a table with spans that had a self-closing span at the top. +

+ + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + + + no + +

+ Each span you copy above increases the time it takes by 2. Also, writing text here increases the time. +

+
+ `) + }) }) describe('horizontal rules', () => { diff --git a/index.tsx b/index.tsx index 4b6a9a74..733a6bc3 100644 --- a/index.tsx +++ b/index.tsx @@ -254,7 +254,7 @@ const HEADING_SETEXT_R = /^([^\n]+)\n *(=|-){3,} *(?:\n *)+\n/ * \n* */ const HTML_BLOCK_ELEMENT_R = - /^ *(?!<[a-z][^ >/]* ?\/>)<([a-z][^ >/]*) ?([^>]*)>\n?(\s*(?:<\1[^>]*?>[\s\S]*?<\/\1>|(?!<\1\b)[\s\S])*?)<\/\1>(?!<\/\1>)\n*/i + /^ *(?!<[a-z][^ >/]* ?\/>)<([a-z][^ >/]*) ?((?:[^>]*[^/])?)>\n?(\s*(?:<\1[^>]*?>[\s\S]*?<\/\1>|(?!<\1\b)[\s\S])*?)<\/\1>(?!<\/\1>)\n*/i const HTML_CHAR_CODE_R = /&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});/gi