[TypeScript] format TSAsExpression with same logic as BinaryExpression (#7869)
* Treat TSAsExpression as like BinaryishNode * Change test file extension, as.js => as.ts * Add tests * Remove old case for TSAsExpression * Remove unnecesary condition * Fix by lint * Update snapshots * Add changelog * Remove convetToBinaryishNode * Fix comment * Use getBinaryishNodeNames * Modify to wrap TSAsExpression with parens * Fix by lint * Do not pass operator when node is TSAsExpression * Refactor shouldNotIndent * Update util.js Co-authored-by: Georgii Dolzhykov <thorn.mailbox@gmail.com>
This commit is contained in:
1 parent
18bf01e8f8
commit
8a48ca2e3d
8 files changed
+172
-86
No files matched your search
@@ -0,0 +1,14 @@
|
||||
#### Wrap TSAsExpression ([#7869](https://github.com/prettier/prettier/pull/7869) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
const varibale = foooooooooooooooooooooooooooooooooooooooooooooooooooo as SomeType;
|
||||
|
||||
// Prettier stable
|
||||
const varibale = foooooooooooooooooooooooooooooooooooooooooooooooooooo as SomeType;
|
||||
|
||||
// Prettier master
|
||||
const varibale =
|
||||
foooooooooooooooooooooooooooooooooooooooooooooooooooo as SomeType;
|
||||
```
|
||||
@@ -553,7 +553,9 @@ function printPathNoParens(path, options, print, args) {
|
||||
);
|
||||
case "BinaryExpression":
|
||||
case "LogicalExpression":
|
||||
case "NGPipeExpression": {
|
||||
case "NGPipeExpression":
|
||||
case "TSAsExpression": {
|
||||
const { rightNodeName, operator } = getBinaryishNodeNames(n);
|
||||
const parent = path.getParentNode();
|
||||
const parentParent = path.getParentNode(1);
|
||||
const isInsideParenthesis =
|
||||
@@ -609,12 +611,12 @@ function printPathNoParens(path, options, print, args) {
|
||||
|
||||
// Avoid indenting sub-expressions in some cases where the first sub-expression is already
|
||||
// indented accordingly. We should indent sub-expressions where the first case isn't indented.
|
||||
const shouldNotIndent =
|
||||
let shouldNotIndent =
|
||||
parent.type === "ReturnStatement" ||
|
||||
parent.type === "ThrowStatement" ||
|
||||
(parent.type === "JSXExpressionContainer" &&
|
||||
parentParent.type === "JSXAttribute") ||
|
||||
(n.operator !== "|" && parent.type === "JsExpressionRoot") ||
|
||||
(operator !== "|" && parent.type === "JsExpressionRoot") ||
|
||||
(n.type !== "NGPipeExpression" &&
|
||||
((parent.type === "NGRoot" && options.parser === "__ng_binding") ||
|
||||
(parent.type === "NGMicrosyntaxExpression" &&
|
||||
@@ -629,23 +631,25 @@ function printPathNoParens(path, options, print, args) {
|
||||
parentParent.type !== "OptionalCallExpression") ||
|
||||
parent.type === "TemplateLiteral";
|
||||
|
||||
const shouldIndentIfInlining =
|
||||
parent.type === "AssignmentExpression" ||
|
||||
parent.type === "VariableDeclarator" ||
|
||||
parent.type === "ClassProperty" ||
|
||||
parent.type === "TSAbstractClassProperty" ||
|
||||
parent.type === "ClassPrivateProperty" ||
|
||||
parent.type === "ObjectProperty" ||
|
||||
parent.type === "Property";
|
||||
if (!shouldNotIndent) {
|
||||
if (shouldInlineLogicalExpression(n)) {
|
||||
const samePrecedenceSubExpression =
|
||||
isBinaryish(n.left) && shouldFlatten(operator, n.left.operator);
|
||||
shouldNotIndent = !samePrecedenceSubExpression;
|
||||
} else {
|
||||
const shouldIndentIfInlining =
|
||||
parent.type === "AssignmentExpression" ||
|
||||
parent.type === "VariableDeclarator" ||
|
||||
parent.type === "ClassProperty" ||
|
||||
parent.type === "TSAbstractClassProperty" ||
|
||||
parent.type === "ClassPrivateProperty" ||
|
||||
parent.type === "ObjectProperty" ||
|
||||
parent.type === "Property";
|
||||
shouldNotIndent = shouldIndentIfInlining;
|
||||
}
|
||||
}
|
||||
|
||||
const samePrecedenceSubExpression =
|
||||
isBinaryish(n.left) && shouldFlatten(n.operator, n.left.operator);
|
||||
|
||||
if (
|
||||
shouldNotIndent ||
|
||||
(shouldInlineLogicalExpression(n) && !samePrecedenceSubExpression) ||
|
||||
(!shouldInlineLogicalExpression(n) && shouldIndentIfInlining)
|
||||
) {
|
||||
if (shouldNotIndent) {
|
||||
return group(concat(parts));
|
||||
}
|
||||
|
||||
@@ -662,7 +666,7 @@ function printPathNoParens(path, options, print, args) {
|
||||
// </Foo>
|
||||
// )
|
||||
|
||||
const hasJSX = isJSXNode(n.right);
|
||||
const hasJSX = isJSXNode(n[rightNodeName]);
|
||||
const rest = concat(hasJSX ? parts.slice(1, -1) : parts.slice(1));
|
||||
|
||||
const groupId = Symbol("logicalChain-" + ++uid);
|
||||
@@ -2489,7 +2493,6 @@ function printPathNoParens(path, options, print, args) {
|
||||
n.expressions[i].type === "OptionalMemberExpression" ||
|
||||
n.expressions[i].type === "ConditionalExpression" ||
|
||||
n.expressions[i].type === "SequenceExpression" ||
|
||||
n.expressions[i].type === "TSAsExpression" ||
|
||||
isBinaryish(n.expressions[i])
|
||||
) {
|
||||
printed = concat([indent(concat([softline, printed])), softline]);
|
||||
@@ -3190,12 +3193,6 @@ function printPathNoParens(path, options, print, args) {
|
||||
return "unknown";
|
||||
case "TSVoidKeyword":
|
||||
return "void";
|
||||
case "TSAsExpression":
|
||||
return concat([
|
||||
path.call(print, "expression"),
|
||||
" as ",
|
||||
path.call(print, "typeAnnotation"),
|
||||
]);
|
||||
case "TSArrayType":
|
||||
return concat([path.call(print, "elementType"), "[]"]);
|
||||
case "TSPropertySignature": {
|
||||
@@ -5695,6 +5692,20 @@ function shouldInlineLogicalExpression(node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getBinaryishNodeNames(node) {
|
||||
const leftNodeName = node.type === "TSAsExpression" ? "expression" : "left";
|
||||
const rightNodeName =
|
||||
node.type === "TSAsExpression" ? "typeAnnotation" : "right";
|
||||
const operator =
|
||||
node.type === "NGPipeExpression"
|
||||
? "|"
|
||||
: node.type === "TSAsExpression"
|
||||
? "as"
|
||||
: node.operator;
|
||||
|
||||
return { leftNodeName, rightNodeName, operator };
|
||||
}
|
||||
|
||||
// For binary expressions to be consistent, we need to group
|
||||
// subsequent operators with the same precedence level under a single
|
||||
// group. Otherwise they will be nested such that some of them break
|
||||
@@ -5713,8 +5724,12 @@ function printBinaryishExpressions(
|
||||
let parts = [];
|
||||
const node = path.getValue();
|
||||
|
||||
// We treat BinaryExpression and LogicalExpression nodes the same.
|
||||
// We treat BinaryExpression, LogicalExpression, NGPipeExpression and TSAsExpression the same.
|
||||
if (isBinaryish(node)) {
|
||||
const { leftNodeName, rightNodeName, operator } = getBinaryishNodeNames(
|
||||
node
|
||||
);
|
||||
|
||||
// Put all operators with the same precedence level in the same
|
||||
// group. The reason we only need to do this with the `left`
|
||||
// expression is because given an expression like `1 + 2 - 3`, it
|
||||
@@ -5724,7 +5739,11 @@ function printBinaryishExpressions(
|
||||
// precedence level and should be treated as a separate group, so
|
||||
// print them normally. (This doesn't hold for the `**` operator,
|
||||
// which is unique in that it is right-associative.)
|
||||
if (shouldFlatten(node.operator, node.left.operator)) {
|
||||
if (
|
||||
node.type === "NGPipeExpression" ||
|
||||
(node.type !== "TSAsExpression" &&
|
||||
shouldFlatten(operator, node[leftNodeName].operator))
|
||||
) {
|
||||
// Flatten them out by recursively calling this function.
|
||||
parts = parts.concat(
|
||||
path.call(
|
||||
@@ -5736,21 +5755,24 @@ function printBinaryishExpressions(
|
||||
/* isNested */ true,
|
||||
isInsideParenthesis
|
||||
),
|
||||
"left"
|
||||
leftNodeName
|
||||
)
|
||||
);
|
||||
} else {
|
||||
parts.push(path.call(print, "left"));
|
||||
parts.push(path.call(print, leftNodeName));
|
||||
}
|
||||
|
||||
const shouldInline = shouldInlineLogicalExpression(node);
|
||||
const lineBeforeOperator =
|
||||
(node.operator === "|>" ||
|
||||
(operator === "|>" ||
|
||||
node.type === "NGPipeExpression" ||
|
||||
(node.operator === "|" && options.parser === "__vue_expression")) &&
|
||||
!hasLeadingOwnLineComment(options.originalText, node.right, options);
|
||||
(operator === "|" && options.parser === "__vue_expression")) &&
|
||||
!hasLeadingOwnLineComment(
|
||||
options.originalText,
|
||||
node[rightNodeName],
|
||||
options
|
||||
);
|
||||
|
||||
const operator = node.type === "NGPipeExpression" ? "|" : node.operator;
|
||||
const rightSuffix =
|
||||
node.type === "NGPipeExpression" && node.arguments.length !== 0
|
||||
? group(
|
||||
@@ -5770,12 +5792,12 @@ function printBinaryishExpressions(
|
||||
: "";
|
||||
|
||||
const right = shouldInline
|
||||
? concat([operator, " ", path.call(print, "right"), rightSuffix])
|
||||
? concat([operator, " ", path.call(print, rightNodeName), rightSuffix])
|
||||
: concat([
|
||||
lineBeforeOperator ? softline : "",
|
||||
operator,
|
||||
lineBeforeOperator ? " " : line,
|
||||
path.call(print, "right"),
|
||||
path.call(print, rightNodeName),
|
||||
rightSuffix,
|
||||
]);
|
||||
|
||||
@@ -5785,8 +5807,8 @@ function printBinaryishExpressions(
|
||||
const shouldGroup =
|
||||
!(isInsideParenthesis && node.type === "LogicalExpression") &&
|
||||
parent.type !== node.type &&
|
||||
node.left.type !== node.type &&
|
||||
node.right.type !== node.type;
|
||||
node[leftNodeName].type !== node.type &&
|
||||
node[rightNodeName].type !== node.type;
|
||||
|
||||
parts.push(" ", shouldGroup ? group(right) : right);
|
||||
|
||||
|
||||
@@ -289,6 +289,7 @@ const binaryishNodeTypes = new Set([
|
||||
"BinaryExpression",
|
||||
"LogicalExpression",
|
||||
"NGPipeExpression",
|
||||
"TSAsExpression",
|
||||
]);
|
||||
function isBinaryish(node) {
|
||||
return binaryishNodeTypes.has(node.type);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`as.js 1`] = `
|
||||
exports[`as.ts 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["typescript"]
|
||||
printWidth: 80
|
||||
@@ -9,9 +9,12 @@ printWidth: 80
|
||||
const name = (description as DescriptionObject).name || (description as string);
|
||||
this.isTabActionBar((e.target || e.srcElement) as HTMLElement);
|
||||
(originalError ? wrappedError(errMsg, originalError) : Error(errMsg)) as InjectionError;
|
||||
'current' in (props.pagination as Object)
|
||||
start + (yearSelectTotal as number)
|
||||
scrollTop > (visibilityHeight as number)
|
||||
'current' in (props.pagination as Object);
|
||||
('current' in props.pagination) as Object;
|
||||
start + (yearSelectTotal as number);
|
||||
(start + yearSelectTotal) as number;
|
||||
scrollTop > (visibilityHeight as number);
|
||||
(scrollTop > visibilityHeight) as number;
|
||||
export default class Column<T> extends (RcTable.Column as React.ComponentClass<ColumnProps<T>,ColumnProps<T>,ColumnProps<T>,ColumnProps<T>>) {}
|
||||
export const MobxTypedForm = class extends (Form as { new (): any }) {}
|
||||
export abstract class MobxTypedForm1 extends (Form as { new (): any }) {}
|
||||
@@ -35,22 +38,33 @@ const state = JSON.stringify({
|
||||
(bValue as boolean) ? 0 : -1;
|
||||
<boolean>bValue ? 0 : -1;
|
||||
|
||||
const value1 = thisIsAReallyReallyReallyReallyReallyLongIdentifier as SomeInterface;
|
||||
const value2 = thisIsAnIdentifier as thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongInterface;
|
||||
const value3 = thisIsAReallyLongIdentifier as (SomeInterface | SomeOtherInterface);
|
||||
const value4 = thisIsAReallyLongIdentifier as { prop1: string, prop2: number, prop3: number }[];
|
||||
const value5 = thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyLongIdentifier as [string, number];
|
||||
|
||||
const iter1 = createIterator(this.controller, child, this.tag as SyncFunctionComponent);
|
||||
const iter2 = createIterator(self.controller, child, self.tag as SyncFunctionComponent);
|
||||
|
||||
=====================================output=====================================
|
||||
const name = (description as DescriptionObject).name || (description as string);
|
||||
this.isTabActionBar((e.target || e.srcElement) as HTMLElement);
|
||||
(originalError
|
||||
? wrappedError(errMsg, originalError)
|
||||
: Error(errMsg)) as InjectionError;
|
||||
(originalError ? wrappedError(errMsg, originalError) : Error(errMsg)) as
|
||||
InjectionError;
|
||||
"current" in (props.pagination as Object);
|
||||
("current" in props.pagination) as Object;
|
||||
start + (yearSelectTotal as number);
|
||||
(start + yearSelectTotal) as number;
|
||||
scrollTop > (visibilityHeight as number);
|
||||
export default class Column<T> extends (RcTable.Column as React.ComponentClass<
|
||||
ColumnProps<T>,
|
||||
ColumnProps<T>,
|
||||
ColumnProps<T>,
|
||||
ColumnProps<T>
|
||||
>) {}
|
||||
(scrollTop > visibilityHeight) as number;
|
||||
export default class Column<T> extends (RcTable.Column as
|
||||
React.ComponentClass<
|
||||
ColumnProps<T>,
|
||||
ColumnProps<T>,
|
||||
ColumnProps<T>,
|
||||
ColumnProps<T>
|
||||
>) {}
|
||||
export const MobxTypedForm = class extends (Form as { new (): any }) {};
|
||||
export abstract class MobxTypedForm1 extends (Form as { new (): any }) {}
|
||||
({} as {});
|
||||
@@ -73,6 +87,31 @@ const state = JSON.stringify({
|
||||
(bValue as boolean) ? 0 : -1;
|
||||
<boolean>bValue ? 0 : -1;
|
||||
|
||||
const value1 =
|
||||
thisIsAReallyReallyReallyReallyReallyLongIdentifier as SomeInterface;
|
||||
const value2 =
|
||||
thisIsAnIdentifier as
|
||||
thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongInterface;
|
||||
const value3 =
|
||||
thisIsAReallyLongIdentifier as SomeInterface | SomeOtherInterface;
|
||||
const value4 =
|
||||
thisIsAReallyLongIdentifier as
|
||||
{ prop1: string; prop2: number; prop3: number }[];
|
||||
const value5 =
|
||||
thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyLongIdentifier as
|
||||
[string, number];
|
||||
|
||||
const iter1 = createIterator(
|
||||
this.controller,
|
||||
child,
|
||||
this.tag as SyncFunctionComponent
|
||||
);
|
||||
const iter2 = createIterator(
|
||||
self.controller,
|
||||
child,
|
||||
self.tag as SyncFunctionComponent
|
||||
);
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
const name = (description as DescriptionObject).name || (description as string);
|
||||
this.isTabActionBar((e.target || e.srcElement) as HTMLElement);
|
||||
(originalError ? wrappedError(errMsg, originalError) : Error(errMsg)) as InjectionError;
|
||||
'current' in (props.pagination as Object)
|
||||
start + (yearSelectTotal as number)
|
||||
scrollTop > (visibilityHeight as number)
|
||||
export default class Column<T> extends (RcTable.Column as React.ComponentClass<ColumnProps<T>,ColumnProps<T>,ColumnProps<T>,ColumnProps<T>>) {}
|
||||
export const MobxTypedForm = class extends (Form as { new (): any }) {}
|
||||
export abstract class MobxTypedForm1 extends (Form as { new (): any }) {}
|
||||
({}) as {};
|
||||
function*g() {
|
||||
const test = (yield 'foo') as number;
|
||||
}
|
||||
async function g1() {
|
||||
const test = (await 'foo') as number;
|
||||
}
|
||||
({}) as X;
|
||||
() => ({}) as X;
|
||||
const state = JSON.stringify({
|
||||
next: window.location.href,
|
||||
nonce,
|
||||
} as State);
|
||||
|
||||
(foo.bar as Baz) = [bar];
|
||||
(foo.bar as any)++;
|
||||
|
||||
(bValue as boolean) ? 0 : -1;
|
||||
<boolean>bValue ? 0 : -1;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
const name = (description as DescriptionObject).name || (description as string);
|
||||
this.isTabActionBar((e.target || e.srcElement) as HTMLElement);
|
||||
(originalError ? wrappedError(errMsg, originalError) : Error(errMsg)) as InjectionError;
|
||||
'current' in (props.pagination as Object);
|
||||
('current' in props.pagination) as Object;
|
||||
start + (yearSelectTotal as number);
|
||||
(start + yearSelectTotal) as number;
|
||||
scrollTop > (visibilityHeight as number);
|
||||
(scrollTop > visibilityHeight) as number;
|
||||
export default class Column<T> extends (RcTable.Column as React.ComponentClass<ColumnProps<T>,ColumnProps<T>,ColumnProps<T>,ColumnProps<T>>) {}
|
||||
export const MobxTypedForm = class extends (Form as { new (): any }) {}
|
||||
export abstract class MobxTypedForm1 extends (Form as { new (): any }) {}
|
||||
({}) as {};
|
||||
function*g() {
|
||||
const test = (yield 'foo') as number;
|
||||
}
|
||||
async function g1() {
|
||||
const test = (await 'foo') as number;
|
||||
}
|
||||
({}) as X;
|
||||
() => ({}) as X;
|
||||
const state = JSON.stringify({
|
||||
next: window.location.href,
|
||||
nonce,
|
||||
} as State);
|
||||
|
||||
(foo.bar as Baz) = [bar];
|
||||
(foo.bar as any)++;
|
||||
|
||||
(bValue as boolean) ? 0 : -1;
|
||||
<boolean>bValue ? 0 : -1;
|
||||
|
||||
const value1 = thisIsAReallyReallyReallyReallyReallyLongIdentifier as SomeInterface;
|
||||
const value2 = thisIsAnIdentifier as thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongInterface;
|
||||
const value3 = thisIsAReallyLongIdentifier as (SomeInterface | SomeOtherInterface);
|
||||
const value4 = thisIsAReallyLongIdentifier as { prop1: string, prop2: number, prop3: number }[];
|
||||
const value5 = thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyLongIdentifier as [string, number];
|
||||
|
||||
const iter1 = createIterator(this.controller, child, this.tag as SyncFunctionComponent);
|
||||
const iter2 = createIterator(self.controller, child, self.tag as SyncFunctionComponent);
|
||||
@@ -25,7 +25,8 @@ const b = \`\${
|
||||
}\`;
|
||||
const b = \`\${
|
||||
(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo +
|
||||
veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) as veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz
|
||||
veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) as
|
||||
veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz
|
||||
}\`;
|
||||
|
||||
================================================================================
|
||||
|
||||
@@ -379,10 +379,8 @@ type State = {
|
||||
| { discriminant: "BAZ"; baz: any }
|
||||
);
|
||||
|
||||
const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (
|
||||
| string
|
||||
| undefined
|
||||
)[];
|
||||
const foo1 =
|
||||
[abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as (string | undefined)[];
|
||||
|
||||
const foo2: (
|
||||
| AAAAAAAAAAAAAAAAAAAAAA
|
||||
|
||||
Reference in new issue
Block a user