From ef348a31b80b18fb02e3363eb32a809494b1993b Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Wed, 23 Nov 2022 10:55:54 -0500 Subject: [PATCH] jsx: pretty-print single-line JSX elements --- .../bundler/snapshots/snapshots_default.txt | 27 +-- .../bundler/snapshots/snapshots_loader.txt | 8 +- .../bundler/snapshots/snapshots_lower.txt | 27 +-- .../bundler/snapshots/snapshots_tsconfig.txt | 62 +++---- internal/js_ast/js_ast.go | 9 +- internal/js_parser/js_parser.go | 29 ++- internal/js_parser/js_parser_test.go | 175 +++++++++--------- internal/js_parser/ts_parser_test.go | 16 +- internal/js_printer/js_printer.go | 21 ++- internal/js_printer/js_printer_test.go | 16 ++ 10 files changed, 199 insertions(+), 191 deletions(-) diff --git a/internal/bundler/snapshots/snapshots_default.txt b/internal/bundler/snapshots/snapshots_default.txt index 6236a532b5c..3446224aaa3 100644 --- a/internal/bundler/snapshots/snapshots_default.txt +++ b/internal/bundler/snapshots/snapshots_default.txt @@ -553,16 +553,10 @@ console.log(123); TestDuplicatePropertyWarning ---------- /out/entry.js ---------- // outside-node-modules/index.jsx -console.log({ a: 1, a: 2 }, /* @__PURE__ */ React.createElement("div", { - a2: true, - a2: 3 -})); +console.log({ a: 1, a: 2 }, /* @__PURE__ */ React.createElement("div", { a2: true, a2: 3 })); // node_modules/inside-node-modules/index.jsx -console.log({ c: 1, c: 2 }, /* @__PURE__ */ React.createElement("div", { - c2: true, - c2: 3 -})); +console.log({ c: 1, c: 2 }, /* @__PURE__ */ React.createElement("div", { c2: true, c2: 3 })); ================================================================================ TestDynamicImportWithExpressionCJS @@ -1439,11 +1433,7 @@ var require_custom_react = __commonJS({ // entry.jsx var import_custom_react = __toESM(require_custom_react()); import { Fragment as Fragment2, jsx as jsx2 } from "react/jsx-runtime"; -console.log(/* @__PURE__ */ jsx2("div", { - jsx: import_custom_react.jsx -}), /* @__PURE__ */ jsx2(Fragment2, { - children: /* @__PURE__ */ jsx2(import_custom_react.Fragment, {}) -})); +console.log(/* @__PURE__ */ jsx2("div", { jsx: import_custom_react.jsx }), /* @__PURE__ */ jsx2(Fragment2, { children: /* @__PURE__ */ jsx2(import_custom_react.Fragment, {}) })); ================================================================================ TestJSXAutomaticImportsES6 @@ -1456,21 +1446,14 @@ function Fragment() { // entry.jsx import { Fragment as Fragment2, jsx as jsx2 } from "react/jsx-runtime"; -console.log(/* @__PURE__ */ jsx2("div", { - jsx -}), /* @__PURE__ */ jsx2(Fragment2, { - children: /* @__PURE__ */ jsx2(Fragment, {}) -})); +console.log(/* @__PURE__ */ jsx2("div", { jsx }), /* @__PURE__ */ jsx2(Fragment2, { children: /* @__PURE__ */ jsx2(Fragment, {}) })); ================================================================================ TestJSXAutomaticNoNameCollision ---------- /out.js ---------- var import_react = require("react"); var import_react2 = require("@remix-run/react"); -const x = /* @__PURE__ */ (0, import_react.createElement)(import_react2.Link, { - ...y, - key: z -}); +const x = /* @__PURE__ */ (0, import_react.createElement)(import_react2.Link, { ...y, key: z }); ================================================================================ TestJSXConstantFragments diff --git a/internal/bundler/snapshots/snapshots_loader.txt b/internal/bundler/snapshots/snapshots_loader.txt index 580a48f5e22..7e5420e9f56 100644 --- a/internal/bundler/snapshots/snapshots_loader.txt +++ b/internal/bundler/snapshots/snapshots_loader.txt @@ -643,9 +643,7 @@ let Foo = { console.log("Fragment", ...args); } }; -export default /* @__PURE__ */ Foo.a(Foo.b, { - c: Foo.e -}); +export default /* @__PURE__ */ Foo.a(Foo.b, { c: Foo.e }); ================================================================================ TestManglePropsJSXTransformNamespace @@ -653,9 +651,7 @@ TestManglePropsJSXTransformNamespace export default [ /* @__PURE__ */ React.createElement(KEEP_THIS_, null), /* @__PURE__ */ React.createElement("KEEP:THIS_", null), - /* @__PURE__ */ React.createElement("foo", { - "KEEP:THIS_": true - }) + /* @__PURE__ */ React.createElement("foo", { "KEEP:THIS_": true }) ]; ================================================================================ diff --git a/internal/bundler/snapshots/snapshots_lower.txt b/internal/bundler/snapshots/snapshots_lower.txt index 5ac32abc3a1..a2d640c315e 100644 --- a/internal/bundler/snapshots/snapshots_lower.txt +++ b/internal/bundler/snapshots/snapshots_lower.txt @@ -800,29 +800,10 @@ let tests = [ ]; let jsx = [ /* @__PURE__ */ React.createElement("div", __spreadValues(__spreadValues({}, a), b)), - /* @__PURE__ */ React.createElement("div", __spreadValues({ - a: true, - b: true - }, c)), - /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues({}, a), { - b: true, - c: true - })), - /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues({ - a: true - }, b), { - c: true - })), - /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues(__spreadValues(__spreadProps(__spreadValues(__spreadValues({ - a: true, - b: true - }, c), d), { - e: true, - f: true - }), g), h), { - i: true, - j: true - })) + /* @__PURE__ */ React.createElement("div", __spreadValues({ a: true, b: true }, c)), + /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues({}, a), { b: true, c: true })), + /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues({ a: true }, b), { c: true })), + /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues(__spreadValues(__spreadProps(__spreadValues(__spreadValues({ a: true, b: true }, c), d), { e: true, f: true }), g), h), { i: true, j: true })) ]; ================================================================================ diff --git a/internal/bundler/snapshots/snapshots_tsconfig.txt b/internal/bundler/snapshots/snapshots_tsconfig.txt index 0debf837282..7d6b3998450 100644 --- a/internal/bundler/snapshots/snapshots_tsconfig.txt +++ b/internal/bundler/snapshots/snapshots_tsconfig.txt @@ -319,32 +319,28 @@ TestTsConfigReactJSX ---------- /Users/user/project/out.js ---------- // Users/user/project/entry.tsx import { Fragment, jsx, jsxs } from "notreact/jsx-runtime"; -console.log(/* @__PURE__ */ jsxs(Fragment, { - children: [ - /* @__PURE__ */ jsx("div", {}), - /* @__PURE__ */ jsx("div", {}) - ] -})); +console.log(/* @__PURE__ */ jsxs(Fragment, { children: [ + /* @__PURE__ */ jsx("div", {}), + /* @__PURE__ */ jsx("div", {}) +] })); ================================================================================ TestTsConfigReactJSXDev ---------- /Users/user/project/out.js ---------- // Users/user/project/entry.tsx import { Fragment, jsxDEV } from "react/jsx-dev-runtime"; -console.log(/* @__PURE__ */ jsxDEV(Fragment, { - children: [ - /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { - fileName: "Users/user/project/entry.tsx", - lineNumber: 2, - columnNumber: 19 - }, this), - /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { - fileName: "Users/user/project/entry.tsx", - lineNumber: 2, - columnNumber: 25 - }, this) - ] -}, void 0, true, { +console.log(/* @__PURE__ */ jsxDEV(Fragment, { children: [ + /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { + fileName: "Users/user/project/entry.tsx", + lineNumber: 2, + columnNumber: 19 + }, this), + /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { + fileName: "Users/user/project/entry.tsx", + lineNumber: 2, + columnNumber: 25 + }, this) +] }, void 0, true, { fileName: "Users/user/project/entry.tsx", lineNumber: 2, columnNumber: 17 @@ -355,20 +351,18 @@ TestTsConfigReactJSXWithDevInMainConfig ---------- /Users/user/project/out.js ---------- // Users/user/project/entry.tsx import { Fragment, jsxDEV } from "react/jsx-dev-runtime"; -console.log(/* @__PURE__ */ jsxDEV(Fragment, { - children: [ - /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { - fileName: "Users/user/project/entry.tsx", - lineNumber: 2, - columnNumber: 19 - }, this), - /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { - fileName: "Users/user/project/entry.tsx", - lineNumber: 2, - columnNumber: 25 - }, this) - ] -}, void 0, true, { +console.log(/* @__PURE__ */ jsxDEV(Fragment, { children: [ + /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { + fileName: "Users/user/project/entry.tsx", + lineNumber: 2, + columnNumber: 19 + }, this), + /* @__PURE__ */ jsxDEV("div", {}, void 0, false, { + fileName: "Users/user/project/entry.tsx", + lineNumber: 2, + columnNumber: 25 + }, this) +] }, void 0, true, { fileName: "Users/user/project/entry.tsx", lineNumber: 2, columnNumber: 17 diff --git a/internal/js_ast/js_ast.go b/internal/js_ast/js_ast.go index 68215b9c0ca..725eabe9126 100644 --- a/internal/js_ast/js_ast.go +++ b/internal/js_ast/js_ast.go @@ -660,10 +660,11 @@ type EMangledProp struct { } type EJSXElement struct { - TagOrNil Expr - Properties []Property - Children []Expr - CloseLoc logger.Loc + TagOrNil Expr + Properties []Property + Children []Expr + CloseLoc logger.Loc + IsTagSingleLine bool } type ENumber struct{ Value float64 } diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index 079290da31d..709f1942250 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -4608,9 +4608,14 @@ func (p *parser) parseJSXElement(loc logger.Loc) js_ast.Expr { // Parse attributes var previousStringWithBackslashLoc logger.Loc properties := []js_ast.Property{} + isSingleLine := true if startTagOrNil.Data != nil { parseAttributes: for { + if p.lexer.HasNewlineBefore { + isSingleLine = false + } + switch p.lexer.Token { case js_lexer.TIdentifier: // Parse the key @@ -4749,9 +4754,10 @@ func (p *parser) parseJSXElement(loc logger.Loc) js_ast.Expr { p.lexer.Expected(js_lexer.TGreaterThan) } return js_ast.Expr{Loc: loc, Data: &js_ast.EJSXElement{ - TagOrNil: startTagOrNil, - Properties: properties, - CloseLoc: closeLoc, + TagOrNil: startTagOrNil, + Properties: properties, + CloseLoc: closeLoc, + IsTagSingleLine: isSingleLine, }} } @@ -4841,10 +4847,11 @@ func (p *parser) parseJSXElement(loc logger.Loc) js_ast.Expr { } return js_ast.Expr{Loc: loc, Data: &js_ast.EJSXElement{ - TagOrNil: startTagOrNil, - Properties: properties, - Children: children, - CloseLoc: lessThanLoc, + TagOrNil: startTagOrNil, + Properties: properties, + Children: children, + CloseLoc: lessThanLoc, + IsTagSingleLine: isSingleLine, }} default: @@ -12394,7 +12401,8 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO args := []js_ast.Expr{e.TagOrNil} if len(e.Properties) > 0 { args = append(args, p.lowerObjectSpread(propsLoc, &js_ast.EObject{ - Properties: e.Properties, + Properties: e.Properties, + IsSingleLine: e.IsTagSingleLine, })) } else { args = append(args, js_ast.Expr{Loc: propsLoc, Data: js_ast.ENullShared}) @@ -12418,6 +12426,7 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO Target: target, Args: args, CloseParenLoc: e.CloseLoc, + IsMultiLine: !e.IsTagSingleLine, // Enable tree shaking CanBeUnwrappedIfUnused: !p.options.ignoreDCEAnnotations && !p.options.jsx.SideEffects, @@ -12496,7 +12505,8 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO } args = append(args, p.lowerObjectSpread(propsLoc, &js_ast.EObject{ - Properties: properties, + Properties: properties, + IsSingleLine: e.IsTagSingleLine, })) // "key" @@ -12546,6 +12556,7 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO Target: p.importJSXSymbol(expr.Loc, jsx), Args: args, CloseParenLoc: e.CloseLoc, + IsMultiLine: !e.IsTagSingleLine, // Enable tree shaking CanBeUnwrappedIfUnused: !p.options.ignoreDCEAnnotations && !p.options.jsx.SideEffects, diff --git a/internal/js_parser/js_parser_test.go b/internal/js_parser/js_parser_test.go index 4c711150bd7..411a2111dc1 100644 --- a/internal/js_parser/js_parser_test.go +++ b/internal/js_parser/js_parser_test.go @@ -3717,15 +3717,15 @@ func TestMangleObject(t *testing.T) { } func TestMangleObjectJSX(t *testing.T) { - expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...{}\n});\n") - expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...null\n});\n") - expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...{ bar }\n});\n") - expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...bar\n});\n") + expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true, ...{} });\n") + expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true, ...null });\n") + expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true, ...{ bar } });\n") + expectPrintedJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true, ...bar });\n") - expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true\n});\n") - expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true\n});\n") - expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n bar\n});\n") - expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...bar\n});\n") + expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true });\n") + expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true });\n") + expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true, bar });\n") + expectPrintedMangleJSX(t, "x = ", "x = /* @__PURE__ */ React.createElement(\"foo\", { bar: true, ...bar });\n") } func TestMangleArrow(t *testing.T) { @@ -4534,7 +4534,7 @@ func TestUnicodeWhitespace(t *testing.T) { // Test "js_lexer.NextInsideJSXElement()" expectParseErrorJSX(t, "", ": ERROR: Expected \">\" but found \"\\b\"\n") for _, s := range whitespace { - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n y: true\n});\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { y: true });\n") } // Test "js_lexer.NextJSXElementChild()" @@ -4624,15 +4624,15 @@ func TestJSX(t *testing.T) { expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a0\", null);\n") expectParseErrorJSX(t, "<0a/>", ": ERROR: Expected identifier but found \"0\"\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: true\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"\\\\\"\n});\n") - expectPrintedJSX(t, "\"/>", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"<>\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"<>\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"&wrong;\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: (1, 2)\n});\n") - expectPrintedJSX(t, "}/>", "/* @__PURE__ */ React.createElement(\"a\", {\n b: /* @__PURE__ */ React.createElement(\"c\", null)\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n ...props\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"šŸ™‚\"\n});\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: true });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"\\\\\" });\n") + expectPrintedJSX(t, "\"/>", "/* @__PURE__ */ React.createElement(\"a\", { b: \"<>\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"<>\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"&wrong;\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: (1, 2) });\n") + expectPrintedJSX(t, "}/>", "/* @__PURE__ */ React.createElement(\"a\", { b: /* @__PURE__ */ React.createElement(\"c\", null) });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { ...props });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"šŸ™‚\" });\n") expectPrintedJSX(t, "\n", "/* @__PURE__ */ React.createElement(\"a\", null);\n") expectPrintedJSX(t, "123", "/* @__PURE__ */ React.createElement(\"a\", null, \"123\");\n") @@ -4650,32 +4650,32 @@ func TestJSX(t *testing.T) { expectPrintedJSX(t, "{...children}", "/* @__PURE__ */ React.createElement(\"a\", null, ...children);\n") // Note: The TypeScript compiler and Babel disagree. This matches TypeScript. - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" c\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" \\nc\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"\\n c\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"c \"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"c \\n\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"c\\n \"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"c d\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"c \\nd\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"c\\n d\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" c\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" \\nc\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"\\n c\"\n});\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" c\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" \\nc\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"\\n c\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"c \" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"c \\n\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"c\\n \" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"c d\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"c \\nd\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"c\\n d\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" c\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" \\nc\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"\\n c\" });\n") // Same test as above except with multi-byte Unicode characters - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" šŸ™‚\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" \\nšŸ™‚\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"\\n šŸ™‚\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"šŸ™‚ \"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"šŸ™‚ \\n\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"šŸ™‚\\n \"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"šŸ™‚ šŸ•\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"šŸ™‚ \\nšŸ•\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"šŸ™‚\\n šŸ•\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" šŸ™‚\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \" \\nšŸ™‚\"\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n b: \"\\n šŸ™‚\"\n});\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" šŸ™‚\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" \\nšŸ™‚\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"\\n šŸ™‚\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"šŸ™‚ \" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"šŸ™‚ \\n\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"šŸ™‚\\n \" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"šŸ™‚ šŸ•\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"šŸ™‚ \\nšŸ•\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"šŸ™‚\\n šŸ•\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" šŸ™‚\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \" \\nšŸ™‚\" });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { b: \"\\n šŸ™‚\" });\n") expectPrintedJSX(t, " b", "/* @__PURE__ */ React.createElement(\"a\", null, \" b\");\n") expectPrintedJSX(t, " \nb", "/* @__PURE__ */ React.createElement(\"a\", null, \"b\");\n") @@ -4746,7 +4746,7 @@ func TestJSX(t *testing.T) { expectPrintedJSX(t, "< /**/ a/>", "/* @__PURE__ */ React.createElement(\"a\", null);\n") expectPrintedJSX(t, "< //\n a/>", "/* @__PURE__ */ React.createElement(\"a\", null);\n") expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", null);\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", null);\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\n \"a\",\n null\n);\n") expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", null);\n") expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", null);\n") @@ -4763,7 +4763,7 @@ func TestJSX(t *testing.T) { // Unicode tests expectPrintedJSX(t, "<\U00020000/>", "/* @__PURE__ */ React.createElement(\U00020000, null);\n") expectPrintedJSX(t, "\U00020000", "/* @__PURE__ */ React.createElement(\"a\", null, \"\U00020000\");\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", {\n \"\U00020000\": 0\n});\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a\", { \"\U00020000\": 0 });\n") // Comment tests expectParseErrorJSX(t, "", ": ERROR: Expected \"*/\" to terminate multi-line comment\n: NOTE: The multi-line comment starts here:\n") @@ -4785,21 +4785,30 @@ func TestJSX(t *testing.T) { expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a-b:c-d\", null);\n") expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a-:b-\", null);\n") expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"Te:st\", null);\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"a:b\": true\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"a-b:c-d\": true\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"a-:b-\": true\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"Te:st\": true\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"a:b\": 0\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"a-b:c-d\": 0\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"a-:b-\": 0\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", {\n \"Te:st\": 0\n});\n") - expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a-b\", {\n \"a-b\": a - b\n});\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"a:b\": true });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"a-b:c-d\": true });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"a-:b-\": true });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"Te:st\": true });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"a:b\": 0 });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"a-b:c-d\": 0 });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"a-:b-\": 0 });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { \"Te:st\": 0 });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"a-b\", { \"a-b\": a - b });\n") expectParseErrorJSX(t, "", ": ERROR: Expected identifier after \"x:\" in namespaced JSX name\n") expectParseErrorJSX(t, "", ": ERROR: Expected \">\" but found \":\"\n") expectParseErrorJSX(t, "", ": ERROR: Expected identifier after \"x:\" in namespaced JSX name\n") } } +func TestJSXSingleLine(t *testing.T) { + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", null);\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\"x\", { y: true });\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\n \"x\",\n null\n);\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\n \"x\",\n {\n y: true\n }\n);\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\n \"x\",\n {\n y: true\n }\n);\n") + expectPrintedJSX(t, "", "/* @__PURE__ */ React.createElement(\n \"x\",\n {\n ...y\n }\n);\n") +} + func TestJSXPragmas(t *testing.T) { expectPrintedJSX(t, "// @jsx h\n", "/* @__PURE__ */ h(\"a\", null);\n") expectPrintedJSX(t, "/*@jsx h*/\n", "/* @__PURE__ */ h(\"a\", null);\n") @@ -4825,15 +4834,15 @@ func TestJSXPragmas(t *testing.T) { func TestJSXAutomatic(t *testing.T) { // Prod, without runtime imports p := JSXAutomaticTestOptions{Development: false, OmitJSXRuntimeForTests: true} - expectPrintedJSXAutomatic(t, p, "
>
", "/* @__PURE__ */ jsx(\"div\", {\n children: \">\"\n});\n") - expectPrintedJSXAutomatic(t, p, "
{1}}
", "/* @__PURE__ */ jsxs(\"div\", {\n children: [\n 1,\n \"}\"\n ]\n});\n") + expectPrintedJSXAutomatic(t, p, "
>
", "/* @__PURE__ */ jsx(\"div\", { children: \">\" });\n") + expectPrintedJSXAutomatic(t, p, "
{1}}
", "/* @__PURE__ */ jsxs(\"div\", { children: [\n 1,\n \"}\"\n] });\n") expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ jsx(\"div\", {}, true);\n") expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ jsx(\"div\", {}, \"key\");\n") - expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ jsx(\"div\", {\n ...props\n}, \"key\");\n") - expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ createElement(\"div\", {\n ...props,\n key: \"key\"\n});\n") // Falls back to createElement - expectPrintedJSXAutomatic(t, p, "
{...children}
", "/* @__PURE__ */ jsxs(\"div\", {\n children: [\n ...children\n ]\n});\n") - expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ jsxs(\"div\", {\n children: [\n ...children,\n /* @__PURE__ */ jsx(\"a\", {})\n ]\n});\n") - expectPrintedJSXAutomatic(t, p, "<>>", "/* @__PURE__ */ jsx(Fragment, {\n children: \">\"\n});\n") + expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ jsx(\"div\", { ...props }, \"key\");\n") + expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ createElement(\"div\", { ...props, key: \"key\" });\n") // Falls back to createElement + expectPrintedJSXAutomatic(t, p, "
{...children}
", "/* @__PURE__ */ jsxs(\"div\", { children: [\n ...children\n] });\n") + expectPrintedJSXAutomatic(t, p, "
", "/* @__PURE__ */ jsxs(\"div\", { children: [\n ...children,\n /* @__PURE__ */ jsx(\"a\", {})\n] });\n") + expectPrintedJSXAutomatic(t, p, "<>>", "/* @__PURE__ */ jsx(Fragment, { children: \">\" });\n") expectParseErrorJSXAutomatic(t, p, "", `: ERROR: Please provide an explicit value for "key": @@ -4851,13 +4860,13 @@ NOTE: Both "__source" and "__self" are set automatically by esbuild when using R // Prod, with runtime imports pr := JSXAutomaticTestOptions{Development: false} expectPrintedJSXAutomatic(t, pr, "
", "import { jsx } from \"react/jsx-runtime\";\n/* @__PURE__ */ jsx(\"div\", {});\n") - expectPrintedJSXAutomatic(t, pr, "<>", "import { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\n/* @__PURE__ */ jsxs(Fragment, {\n children: [\n /* @__PURE__ */ jsx(\"a\", {}),\n /* @__PURE__ */ jsx(\"b\", {})\n ]\n});\n") - expectPrintedJSXAutomatic(t, pr, "
", "import { createElement } from \"react\";\n/* @__PURE__ */ createElement(\"div\", {\n ...props,\n key: \"key\"\n});\n") - expectPrintedJSXAutomatic(t, pr, "<>
", "import { Fragment, jsx } from \"react/jsx-runtime\";\nimport { createElement } from \"react\";\n/* @__PURE__ */ jsx(Fragment, {\n children: /* @__PURE__ */ createElement(\"div\", {\n ...props,\n key: \"key\"\n })\n});\n") + expectPrintedJSXAutomatic(t, pr, "<>", "import { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\n/* @__PURE__ */ jsxs(Fragment, { children: [\n /* @__PURE__ */ jsx(\"a\", {}),\n /* @__PURE__ */ jsx(\"b\", {})\n] });\n") + expectPrintedJSXAutomatic(t, pr, "
", "import { createElement } from \"react\";\n/* @__PURE__ */ createElement(\"div\", { ...props, key: \"key\" });\n") + expectPrintedJSXAutomatic(t, pr, "<>
", "import { Fragment, jsx } from \"react/jsx-runtime\";\nimport { createElement } from \"react\";\n/* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ createElement(\"div\", { ...props, key: \"key\" }) });\n") pri := JSXAutomaticTestOptions{Development: false, ImportSource: "my-jsx-lib"} expectPrintedJSXAutomatic(t, pri, "
", "import { jsx } from \"my-jsx-lib/jsx-runtime\";\n/* @__PURE__ */ jsx(\"div\", {});\n") - expectPrintedJSXAutomatic(t, pri, "
", "import { createElement } from \"my-jsx-lib\";\n/* @__PURE__ */ createElement(\"div\", {\n ...props,\n key: \"key\"\n});\n") + expectPrintedJSXAutomatic(t, pri, "
", "import { createElement } from \"my-jsx-lib\";\n/* @__PURE__ */ createElement(\"div\", { ...props, key: \"key\" });\n") // Impure JSX call expressions pi := JSXAutomaticTestOptions{SideEffects: true, ImportSource: "my-jsx-lib"} @@ -4866,15 +4875,15 @@ NOTE: Both "__source" and "__self" are set automatically by esbuild when using R // Dev, without runtime imports d := JSXAutomaticTestOptions{Development: true, OmitJSXRuntimeForTests: true} - expectPrintedJSXAutomatic(t, d, "
>
", "/* @__PURE__ */ jsxDEV(\"div\", {\n children: \">\"\n}, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, d, "
{1}}
", "/* @__PURE__ */ jsxDEV(\"div\", {\n children: [\n 1,\n \"}\"\n ]\n}, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, d, "
>
", "/* @__PURE__ */ jsxDEV(\"div\", { children: \">\" }, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, d, "
{1}}
", "/* @__PURE__ */ jsxDEV(\"div\", { children: [\n 1,\n \"}\"\n] }, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") expectPrintedJSXAutomatic(t, d, "
", "/* @__PURE__ */ jsxDEV(\"div\", {}, true, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") expectPrintedJSXAutomatic(t, d, "
", "/* @__PURE__ */ jsxDEV(\"div\", {}, \"key\", false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, d, "
", "/* @__PURE__ */ jsxDEV(\"div\", {\n ...props\n}, \"key\", false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, d, "
", "/* @__PURE__ */ createElement(\"div\", {\n ...props,\n key: \"key\"\n});\n") // Falls back to createElement - expectPrintedJSXAutomatic(t, d, "
{...children}
", "/* @__PURE__ */ jsxDEV(\"div\", {\n children: [\n ...children\n ]\n}, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, d, "
\n {...children}\n
", "/* @__PURE__ */ jsxDEV(\"div\", {\n children: [\n ...children,\n /* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 3,\n columnNumber: 3\n }, this)\n ]\n}, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, d, "<>>", "/* @__PURE__ */ jsxDEV(Fragment, {\n children: \">\"\n}, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, d, "
", "/* @__PURE__ */ jsxDEV(\"div\", { ...props }, \"key\", false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, d, "
", "/* @__PURE__ */ createElement(\"div\", { ...props, key: \"key\" });\n") // Falls back to createElement + expectPrintedJSXAutomatic(t, d, "
{...children}
", "/* @__PURE__ */ jsxDEV(\"div\", { children: [\n ...children\n] }, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, d, "
", "/* @__PURE__ */ jsxDEV(\"div\", { children: [\n ...children,\n /* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 3,\n columnNumber: 3\n }, this)\n] }, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, d, "<>>", "/* @__PURE__ */ jsxDEV(Fragment, { children: \">\" }, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") expectParseErrorJSXAutomatic(t, d, "", `: ERROR: Please provide an explicit value for "key": @@ -4894,16 +4903,16 @@ NOTE: Both "__source" and "__self" are set automatically by esbuild when using R // or not, but it seems weird. So I decided to match Babel instead. expectPrintedJSXAutomatic(t, d, "\r\n", "/* @__PURE__ */ jsxDEV(\"x\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 2,\n columnNumber: 1\n}, this);\n") expectPrintedJSXAutomatic(t, d, "\n\r", "/* @__PURE__ */ jsxDEV(\"x\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 3,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, d, "let š€€ = šŸ•šŸ•šŸ•", "let š€€ = /* @__PURE__ */ jsxDEV(\"x\", {\n children: [\n \"šŸ•šŸ•šŸ•\",\n /* @__PURE__ */ jsxDEV(\"y\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 19\n }, this)\n ]\n}, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 10\n}, this);\n") + expectPrintedJSXAutomatic(t, d, "let š€€ = šŸ•šŸ•šŸ•", "let š€€ = /* @__PURE__ */ jsxDEV(\"x\", { children: [\n \"šŸ•šŸ•šŸ•\",\n /* @__PURE__ */ jsxDEV(\"y\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 19\n }, this)\n] }, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 10\n}, this);\n") // Dev, with runtime imports dr := JSXAutomaticTestOptions{Development: true} expectPrintedJSXAutomatic(t, dr, "
", "import { jsxDEV } from \"react/jsx-dev-runtime\";\n/* @__PURE__ */ jsxDEV(\"div\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, dr, "<>\n \n \n", "import { Fragment, jsxDEV } from \"react/jsx-dev-runtime\";\n/* @__PURE__ */ jsxDEV(Fragment, {\n children: [\n /* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 2,\n columnNumber: 3\n }, this),\n /* @__PURE__ */ jsxDEV(\"b\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 3,\n columnNumber: 3\n }, this)\n ]\n}, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, dr, "<>\n \n \n", "import { Fragment, jsxDEV } from \"react/jsx-dev-runtime\";\n/* @__PURE__ */ jsxDEV(Fragment, { children: [\n /* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 2,\n columnNumber: 3\n }, this),\n /* @__PURE__ */ jsxDEV(\"b\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 3,\n columnNumber: 3\n }, this)\n] }, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") dri := JSXAutomaticTestOptions{Development: true, ImportSource: "preact"} expectPrintedJSXAutomatic(t, dri, "
", "import { jsxDEV } from \"preact/jsx-dev-runtime\";\n/* @__PURE__ */ jsxDEV(\"div\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") - expectPrintedJSXAutomatic(t, dri, "<>\n \n \n", "import { Fragment, jsxDEV } from \"preact/jsx-dev-runtime\";\n/* @__PURE__ */ jsxDEV(Fragment, {\n children: [\n /* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 2,\n columnNumber: 3\n }, this),\n /* @__PURE__ */ jsxDEV(\"b\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 3,\n columnNumber: 3\n }, this)\n ]\n}, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") + expectPrintedJSXAutomatic(t, dri, "<>\n \n \n", "import { Fragment, jsxDEV } from \"preact/jsx-dev-runtime\";\n/* @__PURE__ */ jsxDEV(Fragment, { children: [\n /* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 2,\n columnNumber: 3\n }, this),\n /* @__PURE__ */ jsxDEV(\"b\", {}, void 0, false, {\n fileName: \"\",\n lineNumber: 3,\n columnNumber: 3\n }, this)\n] }, void 0, true, {\n fileName: \"\",\n lineNumber: 1,\n columnNumber: 1\n}, this);\n") // JSX namespaced names for _, colon := range []string{":", " :", ": ", " : "} { @@ -4911,15 +4920,15 @@ NOTE: Both "__source" and "__self" are set automatically by esbuild when using R expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"a-b:c-d\", {});\n") expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"a-:b-\", {});\n") expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"Te:st\", {});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"a:b\": true\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"a-b:c-d\": true\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"a-:b-\": true\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"Te:st\": true\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"a:b\": 0\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"a-b:c-d\": 0\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"a-:b-\": 0\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", {\n \"Te:st\": 0\n});\n") - expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"a-b\", {\n \"a-b\": a - b\n});\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"a:b\": true });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"a-b:c-d\": true });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"a-:b-\": true });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"Te:st\": true });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"a:b\": 0 });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"a-b:c-d\": 0 });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"a-:b-\": 0 });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"x\", { \"Te:st\": 0 });\n") + expectPrintedJSXAutomatic(t, p, "", "/* @__PURE__ */ jsx(\"a-b\", { \"a-b\": a - b });\n") expectParseErrorJSXAutomatic(t, p, "", ": ERROR: Expected identifier after \"x:\" in namespaced JSX name\n") expectParseErrorJSXAutomatic(t, p, "", ": ERROR: Expected \">\" but found \":\"\n") expectParseErrorJSXAutomatic(t, p, "", ": ERROR: Expected identifier after \"x:\" in namespaced JSX name\n") diff --git a/internal/js_parser/ts_parser_test.go b/internal/js_parser/ts_parser_test.go index 8a1f34fa889..07c40cc7209 100644 --- a/internal/js_parser/ts_parser_test.go +++ b/internal/js_parser/ts_parser_test.go @@ -356,13 +356,13 @@ func TestTSTypes(t *testing.T) { expectParseErrorTS(t, "let x: { y(): any }", ": ERROR: The modifier \"in\" is not valid here:\n") expectParseErrorTS(t, "let x: { y(): any }", ": ERROR: The modifier \"out\" is not valid here:\n") expectParseErrorTS(t, "let x: { y(): any }", ": ERROR: The modifier \"in\" is not valid here:\n: ERROR: The modifier \"out\" is not valid here:\n") - expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", {\n T: true\n});\n") - expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"out\", {\n T: true\n});\n") - expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", {\n out: true,\n T: true\n});\n") - expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"out\", {\n in: true,\n T: true\n});\n") - expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", {\n T: true,\n extends: true\n});\n") - expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"out\", {\n T: true,\n extends: true\n});\n") - expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", {\n out: true,\n T: true,\n extends: true\n});\n") + expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", { T: true });\n") + expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"out\", { T: true });\n") + expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", { out: true, T: true });\n") + expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"out\", { in: true, T: true });\n") + expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", { T: true, extends: true });\n") + expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"out\", { T: true, extends: true });\n") + expectPrintedTSX(t, "", "/* @__PURE__ */ React.createElement(\"in\", { out: true, T: true, extends: true });\n") expectParseErrorTSX(t, "() => {}", ": ERROR: Expected \">\" but found \",\"\n") expectParseErrorTSX(t, "() => {}", ": ERROR: Expected \">\" but found \",\"\n") expectParseErrorTSX(t, "() => {}", ": ERROR: Expected \">\" but found \",\"\n") @@ -2300,7 +2300,7 @@ func TestTSJSX(t *testing.T) { expectPrintedTSX(t, "a{...b}c", "/* @__PURE__ */ React.createElement(\"x\", null, \"a\", ...b, \"c\");\n") expectPrintedTSX(t, "const x = >", "const x = /* @__PURE__ */ React.createElement(Foo, null);\n") - expectPrintedTSX(t, "const x = data-foo>", "const x = /* @__PURE__ */ React.createElement(Foo, {\n \"data-foo\": true\n});\n") + expectPrintedTSX(t, "const x = data-foo>", "const x = /* @__PURE__ */ React.createElement(Foo, { \"data-foo\": true });\n") expectParseErrorTSX(t, "const x = =>", ": ERROR: Expected \">\" but found \"=>\"\n") expectPrintedTS(t, "const x = () => {}", "const x = () => {\n};\n") diff --git a/internal/js_printer/js_printer.go b/internal/js_printer/js_printer.go index 32249bd48e9..eefea3966e3 100644 --- a/internal/js_printer/js_printer.go +++ b/internal/js_printer/js_printer.go @@ -1594,10 +1594,18 @@ func (p *printer) printExpr(expr js_ast.Expr, level js_ast.L, flags printExprFla p.addSourceMapping(expr.Loc) p.print("<") p.printJSXTag(e.TagOrNil) + if !e.IsTagSingleLine { + p.options.Indent++ + } // Print the attributes for _, property := range e.Properties { - p.printSpace() + if e.IsTagSingleLine { + p.printSpace() + } else { + p.printNewline() + p.printIndent() + } if property.Kind == js_ast.PropertySpread { p.print("{...") @@ -1640,8 +1648,17 @@ func (p *printer) printExpr(expr js_ast.Expr, level js_ast.L, flags printExprFla } // End the opening tag + if !e.IsTagSingleLine { + p.options.Indent-- + if len(e.Properties) > 0 { + p.printNewline() + p.printIndent() + } + } if e.TagOrNil.Data != nil && len(e.Children) == 0 { - p.printSpace() + if e.IsTagSingleLine || len(e.Properties) == 0 { + p.printSpace() + } p.addSourceMapping(e.CloseLoc) p.print("/>") break diff --git a/internal/js_printer/js_printer_test.go b/internal/js_printer/js_printer_test.go index 66acda27a89..846e128cf29 100644 --- a/internal/js_printer/js_printer_test.go +++ b/internal/js_printer/js_printer_test.go @@ -934,6 +934,22 @@ func TestJSX(t *testing.T) { expectPrintedJSXMinify(t, "{' x '}{''}{' y '}", " x {\"\"} y ;") } +func TestJSXSingleLine(t *testing.T) { + expectPrintedJSX(t, "", ";\n") + expectPrintedJSX(t, "", ";\n") + expectPrintedJSX(t, "", ";\n") + expectPrintedJSX(t, "", ";\n") + expectPrintedJSX(t, "", ";\n") + expectPrintedJSX(t, "", ";\n") + + expectPrintedJSXMinify(t, "", ";") + expectPrintedJSXMinify(t, "", ";") + expectPrintedJSXMinify(t, "", ";") + expectPrintedJSXMinify(t, "", ";") + expectPrintedJSXMinify(t, "", ";") + expectPrintedJSXMinify(t, "", ";") +} + func TestAvoidSlashScript(t *testing.T) { // Positive cases expectPrinted(t, "x = '