Skip to content

Commit 7deb6f5

Browse files
committed
allow hyphens in jsx tag names
1 parent 1d4910a commit 7deb6f5

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
@@ -2621,10 +2621,11 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26212621
| GreaterThan -> (
26222622
(* <foo a=b> bar </foo> *)
26232623
let childrenStartPos = p.Parser.startPos in
2624-
Scanner.setJsxMode p.scanner;
26252624
Parser.next p;
26262625
let spread, children = parseJsxChildren p in
26272626
let childrenEndPos = p.Parser.startPos in
2627+
Scanner.popMode p.scanner Jsx;
2628+
Scanner.setJsxMode p.scanner;
26282629
let () =
26292630
match p.token with
26302631
| LessThanSlash -> Parser.next p
@@ -2689,6 +2690,8 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26892690
* jsx-children ::= primary-expr* * => 0 or more
26902691
*)
26912692
and parseJsx p =
2693+
Scanner.popMode p.scanner Jsx;
2694+
Scanner.setJsxMode p.Parser.scanner;
26922695
Parser.leaveBreadcrumb p Grammar.Jsx;
26932696
let startPos = p.Parser.startPos in
26942697
Parser.expect LessThan p;
@@ -2700,6 +2703,7 @@ and parseJsx p =
27002703
parseJsxFragment p
27012704
| _ -> parseJsxName p
27022705
in
2706+
Scanner.popMode p.scanner Jsx;
27032707
Parser.eatBreadcrumb p;
27042708
{jsxExpr with pexp_attributes = [jsxAttr]}
27052709

@@ -2710,12 +2714,12 @@ and parseJsx p =
27102714
*)
27112715
and parseJsxFragment p =
27122716
let childrenStartPos = p.Parser.startPos in
2713-
Scanner.setJsxMode p.scanner;
27142717
Parser.expect GreaterThan p;
27152718
let _spread, children = parseJsxChildren p in
27162719
let childrenEndPos = p.Parser.startPos in
27172720
Parser.expect LessThanSlash p;
27182721
Parser.expect GreaterThan p;
2722+
Scanner.popMode p.scanner Jsx;
27192723
let loc = mkLoc childrenStartPos childrenEndPos in
27202724
makeListExpression loc children None
27212725

@@ -2747,6 +2751,7 @@ and parseJsxProp p =
27472751
Parser.next p;
27482752
(* no punning *)
27492753
let optional = Parser.optional p Question in
2754+
Scanner.popMode p.scanner Jsx;
27502755
let attrExpr =
27512756
let e = parsePrimaryExpr ~operand:(parseAtomicExpr p) p in
27522757
{e with pexp_attributes = propLocAttr :: e.pexp_attributes}
@@ -2769,6 +2774,7 @@ and parseJsxProp p =
27692774
Parser.next p;
27702775
match p.Parser.token with
27712776
| DotDotDot -> (
2777+
Scanner.popMode p.scanner Jsx;
27722778
Parser.next p;
27732779
let loc = mkLoc p.Parser.startPos p.prevEndPos in
27742780
let propLocAttr =
@@ -2794,9 +2800,7 @@ and parseJsxProps p =
27942800
and parseJsxChildren p =
27952801
let rec loop p children =
27962802
match p.Parser.token with
2797-
| Token.Eof | LessThanSlash ->
2798-
Scanner.popMode p.scanner Jsx;
2799-
List.rev children
2803+
| Token.Eof | LessThanSlash -> children
28002804
| LessThan ->
28012805
(* Imagine: <div> <Navbar /> <
28022806
* is `<` the start of a jsx-child? <div …
@@ -2812,23 +2816,23 @@ and parseJsxChildren p =
28122816
else
28132817
(* LessThanSlash *)
28142818
let () = p.token <- token in
2815-
let () = Scanner.popMode p.scanner Jsx in
2816-
List.rev children
2819+
children
28172820
| token when Grammar.isJsxChildStart token ->
28182821
let () = Scanner.popMode p.scanner Jsx in
28192822
let child =
28202823
parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p
28212824
in
28222825
loop p (child :: children)
2823-
| _ ->
2824-
Scanner.popMode p.scanner Jsx;
2825-
List.rev children
2826+
| _ -> children
28262827
in
28272828
match p.Parser.token with
28282829
| DotDotDot ->
28292830
Parser.next p;
28302831
(true, [parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p])
2831-
| _ -> (false, loop p [])
2832+
| _ ->
2833+
let children = List.rev (loop p []) in
2834+
Scanner.popMode p.scanner Jsx;
2835+
(false, children)
28322836

28332837
and parseBracedOrRecordExpr p =
28342838
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

@@ -4404,7 +4406,7 @@ and printJsxProp ~state arg cmtTbl =
44044406
* Navabar.createElement -> Navbar
44054407
* Staff.Users.createElement -> Staff.Users *)
44064408
and printJsxName {txt = lident} =
4407-
let printIdent = printIdentLike ~allowUident:true in
4409+
let printIdent = printIdentLike ~allowUident:true ~allowHyphen:true in
44084410
let rec flatten acc lident =
44094411
match lident with
44104412
| 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)