diff --git a/README.md b/README.md index 943299e12..4076b3ad5 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@

- Github Actions Build Status + Github Actions Build Status - Github Actions Build Status + Github Actions Build Status - Github Actions Build Status + Github Actions Build Status Codecov Coverage Status diff --git a/changelog_unreleased/javascript/14000.md b/changelog_unreleased/javascript/14000.md new file mode 100644 index 000000000..914800969 --- /dev/null +++ b/changelog_unreleased/javascript/14000.md @@ -0,0 +1,19 @@ +#### Fix missing parentheses when an expression statement starts with `let[` (#14000, #14044 by @fisker, @thorn0) + + +```jsx +// Input +(let[0] = 2); + +// Prettier stable +let[0] = 2; + +// Prettier stable (second format) +SyntaxError: Unexpected token (1:5) +> 1 | let[0] = 2; + | ^ + 2 | + +// Prettier main +(let)[0] = 2; +``` diff --git a/changelog_unreleased/typescript/14049.md b/changelog_unreleased/typescript/14049.md new file mode 100644 index 000000000..28448fa96 --- /dev/null +++ b/changelog_unreleased/typescript/14049.md @@ -0,0 +1,10 @@ +#### Support type annotations on auto accessors via `babel-ts` (#14049 by @sosukesuzuki) + +[The bug that `@babel/parser` cannot parse auto accessors with type annotations](https://github.com/babel/babel/issues/15205) has been fixed. So we now support it via `babel-ts` parser. + + +```tsx +class Foo { + accessor prop: number; +} +``` diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 46210197e..b3d090684 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -50,16 +50,64 @@ function needsParens(path, options) { return true; } - // `for (async of []);` is invalid + // `for ((async) of []);` and `for ((let) of []);` if ( key === "left" && - node.name === "async" && + (node.name === "async" || node.name === "let") && parent.type === "ForOfStatement" && !parent.await ) { return true; } + // `for ((let.a) of []);` + if (node.name === "let") { + const expression = path.findAncestor( + (node) => node.type === "ForOfStatement" + )?.left; + if ( + expression && + startsWithNoLookaheadToken( + expression, + (leftmostNode) => leftmostNode === node + ) + ) { + return true; + } + } + + // `(let)[a] = 1` + if ( + key === "object" && + node.name === "let" && + parent.type === "MemberExpression" && + parent.computed && + !parent.optional + ) { + const statement = path.findAncestor( + (node) => + node.type === "ExpressionStatement" || + node.type === "ForStatement" || + node.type === "ForInStatement" + ); + const expression = !statement + ? undefined + : statement.type === "ExpressionStatement" + ? statement.expression + : statement.type === "ForStatement" + ? statement.init + : statement.left; + if ( + expression && + startsWithNoLookaheadToken( + expression, + (leftmostNode) => leftmostNode === node + ) + ) { + return true; + } + } + return false; } @@ -140,7 +188,11 @@ function needsParens(path, options) { if ( startsWithNoLookaheadToken( node, - /* forbidFunctionClassAndDoExpr */ true + (node) => + node.type === "ObjectExpression" || + node.type === "FunctionExpression" || + node.type === "ClassExpression" || + node.type === "DoExpression" ) ) { return true; @@ -153,7 +205,7 @@ function needsParens(path, options) { node.type !== "SequenceExpression" && // these have parens added anyway startsWithNoLookaheadToken( node, - /* forbidFunctionClassAndDoExpr */ false + (node) => node.type === "ObjectExpression" ) ) { return true; diff --git a/src/language-js/print/function.js b/src/language-js/print/function.js index 75bb53720..15ab423b4 100644 --- a/src/language-js/print/function.js +++ b/src/language-js/print/function.js @@ -373,7 +373,10 @@ function printArrowFunction(path, options, print, args) { // a <= a ? a : a const shouldAddParens = node.body.type === "ConditionalExpression" && - !startsWithNoLookaheadToken(node.body, /* forbidFunctionAndClass */ false); + !startsWithNoLookaheadToken( + node.body, + (node) => node.type === "ObjectExpression" + ); return group([ ...parts, diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index c81646aba..d251ae0cd 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -838,74 +838,59 @@ function shouldPrintComma(options, level = "es5") { } /** - * Tests if an expression starts with `{`, or (if forbidFunctionClassAndDoExpr - * holds) `function`, `class`, or `do {}`. Will be overzealous if there's - * already necessary grouping parentheses. + * Tests if the leftmost node of the expression matches the predicate. E.g., + * used to check whether an expression statement needs to be wrapped in extra + * parentheses because it starts with: + * + * - `{` + * - `function`, `class`, or `do {}` + * - `let[` + * + * Will be overzealous if there already are necessary grouping parentheses. * * @param {Node} node - * @param {boolean} forbidFunctionClassAndDoExpr + * @param {(leftmostNode: Node) => boolean} predicate * @returns {boolean} */ -function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) { - node = getLeftMost(node); +function startsWithNoLookaheadToken(node, predicate) { switch (node.type) { - case "FunctionExpression": - case "ClassExpression": - case "DoExpression": - return forbidFunctionClassAndDoExpr; - case "ObjectExpression": - return true; + case "BinaryExpression": + case "LogicalExpression": + case "AssignmentExpression": + case "NGPipeExpression": + return startsWithNoLookaheadToken(node.left, predicate); case "MemberExpression": case "OptionalMemberExpression": - return startsWithNoLookaheadToken( - node.object, - forbidFunctionClassAndDoExpr - ); + return startsWithNoLookaheadToken(node.object, predicate); case "TaggedTemplateExpression": if (node.tag.type === "FunctionExpression") { // IIFEs are always already parenthesized return false; } - return startsWithNoLookaheadToken(node.tag, forbidFunctionClassAndDoExpr); + return startsWithNoLookaheadToken(node.tag, predicate); case "CallExpression": case "OptionalCallExpression": if (node.callee.type === "FunctionExpression") { // IIFEs are always already parenthesized return false; } - return startsWithNoLookaheadToken( - node.callee, - forbidFunctionClassAndDoExpr - ); + return startsWithNoLookaheadToken(node.callee, predicate); case "ConditionalExpression": - return startsWithNoLookaheadToken( - node.test, - forbidFunctionClassAndDoExpr - ); + return startsWithNoLookaheadToken(node.test, predicate); case "UpdateExpression": return ( - !node.prefix && - startsWithNoLookaheadToken(node.argument, forbidFunctionClassAndDoExpr) + !node.prefix && startsWithNoLookaheadToken(node.argument, predicate) ); case "BindExpression": - return ( - node.object && - startsWithNoLookaheadToken(node.object, forbidFunctionClassAndDoExpr) - ); + return node.object && startsWithNoLookaheadToken(node.object, predicate); case "SequenceExpression": - return startsWithNoLookaheadToken( - node.expressions[0], - forbidFunctionClassAndDoExpr - ); - case "TSAsExpression": + return startsWithNoLookaheadToken(node.expressions[0], predicate); case "TSSatisfiesExpression": + case "TSAsExpression": case "TSNonNullExpression": - return startsWithNoLookaheadToken( - node.expression, - forbidFunctionClassAndDoExpr - ); + return startsWithNoLookaheadToken(node.expression, predicate); default: - return false; + return predicate(node); } } @@ -991,13 +976,6 @@ function getPrecedence(operator) { return PRECEDENCE.get(operator); } -function getLeftMost(node) { - while (node.left) { - node = node.left; - } - return node; -} - function isBitwiseOperator(operator) { return ( Boolean(bitshiftOperators[operator]) || diff --git a/tests/config/format-test.js b/tests/config/format-test.js index dd7ed067b..00545ed37 100644 --- a/tests/config/format-test.js +++ b/tests/config/format-test.js @@ -39,6 +39,7 @@ const unstableTests = new Map( "js/for/continue-and-break-comment-without-blocks.js", "js/sequence-expression/parenthesized.js", "typescript/satisfies-operators/comments-unstable.ts", + ["js/identifier/parentheses/let.js", (options) => options.semi === false], ].map((fixture) => { const [file, isUnstable = () => true] = Array.isArray(fixture) ? fixture diff --git a/tests/format/js/identifier/for-of/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/identifier/for-of/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..1ccc4806b --- /dev/null +++ b/tests/format/js/identifier/for-of/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`await.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +async function a() { + for await((let).a of foo); + for await((let)[a] of foo); + for await((let)()[a] of foo); +} + +=====================================output===================================== +async function a() { + for await ((let).a of foo); + for await ((let)[a] of foo); + for await ((let)()[a] of foo); +} + +================================================================================ +`; + +exports[`let.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +for ((let) of foo); +for (foo of let); +for (foo of let.a); +for (foo of let[a]); +for ((let.a) of foo); +for ((let[a]) of foo); +for ((let)().a of foo); +for (letFoo of foo); + +for ((let.a) in foo); +for ((let[a]) in foo); + +=====================================output===================================== +for ((let) of foo); +for (foo of let); +for (foo of let.a); +for (foo of let[a]); +for ((let).a of foo); +for ((let)[a] of foo); +for ((let)().a of foo); +for (letFoo of foo); + +for (let.a in foo); +for ((let)[a] in foo); + +================================================================================ +`; diff --git a/tests/format/js/identifier/for-of/await.js b/tests/format/js/identifier/for-of/await.js new file mode 100644 index 000000000..0fa9d0a50 --- /dev/null +++ b/tests/format/js/identifier/for-of/await.js @@ -0,0 +1,5 @@ +async function a() { + for await((let).a of foo); + for await((let)[a] of foo); + for await((let)()[a] of foo); +} diff --git a/tests/format/js/identifier/for-of/jsfmt.spec.js b/tests/format/js/identifier/for-of/jsfmt.spec.js new file mode 100644 index 000000000..0e6664ec9 --- /dev/null +++ b/tests/format/js/identifier/for-of/jsfmt.spec.js @@ -0,0 +1,5 @@ +run_spec(import.meta, [ + "babel", + // "flow", + "typescript", +]); diff --git a/tests/format/js/identifier/for-of/let.js b/tests/format/js/identifier/for-of/let.js new file mode 100644 index 000000000..5c2398ee2 --- /dev/null +++ b/tests/format/js/identifier/for-of/let.js @@ -0,0 +1,11 @@ +for ((let) of foo); +for (foo of let); +for (foo of let.a); +for (foo of let[a]); +for ((let.a) of foo); +for ((let[a]) of foo); +for ((let)().a of foo); +for (letFoo of foo); + +for ((let.a) in foo); +for ((let[a]) in foo); diff --git a/tests/format/js/identifier/parentheses/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/identifier/parentheses/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..6d0419713 --- /dev/null +++ b/tests/format/js/identifier/parentheses/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,481 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`const.js - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const [a = ((let)[0] = 1)] = 2; + +=====================================output===================================== +const [a = (let[0] = 1)] = 2 + +================================================================================ +`; + +exports[`const.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +const [a = ((let)[0] = 1)] = 2; + +=====================================output===================================== +const [a = (let[0] = 1)] = 2; + +================================================================================ +`; + +exports[`let.js - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +let.a = 1; + +let.a[0] = 1; + +(let[a] = 1); + +(let[a].b.c.e = 1); + +foo[let[a]] = 1; + +(let)[let[a]] = 1; + +(let[a] ??= 1); + +foo = let[a]; + +let()[a] = 1; + +foo(let)[a] = 1; + +foo(let[a])[a] = 1; + +(let[0] = 1); + +(let["a"] = 1); + +let = 1; + +var let = 1; + +[let[a]] = 1; + +({a: let[a]} = 1); + +alert(let[0] = 1); + +(let[0] = 1) || 2; + +((let[0] = 1), 2); + +((let[0] = 1) ? a : b); + +if (let[0] = 1); + +while (let[0] = 1); + +do{} while (let[0] = 1); + +var a = (let[0] = 1); + +(let[0] = 1) instanceof a; + +void (let[0] = 1); + +(let[0] = 1)(); + +new (let[0] = 1)(); + +((let)[0] = 1)\`\`; + +((let)[0] = 1).toString; + +((let)[0] = 1)?.toString; + +[...(let[0] = 1)]; + +foo = () => (let[0] = 1); + +function * foo() {yield (let[0] = 1)} + +async function foo() {await (let[0] = 1)} + +function foo() {return (let[0] = 1)} + +while (true) (let[0] = 1); + +throw (let[0] = 1); + +({foo: (let[0] = 1)}); + +[(let[0] = 1)]; + +for ((let[0] = 1);;); +for ((let)[0] in {}); +for ((let)[0] of []); + +switch (let[0] = 1) {} + +switch (foo) { + case let[0] = 1: +} + +with (let[0] = 1); + +(let[x]).foo(); + +let.let[x].foo(); + +a = let[x].foo(); + +(let)[2]; + +a[1] + (let[2] = 2); + +=====================================output===================================== +let.a = 1 + +let.a[0] = 1 + +;(let)[a] = 1 + +;(let)[a].b.c.e = 1 + +foo[let[a]] = 1 + +;(let)[let[a]] = 1 + +;(let)[a] ??= 1 + +foo = let[a] + +let()[a] = 1 + +foo(let)[a] = 1 + +foo(let[a])[a] = 1 + +;(let)[0] = 1 + +;(let)["a"] = 1 + +let = 1 + +var let = 1 + +;[let[a]] = 1 + +;({ a: let[a] } = 1) + +alert((let[0] = 1)) + +;((let)[0] = 1) || 2 + +;((let)[0] = 1), 2 + +;((let)[0] = 1) ? a : b + +if ((let[0] = 1)); + +while ((let[0] = 1)); + +do {} while ((let[0] = 1)) + +var a = (let[0] = 1) + +;((let)[0] = 1) instanceof a + +void (let[0] = 1) + +;((let)[0] = 1)() + +new (let[0] = 1)() + +;((let)[0] = 1)\`\` + +;((let)[0] = 1).toString + +;((let)[0] = 1)?.toString + +;[...(let[0] = 1)] + +foo = () => (let[0] = 1) + +function* foo() { + yield (let[0] = 1) +} + +async function foo() { + await (let[0] = 1) +} + +function foo() { + return (let[0] = 1) +} + +while (true) (let)[0] = 1 + +throw (let[0] = 1) + +;({ foo: (let[0] = 1) }) + +;[(let[0] = 1)] + +for ((let)[0] = 1; ; ); +for ((let)[0] in {}); +for ((let)[0] of []); + +switch ((let[0] = 1)) { +} + +switch (foo) { + case (let[0] = 1): +} + +with ((let[0] = 1)); + +;(let)[x].foo() + +let.let[x].foo() + +a = let[x].foo() + +;(let)[2] + +a[1] + (let[2] = 2) + +================================================================================ +`; + +exports[`let.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +let.a = 1; + +let.a[0] = 1; + +(let[a] = 1); + +(let[a].b.c.e = 1); + +foo[let[a]] = 1; + +(let)[let[a]] = 1; + +(let[a] ??= 1); + +foo = let[a]; + +let()[a] = 1; + +foo(let)[a] = 1; + +foo(let[a])[a] = 1; + +(let[0] = 1); + +(let["a"] = 1); + +let = 1; + +var let = 1; + +[let[a]] = 1; + +({a: let[a]} = 1); + +alert(let[0] = 1); + +(let[0] = 1) || 2; + +((let[0] = 1), 2); + +((let[0] = 1) ? a : b); + +if (let[0] = 1); + +while (let[0] = 1); + +do{} while (let[0] = 1); + +var a = (let[0] = 1); + +(let[0] = 1) instanceof a; + +void (let[0] = 1); + +(let[0] = 1)(); + +new (let[0] = 1)(); + +((let)[0] = 1)\`\`; + +((let)[0] = 1).toString; + +((let)[0] = 1)?.toString; + +[...(let[0] = 1)]; + +foo = () => (let[0] = 1); + +function * foo() {yield (let[0] = 1)} + +async function foo() {await (let[0] = 1)} + +function foo() {return (let[0] = 1)} + +while (true) (let[0] = 1); + +throw (let[0] = 1); + +({foo: (let[0] = 1)}); + +[(let[0] = 1)]; + +for ((let[0] = 1);;); +for ((let)[0] in {}); +for ((let)[0] of []); + +switch (let[0] = 1) {} + +switch (foo) { + case let[0] = 1: +} + +with (let[0] = 1); + +(let[x]).foo(); + +let.let[x].foo(); + +a = let[x].foo(); + +(let)[2]; + +a[1] + (let[2] = 2); + +=====================================output===================================== +let.a = 1; + +let.a[0] = 1; + +(let)[a] = 1; + +(let)[a].b.c.e = 1; + +foo[let[a]] = 1; + +(let)[let[a]] = 1; + +(let)[a] ??= 1; + +foo = let[a]; + +let()[a] = 1; + +foo(let)[a] = 1; + +foo(let[a])[a] = 1; + +(let)[0] = 1; + +(let)["a"] = 1; + +let = 1; + +var let = 1; + +[let[a]] = 1; + +({ a: let[a] } = 1); + +alert((let[0] = 1)); + +((let)[0] = 1) || 2; + +((let)[0] = 1), 2; + +((let)[0] = 1) ? a : b; + +if ((let[0] = 1)); + +while ((let[0] = 1)); + +do {} while ((let[0] = 1)); + +var a = (let[0] = 1); + +((let)[0] = 1) instanceof a; + +void (let[0] = 1); + +((let)[0] = 1)(); + +new (let[0] = 1)(); + +((let)[0] = 1)\`\`; + +((let)[0] = 1).toString; + +((let)[0] = 1)?.toString; + +[...(let[0] = 1)]; + +foo = () => (let[0] = 1); + +function* foo() { + yield (let[0] = 1); +} + +async function foo() { + await (let[0] = 1); +} + +function foo() { + return (let[0] = 1); +} + +while (true) (let)[0] = 1; + +throw (let[0] = 1); + +({ foo: (let[0] = 1) }); + +[(let[0] = 1)]; + +for ((let)[0] = 1; ; ); +for ((let)[0] in {}); +for ((let)[0] of []); + +switch ((let[0] = 1)) { +} + +switch (foo) { + case (let[0] = 1): +} + +with ((let[0] = 1)); + +(let)[x].foo(); + +let.let[x].foo(); + +a = let[x].foo(); + +(let)[2]; + +a[1] + (let[2] = 2); + +================================================================================ +`; diff --git a/tests/format/js/identifier/parentheses/const.js b/tests/format/js/identifier/parentheses/const.js new file mode 100644 index 000000000..8fa111711 --- /dev/null +++ b/tests/format/js/identifier/parentheses/const.js @@ -0,0 +1 @@ +const [a = ((let)[0] = 1)] = 2; diff --git a/tests/format/js/identifier/parentheses/jsfmt.spec.js b/tests/format/js/identifier/parentheses/jsfmt.spec.js new file mode 100644 index 000000000..202ed2340 --- /dev/null +++ b/tests/format/js/identifier/parentheses/jsfmt.spec.js @@ -0,0 +1,14 @@ +run_spec(import.meta, [ + "babel", + // "flow", + "typescript", +]); +run_spec( + import.meta, + [ + "babel", + // "flow", + "typescript", + ], + { semi: false } +); diff --git a/tests/format/js/identifier/parentheses/let.js b/tests/format/js/identifier/parentheses/let.js new file mode 100644 index 000000000..2f0cc8a37 --- /dev/null +++ b/tests/format/js/identifier/parentheses/let.js @@ -0,0 +1,103 @@ +let.a = 1; + +let.a[0] = 1; + +(let[a] = 1); + +(let[a].b.c.e = 1); + +foo[let[a]] = 1; + +(let)[let[a]] = 1; + +(let[a] ??= 1); + +foo = let[a]; + +let()[a] = 1; + +foo(let)[a] = 1; + +foo(let[a])[a] = 1; + +(let[0] = 1); + +(let["a"] = 1); + +let = 1; + +var let = 1; + +[let[a]] = 1; + +({a: let[a]} = 1); + +alert(let[0] = 1); + +(let[0] = 1) || 2; + +((let[0] = 1), 2); + +((let[0] = 1) ? a : b); + +if (let[0] = 1); + +while (let[0] = 1); + +do{} while (let[0] = 1); + +var a = (let[0] = 1); + +(let[0] = 1) instanceof a; + +void (let[0] = 1); + +(let[0] = 1)(); + +new (let[0] = 1)(); + +((let)[0] = 1)``; + +((let)[0] = 1).toString; + +((let)[0] = 1)?.toString; + +[...(let[0] = 1)]; + +foo = () => (let[0] = 1); + +function * foo() {yield (let[0] = 1)} + +async function foo() {await (let[0] = 1)} + +function foo() {return (let[0] = 1)} + +while (true) (let[0] = 1); + +throw (let[0] = 1); + +({foo: (let[0] = 1)}); + +[(let[0] = 1)]; + +for ((let[0] = 1);;); +for ((let)[0] in {}); +for ((let)[0] of []); + +switch (let[0] = 1) {} + +switch (foo) { + case let[0] = 1: +} + +with (let[0] = 1); + +(let[x]).foo(); + +let.let[x].foo(); + +a = let[x].foo(); + +(let)[2]; + +a[1] + (let[2] = 2); diff --git a/tests/format/misc/errors/js/assignment/__snapshots__/jsfmt.spec.js.snap b/tests/format/misc/errors/js/assignment/__snapshots__/jsfmt.spec.js.snap index 1ece57b5b..f4b45b707 100644 --- a/tests/format/misc/errors/js/assignment/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/misc/errors/js/assignment/__snapshots__/jsfmt.spec.js.snap @@ -6,26 +6,110 @@ exports[`snippet: #0 [acorn] format 1`] = ` | ^" `; +exports[`snippet: #0 [acorn] format 2`] = ` +"The keyword 'let' is reserved (1:1) +> 1 | let?.()[a] =1 + | ^" +`; + +exports[`snippet: #0 [acorn] format 3`] = ` +"The keyword 'let' is reserved (1:21) +> 1 | class Foo extends ((let)[0] = 1) {} + | ^" +`; + exports[`snippet: #0 [babel] format 1`] = ` "Invalid parenthesized assignment pattern. (1:1) > 1 | ({}) = x; | ^" `; +exports[`snippet: #0 [babel] format 2`] = ` +"Invalid left-hand side in assignment expression. (1:1) +> 1 | let?.()[a] =1 + | ^" +`; + exports[`snippet: #0 [babel-ts] format 1`] = ` "Invalid parenthesized assignment pattern. (1:1) > 1 | ({}) = x; | ^" `; +exports[`snippet: #0 [babel-ts] format 2`] = ` +"Invalid left-hand side in assignment expression. (1:1) +> 1 | let?.()[a] =1 + | ^" +`; + exports[`snippet: #0 [espree] format 1`] = ` "Assigning to rvalue (1:1) > 1 | ({}) = x; | ^" `; +exports[`snippet: #0 [espree] format 2`] = ` +"The keyword 'let' is reserved (1:1) +> 1 | let?.()[a] =1 + | ^" +`; + +exports[`snippet: #0 [espree] format 3`] = ` +"The keyword 'let' is reserved (1:21) +> 1 | class Foo extends ((let)[0] = 1) {} + | ^" +`; + +exports[`snippet: #0 [espree] format 4`] = ` +"The keyword 'let' is reserved (1:18) +> 1 | export default ((let)[0] = 1); + | ^" +`; + exports[`snippet: #0 [meriyah] format 1`] = ` "Invalid left-hand side in assignment (1:6) > 1 | ({}) = x; | ^" `; + +exports[`snippet: #0 [meriyah] format 2`] = ` +"The identifier 'let' must not be in expression position in strict mode (1:24) +> 1 | class Foo extends ((let)[0] = 1) {} + | ^" +`; + +exports[`snippet: #0 [meriyah] format 3`] = ` +"The identifier 'let' must not be in expression position in strict mode (1:21) +> 1 | export default ((let)[0] = 1); + | ^" +`; + +exports[`snippet: #1 [acorn] format 1`] = ` +"The keyword 'let' is reserved (1:1) +> 1 | let?.[a] = 1 + | ^" +`; + +exports[`snippet: #1 [babel] format 1`] = ` +"Invalid left-hand side in assignment expression. (1:1) +> 1 | let?.[a] = 1 + | ^" +`; + +exports[`snippet: #1 [babel-ts] format 1`] = ` +"Invalid left-hand side in assignment expression. (1:1) +> 1 | let?.[a] = 1 + | ^" +`; + +exports[`snippet: #1 [espree] format 1`] = ` +"The keyword 'let' is reserved (1:1) +> 1 | let?.[a] = 1 + | ^" +`; + +exports[`snippet: #1 [meriyah] format 1`] = ` +"\`let\` declaration not allowed here and \`let\` cannot be a regular var name in strict mode (1:5) +> 1 | let?.[a] = 1 + | ^" +`; diff --git a/tests/format/misc/errors/js/assignment/jsfmt.spec.js b/tests/format/misc/errors/js/assignment/jsfmt.spec.js index 2435ed514..b8c223d56 100644 --- a/tests/format/misc/errors/js/assignment/jsfmt.spec.js +++ b/tests/format/misc/errors/js/assignment/jsfmt.spec.js @@ -1,7 +1,31 @@ run_spec( { importMeta: import.meta, - snippets: ["({}) = x;"], + snippets: ["({}) = x;", "let?.[a] = 1"], }, ["babel", "babel-ts", "acorn", "espree", "meriyah"] ); + +run_spec( + { + importMeta: import.meta, + snippets: ["let?.()[a] =1"], + }, + ["babel", "babel-ts", "acorn", "espree"] +); + +run_spec( + { + importMeta: import.meta, + snippets: ["class Foo extends ((let)[0] = 1) {}"], + }, + ["acorn", "espree", "meriyah"] +); + +run_spec( + { + importMeta: import.meta, + snippets: ["export default ((let)[0] = 1);"], + }, + ["espree", "meriyah"] +); diff --git a/tests/format/typescript/decorator-auto-accessors/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/decorator-auto-accessors/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..2b9e43887 --- /dev/null +++ b/tests/format/typescript/decorator-auto-accessors/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`decorator-auto-accessors-type-annotations.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +abstract class Foo { + accessor prop: number = 1; + static accessor prop2: number = 1; + accessor #prop3: number = 1; + accessor [prop4]: number = 1; + private accessor prop5: number = 1; + abstract accessor prop6: number; +} + +=====================================output===================================== +abstract class Foo { + accessor prop: number = 1; + static accessor prop2: number = 1; + accessor #prop3: number = 1; + accessor [prop4]: number = 1; + private accessor prop5: number = 1; + abstract accessor prop6: number; +} + +================================================================================ +`; diff --git a/tests/format/misc/typescript-only/decorator-auto-accessors-type-annotations.ts b/tests/format/typescript/decorator-auto-accessors/decorator-auto-accessors-type-annotations.ts similarity index 100% rename from tests/format/misc/typescript-only/decorator-auto-accessors-type-annotations.ts rename to tests/format/typescript/decorator-auto-accessors/decorator-auto-accessors-type-annotations.ts diff --git a/tests/format/typescript/decorator-auto-accessors/jsfmt.spec.js b/tests/format/typescript/decorator-auto-accessors/jsfmt.spec.js new file mode 100644 index 000000000..29084a9c8 --- /dev/null +++ b/tests/format/typescript/decorator-auto-accessors/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(import.meta, ["typescript"]);