diff --git a/changelog_unreleased/javascript/17486.md b/changelog_unreleased/javascript/17486.md new file mode 100644 index 000000000..152d33a8e --- /dev/null +++ b/changelog_unreleased/javascript/17486.md @@ -0,0 +1,20 @@ +#### Fix optional chaining as computed key (#17486 by @fisker) + + +```jsx +// Input +const a = { [y?.z]() {} }; +class A { [y?.z]() {} }; + +// Prettier stable +const a = { [y?.z]?() {} }; +class A { + [y?.z]?() {} +} + +// Prettier main +const a = { [y?.z]() {} }; +class A { + [y?.z]() {} +} +``` diff --git a/src/language-js/print/function.js b/src/language-js/print/function.js index 0c71e4b1c..a93f00358 100644 --- a/src/language-js/print/function.js +++ b/src/language-js/print/function.js @@ -146,7 +146,7 @@ function printMethod(path, options, print) { parts.push( printPropertyKey(path, options, print), - node.optional || node.key.optional ? "?" : "", + node.optional ? "?" : "", node === value ? printMethodValue(path, options, print) : print("value"), ); diff --git a/tests/format/js/optional-chaining/__snapshots__/format.test.js.snap b/tests/format/js/optional-chaining/__snapshots__/format.test.js.snap index e8f59f9d1..8a961c162 100644 --- a/tests/format/js/optional-chaining/__snapshots__/format.test.js.snap +++ b/tests/format/js/optional-chaining/__snapshots__/format.test.js.snap @@ -1,5 +1,111 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`as-key.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +const a = { + [a?.b]: 1, + + [a?.b]() {}, + [a?.b]:function() {}, + + *[a?.b]() {}, + [a?.b]:function*() {}, + + async[a?.b]() {}, + [a?.b]:async function() {}, + + async*[a?.b]() {}, + [a?.b]:async function*() {}, +}; + +class A { + [a?.b]= 1; + + [a?.b]() {}; + [a?.b]=function() {}; + + *[a?.b]() {}; + [a?.b]=function*() {}; + + async[a?.b]() {}; + [a?.b]=async function() {}; + + async*[a?.b]() {}; + [a?.b]=async function*() {}; +} + +class B { + static [a?.b]= 1; + + static [a?.b]() {}; + static [a?.b]=function() {}; + + static *[a?.b]() {}; + static [a?.b]=function*() {}; + + static async[a?.b]() {}; + static [a?.b]=async function() {}; + + static async*[a?.b]() {}; + static [a?.b]=async function*() {}; +} + +=====================================output===================================== +const a = { + [a?.b]: 1, + + [a?.b]() {}, + [a?.b]: function () {}, + + *[a?.b]() {}, + [a?.b]: function* () {}, + + async [a?.b]() {}, + [a?.b]: async function () {}, + + async *[a?.b]() {}, + [a?.b]: async function* () {}, +}; + +class A { + [a?.b] = 1; + + [a?.b]() {} + [a?.b] = function () {}; + + *[a?.b]() {} + [a?.b] = function* () {}; + + async [a?.b]() {} + [a?.b] = async function () {}; + + async *[a?.b]() {} + [a?.b] = async function* () {}; +} + +class B { + static [a?.b] = 1; + + static [a?.b]() {} + static [a?.b] = function () {}; + + static *[a?.b]() {} + static [a?.b] = function* () {}; + + static async [a?.b]() {} + static [a?.b] = async function () {}; + + static async *[a?.b]() {} + static [a?.b] = async function* () {}; +} + +================================================================================ +`; + exports[`chaining.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] diff --git a/tests/format/js/optional-chaining/as-key.js b/tests/format/js/optional-chaining/as-key.js new file mode 100644 index 000000000..f7b59bb9b --- /dev/null +++ b/tests/format/js/optional-chaining/as-key.js @@ -0,0 +1,47 @@ +const a = { + [a?.b]: 1, + + [a?.b]() {}, + [a?.b]:function() {}, + + *[a?.b]() {}, + [a?.b]:function*() {}, + + async[a?.b]() {}, + [a?.b]:async function() {}, + + async*[a?.b]() {}, + [a?.b]:async function*() {}, +}; + +class A { + [a?.b]= 1; + + [a?.b]() {}; + [a?.b]=function() {}; + + *[a?.b]() {}; + [a?.b]=function*() {}; + + async[a?.b]() {}; + [a?.b]=async function() {}; + + async*[a?.b]() {}; + [a?.b]=async function*() {}; +} + +class B { + static [a?.b]= 1; + + static [a?.b]() {}; + static [a?.b]=function() {}; + + static *[a?.b]() {}; + static [a?.b]=function*() {}; + + static async[a?.b]() {}; + static [a?.b]=async function() {}; + + static async*[a?.b]() {}; + static [a?.b]=async function*() {}; +} diff --git a/tests/format/typescript/optional-chaining/__snapshots__/format.test.js.snap b/tests/format/typescript/optional-chaining/__snapshots__/format.test.js.snap new file mode 100644 index 000000000..63a73c703 --- /dev/null +++ b/tests/format/typescript/optional-chaining/__snapshots__/format.test.js.snap @@ -0,0 +1,77 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`as-key.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +class A { + [a?.b]?= 1; + + [a?.b]?() {}; + [a?.b]?= function () {}; + + // https://github.com/babel/babel/issues/17310 + // *[a?.b]?() {}; + [a?.b]?= function *() {}; + + async [a?.b]?() {}; + [a?.b]?= async function () {}; + + async * [a?.b]?() {}; + [a?.b]?= async function *() {}; +} + +class B { + static [a?.b]?= 1; + + static [a?.b]?() {}; + static [a?.b]?= function () {}; + + static *[a?.b]?() {}; + static [a?.b]?= function *() {}; + + static async [a?.b]?() {}; + static [a?.b]?= async function () {}; + + static async * [a?.b]?() {}; + static [a?.b]?= async function *() {}; +} + +=====================================output===================================== +class A { + [a?.b]? = 1; + + [a?.b]?() {} + [a?.b]? = function () {}; + + // https://github.com/babel/babel/issues/17310 + // *[a?.b]?() {}; + [a?.b]? = function* () {}; + + async [a?.b]?() {} + [a?.b]? = async function () {}; + + async *[a?.b]?() {} + [a?.b]? = async function* () {}; +} + +class B { + static [a?.b]? = 1; + + static [a?.b]?() {} + static [a?.b]? = function () {}; + + static *[a?.b]?() {} + static [a?.b]? = function* () {}; + + static async [a?.b]?() {} + static [a?.b]? = async function () {}; + + static async *[a?.b]?() {} + static [a?.b]? = async function* () {}; +} + +================================================================================ +`; diff --git a/tests/format/typescript/optional-chaining/as-key.ts b/tests/format/typescript/optional-chaining/as-key.ts new file mode 100644 index 000000000..6aa6a8e61 --- /dev/null +++ b/tests/format/typescript/optional-chaining/as-key.ts @@ -0,0 +1,32 @@ +class A { + [a?.b]?= 1; + + [a?.b]?() {}; + [a?.b]?= function () {}; + + // https://github.com/babel/babel/issues/17310 + // *[a?.b]?() {}; + [a?.b]?= function *() {}; + + async [a?.b]?() {}; + [a?.b]?= async function () {}; + + async * [a?.b]?() {}; + [a?.b]?= async function *() {}; +} + +class B { + static [a?.b]?= 1; + + static [a?.b]?() {}; + static [a?.b]?= function () {}; + + static *[a?.b]?() {}; + static [a?.b]?= function *() {}; + + static async [a?.b]?() {}; + static [a?.b]?= async function () {}; + + static async * [a?.b]?() {}; + static [a?.b]?= async function *() {}; +} diff --git a/tests/format/typescript/optional-chaining/format.test.js b/tests/format/typescript/optional-chaining/format.test.js new file mode 100644 index 000000000..116dcbd78 --- /dev/null +++ b/tests/format/typescript/optional-chaining/format.test.js @@ -0,0 +1 @@ +runFormatTest(import.meta, ["typescript"]);