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

Commit d7b444a

Browse files
WliuWliu
authored andcommitted
Merge pull request #228 from mislav/keywords-in-ternary
Fix tokenizing of various keywords within ternary expression
2 parents 7b14bbb + 246bfea commit d7b444a

File tree

2 files changed

+94
-17
lines changed

2 files changed

+94
-17
lines changed

grammars/javascript.cson

Lines changed: 41 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,12 @@
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(module|exports|__filename|__dirname|global|process)(?!\\s*:)\\b|(?<=\\?)(?:\\s*)(module|exports|__filename|__dirname|global|process)(?=\\s*:)'
569+
'captures':
570+
'1':
571+
'name': 'support.variable.js'
572+
'2':
573+
'name': 'support.variable.js'
550574
}
551575
{
552576
'match': '\\b(Infinity|NaN|undefined)\\b'

spec/javascript-spec.coffee

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,33 @@ 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 it is an 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 the middle of ternary expressions", ->
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+
78+
it "tokenizes `#{keyword}` at the end of ternary expressions", ->
79+
{tokens} = grammar.tokenizeLine("a ? b : #{keyword}")
80+
expect(tokens[4]).toEqual value: ' ', scopes: ['source.js']
81+
expect(tokens[5]).toEqual value: keyword, scopes: ['source.js', scope]
82+
5683
describe "built-in globals", ->
5784
it "tokenizes them as support classes", ->
5885
{tokens} = grammar.tokenizeLine('window')
@@ -351,6 +378,19 @@ describe "Javascript grammar", ->
351378
expect(tokens[4]).toEqual value: 'systemLanguage', scopes: ['source.js', 'support.constant.js']
352379
expect(tokens[5]).toEqual value: ';', scopes: ['source.js', 'punctuation.terminator.statement.js']
353380

381+
it "does not tokenize constants when they are object keys", ->
382+
{tokens} = grammar.tokenizeLine('FOO: 1')
383+
expect(tokens[0]).toEqual value: 'FOO', scopes: ['source.js']
384+
expect(tokens[1]).toEqual value: ':', scopes: ['source.js', 'keyword.operator.js']
385+
386+
it "tokenizes constants in the middle of ternary expressions", ->
387+
{tokens} = grammar.tokenizeLine('a ? FOO : b')
388+
expect(tokens[3]).toEqual value: 'FOO', scopes: ['source.js', 'constant.other.js']
389+
390+
it "tokenizes constants at the end of ternary expressions", ->
391+
{tokens} = grammar.tokenizeLine('a ? b : FOO')
392+
expect(tokens[5]).toEqual value: 'FOO', scopes: ['source.js', 'constant.other.js']
393+
354394
describe "ES6 string templates", ->
355395
it "tokenizes them as strings", ->
356396
{tokens} = grammar.tokenizeLine('`hey ${name}`')
@@ -414,6 +454,19 @@ describe "Javascript grammar", ->
414454
expect(tokens[0]).toEqual value: 'yield', scopes: ['source.js', 'meta.control.yield.js', 'keyword.control.js']
415455
expect(tokens[2]).toEqual value: '*', scopes: ['source.js', 'meta.control.yield.js', 'storage.modifier.js']
416456

457+
it "does not tokenize yield when it is an object key", ->
458+
{tokens} = grammar.tokenizeLine('yield: 1')
459+
expect(tokens[0]).toEqual value: 'yield', scopes: ['source.js']
460+
expect(tokens[1]).toEqual value: ':', scopes: ['source.js', 'keyword.operator.js']
461+
462+
it "tokenizes yield in the middle of ternary expressions", ->
463+
{tokens} = grammar.tokenizeLine('a ? yield : b')
464+
expect(tokens[3]).toEqual value: 'yield', scopes: ['source.js', 'meta.control.yield.js', 'keyword.control.js']
465+
466+
it "tokenizes yield at the end of ternary expressions", ->
467+
{tokens} = grammar.tokenizeLine('a ? b : yield')
468+
expect(tokens[5]).toEqual value: 'yield', scopes: ['source.js', 'meta.control.yield.js', 'keyword.control.js']
469+
417470
describe "default: in a switch statement", ->
418471
it "tokenizes it as a keyword", ->
419472
{tokens} = grammar.tokenizeLine('default: ')

0 commit comments

Comments
 (0)