Skip to content

Commit ff0529a

Browse files
author
Sosuke Suzuki
authored
Backport "Support TS4.9 satisfies operator (#13764)" (#13783)
1 parent ca246af commit ff0529a

31 files changed

Lines changed: 1460 additions & 128 deletions

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
"dependencies": {
2525
"@angular/compiler": "12.2.16",
2626
"@babel/code-frame": "7.16.7",
27-
"@babel/parser": "7.18.0",
27+
"@babel/parser": "7.20.1",
2828
"@glimmer/syntax": "0.84.2",
2929
"@iarna/toml": "2.2.5",
30-
"@typescript-eslint/typescript-estree": "5.30.0",
30+
"@typescript-eslint/typescript-estree": "5.36.2",
3131
"acorn": "8.8.0",
3232
"acorn-jsx": "5.3.2",
3333
"angular-estree-parser": "2.5.1",
@@ -85,7 +85,7 @@
8585
"semver": "7.3.7",
8686
"string-width": "5.0.1",
8787
"strip-ansi": "7.0.1",
88-
"typescript": "4.7.2",
88+
"typescript": "4.8.2",
8989
"unicode-regex": "3.0.0",
9090
"unified": "9.2.1",
9191
"vnopts": "1.0.2",
@@ -102,7 +102,7 @@
102102
"@types/file-entry-cache": "5.0.2",
103103
"@types/find-cache-dir": "3.2.1",
104104
"@types/jest": "27.4.1",
105-
"@typescript-eslint/eslint-plugin": "5.20.0",
105+
"@typescript-eslint/eslint-plugin": "5.36.2",
106106
"babel-jest": "27.5.1",
107107
"benchmark": "2.1.4",
108108
"browserslist-to-esbuild": "1.1.1",

src/language-js/loc.js

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,16 @@ const isNonEmptyArray = require("../utils/is-non-empty-array.js");
66
* @typedef {import("./types/estree").Node} Node
77
*/
88

9-
function locStart(node, opts) {
10-
const { ignoreDecorators } = opts || {};
9+
function locStart(node) {
10+
const start = node.range ? node.range[0] : node.start;
1111

1212
// Handle nodes with decorators. They should start at the first decorator
13-
if (!ignoreDecorators) {
14-
const decorators =
15-
(node.declaration && node.declaration.decorators) || node.decorators;
16-
17-
if (isNonEmptyArray(decorators)) {
18-
return locStart(decorators[0]);
19-
}
13+
const decorators = node.declaration?.decorators ?? node.decorators;
14+
if (isNonEmptyArray(decorators)) {
15+
return Math.min(locStart(decorators[0]), start);
2016
}
2117

22-
return node.range ? node.range[0] : node.start;
18+
return start;
2319
}
2420

2521
function locEnd(node) {

src/language-js/needs-parens.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515
isCallExpression,
1616
isMemberExpression,
1717
isObjectProperty,
18+
isTSTypeExpression,
1819
} = require("./utils/index.js");
1920

2021
function needsParens(path, options) {
@@ -244,14 +245,16 @@ function needsParens(path, options) {
244245
// fallthrough
245246
case "TSTypeAssertion":
246247
case "TSAsExpression":
248+
case "TSSatisfiesExpression":
247249
case "LogicalExpression":
248250
switch (parent.type) {
251+
case "TSSatisfiesExpression":
249252
case "TSAsExpression":
250253
// example: foo as unknown as Bar
251-
return node.type !== "TSAsExpression";
254+
return !isTSTypeExpression(node);
252255

253256
case "ConditionalExpression":
254-
return node.type === "TSAsExpression";
257+
return isTSTypeExpression(node);
255258

256259
case "CallExpression":
257260
case "NewExpression":
@@ -282,7 +285,7 @@ function needsParens(path, options) {
282285
case "AssignmentPattern":
283286
return (
284287
name === "left" &&
285-
(node.type === "TSTypeAssertion" || node.type === "TSAsExpression")
288+
(node.type === "TSTypeAssertion" || isTSTypeExpression(node))
286289
);
287290

288291
case "LogicalExpression":
@@ -363,7 +366,7 @@ function needsParens(path, options) {
363366
if (
364367
parent.type === "UnaryExpression" ||
365368
parent.type === "AwaitExpression" ||
366-
parent.type === "TSAsExpression" ||
369+
isTSTypeExpression(parent) ||
367370
parent.type === "TSNonNullExpression"
368371
) {
369372
return true;
@@ -377,6 +380,7 @@ function needsParens(path, options) {
377380
case "SpreadElement":
378381
case "SpreadProperty":
379382
case "TSAsExpression":
383+
case "TSSatisfiesExpression":
380384
case "TSNonNullExpression":
381385
case "BindExpression":
382386
return true;
@@ -612,6 +616,7 @@ function needsParens(path, options) {
612616
case "TSTypeAssertion":
613617
case "TypeCastExpression":
614618
case "TSAsExpression":
619+
case "TSSatisfiesExpression":
615620
case "TSNonNullExpression":
616621
return true;
617622

@@ -661,6 +666,7 @@ function needsParens(path, options) {
661666
return name === "object";
662667

663668
case "TSAsExpression":
669+
case "TSSatisfiesExpression":
664670
case "TSNonNullExpression":
665671
case "BindExpression":
666672
case "TaggedTemplateExpression":

src/language-js/parse/postprocess/typescript.js

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
11
"use strict";
22

3+
const isNonEmptyArray = require("../../../utils/is-non-empty-array.js");
34
const visitNode = require("./visit-node.js");
45
const throwSyntaxError = require("./throw-syntax-error.js");
56

7+
// Copied from https://unpkg.com/typescript@4.8.2/lib/typescript.js
8+
function getSourceFileOfNode(node) {
9+
while (node && node.kind !== 305 /* SyntaxKind.SourceFile */) {
10+
node = node.parent;
11+
}
12+
return node;
13+
}
14+
615
// Invalid decorators are removed since `@typescript-eslint/typescript-estree` v4
716
// https://github.com/typescript-eslint/typescript-eslint/pull/2375
8-
function throwErrorForInvalidDecorator(
9-
tsNode,
10-
esTreeNode,
11-
tsNodeToESTreeNodeMap
12-
) {
13-
const tsDecorators = tsNode.decorators;
14-
if (!Array.isArray(tsDecorators)) {
17+
// There is a `checkGrammarDecorators` in `typescript` package, consider use it directly in future
18+
function throwErrorForInvalidDecorator(tsNode) {
19+
const { illegalDecorators } = tsNode;
20+
if (!isNonEmptyArray(illegalDecorators)) {
1521
return;
1622
}
17-
const esTreeDecorators = esTreeNode.decorators;
18-
if (
19-
!Array.isArray(esTreeDecorators) ||
20-
esTreeDecorators.length !== tsDecorators.length ||
21-
tsDecorators.some((tsDecorator) => {
22-
const esTreeDecorator = tsNodeToESTreeNodeMap.get(tsDecorator);
23-
return !esTreeDecorator || !esTreeDecorators.includes(esTreeDecorator);
24-
})
25-
) {
26-
throwSyntaxError(
27-
esTreeNode,
28-
"Leading decorators must be attached to a class declaration"
29-
);
30-
}
23+
24+
const [{ expression }] = illegalDecorators;
25+
26+
const sourceFile = getSourceFileOfNode(expression);
27+
const [start, end] = [expression.pos, expression.end].map((position) => {
28+
const { line, character: column } =
29+
sourceFile.getLineAndCharacterOfPosition(position);
30+
return { line: line + 1, column };
31+
});
32+
33+
throwSyntaxError({ loc: { start, end } }, "Decorators are not valid here.");
3134
}
3235

3336
// Values of abstract property is removed since `@typescript-eslint/typescript-estree` v5
@@ -66,7 +69,7 @@ function throwErrorForInvalidNodes(ast, options) {
6669
return;
6770
}
6871

69-
throwErrorForInvalidDecorator(tsNode, esTreeNode, tsNodeToESTreeNodeMap);
72+
throwErrorForInvalidDecorator(tsNode);
7073
throwErrorForInvalidAbstractProperty(tsNode, esTreeNode);
7174
});
7275
}

src/language-js/print/call-arguments.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
isCallExpression,
1717
isStringLiteral,
1818
isObjectProperty,
19+
isTSTypeExpression,
1920
} = require("../utils/index.js");
2021

2122
const {
@@ -190,7 +191,7 @@ function couldGroupArg(arg, arrowChainRecursion = false) {
190191
(arg.type === "ArrayExpression" &&
191192
(arg.elements.length > 0 || hasComment(arg))) ||
192193
(arg.type === "TSTypeAssertion" && couldGroupArg(arg.expression)) ||
193-
(arg.type === "TSAsExpression" && couldGroupArg(arg.expression)) ||
194+
(isTSTypeExpression(arg) && couldGroupArg(arg.expression)) ||
194195
arg.type === "FunctionExpression" ||
195196
(arg.type === "ArrowFunctionExpression" &&
196197
// we want to avoid breaking inside composite return types but not simple keywords

src/language-js/print/decorators.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ function hasDecoratorsBeforeExport(node) {
7272
const decorators = node.declaration && node.declaration.decorators;
7373

7474
return (
75-
isNonEmptyArray(decorators) &&
76-
locStart(node, { ignoreDecorators: true }) > locStart(decorators[0])
75+
isNonEmptyArray(decorators) && locStart(node) === locStart(decorators[0])
7776
);
7877
}
7978

src/language-js/print/template-literal.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const {
2222
isSimpleTemplateLiteral,
2323
hasComment,
2424
isMemberExpression,
25+
isTSTypeExpression,
2526
} = require("../utils/index.js");
2627

2728
function printTemplateLiteral(path, print, options) {
@@ -90,7 +91,7 @@ function printTemplateLiteral(path, print, options) {
9091
isMemberExpression(expression) ||
9192
expression.type === "ConditionalExpression" ||
9293
expression.type === "SequenceExpression" ||
93-
expression.type === "TSAsExpression" ||
94+
isTSTypeExpression(expression) ||
9495
isBinaryish(expression)
9596
) {
9697
printed = [indent([softline, printed]), softline];

src/language-js/print/ternary.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
getComments,
77
isCallExpression,
88
isMemberExpression,
9+
isTSTypeExpression,
910
} = require("../utils/index.js");
1011
const { locStart, locEnd } = require("../loc.js");
1112
const isBlockComment = require("../utils/is-block-comment.js");
@@ -165,7 +166,7 @@ function shouldExtraIndentForConditionalExpression(path) {
165166

166167
if (
167168
(node.type === "NewExpression" && node.callee === child) ||
168-
(node.type === "TSAsExpression" && node.expression === child)
169+
(isTSTypeExpression(node) && node.expression === child)
169170
) {
170171
parent = path.getParentNode(ancestorCount + 1);
171172
child = node;

src/language-js/print/typescript.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,10 @@ function printTypescript(path, options, print) {
148148
return printTypeParameters(path, options, print, "params");
149149
case "TSTypeParameter":
150150
return printTypeParameter(path, options, print);
151+
case "TSSatisfiesExpression":
151152
case "TSAsExpression": {
152-
parts.push(print("expression"), " as ", print("typeAnnotation"));
153+
const operator = node.type === "TSAsExpression" ? "as" : "satisfies";
154+
parts.push(print("expression"), ` ${operator} `, print("typeAnnotation"));
153155
const parent = path.getParentNode();
154156
if (
155157
(isCallExpression(parent) && parent.callee === node) ||

src/language-js/utils/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ function hasNakedLeftSide(node) {
106106
node.type === "TaggedTemplateExpression" ||
107107
node.type === "BindExpression" ||
108108
(node.type === "UpdateExpression" && !node.prefix) ||
109-
node.type === "TSAsExpression" ||
109+
isTSTypeExpression(node) ||
110110
node.type === "TSNonNullExpression"
111111
);
112112
}
@@ -998,6 +998,8 @@ function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) {
998998
node.expressions[0],
999999
forbidFunctionClassAndDoExpr
10001000
);
1001+
// @ts-expect-error
1002+
case "TSSatisfiesExpression":
10011003
case "TSAsExpression":
10021004
case "TSNonNullExpression":
10031005
return startsWithNoLookaheadToken(
@@ -1305,6 +1307,12 @@ const markerForIfWithoutBlockAndSameLineComment = Symbol(
13051307
"ifWithoutBlockAndSameLineComment"
13061308
);
13071309

1310+
function isTSTypeExpression(node) {
1311+
return (
1312+
node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression"
1313+
);
1314+
}
1315+
13081316
module.exports = {
13091317
getFunctionParameters,
13101318
iterateFunctionParametersPath,
@@ -1369,4 +1377,5 @@ module.exports = {
13691377
getComments,
13701378
CommentCheckFlags,
13711379
markerForIfWithoutBlockAndSameLineComment,
1380+
isTSTypeExpression,
13721381
};

0 commit comments

Comments
 (0)