Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit 6098da4

Browse files
committed
Fix tokenizing of various keywords within ternary expression
Supports proper tokenizing of these keywords when they appear as subexpression `b` within ternary expression `a ? b : c`: yield, true, false, null, [CONSTANT], super, this, debugger, module, exports, __filename, __dirname, global, process
1 parent 5f24325 commit 6098da4

File tree

2 files changed

+82
-17
lines changed

2 files changed

+82
-17
lines changed

grammars/javascript.cson

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -468,12 +468,16 @@
468468
]
469469
}
470470
{
471-
'match': '(?<!\\.)\\b(yield)(?!\\s*:)\\b(?:\\s*(\\*))?',
471+
'match': '(?<!\\.)\\b(yield)(?!\\s*:)\\b(?:\\s*(\\*))?|(?<=\\?)(?:\\s*)(yield)(?=\\s*:)',
472472
'captures':
473473
'1':
474474
'name': 'keyword.control.js'
475475
'2':
476476
'name': 'storage.modifier.js'
477+
'3':
478+
'name': 'keyword.control.js'
479+
'4':
480+
'name': 'storage.modifier.js'
477481
'name': 'meta.control.yield.js'
478482
}
479483
{
@@ -489,28 +493,44 @@
489493
'name': 'keyword.operator.js'
490494
}
491495
{
492-
'match': '(?<!\\.)\\btrue(?!\\s*:)\\b'
493-
'name': 'constant.language.boolean.true.js'
494-
}
495-
{
496-
'match': '(?<!\\.)\\bfalse(?!\\s*:)\\b'
497-
'name': 'constant.language.boolean.false.js'
496+
'match': '(?<!\\.)\\b(true|false)(?!\\s*:)\\b|(?<=\\?)(?:\\s*)(true|false)(?=\\s*:)'
497+
'captures':
498+
'1':
499+
'name': 'constant.language.boolean.$1.js'
500+
'2':
501+
'name': 'constant.language.boolean.$2.js'
498502
}
499503
{
500-
'match': '(?<!\\.)\\bnull(?!\\s*:)\\b'
501-
'name': 'constant.language.null.js'
504+
'match': '(?<!\\.)\\b(null)(?!\\s*:)\\b|(?<=\\?)(?:\\s*)(null)(?=\\s*:)'
505+
'captures':
506+
'1':
507+
'name': 'constant.language.null.js'
508+
'2':
509+
'name': 'constant.language.null.js'
502510
}
503511
{
504-
'match': '(?<!\\.)\\b([A-Z][A-Z0-9_]+)(?!\\s*:)\\b'
505-
'name': 'constant.other.js'
512+
'match': '(?<!\\.)\\b([A-Z][A-Z0-9_]+)(?!\\s*:)\\b|(?<=\\?)(?:\\s*)([A-Z][A-Z0-9_]+)(?=\\s*:)'
513+
'captures':
514+
'1':
515+
'name': 'constant.other.js'
516+
'2':
517+
'name': 'constant.other.js'
506518
}
507519
{
508-
'match': '(?<!\\.)\\b(super|this)(?!\\s*:)\\b'
509-
'name': 'variable.language.js'
520+
'match': '(?<!\\.)\\b(super|this)(?!\\s*:)\\b|(?<=\\?)(?:\\s*)(super|this)(?=\\s*:)'
521+
'captures':
522+
'1':
523+
'name': 'variable.language.js'
524+
'2':
525+
'name': 'variable.language.js'
510526
}
511527
{
512-
'match': '(?<!\\.)\\b(debugger)(?!\\s*:)\\b'
513-
'name': 'keyword.other.js'
528+
'match': '(?<!\\.)\\b(debugger)(?!\\s*:)\\b|(?<=\\?)(?:\\s*)(debugger)(?=\\s*:)'
529+
'captures':
530+
'1':
531+
'name': 'keyword.other.js'
532+
'2':
533+
'name': 'keyword.other.js'
514534
}
515535
{
516536
'match': '(?<!\\$)\\b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\\b'
@@ -545,8 +565,13 @@
545565
'name': 'support.function.js'
546566
}
547567
{
548-
'match': '(?<!\\.)\\b(module|exports|__filename|__dirname|global|process)(?!\\s*:)\\b'
549-
'name': 'support.variable.js'
568+
'match': '(?<!\\.)\\b()(?!\\s*:)\\b'
569+
'match': '(?<!\\.)\\b(module|exports|__filename|__dirname|global|process)(?!\\s*:)\\b|(?<=\\?)(?:\\s*)(module|exports|__filename|__dirname|global|process)(?=\\s*:)'
570+
'captures':
571+
'1':
572+
'name': 'support.variable.js'
573+
'2':
574+
'name': 'support.variable.js'
550575
}
551576
{
552577
'match': '\\b(Infinity|NaN|undefined)\\b'

spec/javascript-spec.coffee

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,28 @@ describe "Javascript grammar", ->
5353
{tokens} = grammar.tokenizeLine('with')
5454
expect(tokens[0]).toEqual value: 'with', scopes: ['source.js', 'keyword.control.js']
5555

56+
map =
57+
super: 'variable.language.js'
58+
this: 'variable.language.js'
59+
null: 'constant.language.null.js'
60+
true: 'constant.language.boolean.true.js'
61+
false: 'constant.language.boolean.false.js'
62+
debugger: 'keyword.other.js'
63+
exports: 'support.variable.js'
64+
__filename: 'support.variable.js'
65+
66+
for keyword, scope of map
67+
do (keyword, scope) ->
68+
it "does not tokenize `#{keyword}` when object key", ->
69+
{tokens} = grammar.tokenizeLine("#{keyword}: 1")
70+
expect(tokens[0]).toEqual value: keyword, scopes: ['source.js']
71+
expect(tokens[1]).toEqual value: ':', scopes: ['source.js', 'keyword.operator.js']
72+
73+
it "tokenizes `#{keyword}` in ternary expression", ->
74+
{tokens} = grammar.tokenizeLine("a ? #{keyword} : b")
75+
expect(tokens[2]).toEqual value: ' ', scopes: ['source.js']
76+
expect(tokens[3]).toEqual value: keyword, scopes: ['source.js', scope]
77+
5678
describe "built-in globals", ->
5779
it "tokenizes them as support classes", ->
5880
{tokens} = grammar.tokenizeLine('window')
@@ -336,6 +358,15 @@ describe "Javascript grammar", ->
336358
expect(tokens[4]).toEqual value: 'systemLanguage', scopes: ['source.js', 'support.constant.js']
337359
expect(tokens[5]).toEqual value: ';', scopes: ['source.js', 'punctuation.terminator.statement.js']
338360

361+
it "does not tokenize constant when object key", ->
362+
{tokens} = grammar.tokenizeLine('FOO: 1')
363+
expect(tokens[0]).toEqual value: 'FOO', scopes: ['source.js']
364+
expect(tokens[1]).toEqual value: ':', scopes: ['source.js', 'keyword.operator.js']
365+
366+
it "tokenizes constant in ternary expression", ->
367+
{tokens} = grammar.tokenizeLine('a ? FOO : b')
368+
expect(tokens[3]).toEqual value: 'FOO', scopes: ['source.js', 'constant.other.js']
369+
339370
describe "ES6 string templates", ->
340371
it "tokenizes them as strings", ->
341372
{tokens} = grammar.tokenizeLine('`hey ${name}`')
@@ -399,6 +430,15 @@ describe "Javascript grammar", ->
399430
expect(tokens[0]).toEqual value: 'yield', scopes: ['source.js', 'meta.control.yield.js', 'keyword.control.js']
400431
expect(tokens[2]).toEqual value: '*', scopes: ['source.js', 'meta.control.yield.js', 'storage.modifier.js']
401432

433+
it "does not tokenize yield when object key", ->
434+
{tokens} = grammar.tokenizeLine('yield: 1')
435+
expect(tokens[0]).toEqual value: 'yield', scopes: ['source.js']
436+
expect(tokens[1]).toEqual value: ':', scopes: ['source.js', 'keyword.operator.js']
437+
438+
it "tokenizes yield in ternary expression", ->
439+
{tokens} = grammar.tokenizeLine('a ? yield : b')
440+
expect(tokens[3]).toEqual value: 'yield', scopes: ['source.js', 'meta.control.yield.js', 'keyword.control.js']
441+
402442
describe "default: in a switch statement", ->
403443
it "tokenizes it as a keyword", ->
404444
{tokens} = grammar.tokenizeLine('default: ')

0 commit comments

Comments
 (0)