Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TypeScript] format TSAsExpression with same logic as BinaryExpression #7869

Merged
merged 17 commits into from Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions changelog_unreleased/typescript/pr-7869.md
@@ -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;
```
46 changes: 23 additions & 23 deletions src/language-js/printer-estree.js
Expand Up @@ -39,6 +39,7 @@ const {
classChildNeedsASIProtection,
classPropMayCauseASIProblems,
conditionalExpressionChainContainsJSX,
convertToBinaryishNode,
getFlowVariance,
getLeftSidePathName,
getParentExportDeclaration,
Expand Down Expand Up @@ -553,11 +554,13 @@ function printPathNoParens(path, options, print, args) {
);
case "BinaryExpression":
case "LogicalExpression":
case "NGPipeExpression": {
case "NGPipeExpression":
case "TSAsExpression": {
const node = convertToBinaryishNode(n);
const parent = path.getParentNode();
const parentParent = path.getParentNode(1);
const isInsideParenthesis =
n !== parent.body &&
node !== parent.body &&
thorn0 marked this conversation as resolved.
Show resolved Hide resolved
(parent.type === "IfStatement" ||
parent.type === "WhileStatement" ||
parent.type === "SwitchStatement" ||
Expand Down Expand Up @@ -596,7 +599,7 @@ function printPathNoParens(path, options, print, args) {
if (
((parent.type === "CallExpression" ||
parent.type === "OptionalCallExpression") &&
parent.callee === n) ||
parent.callee === node) ||
parent.type === "UnaryExpression" ||
((parent.type === "MemberExpression" ||
parent.type === "OptionalMemberExpression") &&
Expand All @@ -614,14 +617,14 @@ function printPathNoParens(path, options, print, args) {
parent.type === "ThrowStatement" ||
(parent.type === "JSXExpressionContainer" &&
parentParent.type === "JSXAttribute") ||
(n.operator !== "|" && parent.type === "JsExpressionRoot") ||
(n.type !== "NGPipeExpression" &&
(node.operator !== "|" && parent.type === "JsExpressionRoot") ||
(node.type !== "NGPipeExpression" &&
((parent.type === "NGRoot" && options.parser === "__ng_binding") ||
(parent.type === "NGMicrosyntaxExpression" &&
parentParent.type === "NGMicrosyntax" &&
parentParent.body.length === 1))) ||
(n === parent.body && parent.type === "ArrowFunctionExpression") ||
(n !== parent.body && parent.type === "ForStatement") ||
(node === parent.body && parent.type === "ArrowFunctionExpression") ||
(node !== parent.body && parent.type === "ForStatement") ||
(parent.type === "ConditionalExpression" &&
parentParent.type !== "ReturnStatement" &&
parentParent.type !== "ThrowStatement" &&
Expand All @@ -639,12 +642,13 @@ function printPathNoParens(path, options, print, args) {
parent.type === "Property";

const samePrecedenceSubExpression =
isBinaryish(n.left) && shouldFlatten(n.operator, n.left.operator);
isBinaryish(node.left) &&
shouldFlatten(node.operator, node.left.operator);

if (
shouldNotIndent ||
(shouldInlineLogicalExpression(n) && !samePrecedenceSubExpression) ||
(!shouldInlineLogicalExpression(n) && shouldIndentIfInlining)
(shouldInlineLogicalExpression(node) && !samePrecedenceSubExpression) ||
(!shouldInlineLogicalExpression(node) && shouldIndentIfInlining)
) {
return group(concat(parts));
}
Expand All @@ -662,7 +666,7 @@ function printPathNoParens(path, options, print, args) {
// </Foo>
// )

const hasJSX = isJSXNode(n.right);
const hasJSX = isJSXNode(node.right);
const rest = concat(hasJSX ? parts.slice(1, -1) : parts.slice(1));

const groupId = Symbol("logicalChain-" + ++uid);
Expand Down Expand Up @@ -2491,7 +2495,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]);
Expand Down Expand Up @@ -3192,12 +3195,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": {
Expand Down Expand Up @@ -5713,10 +5710,13 @@ function printBinaryishExpressions(
isInsideParenthesis
) {
let parts = [];
const node = path.getValue();
const node = convertToBinaryishNode(path.getValue());

// We treat BinaryExpression and LogicalExpression nodes the same.
if (isBinaryish(node)) {
const leftNodeName = node.type === "TSAsExpression" ? "expression" : "left";
const rightNodeName =
node.type === "TSAsExpression" ? "typeAnnotation" : "right";
thorn0 marked this conversation as resolved.
Show resolved Hide resolved
// 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
Expand All @@ -5738,11 +5738,11 @@ function printBinaryishExpressions(
/* isNested */ true,
isInsideParenthesis
),
"left"
leftNodeName
)
);
} else {
parts.push(path.call(print, "left"));
parts.push(path.call(print, leftNodeName));
}

const shouldInline = shouldInlineLogicalExpression(node);
Expand Down Expand Up @@ -5772,12 +5772,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,
]);

Expand Down
20 changes: 20 additions & 0 deletions src/language-js/utils.js
Expand Up @@ -289,6 +289,7 @@ const binaryishNodeTypes = new Set([
"BinaryExpression",
"LogicalExpression",
"NGPipeExpression",
"TSAsExpression",
]);
function isBinaryish(node) {
return binaryishNodeTypes.has(node.type);
Expand Down Expand Up @@ -1003,10 +1004,29 @@ function isTSXFile(options) {
return options.filepath && /\.tsx$/i.test(options.filepath);
}

function convertToBinaryishNode(node) {
if (node.type === "TSAsExpression") {
const binaryishNode = { ...node };

binaryishNode.operator = "as";

binaryishNode.left = node.expression;
delete binaryishNode.expression;

binaryishNode.right = node.typeAnnotation;
delete binaryishNode.typeAnnotation;

return binaryishNode;
}

return node;
}

module.exports = {
classChildNeedsASIProtection,
classPropMayCauseASIProblems,
conditionalExpressionChainContainsJSX,
convertToBinaryishNode,
getFlowVariance,
getLeftSidePathName,
getParentExportDeclaration,
Expand Down
Expand Up @@ -41,7 +41,7 @@ const bar8 = [1,2,3].reduce((carry, value) => {
=====================================output=====================================
const bar1 = [1, 2, 3].reduce((carry, value) => {
return [...carry, value];
}, ([] as unknown) as number[]);
}, [] as unknown as number[]);

const bar2 = [1, 2, 3].reduce((carry, value) => {
return [...carry, value];
Expand All @@ -51,7 +51,7 @@ const bar3 = [1, 2, 3].reduce(
(carry, value) => {
return [...carry, value];
},
([1, 2, 3] as unknown) as number[]
[1, 2, 3] as unknown as number[]
thorn0 marked this conversation as resolved.
Show resolved Hide resolved
);

const bar4 = [1, 2, 3].reduce(
Expand All @@ -63,7 +63,7 @@ const bar4 = [1, 2, 3].reduce(

const bar5 = [1, 2, 3].reduce((carry, value) => {
return { ...carry, [value]: true };
}, ({} as unknown) as { [key: number]: boolean });
}, {} as unknown as { [key: number]: boolean });

const bar6 = [1, 2, 3].reduce((carry, value) => {
return { ...carry, [value]: true };
Expand All @@ -73,7 +73,7 @@ const bar7 = [1, 2, 3].reduce(
(carry, value) => {
return { ...carry, [value]: true };
},
({ 1: true } as unknown) as { [key: number]: boolean }
{ 1: true } as unknown as { [key: number]: boolean }
);

const bar8 = [1, 2, 3].reduce(
Expand Down
65 changes: 52 additions & 13 deletions tests/typescript_as/__snapshots__/jsfmt.spec.js.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`as.js 1`] = `
exports[`as.ts 1`] = `
====================================options=====================================
parsers: ["typescript"]
printWidth: 80
Expand All @@ -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 }) {}
Expand All @@ -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 {});
Expand All @@ -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
);

================================================================================
`;

Expand Down
29 changes: 0 additions & 29 deletions tests/typescript_as/as.js

This file was deleted.