From ac648b7dd08b5141fdba20bf970fc9df68cb0211 Mon Sep 17 00:00:00 2001 From: Pedro B S Lisboa Date: Thu, 30 Jan 2025 05:57:56 -0300 Subject: [PATCH] fix: don't punne record fields and jsx prop with attr Signed-off-by: Pedro B S Lisboa --- src/reason-parser/reason_pprint_ast.ml | 32 +++++++++++++++++--------- test/jsx.t/input.re | 5 ++++ test/jsx.t/run.t | 20 ++++++++++++++++ test/sequences.t/input.re | 17 ++++++++++++++ test/sequences.t/run.t | 18 ++++++++++++++- test/typeDeclarations.t/input.re | 8 +++++++ test/typeDeclarations.t/run.t | 8 +++++++ 7 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/reason-parser/reason_pprint_ast.ml b/src/reason-parser/reason_pprint_ast.ml index f5307671b..1c7d2ba13 100644 --- a/src/reason-parser/reason_pprint_ast.ml +++ b/src/reason-parser/reason_pprint_ast.ml @@ -2113,8 +2113,10 @@ let createFormatter () = true | _ -> false - let isPunnedJsxArg lbl ident = - (not (isLongIdentWithDot ident.txt)) && Longident.last_exn ident.txt = lbl + let isPunnedJsxArg lbl ident attr = + (not (isLongIdentWithDot ident.txt)) + && Longident.last_exn ident.txt = lbl + && attr = [] let is_unit_pattern x = match x.ppat_desc with @@ -4330,7 +4332,8 @@ let createFormatter () = PipeFirstTree.flastNode list) into a more convenient structure * that allows us to express the segments: "foo" "f(a, b)" "g(c, d)". * PipeFirstTree.t expresses those segments. * - [{exp = foo; args = []}; {exp = f; args = [a; b]}; {exp = g; args = [c; d]}] + [{exp = foo; args = []}; {exp = f; args = [a; b]}; {exp = g; args = + [c; d]}] *) let rec parse acc = function | PipeFirstTree.Exp e :: PipeFirstTree.Args args :: xs -> @@ -4360,12 +4363,13 @@ let createFormatter () = *) let (flatNodes : PipeFirstTree.flatT) = flatten ~uncurried [] e in (* Turn * [Exp foo; Exp f; Args [a; b]; Exp g; Args [c; d]] * into * - [{exp = foo; args = []}; {exp = f; args = [a; b]}; {exp = g; args = [c; d]}] + [{exp = foo; args = []}; {exp = f; args = [a; b]}; {exp = g; args = + [c; d]}] *) let (pipetree : PipeFirstTree.t) = parse [] flatNodes in (* Turn * - [{exp = foo; args = []}; {exp = f; args = [a; b]}; {exp = g; args = [c; d]}] - * into * [foo; ->f(a, b); ->g(c, d)] + [{exp = foo; args = []}; {exp = f; args = [a; b]}; {exp = g; args = + [c; d]}] * into * [foo; ->f(a, b); ->g(c, d)] *) let pipeSegments = match pipetree with @@ -5233,13 +5237,14 @@ let createFormatter () = processedAttrs (Some [ self#dotdotdotChild expr ]) | (Optional lbl, expression) :: tail -> - let { Reason_attributes.jsxAttrs; _ } = + let { Reason_attributes.jsxAttrs; stdAttrs; _ } = Reason_attributes.partitionAttributes expression.pexp_attributes in let value_has_jsx = jsxAttrs != [] in let nextAttr = match expression.pexp_desc with - | Pexp_ident ident when isPunnedJsxArg lbl ident -> + | Pexp_ident ident + when isPunnedJsxArg lbl ident stdAttrs -> makeList ~break:Layout.Never [ atom "?"; atom lbl ] | Pexp_construct _ when value_has_jsx -> label @@ -5254,13 +5259,15 @@ let createFormatter () = in processArguments tail (nextAttr :: processedAttrs) children | (Labelled lbl, expression) :: tail -> - let { Reason_attributes.jsxAttrs; _ } = + let { Reason_attributes.jsxAttrs; stdAttrs; _ } = Reason_attributes.partitionAttributes expression.pexp_attributes in let value_has_jsx = jsxAttrs != [] in let nextAttr = match expression.pexp_desc with - | Pexp_ident ident when isPunnedJsxArg lbl ident -> atom lbl + | Pexp_ident ident + when isPunnedJsxArg lbl ident stdAttrs -> + atom lbl | _ when isJSXComponent expression -> label (atom (lbl ^ "=")) @@ -7095,13 +7102,16 @@ let createFormatter () = ; loc_ghost = false } in + let stdAttrs = Reason_attributes.extractStdAttrs e.pexp_attributes in let theRow = match e.pexp_desc, shouldPun, allowPunning with (* record value punning. Turns {foo: foo, bar: 1} into {foo, bar: 1} *) (* also turns {Foo.bar: bar, baz: 1} into {Foo.bar, baz: 1} *) + (* don't turn {bar: [@foo] bar, baz: 1} into {bar, baz: 1} *) (* don't turn {bar: Foo.bar, baz: 1} into {bar, baz: 1}, naturally *) | Pexp_ident { txt = Lident value; _ }, true, true - when Longident.last_exn li.txt = value -> + when Longident.last_exn li.txt = value && stdAttrs = [] + -> makeList (maybeQuoteFirstElem li []) (* Force breaks for nested records or mel.obj sugar * Example: diff --git a/test/jsx.t/input.re b/test/jsx.t/input.re index 3d9de4ce5..b77f48fe7 100644 --- a/test/jsx.t/input.re +++ b/test/jsx.t/input.re @@ -103,6 +103,9 @@ let icon = ; +/* Don't pun for explicitly props with attributes */ +; + /* don't pun explicitly passed optional with module identifier */ ; @@ -131,6 +134,8 @@ let y = [