From c1fe1ebb285dddfd8dbbad7e6ae2455c8aa7157b Mon Sep 17 00:00:00 2001 From: Evan Scott Date: Tue, 10 Jul 2018 11:55:33 -0500 Subject: [PATCH] fix a perf issue in the new bold and emphasis regexes --- __snapshots__/index.spec.js.snap | 31 ++++++++++++++++ index.js | 63 ++++++++++++++++++-------------- index.spec.js | 10 +++++ 3 files changed, 77 insertions(+), 27 deletions(-) diff --git a/__snapshots__/index.spec.js.snap b/__snapshots__/index.spec.js.snap index 8bca09cd..7a11db0a 100644 --- a/__snapshots__/index.spec.js.snap +++ b/__snapshots__/index.spec.js.snap @@ -1,5 +1,36 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`markdown-to-jsx compiler #190 perf regression 1`] = ` + + + Lorum + + ipsum + + : + + + foo + + + + + &nbsp; + + + + + bar + + + + +`; + exports[`markdown-to-jsx compiler GFM tables should handle a basic table 1`] = ` diff --git a/index.js b/index.js index bd5b90f7..a88eba38 100644 --- a/index.js +++ b/index.js @@ -174,10 +174,19 @@ const TABLE_ROW_SPLIT = / *\| */; /** * Bolding requires the same character to be used twice, so we do a detect for which * one is in use, then double-check it's used a second time and then twice at the end. + * + * Bits of the mega regex: + * + * |[^`~()\[\]<>]*? ignore normal stuff + * |(?:.*?([`~]).*?\3.*?)* ignore stuff in backticks & tildes + * |(?:.*?\([^)]*?\).*?)* ignore stuff in parens + * |(?:.*?\[[^\]]*?\].*?)* ignore stuff in square brackets + * |(?:.*?<.*?>.*?)* ignore stuff in angle brackets + * */ -const TEXT_BOLD_R = /^([*_])\1((?:(?:.*?([`~]).*?\3.*?)*|(?:.*?[\[(<].*?[\])>].*?)*|.+?)\1?)\1{2}/; -const TEXT_EMPHASIZED_R = /^([*_])((?:.*?([`~]).*?\3.*?)*|(?:.*?[\[(<].*?[\])>].*?)*|.+?)\1/; -const TEXT_STRIKETHROUGHED_R = /^~~((?:.*?([`~]).*?\2.*?)*|(?:.*?[\[(<].*?[\])>].*?)*|.+?)~~/; +const TEXT_BOLD_R = /^([*_])\1((?:[^`~()\[\]<>]*?|(?:.*?([`~]).*?\3.*?)*|(?:.*?\([^)]*?\).*?)*|(?:.*?\[[^\]]*?\].*?)*|(?:.*?<.*?>.*?)*|[^\1]*?)\1?)\1{2}/; +const TEXT_EMPHASIZED_R = /^([*_])((?:[^`~()\[\]<>]*?|(?:.*?([`~]).*?\3.*?)*|(?:.*?\([^)]*?\).*?)*|(?:.*?\[[^\]]*?\].*?)*|(?:.*?<.*?>.*?)*|[^\1]*?))\1/; +const TEXT_STRIKETHROUGHED_R = /^~~((?:.*?([`~]).*?\2.*?)*|(?:.*?<.*?>.*?)*|.+?)~~/; const TEXT_ESCAPED_R = /^\\([^0-9A-Za-z\s])/; const TEXT_PLAIN_R = /^[\s\S]+?(?=[^0-9A-Z\s\u00c0-\uffff]|\d+\.|\n\n| {2,}\n|\w+:\S|$)/i; @@ -1505,37 +1514,37 @@ export function compiler(markdown, options) { }, }; - Object.keys(rules).forEach(key => { - let { match, parse } = rules[key]; + // Object.keys(rules).forEach(key => { + // let { match, parse } = rules[key]; - rules[key].match = (...args) => { - const start = performance.now(); - const result = match(...args); - const delta = performance.now() - start; + // rules[key].match = (...args) => { + // const start = performance.now(); + // const result = match(...args); + // const delta = performance.now() - start; - if (delta > 5) - console.warn( - `Slow match for ${key}: ${delta.toFixed(3)}ms, input: ${ - args[0] - }` - ); + // if (delta > 5) + // console.warn( + // `Slow match for ${key}: ${delta.toFixed(3)}ms, input: ${ + // args[0] + // }` + // ); - return result; - }; + // return result; + // }; - rules[key].parse = (...args) => { - const start = performance.now(); - const result = parse(...args); - const delta = performance.now() - start; + // rules[key].parse = (...args) => { + // const start = performance.now(); + // const result = parse(...args); + // const delta = performance.now() - start; - if (delta > 5) - console.warn(`Slow parse for ${key}: ${delta.toFixed(3)}ms`); + // if (delta > 5) + // console.warn(`Slow parse for ${key}: ${delta.toFixed(3)}ms`); - console.log(`${key}:parse`, `${delta.toFixed(3)}ms`, args[0]); + // console.log(`${key}:parse`, `${delta.toFixed(3)}ms`, args[0]); - return result; - }; - }); + // return result; + // }; + // }); const parser = parserFor(rules); const emitter = reactFor(ruleOutput(rules)); diff --git a/index.spec.js b/index.spec.js index 4396fab9..a39e0597 100644 --- a/index.spec.js +++ b/index.spec.js @@ -49,6 +49,16 @@ describe('markdown-to-jsx', () => { expect(root.innerHTML).toMatchSnapshot(); }); + it('#190 perf regression', () => { + render( + compiler( + 'Lorum *ipsum*: foo bar' + ) + ); + + expect(root.innerHTML).toMatchSnapshot(); + }); + describe('inline textual elements', () => { it('should handle emphasized text', () => { render(compiler('*Hello.*'));