From ebd1b9a603dc34e58433eacde151bf9a74afd876 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 19 Aug 2018 16:06:34 +0200 Subject: [PATCH] Fix regex for `catch` and `finally` (#1527) When called as methods on a promise chain, the current regex would mark `catch` and `finally` as keywords. This regex improvement ensures they're only caught as part of a `try / catch` block, and are marked as functions as part of the promise chain. --- components/prism-javascript.js | 10 +++++- components/prism-javascript.min.js | 2 +- prism.js | 10 +++++- tests/languages/javascript/issue1526.test | 35 +++++++++++++++++++ .../languages/javascript/keyword_feature.test | 17 +++++---- .../javascript/try-catch_feature.test | 22 ++++++++++++ 6 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 tests/languages/javascript/issue1526.test create mode 100644 tests/languages/javascript/try-catch_feature.test diff --git a/components/prism-javascript.js b/components/prism-javascript.js index 0cad213357..47853d3e0b 100644 --- a/components/prism-javascript.js +++ b/components/prism-javascript.js @@ -1,11 +1,19 @@ Prism.languages.javascript = Prism.languages.extend('clike', { - 'keyword': /\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/, + 'keyword': [ + { + pattern: /((?:^|})\s*)(?:catch|finally)\b/, + lookbehind: true + }, + /\b(?:as|async|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/ + ], 'number': /\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/, // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) 'function': /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i, 'operator': /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/ }); +Prism.languages.javascript['class-name'].pattern = /(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/ + Prism.languages.insertBefore('javascript', 'keyword', { 'regex': { pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/, diff --git a/components/prism-javascript.min.js b/components/prism-javascript.min.js index 8551a48dd7..29cfee7d0a 100644 --- a/components/prism-javascript.min.js +++ b/components/prism-javascript.min.js @@ -1 +1 @@ -Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,"function":/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"},constant:/\b[A-Z][A-Z\d_]*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${[^}]+}|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\${[^}]+}/,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript; \ No newline at end of file +Prism.languages.javascript=Prism.languages.extend("clike",{keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},/\b(?:as|async|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/],number:/\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,"function":/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.javascript["class-name"].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"},constant:/\b[A-Z][A-Z\d_]*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${[^}]+}|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\${[^}]+}/,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript; \ No newline at end of file diff --git a/prism.js b/prism.js index 0ce19ab429..b48a825af2 100644 --- a/prism.js +++ b/prism.js @@ -725,13 +725,21 @@ Prism.languages.clike = { ********************************************** */ Prism.languages.javascript = Prism.languages.extend('clike', { - 'keyword': /\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/, + 'keyword': [ + { + pattern: /((?:^|})\s*)(?:catch|finally)\b/, + lookbehind: true + }, + /\b(?:as|async|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/ + ], 'number': /\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/, // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) 'function': /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i, 'operator': /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/ }); +Prism.languages.javascript['class-name'].pattern = /(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/ + Prism.languages.insertBefore('javascript', 'keyword', { 'regex': { pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/, diff --git a/tests/languages/javascript/issue1526.test b/tests/languages/javascript/issue1526.test new file mode 100644 index 0000000000..d361155e41 --- /dev/null +++ b/tests/languages/javascript/issue1526.test @@ -0,0 +1,35 @@ +fetch('some-resource.json') + .then(response => response.json()) + .catch(console.error); + +---------------------------------------------------- + +[ + ["function", "fetch"], + ["punctuation", "("], + ["string", "'some-resource.json'"], + ["punctuation", ")"], + ["punctuation", "."], + ["function", "then"], + ["punctuation", "("], + "response ", + ["operator", "=>"], + " response", + ["punctuation", "."], + ["function", "json"], + ["punctuation", "("], + ["punctuation", ")"], + ["punctuation", ")"], + ["punctuation", "."], + ["function", "catch"], + ["punctuation", "("], + "console", + ["punctuation", "."], + "error", + ["punctuation", ")"], + ["punctuation", ";"] +] + +---------------------------------------------------- + +Checks for catch function which is not a keyword. See #1526 diff --git a/tests/languages/javascript/keyword_feature.test b/tests/languages/javascript/keyword_feature.test index 13b88875d0..8053f2b1b3 100644 --- a/tests/languages/javascript/keyword_feature.test +++ b/tests/languages/javascript/keyword_feature.test @@ -1,24 +1,28 @@ +catch finally; + as; async; await; break; case; -catch; class; const; continue; debugger; +class; const; continue; debugger; default; delete; do; else; enum; -export; extends; finally; for; +export; extends; for; from; function; get; if; implements; import; in; instanceof; interface; let; new; null; of; package; private; protected; public; return; set; static; -super; switch; this; throw; -try; typeof; var; void; while; +super; switch; this; throw; try; +typeof; var; void; while; with; yield; ---------------------------------------------------- [ + ["keyword", "catch"], + ["keyword", "finally"], ["punctuation", ";"], + ["keyword", "as"], ["punctuation", ";"], ["keyword", "async"], ["punctuation", ";"], ["keyword", "await"], ["punctuation", ";"], ["keyword", "break"], ["punctuation", ";"], ["keyword", "case"], ["punctuation", ";"], - ["keyword", "catch"], ["punctuation", ";"], ["keyword", "class"], ["punctuation", ";"], ["keyword", "const"], ["punctuation", ";"], ["keyword", "continue"], ["punctuation", ";"], @@ -30,7 +34,6 @@ with; yield; ["keyword", "enum"], ["punctuation", ";"], ["keyword", "export"], ["punctuation", ";"], ["keyword", "extends"], ["punctuation", ";"], - ["keyword", "finally"], ["punctuation", ";"], ["keyword", "for"], ["punctuation", ";"], ["keyword", "from"], ["punctuation", ";"], ["keyword", "function"], ["punctuation", ";"], @@ -67,4 +70,4 @@ with; yield; ---------------------------------------------------- -Checks for all keywords. \ No newline at end of file +Checks for all keywords. diff --git a/tests/languages/javascript/try-catch_feature.test b/tests/languages/javascript/try-catch_feature.test new file mode 100644 index 0000000000..c4bbd8b2b8 --- /dev/null +++ b/tests/languages/javascript/try-catch_feature.test @@ -0,0 +1,22 @@ +try { } catch (e) { } finally { } + +---------------------------------------------------- + +[ + ["keyword", "try"], + ["punctuation", "{"], + ["punctuation", "}"], + ["keyword", "catch"], + ["punctuation", "("], + "e", + ["punctuation", ")"], + ["punctuation", "{"], + ["punctuation", "}"], + ["keyword", "finally"], + ["punctuation", "{"], + ["punctuation", "}"] +] + +---------------------------------------------------- + +Checks for try statements. \ No newline at end of file