Skip to content

Commit

Permalink
fix(javascript) fix regex inside parens after a non-regex (#2531)
Browse files Browse the repository at this point in the history
* make the object attr container smarter
* deal with multi-line comments also
* comments in any order, spanning multiple lines

Essentially makes the object attr container much more sensitive by allowing it to look-ahead thru comments to find object keys - and therefore prevent them from being incorrectly matched by the "value container" rule.
  • Loading branch information
joshgoebel committed May 7, 2020
1 parent 9e4f2dc commit 5c125b9
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Expand Up @@ -15,6 +15,8 @@ Deprecations:
- `endSameAsBegin` is now deprecated. (#2261) [Josh Goebel][]

Language Improvements:

- fix(javascript) fix regex inside parens after a non-regex (#2530) [Josh Goebel][]
- enh(typescript) use identifier to match potential keywords, preventing false positivites (#2519) [Josh Goebel][]
- enh(javascript) use identifier to match potential keywords, preventing false positivites (#2519) [Josh Goebel][]
- [enh] Add `OPTIMIZE:` and `HACK:` to the labels highlighted inside comments [Josh Goebel][]
Expand Down
25 changes: 21 additions & 4 deletions src/languages/javascript.js
Expand Up @@ -6,6 +6,7 @@ Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript
*/

import * as ECMAScript from "./lib/ecmascript";
import * as regex from "../lib/regex";

export default function(hljs) {
var IDENT_RE = ECMAScript.IDENT_RE;
Expand Down Expand Up @@ -149,13 +150,29 @@ export default function(hljs) {
hljs.C_BLOCK_COMMENT_MODE,
NUMBER,
{ // object attr container
begin: /[{,\n]\s*/, relevance: 0,
begin: regex.concat(/[{,\n]\s*/,
// we need to look ahead to make sure that we actually have an
// attribute coming up so we don't steal a comma from a potential
// "value" container
//
// NOTE: this might not work how you think. We don't actually always
// enter this mode and stay. Instead it might merely match `,
// <comments up next>` and then immediately end after the , because it
// fails to find any actual attrs. But this still does the job because
// it prevents the value contain rule from grabbing this instead and
// prevening this rule from firing when we actually DO have keys.
regex.lookahead(regex.concat(
// we also need to allow for multiple possible comments inbetween
// the first key:value pairing
/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,
IDENT_RE + '\\s*:'))),
relevance: 0,
contains: [
{
begin: IDENT_RE + '\\s*:', returnBegin: true,
className: 'attr',
begin: IDENT_RE + regex.lookahead('\\s*:'),
relevance: 0,
contains: [{className: 'attr', begin: IDENT_RE, relevance: 0}]
}
},
]
},
{ // "value" container
Expand Down
4 changes: 4 additions & 0 deletions src/lib/regex.js
Expand Up @@ -8,6 +8,10 @@ export function source(re) {
return (re && re.source) || re;
}

export function lookahead(regex) {
return concat('(?=', regex, ')');
}

export function concat(...args) {
const joined = args.map((x) => source(x)).join("");
return joined;
Expand Down
10 changes: 9 additions & 1 deletion test/markup/javascript/object-attr.expect.txt
@@ -1,6 +1,14 @@
{
<span class="hljs-attr">key</span>: value, <span class="hljs-comment">// with comment</span>
<span class="hljs-attr">key2</span>: value,
<span class="hljs-attr">key2clone</span>: value,
<span class="hljs-string">'key-3'</span>: value,
<span class="hljs-attr">key4</span>: <span class="hljs-literal">false</span> ? <span class="hljs-literal">undefined</span> : <span class="hljs-literal">true</span>
<span class="hljs-attr">key4</span>: <span class="hljs-literal">false</span> ? <span class="hljs-literal">undefined</span> : <span class="hljs-literal">true</span>,
<span class="hljs-attr">key5</span>: value, <span class="hljs-comment">/* with a multiline comment */</span>
<span class="hljs-attr">key6</span>: value,
<span class="hljs-attr">key7</span>: value, <span class="hljs-comment">/* with a multiline comment */</span> <span class="hljs-comment">// another comment</span>
<span class="hljs-attr">key8</span>: value,
<span class="hljs-attr">key9</span>: value, <span class="hljs-comment">/* with a REAL multiline
comment */</span>
<span class="hljs-attr">key10</span>: value,
}
11 changes: 10 additions & 1 deletion test/markup/javascript/object-attr.txt
@@ -1,6 +1,15 @@
{
key: value, // with comment
key2: value,
key2clone: value,
'key-3': value,
key4: false ? undefined : true
key4: false ? undefined : true,
key5: value, /* with a multiline comment */
key6: value,
key7: value, /* with a multiline comment */ // another comment
key8: value,
key9: value, /* with a REAL multiline
comment */
key10: value,
}

0 comments on commit 5c125b9

Please sign in to comment.