From eed53fc29a36a0d045a3768e1aba2f61cb5b593a Mon Sep 17 00:00:00 2001 From: Brandon Mills Date: Fri, 3 Jan 2025 11:30:51 -0500 Subject: [PATCH] Break lines before binary operators (#7111) * Add additional binary expression comment tests Refs #3806 These cover a few edge cases I encountered while maintaining `@btmills/prettier` over the last few years. I'm adding them up front to demonstrate that the `experimentalOperatorPosition` changes in a later commit have no effect on this formatting when the flag is not enabled. * Define experimentalOperatorPosition flag Refs #3806 This merely defines the flag. A future commit will use it in updated logic. * Add experimentalOperatorPosition default tests Right now, this flag isn't implemented, so these tests duplicate the existing behavior. I'm adding them now so that when I implement the flag's logic in a future commit, the changed formatting will be obvious in the diff and easier to review. * Implement experimentalOperatorPosition flag Fixes #3806 as requested in https://github.com/prettier/prettier/pull/7111#issuecomment-2252623779 The flag's tests were already added in a previous commit, so the test changes you see in this commit are specifically due to the new flag's implementation. * Document experimentalOperatorPosition flag * Change operator position option start|end In response to https://github.com/prettier/prettier/pull/7111#discussion_r1729382119 * Add TS intersection line wrapping tests This clones TypeScript's type union operator tests in `union-parens.ts` and swaps the operators (& <-> |) to test the the type interesection operator. It also runs intersection tests with the new `experimentalOperatorPosition: "start"` flag. This does _not_ yet update the implementation to consider the flag; to ease review, I'll make that change in the next commit to isolate the impact of the change. * Apply experimentalOperatorPosition: start to type intersections The type union operator was already formatted at the beginning of lines by default, so that logic didn't need to be updated. * Update 7111.md * Update tests after rebasing I rebased from 1dfe28f85 to c7066780e to fix test failures related to https://github.com/prettier/prettier/pull/16601. The rebase applied cleanly, and this was the only change to tests. Since the PR has already been approved, I'll keep this as a separate commit rather than squashing into the prior commits. --------- Co-authored-by: fisker Cheung Co-authored-by: SUZUKI Sosuke --- changelog_unreleased/javascript/7111.md | 23 + docs/options.md | 11 + src/language-js/options.js | 16 + src/language-js/print/binaryish.js | 59 +- src/language-js/print/type-annotation.js | 3 + .../__snapshots__/format.test.js.snap | 1345 +++++++++++++++++ tests/format/js/binary-expressions/comment.js | 12 + .../js/binary-expressions/format.test.js | 4 + .../__snapshots__/format.test.js.snap | 693 +++++++++ .../typescript/intersection/format.test.js | 3 + .../intersection/intersection-parens.ts | 111 ++ .../__snapshots__/early-exit.js.snap | 6 + .../__snapshots__/help-options.js.snap | 17 + .../plugin-options-string.js.snap | 8 +- .../__snapshots__/plugin-options.js.snap | 8 +- .../__tests__/__snapshots__/schema.js.snap | 18 + .../__snapshots__/support-info.js.snap | 26 + 17 files changed, 2342 insertions(+), 21 deletions(-) create mode 100644 changelog_unreleased/javascript/7111.md create mode 100644 tests/format/typescript/intersection/intersection-parens.ts diff --git a/changelog_unreleased/javascript/7111.md b/changelog_unreleased/javascript/7111.md new file mode 100644 index 000000000..ec839c16a --- /dev/null +++ b/changelog_unreleased/javascript/7111.md @@ -0,0 +1,23 @@ +#### Break lines before binary operators (#7111 by @btmills) + +This is implemented behind the `--experimental-operator-position ` flag. + +When binary expressions wrap lines, `start` prints the operators at the start of new lines. Placing binary operators at the beginning of wrapped lines can make the operators more prominent and easier to scan. + + +```jsx +// Input +var a = Math.random() * (yRange * (1 - minVerticalFraction)) + minVerticalFraction * yRange - offset; + +// Default behavior +var a = + Math.random() * (yRange * (1 - minVerticalFraction)) + + minVerticalFraction * yRange - + offset; + +// `experimentalOperatorPosition: true` +var a = + Math.random() * (yRange * (1 - minVerticalFraction)) + + minVerticalFraction * yRange + - offset; +``` diff --git a/docs/options.md b/docs/options.md index 686420e35..68208bb4f 100644 --- a/docs/options.md +++ b/docs/options.md @@ -22,6 +22,17 @@ Valid options: | ------- | -------------------------- | ------------------------------- | | `false` | `--experimental-ternaries` | `experimentalTernaries: ` | +## Experimental Operator Position + +Valid options: + +- `"start"` - When binary expressions wrap lines, print operators at the start of new lines. +- `"end"` - Default behavior; when binary expressions wrap lines, print operators at the end of previous lines. + +| Default | CLI Override | API Override | +| ------- | -------------------------------------------------------------- | ------------------------------------------------------------- | +| `"end"` | --experimental-operator-position | experimentalOperatorPosition: "" | + ## Print Width Specify the line length that the printer will wrap on. diff --git a/src/language-js/options.js b/src/language-js/options.js index f7627c189..f5927e35c 100644 --- a/src/language-js/options.js +++ b/src/language-js/options.js @@ -36,6 +36,22 @@ const options = { oppositeDescription: "Do not print semicolons, except at the beginning of lines which may need them.", }, + experimentalOperatorPosition: { + category: CATEGORY_JAVASCRIPT, + type: "choice", + default: "end", + description: "Where to print operators when binary expressions wrap lines.", + choices: [ + { + value: "start", + description: "Print operators at the start of new lines.", + }, + { + value: "end", + description: "Print operators at the end of previous lines.", + }, + ], + }, experimentalTernaries: { category: CATEGORY_JAVASCRIPT, type: "boolean", diff --git a/src/language-js/print/binaryish.js b/src/language-js/print/binaryish.js index 511a42c8b..715044e40 100644 --- a/src/language-js/print/binaryish.js +++ b/src/language-js/print/binaryish.js @@ -7,8 +7,13 @@ import { line, softline, } from "../../document/builders.js"; -import { DOC_TYPE_FILL, DOC_TYPE_GROUP } from "../../document/constants.js"; -import { cleanDoc } from "../../document/utils.js"; +import { + DOC_TYPE_ARRAY, + DOC_TYPE_FILL, + DOC_TYPE_GROUP, + DOC_TYPE_LABEL, +} from "../../document/constants.js"; +import { cleanDoc, getDocType } from "../../document/utils.js"; import { printComments } from "../../main/comments/print.js"; import { CommentCheckFlags, @@ -23,6 +28,7 @@ import { isObjectProperty, shouldFlatten, } from "../utils/index.js"; +import isTypeCastComment from "../utils/is-type-cast-comment.js"; /** @import {Doc} from "../../document/builders.js" */ @@ -231,6 +237,14 @@ function printBinaryishExpressions( node.type === "NGPipeExpression" || isVueFilterSequenceExpression(path, options)) && !hasLeadingOwnLineComment(options.originalText, node.right); + const hasTypeCastComment = hasComment( + node.right, + CommentCheckFlags.Leading, + isTypeCastComment, + ); + const commentBeforeOperator = + !hasTypeCastComment && + hasLeadingOwnLineComment(options.originalText, node.right); const operator = node.type === "NGPipeExpression" ? "|" : node.operator; const rightSuffix = @@ -267,13 +281,28 @@ function printBinaryishExpressions( "right", ) : print("right"); - right = [ - lineBeforeOperator ? line : "", - operator, - lineBeforeOperator ? " " : line, - rightContent, - rightSuffix, - ]; + if (options.experimentalOperatorPosition === "start") { + let comment = ""; + if (commentBeforeOperator) { + switch (getDocType(rightContent)) { + case DOC_TYPE_ARRAY: + comment = rightContent.splice(0, 1)[0]; + break; + case DOC_TYPE_LABEL: + comment = rightContent.contents.splice(0, 1)[0]; + break; + } + } + right = [line, comment, operator, " ", rightContent, rightSuffix]; + } else { + right = [ + lineBeforeOperator ? line : "", + operator, + lineBeforeOperator ? " " : line, + rightContent, + rightSuffix, + ]; + } } // If there's only a single binary expression, we want to create a group @@ -289,11 +318,15 @@ function printBinaryishExpressions( parent.type !== node.type && node.left.type !== node.type && node.right.type !== node.type); + if (shouldGroup) { + right = group(right, { shouldBreak }); + } - parts.push( - lineBeforeOperator ? "" : " ", - shouldGroup ? group(right, { shouldBreak }) : right, - ); + if (options.experimentalOperatorPosition === "start") { + parts.push(shouldInline || commentBeforeOperator ? " " : "", right); + } else { + parts.push(lineBeforeOperator ? "" : " ", right); + } // The root comments are already printed, but we need to manually print // the other ones since we don't call the normal print on BinaryExpression, diff --git a/src/language-js/print/type-annotation.js b/src/language-js/print/type-annotation.js index 21e57603c..9e5df2b15 100644 --- a/src/language-js/print/type-annotation.js +++ b/src/language-js/print/type-annotation.js @@ -142,6 +142,9 @@ function printIntersectionType(path, options, print) { // If no object is involved, go to the next line if it breaks if (!previousIsObjectType && !currentIsObjectType) { + if (options.experimentalOperatorPosition === "start") { + return indent([line, "& ", doc]); + } return indent([" &", line, doc]); } diff --git a/tests/format/js/binary-expressions/__snapshots__/format.test.js.snap b/tests/format/js/binary-expressions/__snapshots__/format.test.js.snap index b47380932..fc3b495bc 100644 --- a/tests/format/js/binary-expressions/__snapshots__/format.test.js.snap +++ b/tests/format/js/binary-expressions/__snapshots__/format.test.js.snap @@ -1,5 +1,58 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`arrow.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +function f() { + const appEntities = getAppEntities(loadObject).filter( + entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled() + ) +} + +function f2() { + const appEntities = getAppEntities(loadObject).map( + entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled() && { + id: entity.id + } + ) +} + +((x) => x) + ''; +'' + ((x) => x); + +=====================================output===================================== +function f() { + const appEntities = getAppEntities(loadObject).filter( + (entity) => + entity + && entity.isInstallAvailable() + && !entity.isQueue() + && entity.isDisabled(), + ); +} + +function f2() { + const appEntities = getAppEntities(loadObject).map( + (entity) => + entity + && entity.isInstallAvailable() + && !entity.isQueue() + && entity.isDisabled() && { + id: entity.id, + }, + ); +} + +((x) => x) + ""; +"" + ((x) => x); + +================================================================================ +`; + exports[`arrow.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -52,6 +105,29 @@ function f2() { ================================================================================ `; +exports[`bitwise-flags.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +const FLAG_A = 1 << 0; +const FLAG_B = 1 << 1; +const FLAG_C = 1 << 2; + +const all = FLAG_A | FLAG_B | FLAG_C; + +=====================================output===================================== +const FLAG_A = 1 << 0; +const FLAG_B = 1 << 1; +const FLAG_C = 1 << 2; + +const all = FLAG_A | FLAG_B | FLAG_C; + +================================================================================ +`; + exports[`bitwise-flags.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -74,6 +150,137 @@ const all = FLAG_A | FLAG_B | FLAG_C; ================================================================================ `; +exports[`call.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +( + aaaaaaaaaaaaaaaaaaaaaaaaa && + bbbbbbbbbbbbbbbbbbbbbbbbb && + ccccccccccccccccccccccccc && + ddddddddddddddddddddddddd && + eeeeeeeeeeeeeeeeeeeeeeeee +)(); + +( + aa && + bb && + cc && + dd && + ee +)(); + +( + aaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbb + + ccccccccccccccccccccccccc + + ddddddddddddddddddddddddd + + eeeeeeeeeeeeeeeeeeeeeeeee +)(); + +( + aa + + bb + + cc + + dd + + ee +)(); + +( + aaaaaaaaaaaaaaaaaaaaaaaaa && + bbbbbbbbbbbbbbbbbbbbbbbbb && + ccccccccccccccccccccccccc && + ddddddddddddddddddddddddd && + eeeeeeeeeeeeeeeeeeeeeeeee +)()()(); + +( + aaaaaaaaaaaaaaaaaaaaaaaaa && + bbbbbbbbbbbbbbbbbbbbbbbbb && + ccccccccccccccccccccccccc && + ddddddddddddddddddddddddd && + eeeeeeeeeeeeeeeeeeeeeeeee +)( + aaaaaaaaaaaaaaaaaaaaaaaaa && + bbbbbbbbbbbbbbbbbbbbbbbbb && + ccccccccccccccccccccccccc && + ddddddddddddddddddddddddd && + eeeeeeeeeeeeeeeeeeeeeeeee +)( + aaaaaaaaaaaaaaaaaaaaaaaaa && + bbbbbbbbbbbbbbbbbbbbbbbbb && + ccccccccccccccccccccccccc && + ddddddddddddddddddddddddd && + eeeeeeeeeeeeeeeeeeeeeeeee +)( + aaaaaaaaaaaaaaaaaaaaaaaaa && + bbbbbbbbbbbbbbbbbbbbbbbbb && + ccccccccccccccccccccccccc && + ddddddddddddddddddddddddd && + eeeeeeeeeeeeeeeeeeeeeeeee +); + +=====================================output===================================== +( + aaaaaaaaaaaaaaaaaaaaaaaaa + && bbbbbbbbbbbbbbbbbbbbbbbbb + && ccccccccccccccccccccccccc + && ddddddddddddddddddddddddd + && eeeeeeeeeeeeeeeeeeeeeeeee +)(); + +(aa && bb && cc && dd && ee)(); + +( + aaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbb + + ccccccccccccccccccccccccc + + ddddddddddddddddddddddddd + + eeeeeeeeeeeeeeeeeeeeeeeee +)(); + +(aa + bb + cc + dd + ee)(); + +( + aaaaaaaaaaaaaaaaaaaaaaaaa + && bbbbbbbbbbbbbbbbbbbbbbbbb + && ccccccccccccccccccccccccc + && ddddddddddddddddddddddddd + && eeeeeeeeeeeeeeeeeeeeeeeee +)()()(); + +( + aaaaaaaaaaaaaaaaaaaaaaaaa + && bbbbbbbbbbbbbbbbbbbbbbbbb + && ccccccccccccccccccccccccc + && ddddddddddddddddddddddddd + && eeeeeeeeeeeeeeeeeeeeeeeee +)( + aaaaaaaaaaaaaaaaaaaaaaaaa + && bbbbbbbbbbbbbbbbbbbbbbbbb + && ccccccccccccccccccccccccc + && ddddddddddddddddddddddddd + && eeeeeeeeeeeeeeeeeeeeeeeee, +)( + aaaaaaaaaaaaaaaaaaaaaaaaa + && bbbbbbbbbbbbbbbbbbbbbbbbb + && ccccccccccccccccccccccccc + && ddddddddddddddddddddddddd + && eeeeeeeeeeeeeeeeeeeeeeeee, +)( + aaaaaaaaaaaaaaaaaaaaaaaaa + && bbbbbbbbbbbbbbbbbbbbbbbbb + && ccccccccccccccccccccccccc + && ddddddddddddddddddddddddd + && eeeeeeeeeeeeeeeeeeeeeeeee, +); + +================================================================================ +`; + exports[`call.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -204,6 +411,152 @@ printWidth: 80 ================================================================================ `; +exports[`comment.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +a = ( + // Comment 1 + (Math.random() * (yRange * (1 - minVerticalFraction))) + + (minVerticalFraction * yRange) +) - offset; + +a + + a + + a + // comment + a + + a; + +a && + longLongLongLongLongLongLongLongLong && + longLongLongLongLongLongLongLongLong && // comment + longLongLongLongLongLongLongLongLong && + longLongLongLongLongLongLongLongLong + +a || + longLongLongLongLongLongLongLongLong || + longLongLongLongLongLongLongLongLong || // comment + longLongLongLongLongLongLongLongLong || + longLongLongLongLongLongLongLongLong + +var a = x(abifornCringerMoshedPerplexSawder ++ kochabCooieGameOnOboleUnweave // f ++ glimseGlyphsHazardNoopsTieTie+bifornCringerMoshedPerplexSawder); + +foo[ + a + + a + // comment + a + + bar[ + b + + b + + b + // comment + b + + b + ] +]; + +!( + a + + a + // comment + a + + !( + b + + b + + b + // comment + b + + b + ) +); + +const logical_expression = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /* trailing comment */ && + /* leading comment */ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb && + // line comment + cccccccccccccccccccccccc; + +const bc = a /* internal before */ || /* internal after */ b; + +a + + /**/ + a.a().a(); + +=====================================output===================================== +a = + // Comment 1 + Math.random() * (yRange * (1 - minVerticalFraction)) + + minVerticalFraction * yRange + - offset; + +a + + a + + a // comment + + a + + a; + +a + && longLongLongLongLongLongLongLongLong + && longLongLongLongLongLongLongLongLong // comment + && longLongLongLongLongLongLongLongLong + && longLongLongLongLongLongLongLongLong; + +a + || longLongLongLongLongLongLongLongLong + || longLongLongLongLongLongLongLongLong // comment + || longLongLongLongLongLongLongLongLong + || longLongLongLongLongLongLongLongLong; + +var a = x( + abifornCringerMoshedPerplexSawder + + kochabCooieGameOnOboleUnweave // f + + glimseGlyphsHazardNoopsTieTie + + bifornCringerMoshedPerplexSawder, +); + +foo[ + a + + a // comment + + a + + bar[ + b + + b + + b // comment + + b + + b + ] +]; + +!( + a + + a // comment + + a + + !( + b + + b + + b // comment + + b + + b + ) +); + +const logical_expression = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /* trailing comment */ + && /* leading comment */ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + // line comment + && cccccccccccccccccccccccc; + +const bc = a /* internal before */ || /* internal after */ b; + +a + /**/ + + a.a().a(); + +================================================================================ +`; + exports[`comment.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -264,6 +617,18 @@ foo[ ) ); +const logical_expression = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /* trailing comment */ && + /* leading comment */ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb && + // line comment + cccccccccccccccccccccccc; + +const bc = a /* internal before */ || /* internal after */ b; + +a + + /**/ + a.a().a(); + =====================================output===================================== a = // Comment 1 @@ -322,6 +687,49 @@ foo[ ) ); +const logical_expression = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /* trailing comment */ && + /* leading comment */ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb && + // line comment + cccccccccccccccccccccccc; + +const bc = a /* internal before */ || /* internal after */ b; + +a + + /**/ + a.a().a(); + +================================================================================ +`; + +exports[`equality.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +x == y == z; +x != y == z; +x == y != z; +x != y != z; + +x === y === z; +x !== y === z; +x === y !== z; +x !== y !== z; + +=====================================output===================================== +(x == y) == z; +(x != y) == z; +(x == y) != z; +(x != y) != z; + +(x === y) === z; +(x !== y) === z; +(x === y) !== z; +(x !== y) !== z; + ================================================================================ `; @@ -355,6 +763,37 @@ x !== y !== z; ================================================================================ `; +exports[`exp.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +a ** b ** c; +(a ** b) ** c; +a.b ** c; +(-a) ** b; +a ** -b; +-(a**b); +(a * b) ** c; +a ** (b * c); +(a % b) ** c; + +=====================================output===================================== +a ** (b ** c); +(a ** b) ** c; +a.b ** c; +(-a) ** b; +a ** -b; +-(a ** b); +(a * b) ** c; +a ** (b * c); +(a % b) ** c; + +================================================================================ +`; + exports[`exp.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -385,6 +824,46 @@ a ** (b * c); ================================================================================ `; +exports[`if.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +if (this.hasPlugin("dynamicImports") && this.lookahead().type) {} + +if (this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft) {} + +if (this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right) {} + +if (VeryVeryVeryVeryVeryVeryVeryVeryLong === VeryVeryVeryVeryVeryVeryVeryVeryLong) { +} + +=====================================output===================================== +if (this.hasPlugin("dynamicImports") && this.lookahead().type) { +} + +if ( + this.hasPlugin("dynamicImports") + && this.lookahead().type === tt.parenLeft +) { +} + +if ( + this.hasPlugin("dynamicImports") + && this.lookahead().type === tt.parenLeft.right +) { +} + +if ( + VeryVeryVeryVeryVeryVeryVeryVeryLong === VeryVeryVeryVeryVeryVeryVeryVeryLong +) { +} + +================================================================================ +`; + exports[`if.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -424,6 +903,165 @@ if ( ================================================================================ `; +exports[`in_instanceof.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +!foo in bar; +(!foo in bar); +!(foo in bar); +(!foo) in bar; + +!foo instanceof Bar; +(!foo instanceof Bar); +!(foo instanceof Bar); +(!foo) instanceof Bar; + +~foo in bar; +(~foo in bar); +~(foo in bar); +(~foo) in bar; + +~foo instanceof Bar; +(~foo instanceof Bar); +~(foo instanceof Bar); +(~foo) instanceof Bar; + ++foo in bar; +(+foo in bar); ++(foo in bar); +(+foo) in bar; + ++foo instanceof Bar; +(+foo instanceof Bar); ++(foo instanceof Bar); +(+foo) instanceof Bar; + +-foo in bar; +(-foo in bar); +-(foo in bar); +(-foo) in bar; + +-foo instanceof Bar; +(-foo instanceof Bar); +-(foo instanceof Bar); +(-foo) instanceof Bar; + +void 0 in bar; +(void 0 in bar); +void (0 in bar); +(void 0) in bar; + +void 0 instanceof bar; +(void 0 instanceof bar); +void (0 instanceof bar); +(void 0) instanceof bar; + +delete 0 in bar; +(delete 0 in bar); +delete (0 in bar); +(delete 0) in bar; + +delete 0 instanceof bar; +(delete 0 instanceof bar); +delete (0 instanceof bar); +(delete 0) instanceof bar; + +typeof 0 in bar; +(typeof 0 in bar); +typeof (0 in bar); +(typeof 0) in bar; + +typeof 0 instanceof bar; +(typeof 0 instanceof bar); +typeof (0 instanceof bar); +(typeof 0) instanceof bar; + +++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid + +!!foo instanceof Bar; + +=====================================output===================================== +(!foo) in bar; +(!foo) in bar; +!(foo in bar); +(!foo) in bar; + +(!foo) instanceof Bar; +(!foo) instanceof Bar; +!(foo instanceof Bar); +(!foo) instanceof Bar; + +(~foo) in bar; +(~foo) in bar; +~(foo in bar); +(~foo) in bar; + +(~foo) instanceof Bar; +(~foo) instanceof Bar; +~(foo instanceof Bar); +(~foo) instanceof Bar; + +(+foo) in bar; +(+foo) in bar; ++(foo in bar); +(+foo) in bar; + +(+foo) instanceof Bar; +(+foo) instanceof Bar; ++(foo instanceof Bar); +(+foo) instanceof Bar; + +(-foo) in bar; +(-foo) in bar; +-(foo in bar); +(-foo) in bar; + +(-foo) instanceof Bar; +(-foo) instanceof Bar; +-(foo instanceof Bar); +(-foo) instanceof Bar; + +(void 0) in bar; +(void 0) in bar; +void (0 in bar); +(void 0) in bar; + +(void 0) instanceof bar; +(void 0) instanceof bar; +void (0 instanceof bar); +(void 0) instanceof bar; + +(delete 0) in bar; +(delete 0) in bar; +delete (0 in bar); +(delete 0) in bar; + +(delete 0) instanceof bar; +(delete 0) instanceof bar; +delete (0 instanceof bar); +(delete 0) instanceof bar; + +(typeof 0) in bar; +(typeof 0) in bar; +typeof (0 in bar); +(typeof 0) in bar; + +(typeof 0) instanceof bar; +(typeof 0) instanceof bar; +typeof (0 instanceof bar); +(typeof 0) instanceof bar; + +++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid + +(!!foo) instanceof Bar; + +================================================================================ +`; + exports[`in_instanceof.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -582,6 +1220,45 @@ typeof (0 instanceof bar); ================================================================================ `; +exports[`inline-jsx.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +const user = renderedUser ||
; + +const user2 = renderedUser || shouldRenderUser &&
; + +const avatar = hasAvatar && ; + +const avatar2 = (hasAvatar || showPlaceholder) && ; + +=====================================output===================================== +const user = renderedUser || ( +
+ +
+); + +const user2 = + renderedUser + || (shouldRenderUser && ( +
+ +
+ )); + +const avatar = hasAvatar && ; + +const avatar2 = (hasAvatar || showPlaceholder) && ( + +); + +================================================================================ +`; + exports[`inline-jsx.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -620,6 +1297,201 @@ const avatar2 = (hasAvatar || showPlaceholder) && ( ================================================================================ `; +exports[`inline-object-array.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +prevState = prevState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: '', + selectedCatalog: null, +}; + +prevState = prevState || + defaultState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: '', + selectedCatalog: null, + }; + +prevState = prevState || + defaultState && { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: '', + selectedCatalog: null, + }; + +prevState = prevState || useDefault && defaultState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: '', + selectedCatalog: null, + }; + +this.steps = steps || [ + { + name: 'mock-module', + path: '/nux/mock-module', + }, +]; + +this.steps = steps || checkStep && [ + { + name: 'mock-module', + path: '/nux/mock-module', + }, +]; + +this.steps = steps && checkStep || [ + { + name: 'mock-module', + path: '/nux/mock-module', + }, +]; + +const create = () => { + const result = doSomething(); + return ( + shouldReturn && + result.ok && { + status: "ok", + createdAt: result.createdAt, + updatedAt: result.updatedAt + } + ); +} + +const create2 = () => { + const result = doSomething(); + return ( + shouldReturn && result.ok && result || { + status: "ok", + createdAt: result.createdAt, + updatedAt: result.updatedAt + } + ); +} + +const obj = { + state: shouldHaveState && + stateIsOK && { + loadState: LOADED, + opened: false + }, + loadNext: stateIsOK && hasNext || { + skipNext: true + }, + loaded: true +} + +=====================================output===================================== +prevState = prevState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: "", + selectedCatalog: null, +}; + +prevState = prevState + || defaultState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: "", + selectedCatalog: null, + }; + +prevState = + prevState + || (defaultState && { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: "", + selectedCatalog: null, + }); + +prevState = prevState + || (useDefault && defaultState) || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: "", + selectedCatalog: null, + }; + +this.steps = steps || [ + { + name: "mock-module", + path: "/nux/mock-module", + }, +]; + +this.steps = + steps + || (checkStep && [ + { + name: "mock-module", + path: "/nux/mock-module", + }, + ]); + +this.steps = (steps && checkStep) || [ + { + name: "mock-module", + path: "/nux/mock-module", + }, +]; + +const create = () => { + const result = doSomething(); + return ( + shouldReturn + && result.ok && { + status: "ok", + createdAt: result.createdAt, + updatedAt: result.updatedAt, + } + ); +}; + +const create2 = () => { + const result = doSomething(); + return ( + (shouldReturn && result.ok && result) || { + status: "ok", + createdAt: result.createdAt, + updatedAt: result.updatedAt, + } + ); +}; + +const obj = { + state: shouldHaveState + && stateIsOK && { + loadState: LOADED, + opened: false, + }, + loadNext: (stateIsOK && hasNext) || { + skipNext: true, + }, + loaded: true, +}; + +================================================================================ +`; + exports[`inline-object-array.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -814,6 +1686,91 @@ const obj = { ================================================================================ `; +exports[`jsx_parent.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +
; + +
+ {!isJellyfishEnabled && + diffUpdateMessageInput != null && + this.state.isUpdateMessageEmpty} +
; + +
; + +
+ {!isJellyfishEnabled && + diffUpdateMessageInput != null &&
Text
} +
; + +
+ {!isJellyfishEnabled && + diffUpdateMessageInput != null && child ||
Text
} +
; + +=====================================output===================================== +
; + +
+ {!isJellyfishEnabled + && diffUpdateMessageInput != null + && this.state.isUpdateMessageEmpty} +
; + +
; + +
+ {!isJellyfishEnabled && diffUpdateMessageInput != null && ( +
+ Text +
+ )} +
; + +
+ {(!isJellyfishEnabled && diffUpdateMessageInput != null && child) || ( +
+ Text +
+ )} +
; + +================================================================================ +`; + exports[`jsx_parent.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -898,6 +1855,21 @@ printWidth: 80 ================================================================================ `; +exports[`like-regexp.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +0 ? a : { b : 1 }/2; + +=====================================output===================================== +0 ? a : { b: 1 } / 2; + +================================================================================ +`; + exports[`like-regexp.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -912,6 +1884,63 @@ printWidth: 80 ================================================================================ `; +exports[`math.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +x + y / z; +x / y + z; + +x * y % z; +x / y % z; +x % y * z; +x % y / z; + +x % y % z; + +x << y >> z; +x >>> y << z; +x >>> y >>> z; +x + y >> z; + +x | y & z; +x & y | z; +x ^ y ^ z; +x & y & z; +x | y | z; +x & y >> z; +x << y | z; + +=====================================output===================================== +x + y / z; +x / y + z; + +(x * y) % z; +(x / y) % z; +(x % y) * z; +(x % y) / z; + +(x % y) % z; + +(x << y) >> z; +(x >>> y) << z; +(x >>> y) >>> z; +(x + y) >> z; + +x | (y & z); +(x & y) | z; +x ^ y ^ z; +x & y & z; +x | y | z; +x & (y >> z); +(x << y) | z; + +================================================================================ +`; + exports[`math.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -968,6 +1997,54 @@ x & (y >> z); ================================================================================ `; +exports[`return.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +function foo() { + return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right; +} + +function foo2() { + return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right + ? true + : false; +} + +function foo3() { + return this.calculate().compute().first.numberOfThings > this.calculate().compute().last.numberOfThings + ? true + : false; +} + +=====================================output===================================== +function foo() { + return ( + this.hasPlugin("dynamicImports") + && this.lookahead().type === tt.parenLeft.right + ); +} + +function foo2() { + return this.hasPlugin("dynamicImports") + && this.lookahead().type === tt.parenLeft.right + ? true + : false; +} + +function foo3() { + return this.calculate().compute().first.numberOfThings + > this.calculate().compute().last.numberOfThings + ? true + : false; +} + +================================================================================ +`; + exports[`return.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1015,6 +2092,53 @@ function foo3() { ================================================================================ `; +exports[`short-right.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +this._cumulativeHeights && + Math.abs( + this._cachedItemHeight(this._firstVisibleIndex + i) - + this._provider.fastHeight(i + this._firstVisibleIndex), + ) > + 1 + +foooooooooooooooooooooooooooooooooooooooooooooooooooooooooo( + aaaaaaaaaaaaaaaaaaa +) + + a; + +const isPartOfPackageJSON = dependenciesArray.indexOf( + dependencyWithOutRelativePath.split('/')[0], +) !== -1; + +defaultContent.filter(defaultLocale => { + // ... +})[0] || null; + +=====================================output===================================== +this._cumulativeHeights + && Math.abs( + this._cachedItemHeight(this._firstVisibleIndex + i) + - this._provider.fastHeight(i + this._firstVisibleIndex), + ) > 1; + +foooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(aaaaaaaaaaaaaaaaaaa) + + a; + +const isPartOfPackageJSON = + dependenciesArray.indexOf(dependencyWithOutRelativePath.split("/")[0]) !== -1; + +defaultContent.filter((defaultLocale) => { + // ... +})[0] || null; + +================================================================================ +`; + exports[`short-right.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1062,6 +2186,96 @@ defaultContent.filter((defaultLocale) => { ================================================================================ `; +exports[`test.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +// It should always break the highest precedence operators first, and +// break them all at the same time. + +const x = longVariable + longVariable + longVariable; +const x1 = longVariable + longVariable + longVariable + longVariable - longVariable + longVariable; +const x2 = longVariable + longVariable * longVariable + longVariable - longVariable + longVariable; +const x3 = longVariable + longVariable * longVariable * longVariable / longVariable + longVariable; + +const x4 = longVariable && longVariable && longVariable && longVariable && longVariable && longVariable; +const x5 = longVariable && longVariable || longVariable && longVariable || longVariable && longVariable; +const x6 = firstItemWithAVeryLongNameThatKeepsGoing || firstItemWithAVeryLongNameThatKeepsGoing || {}; +const x7 = firstItemWithAVeryLongNameThatKeepsGoing || firstItemWithAVeryLongNameThatKeepsGoing || []; +const x8 = call(firstItemWithAVeryLongNameThatKeepsGoing, firstItemWithAVeryLongNameThatKeepsGoing) || []; + +const x9 = longVariable * longint && longVariable >> 0 && longVariable + longVariable; + +const x10 = longVariable > longint && longVariable === 0 + longVariable * longVariable; + +foo(obj.property * new Class() && obj instanceof Class && longVariable ? number + 5 : false); + +=====================================output===================================== +// It should always break the highest precedence operators first, and +// break them all at the same time. + +const x = longVariable + longVariable + longVariable; +const x1 = + longVariable + + longVariable + + longVariable + + longVariable + - longVariable + + longVariable; +const x2 = + longVariable + + longVariable * longVariable + + longVariable + - longVariable + + longVariable; +const x3 = + longVariable + + (longVariable * longVariable * longVariable) / longVariable + + longVariable; + +const x4 = + longVariable + && longVariable + && longVariable + && longVariable + && longVariable + && longVariable; +const x5 = + (longVariable && longVariable) + || (longVariable && longVariable) + || (longVariable && longVariable); +const x6 = + firstItemWithAVeryLongNameThatKeepsGoing + || firstItemWithAVeryLongNameThatKeepsGoing + || {}; +const x7 = + firstItemWithAVeryLongNameThatKeepsGoing + || firstItemWithAVeryLongNameThatKeepsGoing + || []; +const x8 = + call( + firstItemWithAVeryLongNameThatKeepsGoing, + firstItemWithAVeryLongNameThatKeepsGoing, + ) || []; + +const x9 = + longVariable * longint && longVariable >> 0 && longVariable + longVariable; + +const x10 = + longVariable > longint && longVariable === 0 + longVariable * longVariable; + +foo( + obj.property * new Class() && obj instanceof Class && longVariable + ? number + 5 + : false, +); + +================================================================================ +`; + exports[`test.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1210,6 +2424,116 @@ exports[`tuple-and-record.js [typescript] format 1`] = ` Cause: Invalid character." `; +exports[`tuple-and-record.js - {"experimentalOperatorPosition":"start"} [acorn] format 1`] = ` +"Unexpected character '[' (6:15) + 4 | ] + 5 | +> 6 | foo = foo || #[ + | ^ + 7 | // comment + 8 | a, + 9 | ] +Cause: Unexpected character '[' (6:14)" +`; + +exports[`tuple-and-record.js - {"experimentalOperatorPosition":"start"} [espree] format 1`] = ` +"Unexpected character '[' (6:15) + 4 | ] + 5 | +> 6 | foo = foo || #[ + | ^ + 7 | // comment + 8 | a, + 9 | ] +Cause: Unexpected character '['" +`; + +exports[`tuple-and-record.js - {"experimentalOperatorPosition":"start"} [flow] format 1`] = ` +"Unexpected token \`#\`, expected an identifier (6:14) + 4 | ] + 5 | +> 6 | foo = foo || #[ + | ^ + 7 | // comment + 8 | a, + 9 | ]" +`; + +exports[`tuple-and-record.js - {"experimentalOperatorPosition":"start"} [meriyah] format 1`] = ` +"'#' not followed by identifier (6:14) + 4 | ] + 5 | +> 6 | foo = foo || #[ + | ^ + 7 | // comment + 8 | a, + 9 | ] +Cause: [6:13-6:14]: '#' not followed by identifier" +`; + +exports[`tuple-and-record.js - {"experimentalOperatorPosition":"start"} [typescript] format 1`] = ` +"Invalid character. (6:14) + 4 | ] + 5 | +> 6 | foo = foo || #[ + | ^ + 7 | // comment + 8 | a, + 9 | ] +Cause: Invalid character." +`; + +exports[`tuple-and-record.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +foo = foo || [ + // comment + a, +] + +foo = foo || #[ + // comment + a, +] + +foo = foo || { + // comment + a, +} + +foo = foo || #{ + // comment + a, +} + +=====================================output===================================== +foo = foo || [ + // comment + a, +]; + +foo = foo || #[ + // comment + a, +]; + +foo = foo || { + // comment + a, +}; + +foo = foo || #{ + // comment + a, +}; + +================================================================================ +`; + exports[`tuple-and-record.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1260,6 +2584,27 @@ foo = foo || #{ ================================================================================ `; +exports[`unary.js - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +const anyTestFailures = !( + aggregatedResults.numFailedTests === 0 && + aggregatedResults.numRuntimeErrorTestSuites === 0 +); + +=====================================output===================================== +const anyTestFailures = !( + aggregatedResults.numFailedTests === 0 + && aggregatedResults.numRuntimeErrorTestSuites === 0 +); + +================================================================================ +`; + exports[`unary.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] diff --git a/tests/format/js/binary-expressions/comment.js b/tests/format/js/binary-expressions/comment.js index b8d21dd0c..8845d29d7 100644 --- a/tests/format/js/binary-expressions/comment.js +++ b/tests/format/js/binary-expressions/comment.js @@ -51,3 +51,15 @@ foo[ b ) ); + +const logical_expression = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /* trailing comment */ && + /* leading comment */ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb && + // line comment + cccccccccccccccccccccccc; + +const bc = a /* internal before */ || /* internal after */ b; + +a + + /**/ + a.a().a(); diff --git a/tests/format/js/binary-expressions/format.test.js b/tests/format/js/binary-expressions/format.test.js index 1086afd5f..64e74116f 100644 --- a/tests/format/js/binary-expressions/format.test.js +++ b/tests/format/js/binary-expressions/format.test.js @@ -7,3 +7,7 @@ const errors = { }; runFormatTest(import.meta, ["babel", "flow", "typescript"], { errors }); +runFormatTest(import.meta, ["babel", "flow", "typescript"], { + errors, + experimentalOperatorPosition: "start", +}); diff --git a/tests/format/typescript/intersection/__snapshots__/format.test.js.snap b/tests/format/typescript/intersection/__snapshots__/format.test.js.snap index 5aa71b049..ece35baef 100644 --- a/tests/format/typescript/intersection/__snapshots__/format.test.js.snap +++ b/tests/format/typescript/intersection/__snapshots__/format.test.js.snap @@ -1,5 +1,698 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`intersection-parens.ts - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== + +export type A = ( + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type B = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type C = + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type D = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type Multi = (string & number)[]; + +function f(): (string & number) {} + +var x: (string & number); +var y: ((string & number)); + +class Foo {} + +interface Interface { + i: (X & Y) | Z; + j: Partial<(X & Y)>; +} + +type State = { + sharedProperty: any; +} & ( + & { discriminant: "FOO"; foo: any } + & { discriminant: "BAR"; bar: any } + & { discriminant: "BAZ"; baz: any } +); + +const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as ( + & string + & undefined +)[]; + +const foo2: ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +)[] = []; + +const foo3: keyof ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +) = bar; + +const foo4: + & foo + & ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD + ) = bar; + +let a1 : C; +let a2 : & C; +let a3 : (& C); +let a4 : & (C); +let a5 : (& (C)); +let a6 : /*1*/ & C; +let a7 : /*1*/ & (C); +let a8 : /*1*/ (& C); +let a9 : (/*1*/ & C); +let a10: /*1*/ & /*2*/ C; +let a11: /*1*/ (& /*2*/ C); + +let aa1: /*1*/ & /*2*/ C & D; +let aa2: /*1*/ & /*2*/ C & /*3*/ D; +let aa3: /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type A1 = C; +type A2 = & C; +type A3 = (& C); +type A4 = & (C); +type A5 = (& (C)); +type A6 = /*1*/ & C; +type A7 = /*1*/ & (C); +type A8 = /*1*/ (& C); +type A9 = (/*1*/ & C); +type A10 = /*1*/ & /*2*/ C; +type A11 = /*1*/ (& /*2*/ C); +type A12 = /*1*/ & ( (C)); +type A13 = /*1*/ ( (C)); + +type Aa1 = /*1*/ & /*2*/ C & D; +type Aa2 = /*1*/ & /*2*/ C & /*3*/ D; +type Aa3 = /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type C1 = /*1*/ | a & b; +type C2 = /*1*/ | a & (b); +type C3 = /*1*/ | a & (| b); +type C4 = /*1*/ | (a & b); +type C5 = /*1*/ (| a & b); +type C6 /*0*/ = /*1*/ (| a & b); + +type Ctor = (new () => X) & Y; + +=====================================output===================================== +export type A = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type B = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type C = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type D = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type Multi = (string & number)[]; + +function f(): string & number {} + +var x: string & number; +var y: string & number; + +class Foo {} + +interface Interface { + i: (X & Y) | Z; + j: Partial; +} + +type State = { + sharedProperty: any; +} & ({ discriminant: "FOO"; foo: any } & { discriminant: "BAR"; bar: any } & { + discriminant: "BAZ"; + baz: any; +}); + +const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (string + & undefined)[]; + +const foo2: (AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD)[] = []; + +const foo3: keyof (AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD) = bar; + +const foo4: foo + & (AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD) = bar; + +let a1: C; +let a2: C; +let a3: C; +let a4: C; +let a5: C; +let a6: /*1*/ C; +let a7: /*1*/ C; +let a8: /*1*/ C; +let a9: /*1*/ C; +let a10: /*1*/ /*2*/ C; +let a11: /*1*/ /*2*/ C; + +let aa1: /*1*/ /*2*/ C & D; +let aa2: /*1*/ /*2*/ C & /*3*/ D; +let aa3: /*1*/ /*2*/ C & /*3*/ D /*4*/; + +type A1 = C; +type A2 = C; +type A3 = C; +type A4 = C; +type A5 = C; +type A6 /*1*/ = C; +type A7 /*1*/ = C; +type A8 /*1*/ = C; +type A9 /*1*/ = C; +type A10 /*1*/ = /*2*/ C; +type A11 /*1*/ = /*2*/ C; +type A12 /*1*/ = C; +type A13 = /*1*/ C; + +type Aa1 = /*1*/ /*2*/ C & D; +type Aa2 = /*1*/ /*2*/ C & /*3*/ D; +type Aa3 = /*1*/ /*2*/ C & /*3*/ D /*4*/; + +type C1 /*1*/ = a & b; +type C2 /*1*/ = a & b; +type C3 /*1*/ = a & b; +type C4 /*1*/ = a & b; +type C5 /*1*/ = a & b; +type C6 /*0*/ /*1*/ = a & b; + +type Ctor = (new () => X) & Y; + +================================================================================ +`; + +exports[`intersection-parens.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== + +export type A = ( + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type B = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type C = + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type D = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type Multi = (string & number)[]; + +function f(): (string & number) {} + +var x: (string & number); +var y: ((string & number)); + +class Foo {} + +interface Interface { + i: (X & Y) | Z; + j: Partial<(X & Y)>; +} + +type State = { + sharedProperty: any; +} & ( + & { discriminant: "FOO"; foo: any } + & { discriminant: "BAR"; bar: any } + & { discriminant: "BAZ"; baz: any } +); + +const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as ( + & string + & undefined +)[]; + +const foo2: ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +)[] = []; + +const foo3: keyof ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +) = bar; + +const foo4: + & foo + & ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD + ) = bar; + +let a1 : C; +let a2 : & C; +let a3 : (& C); +let a4 : & (C); +let a5 : (& (C)); +let a6 : /*1*/ & C; +let a7 : /*1*/ & (C); +let a8 : /*1*/ (& C); +let a9 : (/*1*/ & C); +let a10: /*1*/ & /*2*/ C; +let a11: /*1*/ (& /*2*/ C); + +let aa1: /*1*/ & /*2*/ C & D; +let aa2: /*1*/ & /*2*/ C & /*3*/ D; +let aa3: /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type A1 = C; +type A2 = & C; +type A3 = (& C); +type A4 = & (C); +type A5 = (& (C)); +type A6 = /*1*/ & C; +type A7 = /*1*/ & (C); +type A8 = /*1*/ (& C); +type A9 = (/*1*/ & C); +type A10 = /*1*/ & /*2*/ C; +type A11 = /*1*/ (& /*2*/ C); +type A12 = /*1*/ & ( (C)); +type A13 = /*1*/ ( (C)); + +type Aa1 = /*1*/ & /*2*/ C & D; +type Aa2 = /*1*/ & /*2*/ C & /*3*/ D; +type Aa3 = /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type C1 = /*1*/ | a & b; +type C2 = /*1*/ | a & (b); +type C3 = /*1*/ | a & (| b); +type C4 = /*1*/ | (a & b); +type C5 = /*1*/ (| a & b); +type C6 /*0*/ = /*1*/ (| a & b); + +type Ctor = (new () => X) & Y; + +=====================================output===================================== +export type A = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +export type B = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +export type C = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +export type D = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +export type Multi = (string & number)[] + +function f(): string & number {} + +var x: string & number +var y: string & number + +class Foo {} + +interface Interface { + i: (X & Y) | Z + j: Partial +} + +type State = { + sharedProperty: any +} & ({ discriminant: "FOO"; foo: any } & { discriminant: "BAR"; bar: any } & { + discriminant: "BAZ" + baz: any +}) + +const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (string & + undefined)[] + +const foo2: (AAAAAAAAAAAAAAAAAAAAAA & + BBBBBBBBBBBBBBBBBBBBBB & + CCCCCCCCCCCCCCCCCCCCCC & + DDDDDDDDDDDDDDDDDDDDDD)[] = [] + +const foo3: keyof (AAAAAAAAAAAAAAAAAAAAAA & + BBBBBBBBBBBBBBBBBBBBBB & + CCCCCCCCCCCCCCCCCCCCCC & + DDDDDDDDDDDDDDDDDDDDDD) = bar + +const foo4: foo & + (AAAAAAAAAAAAAAAAAAAAAA & + BBBBBBBBBBBBBBBBBBBBBB & + CCCCCCCCCCCCCCCCCCCCCC & + DDDDDDDDDDDDDDDDDDDDDD) = bar + +let a1: C +let a2: C +let a3: C +let a4: C +let a5: C +let a6: /*1*/ C +let a7: /*1*/ C +let a8: /*1*/ C +let a9: /*1*/ C +let a10: /*1*/ /*2*/ C +let a11: /*1*/ /*2*/ C + +let aa1: /*1*/ /*2*/ C & D +let aa2: /*1*/ /*2*/ C & /*3*/ D +let aa3: /*1*/ /*2*/ C & /*3*/ D /*4*/ + +type A1 = C +type A2 = C +type A3 = C +type A4 = C +type A5 = C +type A6 /*1*/ = C +type A7 /*1*/ = C +type A8 /*1*/ = C +type A9 /*1*/ = C +type A10 /*1*/ = /*2*/ C +type A11 /*1*/ = /*2*/ C +type A12 /*1*/ = C +type A13 = /*1*/ C + +type Aa1 = /*1*/ /*2*/ C & D +type Aa2 = /*1*/ /*2*/ C & /*3*/ D +type Aa3 = /*1*/ /*2*/ C & /*3*/ D /*4*/ + +type C1 /*1*/ = a & b +type C2 /*1*/ = a & b +type C3 /*1*/ = a & b +type C4 /*1*/ = a & b +type C5 /*1*/ = a & b +type C6 /*0*/ /*1*/ = a & b + +type Ctor = (new () => X) & Y + +================================================================================ +`; + +exports[`intersection-parens.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== + +export type A = ( + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type B = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type C = + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type D = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type Multi = (string & number)[]; + +function f(): (string & number) {} + +var x: (string & number); +var y: ((string & number)); + +class Foo {} + +interface Interface { + i: (X & Y) | Z; + j: Partial<(X & Y)>; +} + +type State = { + sharedProperty: any; +} & ( + & { discriminant: "FOO"; foo: any } + & { discriminant: "BAR"; bar: any } + & { discriminant: "BAZ"; baz: any } +); + +const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as ( + & string + & undefined +)[]; + +const foo2: ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +)[] = []; + +const foo3: keyof ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +) = bar; + +const foo4: + & foo + & ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD + ) = bar; + +let a1 : C; +let a2 : & C; +let a3 : (& C); +let a4 : & (C); +let a5 : (& (C)); +let a6 : /*1*/ & C; +let a7 : /*1*/ & (C); +let a8 : /*1*/ (& C); +let a9 : (/*1*/ & C); +let a10: /*1*/ & /*2*/ C; +let a11: /*1*/ (& /*2*/ C); + +let aa1: /*1*/ & /*2*/ C & D; +let aa2: /*1*/ & /*2*/ C & /*3*/ D; +let aa3: /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type A1 = C; +type A2 = & C; +type A3 = (& C); +type A4 = & (C); +type A5 = (& (C)); +type A6 = /*1*/ & C; +type A7 = /*1*/ & (C); +type A8 = /*1*/ (& C); +type A9 = (/*1*/ & C); +type A10 = /*1*/ & /*2*/ C; +type A11 = /*1*/ (& /*2*/ C); +type A12 = /*1*/ & ( (C)); +type A13 = /*1*/ ( (C)); + +type Aa1 = /*1*/ & /*2*/ C & D; +type Aa2 = /*1*/ & /*2*/ C & /*3*/ D; +type Aa3 = /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type C1 = /*1*/ | a & b; +type C2 = /*1*/ | a & (b); +type C3 = /*1*/ | a & (| b); +type C4 = /*1*/ | (a & b); +type C5 = /*1*/ (| a & b); +type C6 /*0*/ = /*1*/ (| a & b); + +type Ctor = (new () => X) & Y; + +=====================================output===================================== +export type A = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type B = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type C = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type D = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type Multi = (string & number)[]; + +function f(): string & number {} + +var x: string & number; +var y: string & number; + +class Foo {} + +interface Interface { + i: (X & Y) | Z; + j: Partial; +} + +type State = { + sharedProperty: any; +} & ({ discriminant: "FOO"; foo: any } & { discriminant: "BAR"; bar: any } & { + discriminant: "BAZ"; + baz: any; +}); + +const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (string & + undefined)[]; + +const foo2: (AAAAAAAAAAAAAAAAAAAAAA & + BBBBBBBBBBBBBBBBBBBBBB & + CCCCCCCCCCCCCCCCCCCCCC & + DDDDDDDDDDDDDDDDDDDDDD)[] = []; + +const foo3: keyof (AAAAAAAAAAAAAAAAAAAAAA & + BBBBBBBBBBBBBBBBBBBBBB & + CCCCCCCCCCCCCCCCCCCCCC & + DDDDDDDDDDDDDDDDDDDDDD) = bar; + +const foo4: foo & + (AAAAAAAAAAAAAAAAAAAAAA & + BBBBBBBBBBBBBBBBBBBBBB & + CCCCCCCCCCCCCCCCCCCCCC & + DDDDDDDDDDDDDDDDDDDDDD) = bar; + +let a1: C; +let a2: C; +let a3: C; +let a4: C; +let a5: C; +let a6: /*1*/ C; +let a7: /*1*/ C; +let a8: /*1*/ C; +let a9: /*1*/ C; +let a10: /*1*/ /*2*/ C; +let a11: /*1*/ /*2*/ C; + +let aa1: /*1*/ /*2*/ C & D; +let aa2: /*1*/ /*2*/ C & /*3*/ D; +let aa3: /*1*/ /*2*/ C & /*3*/ D /*4*/; + +type A1 = C; +type A2 = C; +type A3 = C; +type A4 = C; +type A5 = C; +type A6 /*1*/ = C; +type A7 /*1*/ = C; +type A8 /*1*/ = C; +type A9 /*1*/ = C; +type A10 /*1*/ = /*2*/ C; +type A11 /*1*/ = /*2*/ C; +type A12 /*1*/ = C; +type A13 = /*1*/ C; + +type Aa1 = /*1*/ /*2*/ C & D; +type Aa2 = /*1*/ /*2*/ C & /*3*/ D; +type Aa3 = /*1*/ /*2*/ C & /*3*/ D /*4*/; + +type C1 /*1*/ = a & b; +type C2 /*1*/ = a & b; +type C3 /*1*/ = a & b; +type C4 /*1*/ = a & b; +type C5 /*1*/ = a & b; +type C6 /*0*/ /*1*/ = a & b; + +type Ctor = (new () => X) & Y; + +================================================================================ +`; + +exports[`type-arguments.ts - {"experimentalOperatorPosition":"start"} format 1`] = ` +====================================options===================================== +experimentalOperatorPosition: "start" +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +// #6988 + +// functional component with ugly linebreak +export const MyLongNamedReactFunctionalComponent1: FunctionComponent = (props) => {} + +// functional component with valid linebreak +export const MyLongNamedReactFunctionalComponent2: FunctionComponent = (props) => {} + +// functional component with valid linebreak +export const MyLongNamedReactFunctionalComponent3: FunctionComponent = (props) => {} + +=====================================output===================================== +// #6988 + +// functional component with ugly linebreak +export const MyLongNamedReactFunctionalComponent1: FunctionComponent< + ALongNamedInterface1 & ALongNamedInterface2 +> = (props) => {}; + +// functional component with valid linebreak +export const MyLongNamedReactFunctionalComponent2: FunctionComponent< + ALongNamedInterface1 | ALongNamedInterface2 +> = (props) => {}; + +// functional component with valid linebreak +export const MyLongNamedReactFunctionalComponent3: FunctionComponent< + ALongNamedInterface1, + ALongNamedInterface2 +> = (props) => {}; + +================================================================================ +`; + exports[`type-arguments.ts - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["typescript"] diff --git a/tests/format/typescript/intersection/format.test.js b/tests/format/typescript/intersection/format.test.js index ca21c1085..5ee9f29fd 100644 --- a/tests/format/typescript/intersection/format.test.js +++ b/tests/format/typescript/intersection/format.test.js @@ -1,2 +1,5 @@ runFormatTest(import.meta, ["typescript"]); runFormatTest(import.meta, ["typescript"], { semi: false }); +runFormatTest(import.meta, ["typescript"], { + experimentalOperatorPosition: "start", +}); diff --git a/tests/format/typescript/intersection/intersection-parens.ts b/tests/format/typescript/intersection/intersection-parens.ts new file mode 100644 index 000000000..b7aa04603 --- /dev/null +++ b/tests/format/typescript/intersection/intersection-parens.ts @@ -0,0 +1,111 @@ + +export type A = ( + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type B = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); + +export type C = + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + & bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type D = + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; + +export type Multi = (string & number)[]; + +function f(): (string & number) {} + +var x: (string & number); +var y: ((string & number)); + +class Foo {} + +interface Interface { + i: (X & Y) | Z; + j: Partial<(X & Y)>; +} + +type State = { + sharedProperty: any; +} & ( + & { discriminant: "FOO"; foo: any } + & { discriminant: "BAR"; bar: any } + & { discriminant: "BAZ"; baz: any } +); + +const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as ( + & string + & undefined +)[]; + +const foo2: ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +)[] = []; + +const foo3: keyof ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD +) = bar; + +const foo4: + & foo + & ( + & AAAAAAAAAAAAAAAAAAAAAA + & BBBBBBBBBBBBBBBBBBBBBB + & CCCCCCCCCCCCCCCCCCCCCC + & DDDDDDDDDDDDDDDDDDDDDD + ) = bar; + +let a1 : C; +let a2 : & C; +let a3 : (& C); +let a4 : & (C); +let a5 : (& (C)); +let a6 : /*1*/ & C; +let a7 : /*1*/ & (C); +let a8 : /*1*/ (& C); +let a9 : (/*1*/ & C); +let a10: /*1*/ & /*2*/ C; +let a11: /*1*/ (& /*2*/ C); + +let aa1: /*1*/ & /*2*/ C & D; +let aa2: /*1*/ & /*2*/ C & /*3*/ D; +let aa3: /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type A1 = C; +type A2 = & C; +type A3 = (& C); +type A4 = & (C); +type A5 = (& (C)); +type A6 = /*1*/ & C; +type A7 = /*1*/ & (C); +type A8 = /*1*/ (& C); +type A9 = (/*1*/ & C); +type A10 = /*1*/ & /*2*/ C; +type A11 = /*1*/ (& /*2*/ C); +type A12 = /*1*/ & ( (C)); +type A13 = /*1*/ ( (C)); + +type Aa1 = /*1*/ & /*2*/ C & D; +type Aa2 = /*1*/ & /*2*/ C & /*3*/ D; +type Aa3 = /*1*/ & /*2*/ C & /*3*/ D /*4*/; + +type C1 = /*1*/ | a & b; +type C2 = /*1*/ | a & (b); +type C3 = /*1*/ | a & (| b); +type C4 = /*1*/ | (a & b); +type C5 = /*1*/ (| a & b); +type C6 /*0*/ = /*1*/ (| a & b); + +type Ctor = (new () => X) & Y; diff --git a/tests/integration/__tests__/__snapshots__/early-exit.js.snap b/tests/integration/__tests__/__snapshots__/early-exit.js.snap index 822cdb984..73db20120 100644 --- a/tests/integration/__tests__/__snapshots__/early-exit.js.snap +++ b/tests/integration/__tests__/__snapshots__/early-exit.js.snap @@ -53,6 +53,9 @@ Format options: --end-of-line Which end of line characters to apply. Defaults to lf. + --experimental-operator-position + Where to print operators when binary expressions wrap lines. + Defaults to end. --no-experimental-ternaries Default behavior of ternaries; keep question marks on the same line as the consequent. --html-whitespace-sensitivity @@ -218,6 +221,9 @@ Format options: --end-of-line Which end of line characters to apply. Defaults to lf. + --experimental-operator-position + Where to print operators when binary expressions wrap lines. + Defaults to end. --no-experimental-ternaries Default behavior of ternaries; keep question marks on the same line as the consequent. --html-whitespace-sensitivity diff --git a/tests/integration/__tests__/__snapshots__/help-options.js.snap b/tests/integration/__tests__/__snapshots__/help-options.js.snap index fbb7d4189..e3f8580b3 100644 --- a/tests/integration/__tests__/__snapshots__/help-options.js.snap +++ b/tests/integration/__tests__/__snapshots__/help-options.js.snap @@ -191,6 +191,23 @@ Default: lf" exports[`show detailed usage with --help end-of-line (write) 1`] = `[]`; +exports[`show detailed usage with --help experimental-operator-position (stderr) 1`] = `""`; + +exports[`show detailed usage with --help experimental-operator-position (stdout) 1`] = ` +"--experimental-operator-position + + Where to print operators when binary expressions wrap lines. + +Valid options: + + start Print operators at the start of new lines. + end Print operators at the end of previous lines. + +Default: end" +`; + +exports[`show detailed usage with --help experimental-operator-position (write) 1`] = `[]`; + exports[`show detailed usage with --help experimental-ternaries (stderr) 1`] = `""`; exports[`show detailed usage with --help experimental-ternaries (stdout) 1`] = ` diff --git a/tests/integration/__tests__/__snapshots__/plugin-options-string.js.snap b/tests/integration/__tests__/__snapshots__/plugin-options-string.js.snap index 95919cddf..b2f4773ca 100644 --- a/tests/integration/__tests__/__snapshots__/plugin-options-string.js.snap +++ b/tests/integration/__tests__/__snapshots__/plugin-options-string.js.snap @@ -17,10 +17,10 @@ exports[`show external options with \`--help\` 1`] = ` - First value + Second value -@@ -24,16 +24,18 @@ - --end-of-line - Which end of line characters to apply. - Defaults to lf. +@@ -27,16 +27,18 @@ + --experimental-operator-position + Where to print operators when binary expressions wrap lines. + Defaults to end. --no-experimental-ternaries Default behavior of ternaries; keep question marks on the same line as the consequent. + --foo-string foo description diff --git a/tests/integration/__tests__/__snapshots__/plugin-options.js.snap b/tests/integration/__tests__/__snapshots__/plugin-options.js.snap index baa1f447c..468004420 100644 --- a/tests/integration/__tests__/__snapshots__/plugin-options.js.snap +++ b/tests/integration/__tests__/__snapshots__/plugin-options.js.snap @@ -60,10 +60,10 @@ exports[`show external options with \`--help\` 1`] = ` - First value + Second value -@@ -24,16 +24,18 @@ - --end-of-line - Which end of line characters to apply. - Defaults to lf. +@@ -27,16 +27,18 @@ + --experimental-operator-position + Where to print operators when binary expressions wrap lines. + Defaults to end. --no-experimental-ternaries Default behavior of ternaries; keep question marks on the same line as the consequent. + --foo-option foo description diff --git a/tests/integration/__tests__/__snapshots__/schema.js.snap b/tests/integration/__tests__/__snapshots__/schema.js.snap index 2bea69951..b885b5faa 100644 --- a/tests/integration/__tests__/__snapshots__/schema.js.snap +++ b/tests/integration/__tests__/__snapshots__/schema.js.snap @@ -89,6 +89,24 @@ exports[`schema 1`] = ` }, ], }, + "experimentalOperatorPosition": { + "default": "end", + "description": "Where to print operators when binary expressions wrap lines.", + "oneOf": [ + { + "description": "Print operators at the start of new lines.", + "enum": [ + "start", + ], + }, + { + "description": "Print operators at the end of previous lines.", + "enum": [ + "end", + ], + }, + ], + }, "experimentalTernaries": { "default": false, "description": "Use curious ternaries, with the question mark after the condition.", diff --git a/tests/integration/__tests__/__snapshots__/support-info.js.snap b/tests/integration/__tests__/__snapshots__/support-info.js.snap index f9897bd55..057c81bb7 100644 --- a/tests/integration/__tests__/__snapshots__/support-info.js.snap +++ b/tests/integration/__tests__/__snapshots__/support-info.js.snap @@ -130,6 +130,14 @@ exports[`API getSupportInfo() 1`] = ` "default": "lf", "type": "choice", }, + "experimentalOperatorPosition": { + "choices": [ + "start", + "end", + ], + "default": "end", + "type": "choice", + }, "experimentalTernaries": { "default": false, "type": "boolean", @@ -847,6 +855,24 @@ exports[`CLI --support-info (stdout) 1`] = ` "pluginDefaults": {}, "type": "choice" }, + { + "category": "JavaScript", + "choices": [ + { + "description": "Print operators at the start of new lines.", + "value": "start" + }, + { + "description": "Print operators at the end of previous lines.", + "value": "end" + } + ], + "default": "end", + "description": "Where to print operators when binary expressions wrap lines.", + "name": "experimentalOperatorPosition", + "pluginDefaults": {}, + "type": "choice" + }, { "category": "JavaScript", "default": false,