Skip to content

Commit 70c2c47

Browse files
edemaineGeoffreyBooth
authored andcommitted
CSX namespaced tags and attributes (#5218)
* Support namespaces in attributes * Support namespaces in tag names * Support reserved words in CSX boolean properties (fix #5125) * Implement review comments * Build * Revert parser.js
1 parent 9c913f8 commit 70c2c47

File tree

3 files changed

+102
-11
lines changed

3 files changed

+102
-11
lines changed

lib/coffeescript/lexer.js

Lines changed: 16 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lexer.coffee

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ exports.Lexer = class Lexer
206206
@error "'#{prevprev[1]}' cannot be used as a keyword, or as a
207207
function call without parentheses", prevprev[2]
208208

209-
if tag is 'IDENTIFIER' and id in RESERVED
209+
if tag is 'IDENTIFIER' and id in RESERVED and not inCSXTag
210210
@error "reserved word '#{id}'", length: id.length
211211

212212
unless tag is 'PROPERTY' or @exportSpecifierList
@@ -1182,19 +1182,32 @@ IDENTIFIER = /// ^
11821182
( [^\n\S]* : (?!:) )? # Is this a property name?
11831183
///
11841184

1185+
# Like `IDENTIFIER`, but includes `-`s
1186+
CSX_IDENTIFIER_PART = /// (?: (?!\s)[\-$\w\x7f-\uffff] )+ ///.source
1187+
1188+
# In https://facebook.github.io/jsx/ spec, JSXElementName can be
1189+
# JSXIdentifier, JSXNamespacedName (JSXIdentifier : JSXIdentifier), or
1190+
# JSXMemberExpression (two or more JSXIdentifier connected by `.`s).
11851191
CSX_IDENTIFIER = /// ^
11861192
(?![\d<]) # Must not start with `<`.
1187-
( (?: (?!\s)[\.\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s and `.`s.
1193+
( #{CSX_IDENTIFIER_PART}
1194+
(?: \s* : \s* #{CSX_IDENTIFIER_PART} # JSXNamespacedName
1195+
| (?: \s* \. \s* #{CSX_IDENTIFIER_PART} )+ # JSXMemberExpression
1196+
)? )
11881197
///
11891198

11901199
# Fragment: <></>
11911200
CSX_FRAGMENT_IDENTIFIER = /// ^
11921201
()> # Ends immediately with `>`.
11931202
///
11941203

1204+
# In https://facebook.github.io/jsx/ spec, JSXAttributeName can be either
1205+
# JSXIdentifier or JSXNamespacedName which is JSXIdentifier : JSXIdentifier
11951206
CSX_ATTRIBUTE = /// ^
11961207
(?!\d)
1197-
( (?: (?!\s)[\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s.
1208+
( #{CSX_IDENTIFIER_PART}
1209+
(?: \s* : \s* #{CSX_IDENTIFIER_PART} # JSXNamespacedName
1210+
)? )
11981211
( [^\S]* = (?!=) )? # Is this an attribute with a value?
11991212
///
12001213

test/csx.coffee

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ test 'self closing multiline', ->
2323
<div />;
2424
'''
2525

26+
test 'reserved-word self closing', ->
27+
eqJS '''
28+
<static />
29+
''', '''
30+
<static />;
31+
'''
32+
2633
test 'regex attribute', ->
2734
eqJS '''
2835
<div x={/>asds/} />
@@ -69,6 +76,33 @@ test 'attribute without value', ->
6976
<div checked x="hello" />;
7077
'''
7178

79+
test 'reserved-word attribute without value', ->
80+
eqJS '''
81+
<div static x="hello" />
82+
''', '''
83+
<div static x="hello" />;
84+
'''
85+
86+
test 'reserved-word attribute with value', ->
87+
eqJS '''
88+
<div static="yes" x="hello" />
89+
''', '''
90+
<div static="yes" x="hello" />;
91+
'''
92+
93+
test 'attribute with namespace', ->
94+
eqJS '''
95+
<image xlink:href="data:image/png" />
96+
''', '''
97+
<image xlink:href="data:image/png" />;
98+
'''
99+
100+
test 'attribute with double namespace disallowed', ->
101+
throws -> CoffeeScript.compile '<image xlink:href:tag="data:image/png" />'
102+
103+
test 'attribute with member expression disallowed', ->
104+
throws -> CoffeeScript.compile '<image xlink.href="data:image/png" />'
105+
72106
test 'paired', ->
73107
eqJS '''
74108
<div></div>
@@ -462,27 +496,60 @@ test 'tag with {{}}', ->
462496
}} />;
463497
'''
464498

465-
test 'tag with namespace', ->
499+
test 'tag with member expression', ->
466500
eqJS '''
467501
<Something.Tag></Something.Tag>
468502
''', '''
469503
<Something.Tag></Something.Tag>;
470504
'''
471505

472-
test 'tag with lowercase namespace', ->
506+
test 'tag with lowercase member expression', ->
473507
eqJS '''
474508
<something.tag></something.tag>
475509
''', '''
476510
<something.tag></something.tag>;
477511
'''
478512

479-
test 'self closing tag with namespace', ->
513+
test 'self closing tag with member expression', ->
480514
eqJS '''
481515
<Something.Tag />
482516
''', '''
483517
<Something.Tag />;
484518
'''
485519

520+
test 'self closing tag with multiple member expressions', ->
521+
eqJS '''
522+
<Something.Tag.More />
523+
''', '''
524+
<Something.Tag.More />;
525+
'''
526+
527+
test 'tag with namespace', ->
528+
eqJS '''
529+
<Something:Tag></Something:Tag>
530+
''', '''
531+
<Something:Tag></Something:Tag>;
532+
'''
533+
534+
test 'tag with lowercase namespace', ->
535+
eqJS '''
536+
<something:tag></something:tag>
537+
''', '''
538+
<something:tag></something:tag>;
539+
'''
540+
541+
test 'self closing tag with namespace', ->
542+
eqJS '''
543+
<Something:Tag />
544+
''', '''
545+
<Something:Tag />;
546+
'''
547+
548+
test 'self closing tag with namespace and member expression disallowed', ->
549+
throws -> CoffeeScript.compile '''
550+
<Namespace:Something.Tag />
551+
'''
552+
486553
test 'self closing tag with spread attribute', ->
487554
eqJS '''
488555
<Component a={b} {x...} b="c" />

0 commit comments

Comments
 (0)