From 7211cbabf4e63cda35c4b66a1154330745c64e73 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 11:28:53 +0900 Subject: [PATCH 01/23] Print `satisfies` operators --- src/language-js/print/typescript.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/language-js/print/typescript.js b/src/language-js/print/typescript.js index de52a01100f4..29f265715fb9 100644 --- a/src/language-js/print/typescript.js +++ b/src/language-js/print/typescript.js @@ -515,6 +515,8 @@ function printTypescript(path, options, print) { return printJSDocType(path, print, /* token */ "!"); case "TSInstantiationExpression": return [print("expression"), print("typeParameters")]; + case "TSSatisfiesExpression": + return [print("expression"), " satisfies ", print("typeAnnotation")]; default: /* c8 ignore next */ throw new UnexpectedNodeError(node, "TypeScript"); From 6ce205ac6a6279d737533cf372f24dc1e3b6dfa5 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 11:29:09 +0900 Subject: [PATCH 02/23] Add tests --- .../__snapshots__/jsfmt.spec.js.snap | 106 ++++++++++++++++++ .../typescript/satisfies-operators/basic.ts | 30 +++++ .../satisfies-operators/comments.ts | 11 ++ .../satisfies-operators/jsfmt.spec.js | 1 + 4 files changed, 148 insertions(+) create mode 100644 tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/format/typescript/satisfies-operators/basic.ts create mode 100644 tests/format/typescript/satisfies-operators/comments.ts create mode 100644 tests/format/typescript/satisfies-operators/jsfmt.spec.js diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d4a6df826eef --- /dev/null +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,106 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`basic.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = { } satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = (m => m.substring(0)) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: 'test' } satisfies A; +let t8 = { a: 'test', b: 'test' } satisfies A; + +const p = { + isEven: n => n % 2 === 0, + isOdd: n => n % 2 === 1 +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) { }, + g(s) { } +} satisfies { g(s: string): void } & Record; + +({ f(x) { } }) satisfies { f(s: string): void }; + +const car = { + start() { }, + move(d) { + // d should be number + }, + stop() { } +} satisfies Movable & Record; + +var v = undefined satisfies 1; + +=====================================output===================================== +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = {} satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = (m) => m.substring(0) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: "test" } satisfies A; +let t8 = { a: "test", b: "test" } satisfies A; + +const p = { + isEven: (n) => n % 2 === 0, + isOdd: (n) => n % 2 === 1, +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) {}, + g(s) {}, +} satisfies { g(s: string): void } & Record; + +{ f(x) {} } satisfies { f(s: string): void }; + +const car = { + start() {}, + move(d) { + // d should be number + }, + stop() {}, +} satisfies Movable & Record; + +var v = undefined satisfies 1; + +================================================================================ +`; + +exports[`comments.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3 +} satisfies +// Comment +Record; + +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +=====================================output===================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3, +} satisfies // Comment +Record; + +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +================================================================================ +`; diff --git a/tests/format/typescript/satisfies-operators/basic.ts b/tests/format/typescript/satisfies-operators/basic.ts new file mode 100644 index 000000000000..3eff7182b432 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/basic.ts @@ -0,0 +1,30 @@ +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = { } satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = (m => m.substring(0)) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: 'test' } satisfies A; +let t8 = { a: 'test', b: 'test' } satisfies A; + +const p = { + isEven: n => n % 2 === 0, + isOdd: n => n % 2 === 1 +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) { }, + g(s) { } +} satisfies { g(s: string): void } & Record; + +({ f(x) { } }) satisfies { f(s: string): void }; + +const car = { + start() { }, + move(d) { + // d should be number + }, + stop() { } +} satisfies Movable & Record; + +var v = undefined satisfies 1; diff --git a/tests/format/typescript/satisfies-operators/comments.ts b/tests/format/typescript/satisfies-operators/comments.ts new file mode 100644 index 000000000000..8310b122c8be --- /dev/null +++ b/tests/format/typescript/satisfies-operators/comments.ts @@ -0,0 +1,11 @@ +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3 +} satisfies +// Comment +Record; + +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; diff --git a/tests/format/typescript/satisfies-operators/jsfmt.spec.js b/tests/format/typescript/satisfies-operators/jsfmt.spec.js new file mode 100644 index 000000000000..eb7dab7dd4d5 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(import.meta, ["babel-ts"]); From 29cdbc491628c1abf76b19240e3744c53ede6a16 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 11:42:49 +0900 Subject: [PATCH 03/23] Add changelog --- changelog_unreleased/typescript/13764.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 changelog_unreleased/typescript/13764.md diff --git a/changelog_unreleased/typescript/13764.md b/changelog_unreleased/typescript/13764.md new file mode 100644 index 000000000000..43f84930a7ae --- /dev/null +++ b/changelog_unreleased/typescript/13764.md @@ -0,0 +1,16 @@ +#### Support TypeScript 4.9 (#13764 by @sosukesuzuki) + +Support [TypeScript 4.9](https://devblogs.microsoft.com/typescript/announcing-typescript-4-9) features! + +##### [`satisfies` operator](https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-beta/#the-satisfies-operator) + +Supported by only `babel-ts` parser. + + +```tsx +const palette = { + red: [255, 0, 0], + green: "#00ff00", + blue: [0, 0, 255] +} satisfies Record; +``` From ebbb90a321c4e6a549112ec644d29e289395ad6c Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 12:41:19 +0900 Subject: [PATCH 04/23] Add `hug-args` tests --- src/language-js/print/call-arguments.js | 3 ++- src/language-js/utils/index.js | 7 +++++++ .../__snapshots__/jsfmt.spec.js.snap | 21 +++++++++++++++++++ .../satisfies-operators/hug-args.ts | 6 ++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/format/typescript/satisfies-operators/hug-args.ts diff --git a/src/language-js/print/call-arguments.js b/src/language-js/print/call-arguments.js index ed414843eca4..a4fedca4f15c 100644 --- a/src/language-js/print/call-arguments.js +++ b/src/language-js/print/call-arguments.js @@ -19,6 +19,7 @@ import { isRegExpLiteral, isSimpleType, isCallLikeExpression, + isTSTypeExpression, } from "../utils/index.js"; import { @@ -186,7 +187,7 @@ function couldExpandArg(arg, arrowChainRecursion = false) { (arg.type === "ArrayExpression" && (arg.elements.length > 0 || hasComment(arg))) || (arg.type === "TSTypeAssertion" && couldExpandArg(arg.expression)) || - (arg.type === "TSAsExpression" && couldExpandArg(arg.expression)) || + (isTSTypeExpression(arg) && couldExpandArg(arg.expression)) || arg.type === "FunctionExpression" || (arg.type === "ArrowFunctionExpression" && // we want to avoid breaking inside composite return types but not simple keywords diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index d786ec96566d..f519652c461a 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -1219,6 +1219,12 @@ const markerForIfWithoutBlockAndSameLineComment = Symbol( "ifWithoutBlockAndSameLineComment" ); +function isTSTypeExpression(node) { + return ( + node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression" + ); +} + export { getFunctionParameters, iterateFunctionParametersPath, @@ -1280,4 +1286,5 @@ export { getComments, CommentCheckFlags, markerForIfWithoutBlockAndSameLineComment, + isTSTypeExpression, }; diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index d4a6df826eef..06d4aa198329 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -104,3 +104,24 @@ const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; ================================================================================ `; + +exports[`hug-args.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +window.postMessage( + { + context: item.context, + topic: item.topic + } satisfies IActionMessage + ); +=====================================output===================================== +window.postMessage({ + context: item.context, + topic: item.topic, +} satisfies IActionMessage); + +================================================================================ +`; diff --git a/tests/format/typescript/satisfies-operators/hug-args.ts b/tests/format/typescript/satisfies-operators/hug-args.ts new file mode 100644 index 000000000000..19cb5b1f2623 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/hug-args.ts @@ -0,0 +1,6 @@ +window.postMessage( + { + context: item.context, + topic: item.topic + } satisfies IActionMessage + ); \ No newline at end of file From 336bc4c42fdf0edab9075cfaf5b4f334969fb4a1 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 12:55:49 +0900 Subject: [PATCH 05/23] Add more tests for TSAsExpression --- .../argument-expansion/__snapshots__/jsfmt.spec.js.snap | 8 ++++++++ .../typescript/argument-expansion/argument_expansion.ts | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap index b7d32acbf480..8a462ba4840a 100644 --- a/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap @@ -38,6 +38,10 @@ const bar8 = [1,2,3].reduce((carry, value) => { return {...carry, [value]: true}; }, <{[key: number]: boolean}>{1: true}); +const bar9 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] as foo); + =====================================output===================================== const bar1 = [1, 2, 3].reduce( (carry, value) => { @@ -95,6 +99,10 @@ const bar8 = [1, 2, 3].reduce( <{ [key: number]: boolean }>{ 1: true }, ); +const bar9 = [1, 2, 3].reduce((carry, value) => { + return [...carry, value]; +}, [] as foo); + ================================================================================ `; diff --git a/tests/format/typescript/argument-expansion/argument_expansion.ts b/tests/format/typescript/argument-expansion/argument_expansion.ts index 37f77d346e1b..9230cac27569 100644 --- a/tests/format/typescript/argument-expansion/argument_expansion.ts +++ b/tests/format/typescript/argument-expansion/argument_expansion.ts @@ -29,3 +29,7 @@ const bar7 = [1,2,3].reduce((carry, value) => { const bar8 = [1,2,3].reduce((carry, value) => { return {...carry, [value]: true}; }, <{[key: number]: boolean}>{1: true}); + +const bar9 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] as foo); From bdaf5c17ab26d0106034674c8237f063e82930a1 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 13:02:07 +0900 Subject: [PATCH 06/23] Add tests for argument expansion --- src/language-js/print/call-arguments.js | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 62 +++++++++++++++++++ .../satisfies-operators/argument-expansion.ts | 19 ++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/format/typescript/satisfies-operators/argument-expansion.ts diff --git a/src/language-js/print/call-arguments.js b/src/language-js/print/call-arguments.js index a4fedca4f15c..f4a0a37bb052 100644 --- a/src/language-js/print/call-arguments.js +++ b/src/language-js/print/call-arguments.js @@ -287,7 +287,7 @@ function isHopefullyShortCallArgument(node) { return isHopefullyShortCallArgument(node.expression); } - if (node.type === "TSAsExpression") { + if (isTSTypeExpression(node)) { let { typeAnnotation } = node; if (typeAnnotation.type === "TSArrayType") { typeAnnotation = typeAnnotation.elementType; diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 06d4aa198329..203c823dfe2b 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,67 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`argument-expansion.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const bar1 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([] satisfies unknown) satisfies number[]); + +const bar2 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([1, 2, 3] satisfies unknown) satisfies number[]); + +const bar3 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar4 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({1: true} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar5 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); + +=====================================output===================================== +const bar1 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value]; + }, + [] satisfies unknown satisfies number[], +); + +const bar2 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value]; + }, + [1, 2, 3] satisfies unknown satisfies number[], +); + +const bar3 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true }; + }, + {} satisfies unknown satisfies { [key: number]: boolean }, +); + +const bar4 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true }; + }, + { 1: true } satisfies unknown satisfies { [key: number]: boolean }, +); + +const bar5 = [1, 2, 3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); + +================================================================================ +`; + exports[`basic.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] diff --git a/tests/format/typescript/satisfies-operators/argument-expansion.ts b/tests/format/typescript/satisfies-operators/argument-expansion.ts new file mode 100644 index 000000000000..aef1a1410c1a --- /dev/null +++ b/tests/format/typescript/satisfies-operators/argument-expansion.ts @@ -0,0 +1,19 @@ +const bar1 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([] satisfies unknown) satisfies number[]); + +const bar2 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([1, 2, 3] satisfies unknown) satisfies number[]); + +const bar3 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar4 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({1: true} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar5 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); From 096969ae730252094600e4ba8198148fc858ccd3 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 13:11:22 +0900 Subject: [PATCH 07/23] Add tests for template literal --- src/language-js/print/template-literal.js | 3 +- .../__snapshots__/jsfmt.spec.js.snap | 31 +++++++++++++++++++ .../satisfies-operators/template-literal.ts | 5 +++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/format/typescript/satisfies-operators/template-literal.ts diff --git a/src/language-js/print/template-literal.js b/src/language-js/print/template-literal.js index 19308711636e..178d93c13b58 100644 --- a/src/language-js/print/template-literal.js +++ b/src/language-js/print/template-literal.js @@ -17,6 +17,7 @@ import { isSimpleTemplateLiteral, hasComment, isMemberExpression, + isTSTypeExpression, } from "../utils/index.js"; function printTemplateLiteral(path, print, options) { @@ -87,7 +88,7 @@ function printTemplateLiteral(path, print, options) { isMemberExpression(expression) || expression.type === "ConditionalExpression" || expression.type === "SequenceExpression" || - expression.type === "TSAsExpression" || + isTSTypeExpression(expression) || isBinaryish(expression) ) { expressionDoc = [indent([softline, expressionDoc]), softline]; diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 203c823dfe2b..18233d84d7a0 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -187,3 +187,34 @@ window.postMessage({ ================================================================================ `; + +exports[`template-literal.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const a = \`\${(foo + bar) satisfies baz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz}\`; +const b = \`\${(foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz}\`; +const b = \`\${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; + +=====================================output===================================== +const a = \`\${foo + bar satisfies baz}\`; +const b = \`\${ + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar satisfies baz +}\`; +const b = \`\${ + foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies baz +}\`; +const b = \`\${ + foo + bar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\`; +const b = \`\${ + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\`; + +================================================================================ +`; diff --git a/tests/format/typescript/satisfies-operators/template-literal.ts b/tests/format/typescript/satisfies-operators/template-literal.ts new file mode 100644 index 000000000000..d4152adc97e5 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/template-literal.ts @@ -0,0 +1,5 @@ +const a = `${(foo + bar) satisfies baz}`; +const b = `${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz}`; +const b = `${(foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz}`; +const b = `${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}`; +const b = `${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}`; From 0eaedd77468d45777e64ff948f88452a45813e11 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 13:15:56 +0900 Subject: [PATCH 08/23] Add tests for ternary --- src/language-js/print/ternary.js | 3 +- .../__snapshots__/jsfmt.spec.js.snap | 102 ++++++++++++++++++ .../typescript/satisfies-operators/ternary.ts | 40 +++++++ 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 tests/format/typescript/satisfies-operators/ternary.ts diff --git a/src/language-js/print/ternary.js b/src/language-js/print/ternary.js index 310ab3a7d08f..471670c6e59e 100644 --- a/src/language-js/print/ternary.js +++ b/src/language-js/print/ternary.js @@ -4,6 +4,7 @@ import { getComments, isCallExpression, isMemberExpression, + isTSTypeExpression, } from "../utils/index.js"; import { locStart, locEnd } from "../loc.js"; import isBlockComment from "../utils/is-block-comment.js"; @@ -161,7 +162,7 @@ function shouldExtraIndentForConditionalExpression(path) { if ( (node.type === "NewExpression" && node.callee === child) || - (node.type === "TSAsExpression" && node.expression === child) + (isTSTypeExpression(node) && node.expression === child) ) { parent = path.getParentNode(ancestorCount + 1); child = node; diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 18233d84d7a0..e99da2d681e1 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -218,3 +218,105 @@ const b = \`\${ ================================================================================ `; + +exports[`ternary.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +foo = (condition ? firstValue : secondValue) satisfies SomeType; + +const foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +function foo() { + return (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + throw (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + void ((coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo); +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +=====================================output===================================== +foo = + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo; + +foo = condition ? firstValue : secondValue satisfies SomeType; + +const foo = + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo; + +function foo() { + return + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo; +} + +function foo() { + throw + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo; +} + +function foo() { + void + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo; +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay; + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay; + +================================================================================ +`; diff --git a/tests/format/typescript/satisfies-operators/ternary.ts b/tests/format/typescript/satisfies-operators/ternary.ts new file mode 100644 index 000000000000..0baab89c6c37 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/ternary.ts @@ -0,0 +1,40 @@ +foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +foo = (condition ? firstValue : secondValue) satisfies SomeType; + +const foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +function foo() { + return (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + throw (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + void ((coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo); +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); From dc1b41fac8211ca2e93a9ac87c39235cf9bd3882 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 13:26:48 +0900 Subject: [PATCH 09/23] Add tests for export default satisfies --- src/language-js/utils/index.js | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 14 ++++++++++++++ .../satisfies-operators/export-default-as.ts | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/format/typescript/satisfies-operators/export-default-as.ts diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index f519652c461a..935c6e1c8c35 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -62,7 +62,7 @@ function hasNakedLeftSide(node) { node.type === "TaggedTemplateExpression" || node.type === "BindExpression" || (node.type === "UpdateExpression" && !node.prefix) || - node.type === "TSAsExpression" || + isTSTypeExpression(node) || node.type === "TSNonNullExpression" ); } diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index e99da2d681e1..6534d2a8edcb 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -167,6 +167,20 @@ const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; ================================================================================ `; +exports[`export-default-as.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +export default (function log() {} satisfies typeof console.log) + +=====================================output===================================== +export default (function log() {} satisfies typeof console.log); + +================================================================================ +`; + exports[`hug-args.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] diff --git a/tests/format/typescript/satisfies-operators/export-default-as.ts b/tests/format/typescript/satisfies-operators/export-default-as.ts new file mode 100644 index 000000000000..6d6905150d89 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/export-default-as.ts @@ -0,0 +1 @@ +export default (function log() {} satisfies typeof console.log) From cd19ebffcd8ef5f68e8de4c81481e1d5814f5b5a Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 13:32:51 +0900 Subject: [PATCH 10/23] Add tests for no lookahead tokens --- src/language-js/utils/index.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 20 ++++++++++++++++++- .../satisfies-operators/satisfies.ts | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/format/typescript/satisfies-operators/satisfies.ts diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index 935c6e1c8c35..0460c0ae9a57 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -898,6 +898,7 @@ function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) { forbidFunctionClassAndDoExpr ); case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": return startsWithNoLookaheadToken( node.expression, diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 6534d2a8edcb..ab91a8cf5ec1 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -119,7 +119,7 @@ let obj: { f(s: string): void } & Record = { g(s) {}, } satisfies { g(s: string): void } & Record; -{ f(x) {} } satisfies { f(s: string): void }; +({ f(x) {} } satisfies { f(s: string): void }); const car = { start() {}, @@ -202,6 +202,24 @@ window.postMessage({ ================================================================================ `; +exports[`satisfies.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +({}) satisfies {}; +({}) satisfies X; +() => ({}) satisfies X; + +=====================================output===================================== +({} satisfies {}); +({} satisfies X); +() => ({} satisfies X); + +================================================================================ +`; + exports[`template-literal.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts new file mode 100644 index 000000000000..a6f82b58ee66 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -0,0 +1,3 @@ +({}) satisfies {}; +({}) satisfies X; +() => ({}) satisfies X; From 93b886aed505bd2f9d84feec0c83c235070fe27a Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 13:46:33 +0900 Subject: [PATCH 11/23] Add more tests for needs parens 1 --- src/language-js/needs-parens.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 443 +++++++++++++++++- .../typescript/satisfies-operators/gt-lt.ts | 2 + .../satisfies-operators/jsfmt.spec.js | 1 + .../satisfies-operators/non-null.ts | 3 + 5 files changed, 444 insertions(+), 6 deletions(-) create mode 100644 tests/format/typescript/satisfies-operators/gt-lt.ts create mode 100644 tests/format/typescript/satisfies-operators/non-null.ts diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 54da4fefeca9..87771c7634bf 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -227,6 +227,7 @@ function needsParens(path, options) { // fallthrough case "TSTypeAssertion": case "TSAsExpression": + case "TSSatisfiesExpression": case "LogicalExpression": switch (parent.type) { case "TSAsExpression": diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index ab91a8cf5ec1..dc5e6e11c2be 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,68 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`argument-expansion.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const bar1 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([] satisfies unknown) satisfies number[]); + +const bar2 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([1, 2, 3] satisfies unknown) satisfies number[]); + +const bar3 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar4 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({1: true} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar5 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); + +=====================================output===================================== +const bar1 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value] + }, + [] satisfies unknown satisfies number[], +) + +const bar2 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value] + }, + [1, 2, 3] satisfies unknown satisfies number[], +) + +const bar3 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true } + }, + {} satisfies unknown satisfies { [key: number]: boolean }, +) + +const bar4 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true } + }, + { 1: true } satisfies unknown satisfies { [key: number]: boolean }, +) + +const bar5 = [1, 2, 3].reduce((carry, value) => { + return [...carry, value] +}, [] satisfies foo) + +================================================================================ +`; + exports[`argument-expansion.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -62,6 +125,79 @@ const bar5 = [1, 2, 3].reduce((carry, value) => { ================================================================================ `; +exports[`basic.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = { } satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = (m => m.substring(0)) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: 'test' } satisfies A; +let t8 = { a: 'test', b: 'test' } satisfies A; + +const p = { + isEven: n => n % 2 === 0, + isOdd: n => n % 2 === 1 +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) { }, + g(s) { } +} satisfies { g(s: string): void } & Record; + +({ f(x) { } }) satisfies { f(s: string): void }; + +const car = { + start() { }, + move(d) { + // d should be number + }, + stop() { } +} satisfies Movable & Record; + +var v = undefined satisfies 1; + +=====================================output===================================== +const t1 = { a: 1 } satisfies I1 +const t2 = { a: 1, b: 1 } satisfies I1 +const t3 = {} satisfies I1 +const t4: T1 = { a: "a" } satisfies T1 +const t5 = (m) => m.substring(0) satisfies T2 +const t6 = [1, 2] satisfies [number, number] +let t7 = { a: "test" } satisfies A +let t8 = { a: "test", b: "test" } satisfies A + +const p = { + isEven: (n) => n % 2 === 0, + isOdd: (n) => n % 2 === 1, +} satisfies Predicates + +let obj: { f(s: string): void } & Record = { + f(s) {}, + g(s) {}, +} satisfies { g(s: string): void } & Record + +;({ f(x) {} } satisfies { f(s: string): void }) + +const car = { + start() {}, + move(d) { + // d should be number + }, + stop() {}, +} satisfies Movable & Record + +var v = undefined satisfies 1 + +================================================================================ +`; + exports[`basic.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -134,6 +270,40 @@ var v = undefined satisfies 1; ================================================================================ `; +exports[`comments.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3 +} satisfies +// Comment +Record; + +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +=====================================output===================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3, +} satisfies // Comment +Record + +const t2 = {} /* comment */ satisfies {} +const t3 = {} satisfies /* comment */ {} +const t4 = {} /* comment1 */ satisfies /* comment2 */ {} + +================================================================================ +`; + exports[`comments.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -167,6 +337,21 @@ const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; ================================================================================ `; +exports[`export-default-as.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +export default (function log() {} satisfies typeof console.log) + +=====================================output===================================== +export default (function log() {} satisfies typeof console.log) + +================================================================================ +`; + exports[`export-default-as.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -181,6 +366,61 @@ export default (function log() {} satisfies typeof console.log); ================================================================================ `; +exports[`gt-lt.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +x satisfies boolean <= y; // (x satisfies boolean) <= y; +x satisfies boolean ?? y; // (x satisfies boolean) ?? y; + +=====================================output===================================== +;(x satisfies boolean) <= y // (x satisfies boolean) <= y; +;(x satisfies boolean) ?? y // (x satisfies boolean) ?? y; + +================================================================================ +`; + +exports[`gt-lt.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +x satisfies boolean <= y; // (x satisfies boolean) <= y; +x satisfies boolean ?? y; // (x satisfies boolean) ?? y; + +=====================================output===================================== +(x satisfies boolean) <= y; // (x satisfies boolean) <= y; +(x satisfies boolean) ?? y; // (x satisfies boolean) ?? y; + +================================================================================ +`; + +exports[`hug-args.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +window.postMessage( + { + context: item.context, + topic: item.topic + } satisfies IActionMessage + ); +=====================================output===================================== +window.postMessage({ + context: item.context, + topic: item.topic, +} satisfies IActionMessage) + +================================================================================ +`; + exports[`hug-args.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -202,6 +442,62 @@ window.postMessage({ ================================================================================ `; +exports[`non-null.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = 'pointer' + +=====================================output===================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = "pointer" + +================================================================================ +`; + +exports[`non-null.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = 'pointer' + +=====================================output===================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref); +(el satisfies HTMLElement)!.style.cursor = "pointer"; + +================================================================================ +`; + +exports[`satisfies.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +({}) satisfies {}; +({}) satisfies X; +() => ({}) satisfies X; + +=====================================output===================================== +;({} satisfies {}) +;({} satisfies X) +;() => ({} satisfies X) + +================================================================================ +`; + exports[`satisfies.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -220,6 +516,38 @@ printWidth: 80 ================================================================================ `; +exports[`template-literal.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const a = \`\${(foo + bar) satisfies baz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz}\`; +const b = \`\${(foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz}\`; +const b = \`\${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; + +=====================================output===================================== +const a = \`\${foo + bar satisfies baz}\` +const b = \`\${ + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar satisfies baz +}\` +const b = \`\${ + foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies baz +}\` +const b = \`\${ + foo + bar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\` +const b = \`\${ + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\` + +================================================================================ +`; + exports[`template-literal.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -251,6 +579,109 @@ const b = \`\${ ================================================================================ `; +exports[`ternary.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +foo = (condition ? firstValue : secondValue) satisfies SomeType; + +const foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +function foo() { + return (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + throw (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + void ((coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo); +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +=====================================output===================================== +foo = + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo + +foo = condition ? firstValue : secondValue satisfies SomeType + +const foo = + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo + +function foo() { + return + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo +} + +function foo() { + throw + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo +} + +function foo() { + void ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + satisfies Fooooooooooo) +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + (glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay) + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + (glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay) + +================================================================================ +`; + exports[`ternary.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -330,25 +761,25 @@ function foo() { } function foo() { - void + void ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo; + satisfies Fooooooooooo); } bifornCringerMoshedPerplexSawder = askTrovenaBeenaDependsRowans + - glimseGlyphsHazardNoopsTieTie === 0 + (glimseGlyphsHazardNoopsTieTie === 0 ? averredBathersBoxroomBuggyNurl - : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay; + : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay); bifornCringerMoshedPerplexSawder = askTrovenaBeenaDependsRowans + - glimseGlyphsHazardNoopsTieTie === 0 && + (glimseGlyphsHazardNoopsTieTie === 0 && kochabCooieGameOnOboleUnweave === Math.PI ? averredBathersBoxroomBuggyNurl - : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay; + : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay); ================================================================================ `; diff --git a/tests/format/typescript/satisfies-operators/gt-lt.ts b/tests/format/typescript/satisfies-operators/gt-lt.ts new file mode 100644 index 000000000000..bdc95deefbed --- /dev/null +++ b/tests/format/typescript/satisfies-operators/gt-lt.ts @@ -0,0 +1,2 @@ +x satisfies boolean <= y; // (x satisfies boolean) <= y; +x satisfies boolean ?? y; // (x satisfies boolean) ?? y; diff --git a/tests/format/typescript/satisfies-operators/jsfmt.spec.js b/tests/format/typescript/satisfies-operators/jsfmt.spec.js index eb7dab7dd4d5..9b9787422054 100644 --- a/tests/format/typescript/satisfies-operators/jsfmt.spec.js +++ b/tests/format/typescript/satisfies-operators/jsfmt.spec.js @@ -1 +1,2 @@ run_spec(import.meta, ["babel-ts"]); +run_spec(import.meta, ["babel-ts"], { semi: false }); diff --git a/tests/format/typescript/satisfies-operators/non-null.ts b/tests/format/typescript/satisfies-operators/non-null.ts new file mode 100644 index 000000000000..9e1e0b3ac0b0 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/non-null.ts @@ -0,0 +1,3 @@ +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = 'pointer' From e05ea2c33d7cc75f06fa47cf353725184dbd01ec Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 13:52:30 +0900 Subject: [PATCH 12/23] Add more tests for needs-parens 2 --- src/language-js/needs-parens.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 139 +++++++++++++++--- .../satisfies-operators/assignment.ts | 10 ++ .../satisfies-operators/satisfies.ts | 8 + 4 files changed, 138 insertions(+), 20 deletions(-) create mode 100644 tests/format/typescript/satisfies-operators/assignment.ts diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 87771c7634bf..c0e723d32b46 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -230,6 +230,7 @@ function needsParens(path, options) { case "TSSatisfiesExpression": case "LogicalExpression": switch (parent.type) { + case "TSSatisfiesExpression": case "TSAsExpression": // example: foo as unknown as Bar return node.type !== "TSAsExpression"; diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index dc5e6e11c2be..b1bd0059b1a4 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -32,28 +32,28 @@ const bar1 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value] }, - [] satisfies unknown satisfies number[], + ([] satisfies unknown) satisfies number[], ) const bar2 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value] }, - [1, 2, 3] satisfies unknown satisfies number[], + ([1, 2, 3] satisfies unknown) satisfies number[], ) const bar3 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true } }, - {} satisfies unknown satisfies { [key: number]: boolean }, + ({} satisfies unknown) satisfies { [key: number]: boolean }, ) const bar4 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true } }, - { 1: true } satisfies unknown satisfies { [key: number]: boolean }, + ({ 1: true } satisfies unknown) satisfies { [key: number]: boolean }, ) const bar5 = [1, 2, 3].reduce((carry, value) => { @@ -94,28 +94,28 @@ const bar1 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value]; }, - [] satisfies unknown satisfies number[], + ([] satisfies unknown) satisfies number[], ); const bar2 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value]; }, - [1, 2, 3] satisfies unknown satisfies number[], + ([1, 2, 3] satisfies unknown) satisfies number[], ); const bar3 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true }; }, - {} satisfies unknown satisfies { [key: number]: boolean }, + ({} satisfies unknown) satisfies { [key: number]: boolean }, ); const bar4 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true }; }, - { 1: true } satisfies unknown satisfies { [key: number]: boolean }, + ({ 1: true } satisfies unknown) satisfies { [key: number]: boolean }, ); const bar5 = [1, 2, 3].reduce((carry, value) => { @@ -125,6 +125,73 @@ const bar5 = [1, 2, 3].reduce((carry, value) => { ================================================================================ `; +exports[`assignment.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, + propertyToServiceName = originalPrototype._inject; + +=====================================output===================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function, +) => string[] + +const originalPrototype = originalConstructor.prototype satisfies TComponent & + InjectionTarget, + propertyToServiceName = originalPrototype._inject + +================================================================================ +`; + +exports[`assignment.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, + propertyToServiceName = originalPrototype._inject; + +=====================================output===================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function, +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & + InjectionTarget, + propertyToServiceName = originalPrototype._inject; + +================================================================================ +`; + exports[`basic.ts - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -489,11 +556,27 @@ semi: false ({}) satisfies {}; ({}) satisfies X; () => ({}) satisfies X; +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +'current' in (props.pagination satisfies Object); +('current' in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; =====================================output===================================== ;({} satisfies {}) ;({} satisfies X) ;() => ({} satisfies X) +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement) + +"current" in (props.pagination satisfies Object) +;("current" in props.pagination) satisfies Object +start + (yearSelectTotal satisfies number) +;(start + yearSelectTotal) satisfies number +scrollTop > (visibilityHeight satisfies number) +;(scrollTop > visibilityHeight) satisfies number ================================================================================ `; @@ -507,11 +590,27 @@ printWidth: 80 ({}) satisfies {}; ({}) satisfies X; () => ({}) satisfies X; +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +'current' in (props.pagination satisfies Object); +('current' in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; =====================================output===================================== ({} satisfies {}); ({} satisfies X); () => ({} satisfies X); +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +"current" in (props.pagination satisfies Object); +("current" in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; ================================================================================ `; @@ -530,19 +629,19 @@ const b = \`\${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVer const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; =====================================output===================================== -const a = \`\${foo + bar satisfies baz}\` +const a = \`\${(foo + bar) satisfies baz}\` const b = \`\${ - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar satisfies baz + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz }\` const b = \`\${ - foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies baz + (foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz }\` const b = \`\${ - foo + bar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz + (foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz }\` const b = \`\${ - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz }\` ================================================================================ @@ -561,19 +660,19 @@ const b = \`\${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVer const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; =====================================output===================================== -const a = \`\${foo + bar satisfies baz}\`; +const a = \`\${(foo + bar) satisfies baz}\`; const b = \`\${ - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar satisfies baz + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz }\`; const b = \`\${ - foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies baz + (foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz }\`; const b = \`\${ - foo + bar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz + (foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz }\`; const b = \`\${ - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz }\`; ================================================================================ diff --git a/tests/format/typescript/satisfies-operators/assignment.ts b/tests/format/typescript/satisfies-operators/assignment.ts new file mode 100644 index 000000000000..3a6b25f88879 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/assignment.ts @@ -0,0 +1,10 @@ +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, + propertyToServiceName = originalPrototype._inject; diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts index a6f82b58ee66..074bea1b8091 100644 --- a/tests/format/typescript/satisfies-operators/satisfies.ts +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -1,3 +1,11 @@ ({}) satisfies {}; ({}) satisfies X; () => ({}) satisfies X; +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +'current' in (props.pagination satisfies Object); +('current' in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; From e76e848c7395fc884be0abc0bf0f926f8730b2af Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:03:54 +0900 Subject: [PATCH 13/23] Add more tests for needs parens 3 --- src/language-js/needs-parens.js | 5 +- .../__snapshots__/jsfmt.spec.js.snap | 60 ++++++++++++++++--- .../satisfies-operators/assignment.ts | 11 ++++ 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index c0e723d32b46..4037edc93ad9 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -230,11 +230,14 @@ function needsParens(path, options) { case "TSSatisfiesExpression": case "LogicalExpression": switch (parent.type) { - case "TSSatisfiesExpression": case "TSAsExpression": // example: foo as unknown as Bar return node.type !== "TSAsExpression"; + case "TSSatisfiesExpression": + // example: foo satisfies unknown satisfies Bar + return node.type !== "TSSatisfiesExpression"; + case "ConditionalExpression": return node.type === "TSAsExpression"; diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index b1bd0059b1a4..2f9e37d22b7b 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -32,28 +32,28 @@ const bar1 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value] }, - ([] satisfies unknown) satisfies number[], + [] satisfies unknown satisfies number[], ) const bar2 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value] }, - ([1, 2, 3] satisfies unknown) satisfies number[], + [1, 2, 3] satisfies unknown satisfies number[], ) const bar3 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true } }, - ({} satisfies unknown) satisfies { [key: number]: boolean }, + {} satisfies unknown satisfies { [key: number]: boolean }, ) const bar4 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true } }, - ({ 1: true } satisfies unknown) satisfies { [key: number]: boolean }, + { 1: true } satisfies unknown satisfies { [key: number]: boolean }, ) const bar5 = [1, 2, 3].reduce((carry, value) => { @@ -94,28 +94,28 @@ const bar1 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value]; }, - ([] satisfies unknown) satisfies number[], + [] satisfies unknown satisfies number[], ); const bar2 = [1, 2, 3].reduce( (carry, value) => { return [...carry, value]; }, - ([1, 2, 3] satisfies unknown) satisfies number[], + [1, 2, 3] satisfies unknown satisfies number[], ); const bar3 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true }; }, - ({} satisfies unknown) satisfies { [key: number]: boolean }, + {} satisfies unknown satisfies { [key: number]: boolean }, ); const bar4 = [1, 2, 3].reduce( (carry, value) => { return { ...carry, [value]: true }; }, - ({ 1: true } satisfies unknown) satisfies { [key: number]: boolean }, + { 1: true } satisfies unknown satisfies { [key: number]: boolean }, ); const bar5 = [1, 2, 3].reduce((carry, value) => { @@ -143,6 +143,17 @@ const annotate = (angular.injector satisfies any).$$annotate satisfies ( const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, propertyToServiceName = originalPrototype._inject; +this.previewPlayerHandle = (setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown) satisfies number; + +this.intervalID = (setInterval(() => { + self.step(); +}, 30) satisfies unknown) satisfies number; + =====================================output===================================== const extraRendererAttrs = ((attrs.rendererAttrs && this.utils.safeParseJsonString(attrs.rendererAttrs)) || @@ -156,6 +167,17 @@ const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, propertyToServiceName = originalPrototype._inject +this.previewPlayerHandle = setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews() + this.currentPreviewIndex++ + } +}, this.refreshDelay) satisfies unknown satisfies number + +this.intervalID = setInterval(() => { + self.step() +}, 30) satisfies unknown satisfies number + ================================================================================ `; @@ -176,6 +198,17 @@ const annotate = (angular.injector satisfies any).$$annotate satisfies ( const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, propertyToServiceName = originalPrototype._inject; +this.previewPlayerHandle = (setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown) satisfies number; + +this.intervalID = (setInterval(() => { + self.step(); +}, 30) satisfies unknown) satisfies number; + =====================================output===================================== const extraRendererAttrs = ((attrs.rendererAttrs && this.utils.safeParseJsonString(attrs.rendererAttrs)) || @@ -189,6 +222,17 @@ const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, propertyToServiceName = originalPrototype._inject; +this.previewPlayerHandle = setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown satisfies number; + +this.intervalID = setInterval(() => { + self.step(); +}, 30) satisfies unknown satisfies number; + ================================================================================ `; diff --git a/tests/format/typescript/satisfies-operators/assignment.ts b/tests/format/typescript/satisfies-operators/assignment.ts index 3a6b25f88879..9b7139253bc4 100644 --- a/tests/format/typescript/satisfies-operators/assignment.ts +++ b/tests/format/typescript/satisfies-operators/assignment.ts @@ -8,3 +8,14 @@ const annotate = (angular.injector satisfies any).$$annotate satisfies ( const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, propertyToServiceName = originalPrototype._inject; + +this.previewPlayerHandle = (setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown) satisfies number; + +this.intervalID = (setInterval(() => { + self.step(); +}, 30) satisfies unknown) satisfies number; From 911c47a1761bad71b0a035ab8aa2455dc7d35df1 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:06:03 +0900 Subject: [PATCH 14/23] Add tests for needs parens 4 --- src/language-js/needs-parens.js | 3 ++- .../satisfies-operators/__snapshots__/jsfmt.spec.js.snap | 8 ++++++++ tests/format/typescript/satisfies-operators/satisfies.ts | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 4037edc93ad9..fef9d4157076 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -11,6 +11,7 @@ import { isCallExpression, isMemberExpression, isObjectProperty, + isTSTypeExpression, } from "./utils/index.js"; function needsParens(path, options) { @@ -239,7 +240,7 @@ function needsParens(path, options) { return node.type !== "TSSatisfiesExpression"; case "ConditionalExpression": - return node.type === "TSAsExpression"; + return isTSTypeExpression(node); case "CallExpression": case "NewExpression": diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 2f9e37d22b7b..18f930c6015c 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -609,6 +609,8 @@ start + (yearSelectTotal satisfies number); scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; +(bValue satisfies boolean) ? 0 : -1; + =====================================output===================================== ;({} satisfies {}) ;({} satisfies X) @@ -622,6 +624,8 @@ start + (yearSelectTotal satisfies number) scrollTop > (visibilityHeight satisfies number) ;(scrollTop > visibilityHeight) satisfies number +;(bValue satisfies boolean) ? 0 : -1 + ================================================================================ `; @@ -643,6 +647,8 @@ start + (yearSelectTotal satisfies number); scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; +(bValue satisfies boolean) ? 0 : -1; + =====================================output===================================== ({} satisfies {}); ({} satisfies X); @@ -656,6 +662,8 @@ start + (yearSelectTotal satisfies number); scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; +(bValue satisfies boolean) ? 0 : -1; + ================================================================================ `; diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts index 074bea1b8091..88d71268b8dc 100644 --- a/tests/format/typescript/satisfies-operators/satisfies.ts +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -9,3 +9,5 @@ start + (yearSelectTotal satisfies number); (start + yearSelectTotal) satisfies number; scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; + +(bValue satisfies boolean) ? 0 : -1; From a1486743aff96ffa55d9df2b09bb0e431f571087 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:18:01 +0900 Subject: [PATCH 15/23] Add comment --- src/language-js/needs-parens.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index fef9d4157076..95af8dcffb69 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -271,7 +271,12 @@ function needsParens(path, options) { case "AssignmentPattern": return ( key === "left" && - (node.type === "TSTypeAssertion" || node.type === "TSAsExpression") + (node.type === "TSTypeAssertion" || + node.type === "TSAsExpression" || + // babel-parser cannot parse `satisfies` operator in left side of assignment + // https://github.com/babel/babel/issues/15095 + // TODO: Add tests after the bug is fixed + node.type === "TSSatisfiesExpression") ); case "LogicalExpression": From b2aa3f282b4e242cecb120732430817b02c3e5da Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:21:33 +0900 Subject: [PATCH 16/23] Add more tests for needs parens 5 --- src/language-js/needs-parens.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 67 +++++++++++++++++++ .../nested-await-and-satisfies.ts | 7 ++ .../satisfies-operators/satisfies.ts | 4 ++ 4 files changed, 79 insertions(+) create mode 100644 tests/format/typescript/satisfies-operators/nested-await-and-satisfies.ts diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 95af8dcffb69..b14e228a0e4f 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -371,6 +371,7 @@ function needsParens(path, options) { case "SpreadElement": case "SpreadProperty": case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": case "BindExpression": return true; diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 18f930c6015c..522e7f10d32d 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -553,6 +553,57 @@ window.postMessage({ ================================================================================ `; +exports[`nested-await-and-satisfies.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const getAccountCount = async () => + (await + ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length + +=====================================output===================================== +const getAccountCount = async () => + ( + await ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem).getChildren() + ).length + +================================================================================ +`; + +exports[`nested-await-and-satisfies.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const getAccountCount = async () => + (await + ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length + +=====================================output===================================== +const getAccountCount = async () => + ( + await ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem).getChildren() + ).length; + +================================================================================ +`; + exports[`non-null.ts - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] @@ -611,6 +662,10 @@ scrollTop > (visibilityHeight satisfies number); (bValue satisfies boolean) ? 0 : -1; +async function g1() { + const test = (await 'foo') satisfies number; +} + =====================================output===================================== ;({} satisfies {}) ;({} satisfies X) @@ -626,6 +681,10 @@ scrollTop > (visibilityHeight satisfies number) ;(bValue satisfies boolean) ? 0 : -1 +async function g1() { + const test = (await "foo") satisfies number +} + ================================================================================ `; @@ -649,6 +708,10 @@ scrollTop > (visibilityHeight satisfies number); (bValue satisfies boolean) ? 0 : -1; +async function g1() { + const test = (await 'foo') satisfies number; +} + =====================================output===================================== ({} satisfies {}); ({} satisfies X); @@ -664,6 +727,10 @@ scrollTop > (visibilityHeight satisfies number); (bValue satisfies boolean) ? 0 : -1; +async function g1() { + const test = (await "foo") satisfies number; +} + ================================================================================ `; diff --git a/tests/format/typescript/satisfies-operators/nested-await-and-satisfies.ts b/tests/format/typescript/satisfies-operators/nested-await-and-satisfies.ts new file mode 100644 index 000000000000..d9c2b4a600be --- /dev/null +++ b/tests/format/typescript/satisfies-operators/nested-await-and-satisfies.ts @@ -0,0 +1,7 @@ +const getAccountCount = async () => + (await + ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts index 88d71268b8dc..e2e0999ec7d8 100644 --- a/tests/format/typescript/satisfies-operators/satisfies.ts +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -11,3 +11,7 @@ scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; (bValue satisfies boolean) ? 0 : -1; + +async function g1() { + const test = (await 'foo') satisfies number; +} From a7f78e8de235e5383021eddf03d05b5803682d2e Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:28:34 +0900 Subject: [PATCH 17/23] Add more tests for needs parens 6 --- src/language-js/needs-parens.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 109 +++++++++++++----- .../satisfies-operators/satisfies.ts | 2 + .../satisfies-operators/types-comments.ts | 4 + 4 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 tests/format/typescript/satisfies-operators/types-comments.ts diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index b14e228a0e4f..7fddb641a6c8 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -604,6 +604,7 @@ function needsParens(path, options) { case "TSTypeAssertion": case "TypeCastExpression": case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": return true; @@ -653,6 +654,7 @@ function needsParens(path, options) { return key === "object"; case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": case "BindExpression": case "TaggedTemplateExpression": diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 522e7f10d32d..d6e90086c769 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -279,7 +279,7 @@ const t1 = { a: 1 } satisfies I1 const t2 = { a: 1, b: 1 } satisfies I1 const t3 = {} satisfies I1 const t4: T1 = { a: "a" } satisfies T1 -const t5 = (m) => m.substring(0) satisfies T2 +const t5 = ((m) => m.substring(0)) satisfies T2 const t6 = [1, 2] satisfies [number, number] let t7 = { a: "test" } satisfies A let t8 = { a: "test", b: "test" } satisfies A @@ -351,7 +351,7 @@ const t1 = { a: 1 } satisfies I1; const t2 = { a: 1, b: 1 } satisfies I1; const t3 = {} satisfies I1; const t4: T1 = { a: "a" } satisfies T1; -const t5 = (m) => m.substring(0) satisfies T2; +const t5 = ((m) => m.substring(0)) satisfies T2; const t6 = [1, 2] satisfies [number, number]; let t7 = { a: "test" } satisfies A; let t8 = { a: "test", b: "test" } satisfies A; @@ -666,6 +666,8 @@ async function g1() { const test = (await 'foo') satisfies number; } +var x = (v => v) satisfies (x: number) => string; + =====================================output===================================== ;({} satisfies {}) ;({} satisfies X) @@ -685,6 +687,8 @@ async function g1() { const test = (await "foo") satisfies number } +var x = ((v) => v) satisfies (x: number) => string + ================================================================================ `; @@ -712,6 +716,8 @@ async function g1() { const test = (await 'foo') satisfies number; } +var x = (v => v) satisfies (x: number) => string; + =====================================output===================================== ({} satisfies {}); ({} satisfies X); @@ -731,6 +737,8 @@ async function g1() { const test = (await "foo") satisfies number; } +var x = ((v) => v) satisfies (x: number) => string; + ================================================================================ `; @@ -846,56 +854,56 @@ bifornCringerMoshedPerplexSawder = : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); =====================================output===================================== -foo = +foo = ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo +) satisfies Fooooooooooo -foo = condition ? firstValue : secondValue satisfies SomeType +foo = (condition ? firstValue : secondValue) satisfies SomeType -const foo = +const foo = ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo +) satisfies Fooooooooooo function foo() { - return + return ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo + ) satisfies Fooooooooooo } function foo() { - throw + throw ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo + ) satisfies Fooooooooooo } function foo() { - void ( + void (( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo) + ) satisfies Fooooooooooo) } bifornCringerMoshedPerplexSawder = askTrovenaBeenaDependsRowans + - (glimseGlyphsHazardNoopsTieTie === 0 + ((glimseGlyphsHazardNoopsTieTie === 0 ? averredBathersBoxroomBuggyNurl - : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay) + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay) bifornCringerMoshedPerplexSawder = askTrovenaBeenaDependsRowans + - (glimseGlyphsHazardNoopsTieTie === 0 && + ((glimseGlyphsHazardNoopsTieTie === 0 && kochabCooieGameOnOboleUnweave === Math.PI ? averredBathersBoxroomBuggyNurl - : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay) + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay) ================================================================================ `; @@ -948,56 +956,93 @@ bifornCringerMoshedPerplexSawder = : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); =====================================output===================================== -foo = +foo = ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo; +) satisfies Fooooooooooo; -foo = condition ? firstValue : secondValue satisfies SomeType; +foo = (condition ? firstValue : secondValue) satisfies SomeType; -const foo = +const foo = ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo; +) satisfies Fooooooooooo; function foo() { - return + return ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo; + ) satisfies Fooooooooooo; } function foo() { - throw + throw ( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo; + ) satisfies Fooooooooooo; } function foo() { - void ( + void (( coooooooooooooooooooooooooooooooooooooooooooooooooooond ? baaaaaaaaaaaaaaaaaaaaar : baaaaaaaaaaaaaaaaaaaaaz - satisfies Fooooooooooo); + ) satisfies Fooooooooooo); } bifornCringerMoshedPerplexSawder = askTrovenaBeenaDependsRowans + - (glimseGlyphsHazardNoopsTieTie === 0 + ((glimseGlyphsHazardNoopsTieTie === 0 ? averredBathersBoxroomBuggyNurl - : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay); + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); bifornCringerMoshedPerplexSawder = askTrovenaBeenaDependsRowans + - (glimseGlyphsHazardNoopsTieTie === 0 && + ((glimseGlyphsHazardNoopsTieTie === 0 && kochabCooieGameOnOboleUnweave === Math.PI ? averredBathersBoxroomBuggyNurl - : anodyneCondosMalateOverateRetinol satisfies AnnularCooeedSplicesWalksWayWay); + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +================================================================================ +`; + +exports[`types-comments.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[]; + +=====================================output===================================== +;(() => { + // swallow error and fallback to using directory as path +}) satisfies string[] + +================================================================================ +`; + +exports[`types-comments.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[]; + +=====================================output===================================== +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[]; ================================================================================ `; diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts index e2e0999ec7d8..81ad94508156 100644 --- a/tests/format/typescript/satisfies-operators/satisfies.ts +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -15,3 +15,5 @@ scrollTop > (visibilityHeight satisfies number); async function g1() { const test = (await 'foo') satisfies number; } + +var x = (v => v) satisfies (x: number) => string; diff --git a/tests/format/typescript/satisfies-operators/types-comments.ts b/tests/format/typescript/satisfies-operators/types-comments.ts new file mode 100644 index 000000000000..2c2a4fb069bf --- /dev/null +++ b/tests/format/typescript/satisfies-operators/types-comments.ts @@ -0,0 +1,4 @@ +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[]; + \ No newline at end of file From 1173f550cf5ca1c7ea35ebc6b2d6a0bf48b8bda4 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:31:15 +0900 Subject: [PATCH 18/23] Fix test cases --- tests/format/typescript/satisfies-operators/hug-args.ts | 2 +- tests/format/typescript/satisfies-operators/types-comments.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/format/typescript/satisfies-operators/hug-args.ts b/tests/format/typescript/satisfies-operators/hug-args.ts index 19cb5b1f2623..c35cf66fb521 100644 --- a/tests/format/typescript/satisfies-operators/hug-args.ts +++ b/tests/format/typescript/satisfies-operators/hug-args.ts @@ -3,4 +3,4 @@ window.postMessage( context: item.context, topic: item.topic } satisfies IActionMessage - ); \ No newline at end of file + ); diff --git a/tests/format/typescript/satisfies-operators/types-comments.ts b/tests/format/typescript/satisfies-operators/types-comments.ts index 2c2a4fb069bf..8ef9413c2a31 100644 --- a/tests/format/typescript/satisfies-operators/types-comments.ts +++ b/tests/format/typescript/satisfies-operators/types-comments.ts @@ -1,4 +1,3 @@ (() => { // swallow error and fallback to using directory as path }) satisfies string[]; - \ No newline at end of file From 966c5df889bc550c07d062808af8847dd29cb1a9 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:39:58 +0900 Subject: [PATCH 19/23] Fix snapshots --- .../satisfies-operators/__snapshots__/jsfmt.spec.js.snap | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index d6e90086c769..f793b673d5bc 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -523,6 +523,7 @@ window.postMessage( topic: item.topic } satisfies IActionMessage ); + =====================================output===================================== window.postMessage({ context: item.context, @@ -544,6 +545,7 @@ window.postMessage( topic: item.topic } satisfies IActionMessage ); + =====================================output===================================== window.postMessage({ context: item.context, @@ -1020,7 +1022,7 @@ semi: false (() => { // swallow error and fallback to using directory as path }) satisfies string[]; - + =====================================output===================================== ;(() => { // swallow error and fallback to using directory as path @@ -1038,7 +1040,7 @@ printWidth: 80 (() => { // swallow error and fallback to using directory as path }) satisfies string[]; - + =====================================output===================================== (() => { // swallow error and fallback to using directory as path From e3e112d979542529fd905571371833c9d2e88a7c Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 30 Oct 2022 14:44:00 +0900 Subject: [PATCH 20/23] Fix unstable tests --- tests/config/format-test.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 59 ++++++++++++------- .../satisfies-operators/comments-unstable.ts | 7 +++ .../satisfies-operators/comments.ts | 8 --- .../satisfies-operators/satisfies.ts | 1 - 5 files changed, 46 insertions(+), 30 deletions(-) create mode 100644 tests/format/typescript/satisfies-operators/comments-unstable.ts diff --git a/tests/config/format-test.js b/tests/config/format-test.js index cfd11bae8a0b..51c51d695e66 100644 --- a/tests/config/format-test.js +++ b/tests/config/format-test.js @@ -37,6 +37,7 @@ const unstableTests = new Map( "typescript/prettier-ignore/mapped-types.ts", "js/comments/html-like/comment.js", "js/for/continue-and-break-comment-without-blocks.js", + "typescript/satisfies-operators/comments-unstable.ts", ].map((fixture) => { const [file, isUnstable = () => true] = Array.isArray(fixture) ? fixture diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index f793b673d5bc..8a6d2a5d77a1 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -388,6 +388,43 @@ printWidth: 80 semi: false | printWidth =====================================input====================================== +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +=====================================output===================================== +const t2 = {} /* comment */ satisfies {} +const t3 = {} satisfies /* comment */ {} +const t4 = {} /* comment1 */ satisfies /* comment2 */ {} + +================================================================================ +`; + +exports[`comments.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +=====================================output===================================== +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +================================================================================ +`; + +exports[`comments-unstable.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== const t1 = { prop1: 1, prop2: 2, @@ -396,10 +433,6 @@ const t1 = { // Comment Record; -const t2 = {} /* comment */ satisfies {}; -const t3 = {} satisfies /* comment */ {}; -const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; - =====================================output===================================== const t1 = { prop1: 1, @@ -408,14 +441,10 @@ const t1 = { } satisfies // Comment Record -const t2 = {} /* comment */ satisfies {} -const t3 = {} satisfies /* comment */ {} -const t4 = {} /* comment1 */ satisfies /* comment2 */ {} - ================================================================================ `; -exports[`comments.ts format 1`] = ` +exports[`comments-unstable.ts format 1`] = ` ====================================options===================================== parsers: ["babel-ts"] printWidth: 80 @@ -429,10 +458,6 @@ const t1 = { // Comment Record; -const t2 = {} /* comment */ satisfies {}; -const t3 = {} satisfies /* comment */ {}; -const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; - =====================================output===================================== const t1 = { prop1: 1, @@ -441,10 +466,6 @@ const t1 = { } satisfies // Comment Record; -const t2 = {} /* comment */ satisfies {}; -const t3 = {} satisfies /* comment */ {}; -const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; - ================================================================================ `; @@ -661,7 +682,6 @@ start + (yearSelectTotal satisfies number); (start + yearSelectTotal) satisfies number; scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; - (bValue satisfies boolean) ? 0 : -1; async function g1() { @@ -682,7 +702,6 @@ start + (yearSelectTotal satisfies number) ;(start + yearSelectTotal) satisfies number scrollTop > (visibilityHeight satisfies number) ;(scrollTop > visibilityHeight) satisfies number - ;(bValue satisfies boolean) ? 0 : -1 async function g1() { @@ -711,7 +730,6 @@ start + (yearSelectTotal satisfies number); (start + yearSelectTotal) satisfies number; scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; - (bValue satisfies boolean) ? 0 : -1; async function g1() { @@ -732,7 +750,6 @@ start + (yearSelectTotal satisfies number); (start + yearSelectTotal) satisfies number; scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; - (bValue satisfies boolean) ? 0 : -1; async function g1() { diff --git a/tests/format/typescript/satisfies-operators/comments-unstable.ts b/tests/format/typescript/satisfies-operators/comments-unstable.ts new file mode 100644 index 000000000000..0f658aa54605 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/comments-unstable.ts @@ -0,0 +1,7 @@ +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3 +} satisfies +// Comment +Record; diff --git a/tests/format/typescript/satisfies-operators/comments.ts b/tests/format/typescript/satisfies-operators/comments.ts index 8310b122c8be..9ab0ae58c20c 100644 --- a/tests/format/typescript/satisfies-operators/comments.ts +++ b/tests/format/typescript/satisfies-operators/comments.ts @@ -1,11 +1,3 @@ -const t1 = { - prop1: 1, - prop2: 2, - prop3: 3 -} satisfies -// Comment -Record; - const t2 = {} /* comment */ satisfies {}; const t3 = {} satisfies /* comment */ {}; const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts index 81ad94508156..4d7f7f5ccad7 100644 --- a/tests/format/typescript/satisfies-operators/satisfies.ts +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -9,7 +9,6 @@ start + (yearSelectTotal satisfies number); (start + yearSelectTotal) satisfies number; scrollTop > (visibilityHeight satisfies number); (scrollTop > visibilityHeight) satisfies number; - (bValue satisfies boolean) ? 0 : -1; async function g1() { From fcba739e81c01e215985e562af98bed4c96d92fe Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Mon, 31 Oct 2022 00:09:20 +0900 Subject: [PATCH 21/23] No parens for mixed --- src/language-js/needs-parens.js | 14 +++++++++----- .../__snapshots__/jsfmt.spec.js.snap | 16 ++++++++++++++++ .../typescript/satisfies-operators/satisfies.ts | 4 ++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 7fddb641a6c8..527fb8ef7f90 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -232,12 +232,16 @@ function needsParens(path, options) { case "LogicalExpression": switch (parent.type) { case "TSAsExpression": - // example: foo as unknown as Bar - return node.type !== "TSAsExpression"; - case "TSSatisfiesExpression": - // example: foo satisfies unknown satisfies Bar - return node.type !== "TSSatisfiesExpression"; + // examples: + // foo as unknown as Bar + // foo satisfies unknown satisfies Bar + // foo satisfies unknown as Bar + // foo as unknown satisfies Bar + return ( + node.type !== "TSAsExpression" && + node.type !== "TSSatisfiesExpression" + ); case "ConditionalExpression": return isTSTypeExpression(node); diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 8a6d2a5d77a1..55679c0479ac 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -690,6 +690,10 @@ async function g1() { var x = (v => v) satisfies (x: number) => string; +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; + =====================================output===================================== ;({} satisfies {}) ;({} satisfies X) @@ -710,6 +714,10 @@ async function g1() { var x = ((v) => v) satisfies (x: number) => string +foo satisfies unknown satisfies Bar +foo satisfies unknown as Bar +foo as unknown satisfies Bar + ================================================================================ `; @@ -738,6 +746,10 @@ async function g1() { var x = (v => v) satisfies (x: number) => string; +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; + =====================================output===================================== ({} satisfies {}); ({} satisfies X); @@ -758,6 +770,10 @@ async function g1() { var x = ((v) => v) satisfies (x: number) => string; +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; + ================================================================================ `; diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts index 4d7f7f5ccad7..f9b3f6f2acb3 100644 --- a/tests/format/typescript/satisfies-operators/satisfies.ts +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -16,3 +16,7 @@ async function g1() { } var x = (v => v) satisfies (x: number) => string; + +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; From bf0daa959ab883e39e61a0854260a863baf49882 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Mon, 31 Oct 2022 00:13:55 +0900 Subject: [PATCH 22/23] Merge printing logic --- src/language-js/print/typescript.js | 8 ++++---- .../__snapshots__/jsfmt.spec.js.snap | 16 ++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/language-js/print/typescript.js b/src/language-js/print/typescript.js index 29f265715fb9..36af1c8f0626 100644 --- a/src/language-js/print/typescript.js +++ b/src/language-js/print/typescript.js @@ -142,8 +142,10 @@ function printTypescript(path, options, print) { return printTypeParameters(path, options, print, "params"); case "TSTypeParameter": return printTypeParameter(path, options, print); - case "TSAsExpression": { - parts.push(print("expression"), " as ", print("typeAnnotation")); + case "TSAsExpression": + case "TSSatisfiesExpression": { + const operator = node.type === "TSAsExpression" ? "as" : "satisfies"; + parts.push(print("expression"), ` ${operator} `, print("typeAnnotation")); const { parent } = path; if ( (isCallExpression(parent) && parent.callee === node) || @@ -515,8 +517,6 @@ function printTypescript(path, options, print) { return printJSDocType(path, print, /* token */ "!"); case "TSInstantiationExpression": return [print("expression"), print("typeParameters")]; - case "TSSatisfiesExpression": - return [print("expression"), " satisfies ", print("typeAnnotation")]; default: /* c8 ignore next */ throw new UnexpectedNodeError(node, "TypeScript"); diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap index 55679c0479ac..2a4c951f3588 100644 --- a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -594,9 +594,11 @@ const getAccountCount = async () => =====================================output===================================== const getAccountCount = async () => ( - await ((await ( - await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) - ).findItem("My bookmarks")) satisfies TreeItem).getChildren() + await ( + (await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() ).length ================================================================================ @@ -619,9 +621,11 @@ const getAccountCount = async () => =====================================output===================================== const getAccountCount = async () => ( - await ((await ( - await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) - ).findItem("My bookmarks")) satisfies TreeItem).getChildren() + await ( + (await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() ).length; ================================================================================ From 5f31b99079f439f891c9990386f42440ad9abc62 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Mon, 31 Oct 2022 00:25:58 +0900 Subject: [PATCH 23/23] More reuse `isTSTypeExpression` --- src/language-js/needs-parens.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 527fb8ef7f90..20d2e0f789ea 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -238,10 +238,7 @@ function needsParens(path, options) { // foo satisfies unknown satisfies Bar // foo satisfies unknown as Bar // foo as unknown satisfies Bar - return ( - node.type !== "TSAsExpression" && - node.type !== "TSSatisfiesExpression" - ); + return !isTSTypeExpression(node); case "ConditionalExpression": return isTSTypeExpression(node); @@ -276,11 +273,10 @@ function needsParens(path, options) { return ( key === "left" && (node.type === "TSTypeAssertion" || - node.type === "TSAsExpression" || // babel-parser cannot parse `satisfies` operator in left side of assignment // https://github.com/babel/babel/issues/15095 // TODO: Add tests after the bug is fixed - node.type === "TSSatisfiesExpression") + isTSTypeExpression(node)) ); case "LogicalExpression":