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

Commit c44c04c

Browse files
Implement jsx spread printing (#368)
* Implement jsx spread printing. Fixes #364 Printing of `<Animated> ...{x => <div />} </Animated>` was not implemented * Add extra test cases
1 parent 5f3849d commit c44c04c

File tree

7 files changed

+230
-29
lines changed

7 files changed

+230
-29
lines changed

src/res_printer.ml

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3834,7 +3834,11 @@ and printJsxExpression lident args cmtTbl =
38343834
let name = printJsxName lident in
38353835
let (formattedProps, children) = printJsxProps args cmtTbl in
38363836
(* <div className="test" /> *)
3837-
let isSelfClosing = match children with | [] -> true | _ -> false in
3837+
let isSelfClosing =
3838+
match children with
3839+
| Some ({Parsetree.pexp_desc = Pexp_construct ({txt = Longident.Lident "[]"}, None)}) -> true
3840+
| _ -> false
3841+
in
38383842
Doc.group (
38393843
Doc.concat [
38403844
Doc.group (
@@ -3851,7 +3855,10 @@ and printJsxExpression lident args cmtTbl =
38513855
Doc.indent (
38523856
Doc.concat [
38533857
Doc.line;
3854-
printJsxChildren children cmtTbl;
3858+
(match children with
3859+
| Some childrenExpression -> printJsxChildren childrenExpression cmtTbl
3860+
| None -> Doc.nil
3861+
);
38553862
]
38563863
);
38573864
Doc.line;
@@ -3865,17 +3872,17 @@ and printJsxExpression lident args cmtTbl =
38653872
and printJsxFragment expr cmtTbl =
38663873
let opening = Doc.text "<>" in
38673874
let closing = Doc.text "</>" in
3868-
let (children, _) = ParsetreeViewer.collectListExpressions expr in
3875+
(* let (children, _) = ParsetreeViewer.collectListExpressions expr in *)
38693876
Doc.group (
38703877
Doc.concat [
38713878
opening;
3872-
begin match children with
3873-
| [] -> Doc.nil
3874-
| children ->
3879+
begin match expr.pexp_desc with
3880+
| Pexp_construct ({txt = Longident.Lident "[]"}, None) -> Doc.nil
3881+
| _ ->
38753882
Doc.indent (
38763883
Doc.concat [
38773884
Doc.line;
3878-
printJsxChildren children cmtTbl;
3885+
printJsxChildren expr cmtTbl;
38793886
]
38803887
)
38813888
end;
@@ -3884,29 +3891,46 @@ and printJsxFragment expr cmtTbl =
38843891
]
38853892
)
38863893

3887-
and printJsxChildren (children: Parsetree.expression list) cmtTbl =
3888-
Doc.group (
3889-
Doc.join ~sep:Doc.line (
3890-
List.map (fun (expr : Parsetree.expression) ->
3891-
let leadingLineCommentPresent = hasLeadingLineComment cmtTbl expr.pexp_loc in
3892-
let exprDoc = printExpressionWithComments expr cmtTbl in
3893-
match Parens.jsxChildExpr expr with
3894-
| Parenthesized | Braced _ ->
3895-
(* {(20: int)} make sure that we also protect the expression inside *)
3896-
let innerDoc = if Parens.bracedExpr expr then addParens exprDoc else exprDoc in
3897-
if leadingLineCommentPresent then
3898-
addBraces innerDoc
3899-
else
3900-
Doc.concat [Doc.lbrace; innerDoc; Doc.rbrace]
3901-
| Nothing -> exprDoc
3902-
) children
3894+
and printJsxChildren (childrenExpr : Parsetree.expression) cmtTbl =
3895+
match childrenExpr.pexp_desc with
3896+
| Pexp_construct ({txt = Longident.Lident "::"}, _) ->
3897+
let (children, _) = ParsetreeViewer.collectListExpressions childrenExpr in
3898+
Doc.group (
3899+
Doc.join ~sep:Doc.line (
3900+
List.map (fun (expr : Parsetree.expression) ->
3901+
let leadingLineCommentPresent = hasLeadingLineComment cmtTbl expr.pexp_loc in
3902+
let exprDoc = printExpressionWithComments expr cmtTbl in
3903+
match Parens.jsxChildExpr expr with
3904+
| Parenthesized | Braced _ ->
3905+
(* {(20: int)} make sure that we also protect the expression inside *)
3906+
let innerDoc = if Parens.bracedExpr expr then addParens exprDoc else exprDoc in
3907+
if leadingLineCommentPresent then
3908+
addBraces innerDoc
3909+
else
3910+
Doc.concat [Doc.lbrace; innerDoc; Doc.rbrace]
3911+
| Nothing -> exprDoc
3912+
) children
3913+
)
39033914
)
3904-
)
3915+
| _ ->
3916+
let leadingLineCommentPresent = hasLeadingLineComment cmtTbl childrenExpr.pexp_loc in
3917+
let exprDoc = printExpressionWithComments childrenExpr cmtTbl in
3918+
Doc.concat [
3919+
Doc.dotdotdot;
3920+
match Parens.jsxChildExpr childrenExpr with
3921+
| Parenthesized | Braced _ ->
3922+
let innerDoc = if Parens.bracedExpr childrenExpr then addParens exprDoc else exprDoc in
3923+
if leadingLineCommentPresent then
3924+
addBraces innerDoc
3925+
else
3926+
Doc.concat [Doc.lbrace; innerDoc; Doc.rbrace]
3927+
| Nothing -> exprDoc
3928+
]
39053929

3906-
and printJsxProps args cmtTbl =
3930+
and printJsxProps args cmtTbl :(Doc.t * Parsetree.expression option) =
39073931
let rec loop props args =
39083932
match args with
3909-
| [] -> (Doc.nil, [])
3933+
| [] -> (Doc.nil, None)
39103934
| [
39113935
(Asttypes.Labelled "children", children);
39123936
(
@@ -3925,8 +3949,7 @@ and printJsxProps args cmtTbl =
39253949
)
39263950
]
39273951
) in
3928-
let (children, _) = ParsetreeViewer.collectListExpressions children in
3929-
(formattedProps, children)
3952+
(formattedProps, Some children)
39303953
| arg::args ->
39313954
let propDoc = printJsxProp arg cmtTbl in
39323955
loop (propDoc::props) args

tests/conversion/reason/expected/jsxProps.re.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,11 @@ let handleClick = (href, event) =>
77
@react.component
88
let make = (~href, ~className="", ~children) =>
99
<a href className onClick={event => handleClick(href, event)}> children </a>
10+
11+
<Animated> ...{x => <div />} </Animated>
12+
13+
<div> ...element </div>
14+
<div> ...{a => 1} </div>
15+
<div> ...<span /> </div>
16+
<div> ...[a, b] </div>
17+
<div> ...{(1, 2)} </div>

tests/conversion/reason/jsxProps.re

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,11 @@ let make = (~href, ~className="", ~children) =>
99
<a href className onClick={event => handleClick(href, event)}>
1010
children
1111
</a>;
12+
13+
<Animated> ...{x => <div />} </Animated>;
14+
15+
<div> ...element </div>;
16+
<div> ...{(a) => 1} </div>;
17+
<div> ...<span /> </div>;
18+
<div> ...[|a, b|] </div>;
19+
<div> ...(1, 2) </div>;

tests/parsing/grammar/expressions/expected/jsx.res.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,4 +560,14 @@ let _ =
560560
~children:[((Js.log (a <= 10))
561561
[@ns.braces ])] ())
562562
[@JSX ])] ())
563-
[@JSX ])] ())[@JSX ])
563+
[@JSX ])] ())[@JSX ])
564+
;;((div ~children:element ())[@JSX ])
565+
;;((div ~children:((fun a -> 1)[@ns.braces ]) ())[@JSX ])
566+
;;((div ~children:((span ~children:[] ())[@JSX ]) ())[@JSX ])
567+
;;((div ~children:[|a|] ())[@JSX ])
568+
;;((div ~children:(1, 2) ())[@JSX ])
569+
;;(([element])[@JSX ])
570+
;;(([(((fun a -> 1))[@ns.braces ])])[@JSX ])
571+
;;(([((span ~children:[] ())[@JSX ])])[@JSX ])
572+
;;(([[|a|]])[@JSX ])
573+
;;(([(1, 2)])[@JSX ])

tests/parsing/grammar/expressions/jsx.res

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,16 @@ let _ = <View style=styles["backgroundImageWrapper"]>
500500
<div> {Js.log(a <= 10)} </div>
501501
<div> <div> {Js.log(a <= 10)} </div> </div>
502502
<div> <div onClick={_ => Js.log(a <= 10) }> <div> {Js.log(a <= 10)} </div> </div> </div>
503+
504+
505+
<div> ...element </div>
506+
<div> ...{(a) => 1} </div>
507+
<div> ...<span /> </div>
508+
<div> ...[a] </div>
509+
<div> ...(1, 2) </div>
510+
511+
<> ...element </>
512+
<> ...{(a) => 1} </>
513+
<> ...<span /> </>
514+
<> ...[a] </>
515+
<> ...(1, 2) </>

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,63 @@ module App = {
307307
}
308308
}
309309
</div>
310+
311+
<Animated> ...{x => <div />} </Animated>
312+
<div> ...c </div>
313+
314+
<Animated initialValue=0.0 value>
315+
...{ReactDOMRe.Style.make(
316+
~width="20px",
317+
~height="20px",
318+
~borderRadius="100%",
319+
~backgroundColor="red",
320+
)}
321+
</Animated>
322+
323+
<Animated initialValue=0.0 value>
324+
...{value =>
325+
<div
326+
style={ReactDOMRe.Style.make(
327+
~width="20px",
328+
~height="20px",
329+
~borderRadius="100%",
330+
~backgroundColor="red",
331+
)}
332+
/>}
333+
</Animated>
334+
335+
<Animated initialValue=0.0 value>
336+
...{(value): ReasonReact.element =>
337+
<div
338+
style={ReactDOMRe.Style.make(
339+
~width="20px",
340+
~height="20px",
341+
~borderRadius="100%",
342+
~backgroundColor="red",
343+
)}
344+
/>}
345+
</Animated>
346+
347+
<Animated initialValue=0.0 value>
348+
...{value => {
349+
let width = "20px"
350+
let height = "20px"
351+
352+
<div
353+
style={ReactDOMRe.Style.make(~width, ~height, ~borderRadius="100%", ~backgroundColor="red")}
354+
/>
355+
}}
356+
</Animated>
357+
358+
let v =
359+
<A>
360+
<B>
361+
...{_ => {
362+
let renderX = x => {
363+
let y = x ++ x
364+
<div key=y />
365+
}
366+
renderX("foo")
367+
}}
368+
</B>
369+
</A>

tests/printer/expr/jsx.res

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,82 @@ module App = {
316316
}
317317
}
318318
</div>
319+
320+
<Animated> ...{x => <div />} </Animated>
321+
<div>...c</div>;
322+
323+
<Animated initialValue=0.0 value>
324+
...{
325+
ReactDOMRe.Style.make(
326+
~width="20px",
327+
~height="20px",
328+
~borderRadius="100%",
329+
~backgroundColor="red",
330+
)
331+
}
332+
</Animated>;
333+
334+
<Animated initialValue=0.0 value>
335+
...{
336+
value =>
337+
<div
338+
style={
339+
ReactDOMRe.Style.make(
340+
~width="20px",
341+
~height="20px",
342+
~borderRadius="100%",
343+
~backgroundColor="red",
344+
)
345+
}
346+
/>
347+
}
348+
</Animated>
349+
350+
<Animated initialValue=0.0 value>
351+
...{
352+
(value) :ReasonReact.element =>
353+
<div
354+
style={
355+
ReactDOMRe.Style.make(
356+
~width="20px",
357+
~height="20px",
358+
~borderRadius="100%",
359+
~backgroundColor="red",
360+
)
361+
}
362+
/>
363+
}
364+
</Animated>;
365+
366+
<Animated initialValue=0.0 value>
367+
...{value => {
368+
let width = "20px"
369+
let height = "20px"
370+
371+
<div
372+
style={
373+
ReactDOMRe.Style.make(
374+
~width,
375+
~height,
376+
~borderRadius="100%",
377+
~backgroundColor="red",
378+
)
379+
}
380+
/>
381+
}
382+
}
383+
</Animated>
384+
385+
386+
let v =
387+
<A>
388+
<B>
389+
...{_ => {
390+
let renderX = x => {
391+
let y = x ++ x;
392+
<div key=y />;
393+
}
394+
renderX("foo")
395+
}}
396+
</B>
397+
</A>

0 commit comments

Comments
 (0)