From 0f6db9143663e18b1ad00667820f46747dba495e Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Wed, 10 Oct 2018 20:12:53 +1300 Subject: [PATCH 1/3] Add support for JSX tags to the CoffeeScript grammar In CoffeeScript 2.0, JSX tags became part of the language (https://coffeescript.org/#jsx). This change adds recognition of tags and attributes to the existing coffeescript grammar. --- grammars/coffeescript.cson | 85 ++++++++++++++++++++++++++++++++++ spec/coffee-script-spec.coffee | 53 +++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/grammars/coffeescript.cson b/grammars/coffeescript.cson index 4d884f0..aba77dc 100644 --- a/grammars/coffeescript.cson +++ b/grammars/coffeescript.cson @@ -6,6 +6,7 @@ 'coffee.erb' 'cson' '_coffee' + 'cjsx' ] 'firstLineMatch': '''(?x) # Hashbang @@ -27,6 +28,9 @@ ) ''' 'patterns': [ + { + 'include': '#jsx' + } { 'match': '(new)\\s+(?:(?:(class)\\s+(\\w+(?:\\.\\w*)*)?)|(\\w+(?:\\.\\w*)*))' 'name': 'meta.class.instance.constructor.coffee' @@ -1148,3 +1152,84 @@ 'include': '#embedded_comment' } ] + + 'jsx': + 'patterns': [ + { + 'include': '#jsx-tag' + } + { + 'include': '#jsx-end-tag' + } + ] + + 'jsx-expression': + 'begin': '{' + 'beginCaptures': + '0': + 'name': 'meta.brace.curly.coffee' + 'end': '}' + 'endCaptures': + '0': + 'name': 'meta.brace.curly.coffee' + + 'patterns': [ + { + 'include': '#double_quoted_string' + } + { + 'include': '$self' + } + ] + + 'jsx-attribute': + 'patterns': [ + { + 'captures': + '1': + 'name': 'entity.other.attribute-name.coffee' + '2': + 'name': 'keyword.operator.assignment.coffee' + 'match': '(?:^|\\s+)([-\\w.]+)\\s*(=)' + } + { + 'include': '#double_quoted_string' + } + { + 'include': '#single_quoted_string' + } + { + 'include': '#jsx-expression' + } + ] + + 'jsx-tag': + 'patterns': [ + { + 'begin': '(<)([-\\w\\.]+)' + 'beginCaptures': + '1': + 'name': 'punctuation.definition.tag.coffee' + '2': + 'name': 'entity.name.tag.coffee' + 'end': '(/?>)' + 'name': 'meta.tag.coffee' + 'patterns': [ + 'include': '#jsx-attribute' + ] + } + ] + + 'jsx-end-tag': + 'patterns': [ + { + 'begin': '()' + 'name': 'meta.tag.coffee' + } + ] diff --git a/spec/coffee-script-spec.coffee b/spec/coffee-script-spec.coffee index 9727f8f..5badf29 100644 --- a/spec/coffee-script-spec.coffee +++ b/spec/coffee-script-spec.coffee @@ -1322,6 +1322,59 @@ describe "CoffeeScript grammar", -> expect(tokens[8]).toEqual value: 'b', scopes: ['source.coffee', 'string.quoted.single.coffee', 'constant.character.escape.backslash.coffee'] expect(tokens[9]).toEqual value: "'", scopes: ['source.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.end.coffee'] + describe "jsx", -> + it "tokenises HTML tags", -> + {tokens} = grammar.tokenizeLine("
") + expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] + expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[3]).toEqual value : '', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + + {tokens} = grammar.tokenizeLine("
") + expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] + expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value : '/>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + + it "tokenises HTML tags with attributes", -> + {tokens} = grammar.tokenizeLine("
") + expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] + expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[3]).toEqual value : 'class', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] + expect(tokens[4]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] + expect(tokens[5]).toEqual value : '\'', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.begin.coffee' ] + expect(tokens[6]).toEqual value : 'myclass', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee' ] + expect(tokens[7]).toEqual value : '\'', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.end.coffee' ] + expect(tokens[8]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[9]).toEqual value : 'id', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] + expect(tokens[10]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] + expect(tokens[11]).toEqual value : '"', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.begin.coffee' ] + expect(tokens[12]).toEqual value : 'myid', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee' ] + expect(tokens[13]).toEqual value : '"', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.end.coffee' ] + expect(tokens[14]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + + it "tokenises HTML tags with attributes that have expressions", -> + {tokens} = grammar.tokenizeLine("
@handleClick(e)}>") + expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] + expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[3]).toEqual value : 'on-click', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] + expect(tokens[4]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] + expect(tokens[5]).toEqual value : '{', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee'] + expect(tokens[6]).toEqual value : '(', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'punctuation.definition.parameters.begin.bracket.round.coffee' ] + expect(tokens[7]).toEqual value : 'e', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'variable.parameter.function.coffee' ] + expect(tokens[8]).toEqual value : ')', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'punctuation.definition.parameters.end.bracket.round.coffee' ] + expect(tokens[9]).toEqual value : '->', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'storage.type.function.coffee' ] + expect(tokens[10]).toEqual value : '@', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'variable.other.readwrite.instance.coffee' ] + expect(tokens[11]).toEqual value : 'handleClick', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'entity.name.function.coffee' ] + expect(tokens[12]).toEqual value : '(', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee', 'punctuation.definition.arguments.begin.bracket.round.coffee' ] + expect(tokens[13]).toEqual value : 'e', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee' ] + expect(tokens[14]).toEqual value : ')', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee', 'punctuation.definition.arguments.end.bracket.round.coffee' ] + expect(tokens[15]).toEqual value : '}', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee'] + expect(tokens[16]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + describe "firstLineMatch", -> it "recognises interpreter directives", -> valid = """ From f46033c637ca5eb258a93b5b5f54ef24683a543e Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Thu, 11 Oct 2018 08:33:09 +1300 Subject: [PATCH 2/3] Fix lint error with whitespace --- spec/coffee-script-spec.coffee | 74 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/spec/coffee-script-spec.coffee b/spec/coffee-script-spec.coffee index 5badf29..4a72f34 100644 --- a/spec/coffee-script-spec.coffee +++ b/spec/coffee-script-spec.coffee @@ -1326,54 +1326,54 @@ describe "CoffeeScript grammar", -> it "tokenises HTML tags", -> {tokens} = grammar.tokenizeLine("
") expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] - expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] - expect(tokens[2]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] - expect(tokens[3]).toEqual value : '', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[1]).toEqual value: 'div', scopes: ['source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value: '>', scopes: ['source.coffee', 'meta.tag.coffee' ] + expect(tokens[3]).toEqual value: '', scopes: ['source.coffee', 'meta.tag.coffee' ] {tokens} = grammar.tokenizeLine("
") expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] - expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] - expect(tokens[2]).toEqual value : '/>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[1]).toEqual value: 'div', scopes: ['source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value: '/>', scopes: ['source.coffee', 'meta.tag.coffee' ] it "tokenises HTML tags with attributes", -> {tokens} = grammar.tokenizeLine("
") expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] - expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] - expect(tokens[2]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ] - expect(tokens[3]).toEqual value : 'class', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] - expect(tokens[4]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] - expect(tokens[5]).toEqual value : '\'', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.begin.coffee' ] - expect(tokens[6]).toEqual value : 'myclass', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee' ] - expect(tokens[7]).toEqual value : '\'', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.end.coffee' ] - expect(tokens[8]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ] - expect(tokens[9]).toEqual value : 'id', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] - expect(tokens[10]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] - expect(tokens[11]).toEqual value : '"', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.begin.coffee' ] - expect(tokens[12]).toEqual value : 'myid', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee' ] - expect(tokens[13]).toEqual value : '"', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.end.coffee' ] - expect(tokens[14]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[1]).toEqual value: 'div', scopes: ['source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value: ' ', scopes: ['source.coffee', 'meta.tag.coffee' ] + expect(tokens[3]).toEqual value: 'class', scopes: ['source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] + expect(tokens[4]).toEqual value: '=', scopes: ['source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] + expect(tokens[5]).toEqual value: '\'', scopes: ['source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.begin.coffee' ] + expect(tokens[6]).toEqual value: 'myclass', scopes: ['source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee' ] + expect(tokens[7]).toEqual value: '\'', scopes: ['source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.end.coffee' ] + expect(tokens[8]).toEqual value: ' ', scopes: ['source.coffee', 'meta.tag.coffee' ] + expect(tokens[9]).toEqual value: 'id', scopes: ['source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] + expect(tokens[10]).toEqual value: '=', scopes: ['source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] + expect(tokens[11]).toEqual value: '"', scopes: ['source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.begin.coffee' ] + expect(tokens[12]).toEqual value: 'myid', scopes: ['source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee' ] + expect(tokens[13]).toEqual value: '"', scopes: ['source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.end.coffee' ] + expect(tokens[14]).toEqual value: '>', scopes: ['source.coffee', 'meta.tag.coffee' ] it "tokenises HTML tags with attributes that have expressions", -> {tokens} = grammar.tokenizeLine("
@handleClick(e)}>") expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee'] - expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] - expect(tokens[2]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ] - expect(tokens[3]).toEqual value : 'on-click', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] - expect(tokens[4]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] - expect(tokens[5]).toEqual value : '{', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee'] - expect(tokens[6]).toEqual value : '(', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'punctuation.definition.parameters.begin.bracket.round.coffee' ] - expect(tokens[7]).toEqual value : 'e', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'variable.parameter.function.coffee' ] - expect(tokens[8]).toEqual value : ')', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'punctuation.definition.parameters.end.bracket.round.coffee' ] - expect(tokens[9]).toEqual value : '->', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'storage.type.function.coffee' ] - expect(tokens[10]).toEqual value : '@', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'variable.other.readwrite.instance.coffee' ] - expect(tokens[11]).toEqual value : 'handleClick', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'entity.name.function.coffee' ] - expect(tokens[12]).toEqual value : '(', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee', 'punctuation.definition.arguments.begin.bracket.round.coffee' ] - expect(tokens[13]).toEqual value : 'e', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee' ] - expect(tokens[14]).toEqual value : ')', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee', 'punctuation.definition.arguments.end.bracket.round.coffee' ] - expect(tokens[15]).toEqual value : '}', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee'] - expect(tokens[16]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ] + expect(tokens[1]).toEqual value: 'div', scopes: ['source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ] + expect(tokens[2]).toEqual value: ' ', scopes: ['source.coffee', 'meta.tag.coffee' ] + expect(tokens[3]).toEqual value: 'on-click', scopes: ['source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ] + expect(tokens[4]).toEqual value: '=', scopes: ['source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ] + expect(tokens[5]).toEqual value: '{', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee'] + expect(tokens[6]).toEqual value: '(', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'punctuation.definition.parameters.begin.bracket.round.coffee' ] + expect(tokens[7]).toEqual value: 'e', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'variable.parameter.function.coffee' ] + expect(tokens[8]).toEqual value: ')', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'punctuation.definition.parameters.end.bracket.round.coffee' ] + expect(tokens[9]).toEqual value: '->', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'storage.type.function.coffee' ] + expect(tokens[10]).toEqual value: '@', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'variable.other.readwrite.instance.coffee' ] + expect(tokens[11]).toEqual value: 'handleClick', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'entity.name.function.coffee' ] + expect(tokens[12]).toEqual value: '(', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee', 'punctuation.definition.arguments.begin.bracket.round.coffee' ] + expect(tokens[13]).toEqual value: 'e', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee' ] + expect(tokens[14]).toEqual value: ')', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee', 'punctuation.definition.arguments.end.bracket.round.coffee' ] + expect(tokens[15]).toEqual value: '}', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee'] + expect(tokens[16]).toEqual value: '>', scopes: ['source.coffee', 'meta.tag.coffee' ] describe "firstLineMatch", -> it "recognises interpreter directives", -> From 6f9a2311b4c78229c4bd531033793deec2676790 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Thu, 11 Oct 2018 08:50:57 +1300 Subject: [PATCH 3/3] Fix one small whitespace error And, also kick the build which seems to have hiccupped --- spec/coffee-script-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/coffee-script-spec.coffee b/spec/coffee-script-spec.coffee index 4a72f34..1389597 100644 --- a/spec/coffee-script-spec.coffee +++ b/spec/coffee-script-spec.coffee @@ -1373,7 +1373,7 @@ describe "CoffeeScript grammar", -> expect(tokens[13]).toEqual value: 'e', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee' ] expect(tokens[14]).toEqual value: ')', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee', 'punctuation.definition.arguments.end.bracket.round.coffee' ] expect(tokens[15]).toEqual value: '}', scopes: ['source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee'] - expect(tokens[16]).toEqual value: '>', scopes: ['source.coffee', 'meta.tag.coffee' ] + expect(tokens[16]).toEqual value: '>', scopes: ['source.coffee', 'meta.tag.coffee'] describe "firstLineMatch", -> it "recognises interpreter directives", ->