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 <lionkay@gmail.com>
Co-authored-by: SUZUKI Sosuke <aosukeke@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-01-04 01:30:51 +09:00
1 parent d9d0999aac
commit eed53fc29a
17 files changed
+2342 -21

No files matched your search

+23
View File
@@ -0,0 +1,23 @@
#### Break lines before binary operators (#7111 by @btmills)
This is implemented behind the `--experimental-operator-position <start|end>` 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.
<!-- prettier-ignore -->
```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;
```
+11
View File
@@ -22,6 +22,17 @@ Valid options:
| ------- | -------------------------- | ------------------------------- |
| `false` | `--experimental-ternaries` | `experimentalTernaries: <bool>` |
## 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"` | <code>--experimental-operator-position <start&#124;end></code> | <code>experimentalOperatorPosition: "<start&#124;end>"</code> |
## Print Width
Specify the line length that the printer will wrap on.
+16
View File
@@ -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",
+46 -13
View File
@@ -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,
+3
View File
@@ -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]);
}
File diff suppressed because it is too large. Load diff
@@ -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();
@@ -7,3 +7,7 @@ const errors = {
};
runFormatTest(import.meta, ["babel", "flow", "typescript"], { errors });
runFormatTest(import.meta, ["babel", "flow", "typescript"], {
errors,
experimentalOperatorPosition: "start",
});
@@ -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<T extends (string & number)> {}
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<T extends string & number> {}
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;
================================================================================
`;
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<T extends (string & number)> {}
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<T extends string & number> {}
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
================================================================================
`;
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<T extends (string & number)> {}
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<T extends string & number> {}
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;
================================================================================
`;
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<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) => {}
=====================================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"]
@@ -1,2 +1,5 @@
runFormatTest(import.meta, ["typescript"]);
runFormatTest(import.meta, ["typescript"], { semi: false });
runFormatTest(import.meta, ["typescript"], {
experimentalOperatorPosition: "start",
});
@@ -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<T extends (string & number)> {}
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;
@@ -53,6 +53,9 @@ Format options:
--end-of-line <lf|crlf|cr|auto>
Which end of line characters to apply.
Defaults to lf.
--experimental-operator-position <start|end>
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 <css|strict|ignore>
@@ -218,6 +221,9 @@ Format options:
--end-of-line <lf|crlf|cr|auto>
Which end of line characters to apply.
Defaults to lf.
--experimental-operator-position <start|end>
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 <css|strict|ignore>
@@ -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 <start|end>
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`] = `
@@ -17,10 +17,10 @@ exports[`show external options with \`--help\` 1`] = `
- First value
+ Second value
@@ -24,16 +24,18 @@
--end-of-line <lf|crlf|cr|auto>
Which end of line characters to apply.
Defaults to lf.
@@ -27,16 +27,18 @@
--experimental-operator-position <start|end>
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 <string> foo description
@@ -60,10 +60,10 @@ exports[`show external options with \`--help\` 1`] = `
- First value
+ Second value
@@ -24,16 +24,18 @@
--end-of-line <lf|crlf|cr|auto>
Which end of line characters to apply.
Defaults to lf.
@@ -27,16 +27,18 @@
--experimental-operator-position <start|end>
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 <bar|baz> foo description
@@ -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.",
@@ -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,