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

Commit 0f6db91

Browse files
committed
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.
1 parent c851642 commit 0f6db91

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

grammars/coffeescript.cson

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
'coffee.erb'
77
'cson'
88
'_coffee'
9+
'cjsx'
910
]
1011
'firstLineMatch': '''(?x)
1112
# Hashbang
@@ -27,6 +28,9 @@
2728
)
2829
'''
2930
'patterns': [
31+
{
32+
'include': '#jsx'
33+
}
3034
{
3135
'match': '(new)\\s+(?:(?:(class)\\s+(\\w+(?:\\.\\w*)*)?)|(\\w+(?:\\.\\w*)*))'
3236
'name': 'meta.class.instance.constructor.coffee'
@@ -1148,3 +1152,84 @@
11481152
'include': '#embedded_comment'
11491153
}
11501154
]
1155+
1156+
'jsx':
1157+
'patterns': [
1158+
{
1159+
'include': '#jsx-tag'
1160+
}
1161+
{
1162+
'include': '#jsx-end-tag'
1163+
}
1164+
]
1165+
1166+
'jsx-expression':
1167+
'begin': '{'
1168+
'beginCaptures':
1169+
'0':
1170+
'name': 'meta.brace.curly.coffee'
1171+
'end': '}'
1172+
'endCaptures':
1173+
'0':
1174+
'name': 'meta.brace.curly.coffee'
1175+
1176+
'patterns': [
1177+
{
1178+
'include': '#double_quoted_string'
1179+
}
1180+
{
1181+
'include': '$self'
1182+
}
1183+
]
1184+
1185+
'jsx-attribute':
1186+
'patterns': [
1187+
{
1188+
'captures':
1189+
'1':
1190+
'name': 'entity.other.attribute-name.coffee'
1191+
'2':
1192+
'name': 'keyword.operator.assignment.coffee'
1193+
'match': '(?:^|\\s+)([-\\w.]+)\\s*(=)'
1194+
}
1195+
{
1196+
'include': '#double_quoted_string'
1197+
}
1198+
{
1199+
'include': '#single_quoted_string'
1200+
}
1201+
{
1202+
'include': '#jsx-expression'
1203+
}
1204+
]
1205+
1206+
'jsx-tag':
1207+
'patterns': [
1208+
{
1209+
'begin': '(<)([-\\w\\.]+)'
1210+
'beginCaptures':
1211+
'1':
1212+
'name': 'punctuation.definition.tag.coffee'
1213+
'2':
1214+
'name': 'entity.name.tag.coffee'
1215+
'end': '(/?>)'
1216+
'name': 'meta.tag.coffee'
1217+
'patterns': [
1218+
'include': '#jsx-attribute'
1219+
]
1220+
}
1221+
]
1222+
1223+
'jsx-end-tag':
1224+
'patterns': [
1225+
{
1226+
'begin': '(</)([-\\w\\.]+)'
1227+
'beginCaptures':
1228+
'1':
1229+
'name': 'punctuation.definition.tag.coffee'
1230+
'2':
1231+
'name': 'entity.name.tag.coffee'
1232+
'end': '(/?>)'
1233+
'name': 'meta.tag.coffee'
1234+
}
1235+
]

spec/coffee-script-spec.coffee

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,59 @@ describe "CoffeeScript grammar", ->
13221322
expect(tokens[8]).toEqual value: 'b', scopes: ['source.coffee', 'string.quoted.single.coffee', 'constant.character.escape.backslash.coffee']
13231323
expect(tokens[9]).toEqual value: "'", scopes: ['source.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.end.coffee']
13241324

1325+
describe "jsx", ->
1326+
it "tokenises HTML tags", ->
1327+
{tokens} = grammar.tokenizeLine("<div></div>")
1328+
expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee']
1329+
expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ]
1330+
expect(tokens[2]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1331+
expect(tokens[3]).toEqual value : '</', scopes : [ 'source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee' ]
1332+
expect(tokens[4]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ]
1333+
expect(tokens[5]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1334+
1335+
{tokens} = grammar.tokenizeLine("<div/>")
1336+
expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee']
1337+
expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ]
1338+
expect(tokens[2]).toEqual value : '/>', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1339+
1340+
it "tokenises HTML tags with attributes", ->
1341+
{tokens} = grammar.tokenizeLine("<div class='myclass' id=\"myid\">")
1342+
expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee']
1343+
expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ]
1344+
expect(tokens[2]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1345+
expect(tokens[3]).toEqual value : 'class', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ]
1346+
expect(tokens[4]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ]
1347+
expect(tokens[5]).toEqual value : '\'', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.begin.coffee' ]
1348+
expect(tokens[6]).toEqual value : 'myclass', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee' ]
1349+
expect(tokens[7]).toEqual value : '\'', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.single.coffee', 'punctuation.definition.string.end.coffee' ]
1350+
expect(tokens[8]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1351+
expect(tokens[9]).toEqual value : 'id', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ]
1352+
expect(tokens[10]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ]
1353+
expect(tokens[11]).toEqual value : '"', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.begin.coffee' ]
1354+
expect(tokens[12]).toEqual value : 'myid', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee' ]
1355+
expect(tokens[13]).toEqual value : '"', scopes : [ 'source.coffee', 'meta.tag.coffee', 'string.quoted.double.coffee', 'punctuation.definition.string.end.coffee' ]
1356+
expect(tokens[14]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1357+
1358+
it "tokenises HTML tags with attributes that have expressions", ->
1359+
{tokens} = grammar.tokenizeLine("<div on-click={(e)->@handleClick(e)}>")
1360+
expect(tokens[0]).toEqual value: '<', scopes: ['source.coffee', 'meta.tag.coffee', 'punctuation.definition.tag.coffee']
1361+
expect(tokens[1]).toEqual value : 'div', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.name.tag.coffee' ]
1362+
expect(tokens[2]).toEqual value : ' ', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1363+
expect(tokens[3]).toEqual value : 'on-click', scopes : [ 'source.coffee', 'meta.tag.coffee', 'entity.other.attribute-name.coffee' ]
1364+
expect(tokens[4]).toEqual value : '=', scopes : [ 'source.coffee', 'meta.tag.coffee', 'keyword.operator.assignment.coffee' ]
1365+
expect(tokens[5]).toEqual value : '{', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee']
1366+
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' ]
1367+
expect(tokens[7]).toEqual value : 'e', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'meta.parameters.coffee', 'variable.parameter.function.coffee' ]
1368+
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' ]
1369+
expect(tokens[9]).toEqual value : '->', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function.inline.coffee', 'storage.type.function.coffee' ]
1370+
expect(tokens[10]).toEqual value : '@', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'variable.other.readwrite.instance.coffee' ]
1371+
expect(tokens[11]).toEqual value : 'handleClick', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'entity.name.function.coffee' ]
1372+
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' ]
1373+
expect(tokens[13]).toEqual value : 'e', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.function-call.coffee', 'meta.arguments.coffee' ]
1374+
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' ]
1375+
expect(tokens[15]).toEqual value : '}', scopes : [ 'source.coffee', 'meta.tag.coffee', 'meta.brace.curly.coffee']
1376+
expect(tokens[16]).toEqual value : '>', scopes : [ 'source.coffee', 'meta.tag.coffee' ]
1377+
13251378
describe "firstLineMatch", ->
13261379
it "recognises interpreter directives", ->
13271380
valid = """

0 commit comments

Comments
 (0)