Skip to content

Commit ee44fa2

Browse files
committed
allow hyphens in jsx tag names
1 parent f510d13 commit ee44fa2

File tree

6 files changed

+32
-41
lines changed

6 files changed

+32
-41
lines changed

jscomp/syntax/src/res_core.ml

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,10 +2617,11 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26172617
| GreaterThan -> (
26182618
(* <foo a=b> bar </foo> *)
26192619
let childrenStartPos = p.Parser.startPos in
2620-
Scanner.setJsxMode p.scanner;
26212620
Parser.next p;
26222621
let spread, children = parseJsxChildren p in
26232622
let childrenEndPos = p.Parser.startPos in
2623+
Scanner.popMode p.scanner Jsx;
2624+
Scanner.setJsxMode p.scanner;
26242625
let () =
26252626
match p.token with
26262627
| LessThanSlash -> Parser.next p
@@ -2685,6 +2686,8 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26852686
* jsx-children ::= primary-expr* * => 0 or more
26862687
*)
26872688
and parseJsx p =
2689+
Scanner.popMode p.scanner Jsx;
2690+
Scanner.setJsxMode p.Parser.scanner;
26882691
Parser.leaveBreadcrumb p Grammar.Jsx;
26892692
let startPos = p.Parser.startPos in
26902693
Parser.expect LessThan p;
@@ -2696,6 +2699,7 @@ and parseJsx p =
26962699
parseJsxFragment p
26972700
| _ -> parseJsxName p
26982701
in
2702+
Scanner.popMode p.scanner Jsx;
26992703
Parser.eatBreadcrumb p;
27002704
{jsxExpr with pexp_attributes = [jsxAttr]}
27012705

@@ -2706,12 +2710,12 @@ and parseJsx p =
27062710
*)
27072711
and parseJsxFragment p =
27082712
let childrenStartPos = p.Parser.startPos in
2709-
Scanner.setJsxMode p.scanner;
27102713
Parser.expect GreaterThan p;
27112714
let _spread, children = parseJsxChildren p in
27122715
let childrenEndPos = p.Parser.startPos in
27132716
Parser.expect LessThanSlash p;
27142717
Parser.expect GreaterThan p;
2718+
Scanner.popMode p.scanner Jsx;
27152719
let loc = mkLoc childrenStartPos childrenEndPos in
27162720
makeListExpression loc children None
27172721

@@ -2743,6 +2747,7 @@ and parseJsxProp p =
27432747
Parser.next p;
27442748
(* no punning *)
27452749
let optional = Parser.optional p Question in
2750+
Scanner.popMode p.scanner Jsx;
27462751
let attrExpr =
27472752
let e = parsePrimaryExpr ~operand:(parseAtomicExpr p) p in
27482753
{e with pexp_attributes = propLocAttr :: e.pexp_attributes}
@@ -2765,6 +2770,7 @@ and parseJsxProp p =
27652770
Parser.next p;
27662771
match p.Parser.token with
27672772
| DotDotDot -> (
2773+
Scanner.popMode p.scanner Jsx;
27682774
Parser.next p;
27692775
let loc = mkLoc p.Parser.startPos p.prevEndPos in
27702776
let propLocAttr =
@@ -2790,9 +2796,7 @@ and parseJsxProps p =
27902796
and parseJsxChildren p =
27912797
let rec loop p children =
27922798
match p.Parser.token with
2793-
| Token.Eof | LessThanSlash ->
2794-
Scanner.popMode p.scanner Jsx;
2795-
List.rev children
2799+
| Token.Eof | LessThanSlash -> children
27962800
| LessThan ->
27972801
(* Imagine: <div> <Navbar /> <
27982802
* is `<` the start of a jsx-child? <div …
@@ -2808,23 +2812,23 @@ and parseJsxChildren p =
28082812
else
28092813
(* LessThanSlash *)
28102814
let () = p.token <- token in
2811-
let () = Scanner.popMode p.scanner Jsx in
2812-
List.rev children
2815+
children
28132816
| token when Grammar.isJsxChildStart token ->
28142817
let () = Scanner.popMode p.scanner Jsx in
28152818
let child =
28162819
parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p
28172820
in
28182821
loop p (child :: children)
2819-
| _ ->
2820-
Scanner.popMode p.scanner Jsx;
2821-
List.rev children
2822+
| _ -> children
28222823
in
28232824
match p.Parser.token with
28242825
| DotDotDot ->
28252826
Parser.next p;
28262827
(true, [parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p])
2827-
| _ -> (false, loop p [])
2828+
| _ ->
2829+
let children = List.rev (loop p []) in
2830+
Scanner.popMode p.scanner Jsx;
2831+
(false, children)
28282832

28292833
and parseBracedOrRecordExpr p =
28302834
let startPos = p.Parser.startPos in

jscomp/syntax/src/res_printer.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ let printLongident = function
421421

422422
type identifierStyle = ExoticIdent | NormalIdent
423423

424-
let classifyIdentContent ?(allowUident = false) txt =
424+
let classifyIdentContent ?(allowUident = false) ?(allowHyphen = false) txt =
425425
if Token.isKeywordTxt txt then ExoticIdent
426426
else
427427
let len = String.length txt in
@@ -431,16 +431,18 @@ let classifyIdentContent ?(allowUident = false) txt =
431431
match String.unsafe_get txt i with
432432
| 'A' .. 'Z' when allowUident -> loop (i + 1)
433433
| 'a' .. 'z' | '_' -> loop (i + 1)
434+
| '-' when allowHyphen -> loop (i + 1)
434435
| _ -> ExoticIdent
435436
else
436437
match String.unsafe_get txt i with
437438
| 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '\'' | '_' -> loop (i + 1)
439+
| '-' when allowHyphen -> loop (i + 1)
438440
| _ -> ExoticIdent
439441
in
440442
loop 0
441443

442-
let printIdentLike ?allowUident txt =
443-
match classifyIdentContent ?allowUident txt with
444+
let printIdentLike ?allowUident ?allowHyphen txt =
445+
match classifyIdentContent ?allowUident ?allowHyphen txt with
444446
| ExoticIdent -> Doc.concat [Doc.text "\\\""; Doc.text txt; Doc.text "\""]
445447
| NormalIdent -> Doc.text txt
446448

@@ -4462,7 +4464,7 @@ and printJsxProp ~state arg cmtTbl =
44624464
* Navabar.createElement -> Navbar
44634465
* Staff.Users.createElement -> Staff.Users *)
44644466
and printJsxName {txt = lident} =
4465-
let printIdent = printIdentLike ~allowUident:true in
4467+
let printIdent = printIdentLike ~allowUident:true ~allowHyphen:true in
44664468
let rec flatten acc lident =
44674469
match lident with
44684470
| Longident.Lident txt -> printIdent txt :: acc

jscomp/syntax/src/res_scanner.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,11 @@ let digitValue ch =
182182
let scanIdentifier scanner =
183183
let startOff = scanner.offset in
184184
let rec skipGoodChars scanner =
185-
match scanner.ch with
186-
| 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '\'' ->
185+
match (scanner.ch, inJsxMode scanner) with
186+
| ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '\''), false ->
187+
next scanner;
188+
skipGoodChars scanner
189+
| ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '\'' | '-'), true ->
187190
next scanner;
188191
skipGoodChars scanner
189192
| _ -> ()

jscomp/syntax/tests/parsing/errors/expressions/expected/jsx.res.txt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,4 @@
11

2-
Syntax error!
3-
tests/parsing/errors/expressions/jsx.res:1:12
4-
5-
1 │ let x = <di-v />
6-
2 │ let x = <Unclosed >;
7-
3 │ let x = <Foo.Bar></Free.Will>;
8-
9-
I'm not sure what to parse here when looking at "-".
10-
11-
122
Syntax error!
133
tests/parsing/errors/expressions/jsx.res:2:20
144

@@ -66,7 +56,7 @@
6656

6757
I'm not sure what to parse here when looking at ".".
6858

69-
let x = ((di ~children:[] ())[@JSX ]) - (v / ([%rescript.exprhole ]))
59+
let x = ((di-v ~children:[] ())[@JSX ])
7060
let x = ((Unclosed.createElement ~children:[] ())[@JSX ])
7161
let x =
7262
((Foo.Bar.createElement ~children:[] ())[@JSX ]) > ([%rescript.exprhole ])

jscomp/syntax/tests/printer/expr/expected/jsx.res.txt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ let x = <Foo.Bar className="container" />
44
let x = <Foo.Bar.Baz className="container" />
55
let x = <Foo.bar className="container" />
66
let x = <Foo.baz className="multiline" />
7-
let x = <\"custom-tag" className="container" />
8-
let x = <Foo.\"custom-tag" className="container" />
7+
let x = <custom-tag className="container" />
98

109
// https://github.com/rescript-lang/syntax/issues/570
1110
let x =
@@ -38,15 +37,10 @@ let x =
3837
{b}
3938
</A>
4039
let x =
41-
<\"custom-tag" className="container">
40+
<custom-tag className="container">
4241
{a}
4342
<B />
44-
</\"custom-tag">
45-
let x =
46-
<Foo.\"custom-tag" className="container">
47-
{a}
48-
<B />
49-
</Foo.\"custom-tag">
43+
</custom-tag>
5044

5145
let x = <div className="container" className2="container2" className3="container3" onClick />
5246

jscomp/syntax/tests/printer/expr/jsx.res

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ let x = <Foo.bar className="container" />
66
let x = <Foo.baz
77
className="multiline"
88
/>
9-
let x = <\"custom-tag" className="container" />
10-
let x = <Foo.\"custom-tag" className="container" />
9+
let x = <custom-tag className="container" />
1110

1211
// https://github.com/rescript-lang/syntax/issues/570
1312
let x = <A> <B> <C> <D /> <E /> </C> <F> <G /> <H /> </F> </B> </A>
1413
let x = <A> {children} <B/> </A>
1514
let x = <A> <B/> {children} </A>
1615
let x = <A> {a} </A>
1716
let x = <A> {a} {b} </A>
18-
let x = <\"custom-tag" className="container" > {a} <B/> </\"custom-tag">
19-
let x = <Foo.\"custom-tag" className="container" > {a} <B/> </Foo.\"custom-tag">
17+
let x = <custom-tag className="container" > {a} <B/> </custom-tag>
2018

2119
let x =
2220
<div

0 commit comments

Comments
 (0)