@eslint-react/ast 2.0.0-next.2 → 2.0.0-next.200
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +188 -206
- package/dist/index.js +592 -546
- package/package.json +8 -9
package/dist/index.js
CHANGED
|
@@ -1,589 +1,635 @@
|
|
|
1
|
-
import { AST_NODE_TYPES } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
2
|
+
import { dual, unit } from "@eslint-react/eff";
|
|
3
|
+
import { delimiterCase, replace, toLowerCase } from "string-ts";
|
|
4
|
+
import { ASTUtils } from "@typescript-eslint/utils";
|
|
5
|
+
import { simpleTraverse } from "@typescript-eslint/typescript-estree";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
//#region src/array-index.ts
|
|
8
|
+
const indexParamPosition = new Map([
|
|
9
|
+
["every", 1],
|
|
10
|
+
["filter", 1],
|
|
11
|
+
["find", 1],
|
|
12
|
+
["findIndex", 1],
|
|
13
|
+
["findLast", 1],
|
|
14
|
+
["findLastIndex", 1],
|
|
15
|
+
["flatMap", 1],
|
|
16
|
+
["forEach", 1],
|
|
17
|
+
["map", 1],
|
|
18
|
+
["reduce", 2],
|
|
19
|
+
["reduceRight", 2],
|
|
20
|
+
["some", 1]
|
|
21
|
+
]);
|
|
22
|
+
function getArrayMethodCallbackIndexParamPosition(methodName) {
|
|
23
|
+
return indexParamPosition.get(methodName) ?? -1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/array-method.ts
|
|
8
28
|
function isArrayFromCall(node, loose = true) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
30
|
+
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
31
|
+
if (node.callee.property.type !== AST_NODE_TYPES.Identifier) return false;
|
|
32
|
+
const name = node.callee.property.name;
|
|
33
|
+
return name === "from" || loose && name.startsWith("from");
|
|
14
34
|
}
|
|
15
35
|
function isArrayMapCall(node, loose = true) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
36
|
+
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
37
|
+
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
38
|
+
if (node.callee.property.type !== AST_NODE_TYPES.Identifier) return false;
|
|
39
|
+
const name = node.callee.property.name;
|
|
40
|
+
return name === "map" || loose && name.endsWith("Map");
|
|
21
41
|
}
|
|
22
42
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
["every", 1],
|
|
26
|
-
["filter", 1],
|
|
27
|
-
["find", 1],
|
|
28
|
-
["findIndex", 1],
|
|
29
|
-
["findLast", 1],
|
|
30
|
-
["findLastIndex", 1],
|
|
31
|
-
["flatMap", 1],
|
|
32
|
-
["forEach", 1],
|
|
33
|
-
["map", 1],
|
|
34
|
-
["reduce", 2],
|
|
35
|
-
["reduceRight", 2],
|
|
36
|
-
["some", 1]
|
|
37
|
-
]);
|
|
38
|
-
function getArrayMethodCallbackIndexParamPosition(methodName) {
|
|
39
|
-
return indexParamPosition.get(methodName) ?? -1;
|
|
40
|
-
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/class-id.ts
|
|
41
45
|
function getClassId(node) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
return _;
|
|
46
|
+
if (node.id != null) return node.id;
|
|
47
|
+
if (node.parent.type === AST_NODE_TYPES.VariableDeclarator && node.parent.id.type === AST_NODE_TYPES.Identifier) return node.parent.id;
|
|
48
|
+
return unit;
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
AST_NODE_TYPES.TSParameterProperty,
|
|
97
|
-
AST_NODE_TYPES.TSPropertySignature
|
|
98
|
-
]);
|
|
99
|
-
var isJSXElement = is(AST_NODE_TYPES.JSXElement);
|
|
100
|
-
var isJSXFragment = is(AST_NODE_TYPES.JSXFragment);
|
|
101
|
-
var isJSXTagNameExpression = isOneOf([
|
|
102
|
-
AST_NODE_TYPES.JSXIdentifier,
|
|
103
|
-
AST_NODE_TYPES.JSXMemberExpression,
|
|
104
|
-
AST_NODE_TYPES.JSXNamespacedName
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/node-equal.ts
|
|
53
|
+
/**
|
|
54
|
+
* Determines whether node equals to another node
|
|
55
|
+
* @param a node to compare
|
|
56
|
+
* @param b node to compare
|
|
57
|
+
* @returns `true` if node equal
|
|
58
|
+
* @see https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/util/isNodeEqual.ts
|
|
59
|
+
*/
|
|
60
|
+
const isNodeEqual = dual(2, (a, b) => {
|
|
61
|
+
switch (true) {
|
|
62
|
+
case a === b: return true;
|
|
63
|
+
case a.type !== b.type: return false;
|
|
64
|
+
case a.type === AST_NODE_TYPES.Literal && b.type === AST_NODE_TYPES.Literal: return a.value === b.value;
|
|
65
|
+
case a.type === AST_NODE_TYPES.TemplateElement && b.type === AST_NODE_TYPES.TemplateElement: return a.value.raw === b.value.raw;
|
|
66
|
+
case a.type === AST_NODE_TYPES.TemplateLiteral && b.type === AST_NODE_TYPES.TemplateLiteral: {
|
|
67
|
+
if (a.quasis.length !== b.quasis.length || a.expressions.length !== b.expressions.length) return false;
|
|
68
|
+
let i = a.quasis.length;
|
|
69
|
+
while (i--) if (a.quasis[i]?.value.raw !== b.quasis[i]?.value.raw) return false;
|
|
70
|
+
i = a.expressions.length;
|
|
71
|
+
while (i--) {
|
|
72
|
+
const exprA = a.expressions[i];
|
|
73
|
+
const exprB = b.expressions[i];
|
|
74
|
+
if (!isNodeEqual(exprA, exprB)) return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
case a.type === AST_NODE_TYPES.Identifier && b.type === AST_NODE_TYPES.Identifier: return a.name === b.name;
|
|
79
|
+
case a.type === AST_NODE_TYPES.PrivateIdentifier && b.type === AST_NODE_TYPES.PrivateIdentifier: return a.name === b.name;
|
|
80
|
+
case a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression: return isNodeEqual(a.property, b.property) && isNodeEqual(a.object, b.object);
|
|
81
|
+
case a.type === AST_NODE_TYPES.JSXAttribute && b.type === AST_NODE_TYPES.JSXAttribute:
|
|
82
|
+
if (a.name.name !== b.name.name) return false;
|
|
83
|
+
if (a.value == null || b.value == null) return a.value === b.value;
|
|
84
|
+
return isNodeEqual(a.value, b.value);
|
|
85
|
+
case a.type === AST_NODE_TYPES.ThisExpression && b.type === AST_NODE_TYPES.ThisExpression: return true;
|
|
86
|
+
default: return false;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/node-is.ts
|
|
92
|
+
const is = ASTUtils.isNodeOfType;
|
|
93
|
+
const isOneOf = ASTUtils.isNodeOfTypes;
|
|
94
|
+
const isFunction = isOneOf([
|
|
95
|
+
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
96
|
+
AST_NODE_TYPES.FunctionDeclaration,
|
|
97
|
+
AST_NODE_TYPES.FunctionExpression
|
|
105
98
|
]);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
AST_NODE_TYPES.JSXNamespacedName,
|
|
117
|
-
AST_NODE_TYPES.JSXOpeningElement,
|
|
118
|
-
AST_NODE_TYPES.JSXOpeningFragment,
|
|
119
|
-
AST_NODE_TYPES.JSXSpreadAttribute,
|
|
120
|
-
AST_NODE_TYPES.JSXSpreadChild,
|
|
121
|
-
AST_NODE_TYPES.JSXText
|
|
99
|
+
const isFunctionType = isOneOf([
|
|
100
|
+
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
101
|
+
AST_NODE_TYPES.FunctionDeclaration,
|
|
102
|
+
AST_NODE_TYPES.FunctionExpression,
|
|
103
|
+
AST_NODE_TYPES.TSCallSignatureDeclaration,
|
|
104
|
+
AST_NODE_TYPES.TSConstructSignatureDeclaration,
|
|
105
|
+
AST_NODE_TYPES.TSDeclareFunction,
|
|
106
|
+
AST_NODE_TYPES.TSEmptyBodyFunctionExpression,
|
|
107
|
+
AST_NODE_TYPES.TSFunctionType,
|
|
108
|
+
AST_NODE_TYPES.TSMethodSignature
|
|
122
109
|
]);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
110
|
+
const isClass = isOneOf([AST_NODE_TYPES.ClassDeclaration, AST_NODE_TYPES.ClassExpression]);
|
|
111
|
+
const isMethodOrProperty = isOneOf([AST_NODE_TYPES.PropertyDefinition, AST_NODE_TYPES.MethodDefinition]);
|
|
112
|
+
const isProperty = isOneOf([
|
|
113
|
+
AST_NODE_TYPES.PropertyDefinition,
|
|
114
|
+
AST_NODE_TYPES.TSIndexSignature,
|
|
115
|
+
AST_NODE_TYPES.TSParameterProperty,
|
|
116
|
+
AST_NODE_TYPES.TSPropertySignature
|
|
128
117
|
]);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
const isJSXElement = is(AST_NODE_TYPES.JSXElement);
|
|
119
|
+
const isJSXFragment = is(AST_NODE_TYPES.JSXFragment);
|
|
120
|
+
const isJSXTagNameExpression = isOneOf([
|
|
121
|
+
AST_NODE_TYPES.JSXIdentifier,
|
|
122
|
+
AST_NODE_TYPES.JSXMemberExpression,
|
|
123
|
+
AST_NODE_TYPES.JSXNamespacedName
|
|
132
124
|
]);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
AST_NODE_TYPES.SequenceExpression,
|
|
150
|
-
AST_NODE_TYPES.Super,
|
|
151
|
-
AST_NODE_TYPES.TaggedTemplateExpression,
|
|
152
|
-
AST_NODE_TYPES.ThisExpression
|
|
125
|
+
const isJSX = isOneOf([
|
|
126
|
+
AST_NODE_TYPES.JSXAttribute,
|
|
127
|
+
AST_NODE_TYPES.JSXClosingElement,
|
|
128
|
+
AST_NODE_TYPES.JSXClosingFragment,
|
|
129
|
+
AST_NODE_TYPES.JSXElement,
|
|
130
|
+
AST_NODE_TYPES.JSXEmptyExpression,
|
|
131
|
+
AST_NODE_TYPES.JSXExpressionContainer,
|
|
132
|
+
AST_NODE_TYPES.JSXFragment,
|
|
133
|
+
AST_NODE_TYPES.JSXIdentifier,
|
|
134
|
+
AST_NODE_TYPES.JSXMemberExpression,
|
|
135
|
+
AST_NODE_TYPES.JSXNamespacedName,
|
|
136
|
+
AST_NODE_TYPES.JSXOpeningElement,
|
|
137
|
+
AST_NODE_TYPES.JSXOpeningFragment,
|
|
138
|
+
AST_NODE_TYPES.JSXSpreadAttribute,
|
|
139
|
+
AST_NODE_TYPES.JSXSpreadChild,
|
|
140
|
+
AST_NODE_TYPES.JSXText
|
|
153
141
|
]);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
AST_NODE_TYPES.FunctionExpression,
|
|
161
|
-
AST_NODE_TYPES.Identifier,
|
|
162
|
-
AST_NODE_TYPES.JSXElement,
|
|
163
|
-
AST_NODE_TYPES.JSXFragment,
|
|
164
|
-
AST_NODE_TYPES.Literal,
|
|
165
|
-
AST_NODE_TYPES.TemplateLiteral,
|
|
166
|
-
AST_NODE_TYPES.MemberExpression,
|
|
167
|
-
AST_NODE_TYPES.MetaProperty,
|
|
168
|
-
AST_NODE_TYPES.ObjectExpression,
|
|
169
|
-
AST_NODE_TYPES.ObjectPattern,
|
|
170
|
-
AST_NODE_TYPES.SequenceExpression,
|
|
171
|
-
AST_NODE_TYPES.Super,
|
|
172
|
-
AST_NODE_TYPES.TaggedTemplateExpression,
|
|
173
|
-
AST_NODE_TYPES.ThisExpression,
|
|
174
|
-
AST_NODE_TYPES.TSAsExpression,
|
|
175
|
-
AST_NODE_TYPES.TSNonNullExpression,
|
|
176
|
-
AST_NODE_TYPES.TSTypeAssertion
|
|
142
|
+
const isLoop = isOneOf([
|
|
143
|
+
AST_NODE_TYPES.DoWhileStatement,
|
|
144
|
+
AST_NODE_TYPES.ForInStatement,
|
|
145
|
+
AST_NODE_TYPES.ForOfStatement,
|
|
146
|
+
AST_NODE_TYPES.ForStatement,
|
|
147
|
+
AST_NODE_TYPES.WhileStatement
|
|
177
148
|
]);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
149
|
+
const isTypeExpression = isOneOf([
|
|
150
|
+
AST_NODE_TYPES.TSAsExpression,
|
|
151
|
+
AST_NODE_TYPES.TSTypeAssertion,
|
|
152
|
+
AST_NODE_TYPES.TSNonNullExpression,
|
|
153
|
+
AST_NODE_TYPES.TSSatisfiesExpression,
|
|
154
|
+
AST_NODE_TYPES.TSInstantiationExpression
|
|
184
155
|
]);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
156
|
+
const isTypeAssertionExpression = isOneOf([
|
|
157
|
+
AST_NODE_TYPES.TSAsExpression,
|
|
158
|
+
AST_NODE_TYPES.TSTypeAssertion,
|
|
159
|
+
AST_NODE_TYPES.TSNonNullExpression,
|
|
160
|
+
AST_NODE_TYPES.TSSatisfiesExpression
|
|
190
161
|
]);
|
|
191
162
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return node;
|
|
198
|
-
}
|
|
199
|
-
function isThisExpression(node) {
|
|
200
|
-
return getJSExpression(node).type === AST_NODE_TYPES.ThisExpression;
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region src/node-format.ts
|
|
165
|
+
function getLiteralValueType(input) {
|
|
166
|
+
if (input === null) return "null";
|
|
167
|
+
return typeof input;
|
|
201
168
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return node.parent.left;
|
|
213
|
-
// {MaybeComponent: () => {}}
|
|
214
|
-
// {MaybeComponent() {}}
|
|
215
|
-
case (node.parent.type === AST_NODE_TYPES.Property && node.parent.value === node && !node.parent.computed && node.parent.key.type === AST_NODE_TYPES.Identifier):
|
|
216
|
-
return node.parent.key;
|
|
217
|
-
// class {MaybeComponent = () => {}}
|
|
218
|
-
// class {MaybeComponent() {}}
|
|
219
|
-
case (isMethodOrProperty(node.parent) && node.parent.value === node && node.parent.key.type === AST_NODE_TYPES.Identifier):
|
|
220
|
-
return node.parent.key;
|
|
221
|
-
// Follow spec convention for `IsAnonymousFunctionDefinition()` usage.
|
|
222
|
-
//
|
|
223
|
-
// const {MaybeComponent = () => {}} = {};
|
|
224
|
-
// ({MaybeComponent = () => {}} = {});
|
|
225
|
-
case (node.parent.type === AST_NODE_TYPES.AssignmentPattern && node.parent.right === node && node.parent.left.type === AST_NODE_TYPES.Identifier):
|
|
226
|
-
return node.parent.left;
|
|
227
|
-
// const MaybeComponent = (() => {})!;
|
|
228
|
-
// const MaybeComponent = (() => {}) as FunctionComponent;
|
|
229
|
-
// const MaybeComponent = (() => {}) satisfies FunctionComponent;
|
|
230
|
-
case isTypeAssertionExpression(node.parent):
|
|
231
|
-
return getFunctionId(node.parent);
|
|
232
|
-
}
|
|
233
|
-
return _;
|
|
169
|
+
/**
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
172
|
+
function toDelimiterFormat(node, delimiter = " ") {
|
|
173
|
+
if (node.type === AST_NODE_TYPES.Literal) {
|
|
174
|
+
if ("regex" in node) return "RegExp literal";
|
|
175
|
+
return `${getLiteralValueType(node.value)} literal`;
|
|
176
|
+
}
|
|
177
|
+
if (isJSX(node)) return `JSX ${toLowerCase(delimiterCase(replace(node.type, "JSX", ""), delimiter))}`;
|
|
178
|
+
return toLowerCase(delimiterCase(node.type, delimiter));
|
|
234
179
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
return [parent.parent.parent, parent.parent, parent, node];
|
|
253
|
-
}
|
|
254
|
-
return _;
|
|
180
|
+
/**
|
|
181
|
+
* Incomplete but sufficient stringification of AST nodes for common use cases
|
|
182
|
+
*
|
|
183
|
+
* @internal
|
|
184
|
+
*/
|
|
185
|
+
function toStringFormat(node, getText) {
|
|
186
|
+
switch (node.type) {
|
|
187
|
+
case AST_NODE_TYPES.Identifier:
|
|
188
|
+
case AST_NODE_TYPES.JSXIdentifier:
|
|
189
|
+
case AST_NODE_TYPES.PrivateIdentifier: return node.name;
|
|
190
|
+
case AST_NODE_TYPES.MemberExpression:
|
|
191
|
+
case AST_NODE_TYPES.JSXMemberExpression: return `${toStringFormat(node.object, getText)}.${toStringFormat(node.property, getText)}`;
|
|
192
|
+
case AST_NODE_TYPES.JSXNamespacedName: return `${node.namespace.name}:${node.name.name}`;
|
|
193
|
+
case AST_NODE_TYPES.JSXText: return node.value;
|
|
194
|
+
case AST_NODE_TYPES.Literal: return node.raw;
|
|
195
|
+
default: return getText(node);
|
|
196
|
+
}
|
|
255
197
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
});
|
|
198
|
+
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/expression-base.ts
|
|
201
|
+
/**
|
|
202
|
+
* Unwraps any type expressions to get the underlying JavaScript expression node.
|
|
203
|
+
* Recursively processes nodes until a non-type expression is found.
|
|
204
|
+
*
|
|
205
|
+
* @param node - The AST node to unwrap
|
|
206
|
+
* @returns The underlying JavaScript expression node
|
|
207
|
+
*/
|
|
208
|
+
function getUnderlyingExpression(node) {
|
|
209
|
+
if (isTypeExpression(node)) return getUnderlyingExpression(node.expression);
|
|
210
|
+
return node;
|
|
270
211
|
}
|
|
271
|
-
|
|
272
|
-
|
|
212
|
+
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/expression-is.ts
|
|
215
|
+
/**
|
|
216
|
+
* Checks if the given expression is a 'this' expression.
|
|
217
|
+
* Unwraps any type expressions before checking.
|
|
218
|
+
*
|
|
219
|
+
* @param node - The expression node to check
|
|
220
|
+
* @returns true if the expression is a ThisExpression, false otherwise
|
|
221
|
+
*/
|
|
222
|
+
function isThisExpression(node) {
|
|
223
|
+
return getUnderlyingExpression(node).type === AST_NODE_TYPES.ThisExpression;
|
|
273
224
|
}
|
|
225
|
+
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/traverse-up.ts
|
|
274
228
|
function findParentNode(node, test) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
return _;
|
|
229
|
+
if (node == null) return unit;
|
|
230
|
+
let parent = node.parent;
|
|
231
|
+
while (parent != null && parent.type !== AST_NODE_TYPES.Program) {
|
|
232
|
+
if (test(parent)) return parent;
|
|
233
|
+
parent = parent.parent;
|
|
234
|
+
}
|
|
235
|
+
return unit;
|
|
284
236
|
}
|
|
237
|
+
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/expression-nested.ts
|
|
240
|
+
/**
|
|
241
|
+
* Get all nested identifiers in a expression like node
|
|
242
|
+
* @param node The node to get the nested identifiers from
|
|
243
|
+
* @returns All nested identifiers
|
|
244
|
+
*/
|
|
285
245
|
function getNestedIdentifiers(node) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
return identifiers;
|
|
246
|
+
const identifiers = [];
|
|
247
|
+
if (node.type === AST_NODE_TYPES.Identifier) identifiers.push(node);
|
|
248
|
+
if ("arguments" in node) {
|
|
249
|
+
const chunk = node.arguments.map(getNestedIdentifiers).flat(1);
|
|
250
|
+
identifiers.push(...chunk);
|
|
251
|
+
}
|
|
252
|
+
if ("elements" in node) {
|
|
253
|
+
const chunk = node.elements.filter((x) => x != null).map(getNestedIdentifiers).flat(1);
|
|
254
|
+
identifiers.push(...chunk);
|
|
255
|
+
}
|
|
256
|
+
if ("properties" in node) {
|
|
257
|
+
const chunk = node.properties.map(getNestedIdentifiers).flat(1);
|
|
258
|
+
identifiers.push(...chunk);
|
|
259
|
+
}
|
|
260
|
+
if ("expressions" in node) {
|
|
261
|
+
const chunk = node.expressions.map(getNestedIdentifiers).flat(1);
|
|
262
|
+
identifiers.push(...chunk);
|
|
263
|
+
}
|
|
264
|
+
if ("left" in node) {
|
|
265
|
+
const chunk = getNestedIdentifiers(node.left);
|
|
266
|
+
identifiers.push(...chunk);
|
|
267
|
+
}
|
|
268
|
+
if ("right" in node) {
|
|
269
|
+
const chunk = getNestedIdentifiers(node.right);
|
|
270
|
+
identifiers.push(...chunk);
|
|
271
|
+
}
|
|
272
|
+
if (node.type === AST_NODE_TYPES.Property) {
|
|
273
|
+
const chunk = getNestedIdentifiers(node.value);
|
|
274
|
+
identifiers.push(...chunk);
|
|
275
|
+
}
|
|
276
|
+
if (node.type === AST_NODE_TYPES.SpreadElement) {
|
|
277
|
+
const chunk = getNestedIdentifiers(node.argument);
|
|
278
|
+
identifiers.push(...chunk);
|
|
279
|
+
}
|
|
280
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
281
|
+
const chunk = getNestedIdentifiers(node.object);
|
|
282
|
+
identifiers.push(...chunk);
|
|
283
|
+
}
|
|
284
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression) {
|
|
285
|
+
const chunk = getNestedIdentifiers(node.argument);
|
|
286
|
+
identifiers.push(...chunk);
|
|
287
|
+
}
|
|
288
|
+
if (node.type === AST_NODE_TYPES.ChainExpression) {
|
|
289
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
290
|
+
identifiers.push(...chunk);
|
|
291
|
+
}
|
|
292
|
+
if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
|
|
293
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
294
|
+
identifiers.push(...chunk);
|
|
295
|
+
}
|
|
296
|
+
if (node.type === AST_NODE_TYPES.TSAsExpression) {
|
|
297
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
298
|
+
identifiers.push(...chunk);
|
|
299
|
+
}
|
|
300
|
+
if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
|
|
301
|
+
const chunk = getNestedIdentifiers(node.expression);
|
|
302
|
+
identifiers.push(...chunk);
|
|
303
|
+
}
|
|
304
|
+
return identifiers;
|
|
347
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Gets the nested return statements in the node that are within the same function
|
|
308
|
+
* @param node The AST node
|
|
309
|
+
* @returns The nested return statements in the node
|
|
310
|
+
*/
|
|
348
311
|
function getNestedReturnStatements(node) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (parentFunction !== boundaryNode) {
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
statements.push(node2);
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
return statements;
|
|
312
|
+
const statements = [];
|
|
313
|
+
const boundaryNode = isFunction(node) ? node : findParentNode(node, isFunction);
|
|
314
|
+
simpleTraverse(node, { enter(node$1) {
|
|
315
|
+
if (node$1.type !== AST_NODE_TYPES.ReturnStatement) return;
|
|
316
|
+
if (findParentNode(node$1, isFunction) !== boundaryNode) return;
|
|
317
|
+
statements.push(node$1);
|
|
318
|
+
} });
|
|
319
|
+
return statements;
|
|
364
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Get all nested expressions of type T in an expression like node
|
|
323
|
+
* @param type The type of the expression to retrieve within the node
|
|
324
|
+
* @returns A partially applied function bound to a predicate of type T. The returned function can be called passing a
|
|
325
|
+
* node, and it will return an array of all nested expressions of type T.
|
|
326
|
+
*/
|
|
365
327
|
function getNestedExpressionsOfType(type) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
return expressions;
|
|
446
|
-
};
|
|
328
|
+
const isNodeOfType = is(type);
|
|
329
|
+
return function(node) {
|
|
330
|
+
const boundGetNestedExpressionsOfType = getNestedExpressionsOfType(type);
|
|
331
|
+
const expressions = [];
|
|
332
|
+
if (isNodeOfType(node)) expressions.push(node);
|
|
333
|
+
if ("arguments" in node) {
|
|
334
|
+
const chunk = node.arguments.map(getNestedExpressionsOfType(type)).flat(1);
|
|
335
|
+
expressions.push(...chunk);
|
|
336
|
+
}
|
|
337
|
+
if ("expression" in node && node.expression !== true && node.expression !== false) {
|
|
338
|
+
const chunk = boundGetNestedExpressionsOfType(node.expression);
|
|
339
|
+
expressions.push(...chunk);
|
|
340
|
+
}
|
|
341
|
+
if ("left" in node) {
|
|
342
|
+
const chunk = boundGetNestedExpressionsOfType(node.left);
|
|
343
|
+
expressions.push(...chunk);
|
|
344
|
+
}
|
|
345
|
+
if ("right" in node) {
|
|
346
|
+
const chunk = boundGetNestedExpressionsOfType(node.right);
|
|
347
|
+
expressions.push(...chunk);
|
|
348
|
+
}
|
|
349
|
+
if ("test" in node && node.test != null) {
|
|
350
|
+
const chunk = boundGetNestedExpressionsOfType(node.test);
|
|
351
|
+
expressions.push(...chunk);
|
|
352
|
+
}
|
|
353
|
+
if ("consequent" in node) {
|
|
354
|
+
const chunk = Array.isArray(node.consequent) ? node.consequent.map(boundGetNestedExpressionsOfType).flat(1) : boundGetNestedExpressionsOfType(node.consequent);
|
|
355
|
+
expressions.push(...chunk);
|
|
356
|
+
}
|
|
357
|
+
if ("alternate" in node && node.alternate != null) {
|
|
358
|
+
const chunk = Array.isArray(node.alternate) ? node.alternate.map(boundGetNestedExpressionsOfType).flat(1) : boundGetNestedExpressionsOfType(node.alternate);
|
|
359
|
+
expressions.push(...chunk);
|
|
360
|
+
}
|
|
361
|
+
if ("elements" in node) {
|
|
362
|
+
const chunk = node.elements.filter((x) => x != null).map(getNestedExpressionsOfType(type)).flat(1);
|
|
363
|
+
expressions.push(...chunk);
|
|
364
|
+
}
|
|
365
|
+
if ("properties" in node) {
|
|
366
|
+
const chunk = node.properties.map(boundGetNestedExpressionsOfType).flat(1);
|
|
367
|
+
expressions.push(...chunk);
|
|
368
|
+
}
|
|
369
|
+
if ("expressions" in node) {
|
|
370
|
+
const chunk = node.expressions.map(boundGetNestedExpressionsOfType).flat(1);
|
|
371
|
+
expressions.push(...chunk);
|
|
372
|
+
}
|
|
373
|
+
if (node.type === AST_NODE_TYPES.Property) {
|
|
374
|
+
const chunk = boundGetNestedExpressionsOfType(node.value);
|
|
375
|
+
expressions.push(...chunk);
|
|
376
|
+
}
|
|
377
|
+
if (node.type === AST_NODE_TYPES.SpreadElement) {
|
|
378
|
+
const chunk = boundGetNestedExpressionsOfType(node.argument);
|
|
379
|
+
expressions.push(...chunk);
|
|
380
|
+
}
|
|
381
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
382
|
+
const chunk = boundGetNestedExpressionsOfType(node.object);
|
|
383
|
+
expressions.push(...chunk);
|
|
384
|
+
}
|
|
385
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression) {
|
|
386
|
+
const chunk = boundGetNestedExpressionsOfType(node.argument);
|
|
387
|
+
expressions.push(...chunk);
|
|
388
|
+
}
|
|
389
|
+
if (node.type === AST_NODE_TYPES.ChainExpression) {
|
|
390
|
+
const chunk = boundGetNestedExpressionsOfType(node.expression);
|
|
391
|
+
expressions.push(...chunk);
|
|
392
|
+
}
|
|
393
|
+
if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
|
|
394
|
+
const chunk = boundGetNestedExpressionsOfType(node.expression);
|
|
395
|
+
expressions.push(...chunk);
|
|
396
|
+
}
|
|
397
|
+
if (node.type === AST_NODE_TYPES.TSAsExpression) {
|
|
398
|
+
const chunk = boundGetNestedExpressionsOfType(node.expression);
|
|
399
|
+
expressions.push(...chunk);
|
|
400
|
+
}
|
|
401
|
+
if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
|
|
402
|
+
const chunk = boundGetNestedExpressionsOfType(node.expression);
|
|
403
|
+
expressions.push(...chunk);
|
|
404
|
+
}
|
|
405
|
+
return expressions;
|
|
406
|
+
};
|
|
447
407
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
408
|
+
/**
|
|
409
|
+
* Get all nested new expressions in an expression like node
|
|
410
|
+
* @param node The node to get the nested new expressions from
|
|
411
|
+
* @returns All nested new expressions
|
|
412
|
+
*/
|
|
413
|
+
const getNestedNewExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.NewExpression);
|
|
414
|
+
/**
|
|
415
|
+
* Get all nested call expressions in a expression like node
|
|
416
|
+
* @param node The node to get the nested call expressions from
|
|
417
|
+
* @returns All nested call expressions
|
|
418
|
+
*/
|
|
419
|
+
const getNestedCallExpressions = getNestedExpressionsOfType(AST_NODE_TYPES.CallExpression);
|
|
420
|
+
|
|
421
|
+
//#endregion
|
|
422
|
+
//#region src/function-id.ts
|
|
423
|
+
/**
|
|
424
|
+
* Gets the static name of a function AST node. For function declarations it is
|
|
425
|
+
* easy. For anonymous function expressions it is much harder. If you search for
|
|
426
|
+
* `IsAnonymousFunctionDefinition()` in the ECMAScript spec you'll find places
|
|
427
|
+
* where JS gives anonymous function expressions names. We roughly detect the
|
|
428
|
+
* same AST nodes with some exceptions to better fit our use case.
|
|
429
|
+
*/
|
|
430
|
+
function getFunctionId(node) {
|
|
431
|
+
switch (true) {
|
|
432
|
+
case "id" in node && node.id != null: return node.id;
|
|
433
|
+
case node.parent.type === AST_NODE_TYPES.VariableDeclarator && node.parent.init === node && node.parent.id.type === AST_NODE_TYPES.Identifier: return node.parent.id;
|
|
434
|
+
case node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.right === node && node.parent.operator === "=" && node.parent.left.type === AST_NODE_TYPES.Identifier: return node.parent.left;
|
|
435
|
+
case node.parent.type === AST_NODE_TYPES.Property && node.parent.value === node && !node.parent.computed && node.parent.key.type === AST_NODE_TYPES.Identifier: return node.parent.key;
|
|
436
|
+
case isMethodOrProperty(node.parent) && node.parent.value === node && node.parent.key.type === AST_NODE_TYPES.Identifier: return node.parent.key;
|
|
437
|
+
case node.parent.type === AST_NODE_TYPES.AssignmentPattern && node.parent.right === node && node.parent.left.type === AST_NODE_TYPES.Identifier: return node.parent.left;
|
|
438
|
+
case isTypeAssertionExpression(node.parent): return getFunctionId(node.parent);
|
|
439
|
+
}
|
|
440
|
+
return unit;
|
|
452
441
|
}
|
|
453
|
-
|
|
454
|
-
|
|
442
|
+
|
|
443
|
+
//#endregion
|
|
444
|
+
//#region src/function-init-path.ts
|
|
445
|
+
/**
|
|
446
|
+
* Identifies the initialization path of a function node in the AST.
|
|
447
|
+
* Determines what kind of component declaration pattern the function belongs to.
|
|
448
|
+
*
|
|
449
|
+
* @param node - The function node to analyze
|
|
450
|
+
* @returns The function initialization path or unit if not identifiable
|
|
451
|
+
*/
|
|
452
|
+
function getFunctionInitPath(node) {
|
|
453
|
+
if (node.type === AST_NODE_TYPES.FunctionDeclaration) return [node];
|
|
454
|
+
const { parent } = node;
|
|
455
|
+
switch (true) {
|
|
456
|
+
case parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
457
|
+
parent.parent,
|
|
458
|
+
parent,
|
|
459
|
+
node
|
|
460
|
+
];
|
|
461
|
+
case parent.type === AST_NODE_TYPES.CallExpression && parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
462
|
+
parent.parent.parent,
|
|
463
|
+
parent.parent,
|
|
464
|
+
parent,
|
|
465
|
+
node
|
|
466
|
+
];
|
|
467
|
+
case parent.type === AST_NODE_TYPES.CallExpression && parent.parent.type === AST_NODE_TYPES.CallExpression && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
468
|
+
parent.parent.parent.parent,
|
|
469
|
+
parent.parent.parent,
|
|
470
|
+
parent.parent,
|
|
471
|
+
parent,
|
|
472
|
+
node
|
|
473
|
+
];
|
|
474
|
+
case parent.type === AST_NODE_TYPES.Property && parent.parent.type === AST_NODE_TYPES.ObjectExpression && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
475
|
+
parent.parent.parent.parent,
|
|
476
|
+
parent.parent.parent,
|
|
477
|
+
parent.parent,
|
|
478
|
+
parent,
|
|
479
|
+
node
|
|
480
|
+
];
|
|
481
|
+
case parent.type === AST_NODE_TYPES.MethodDefinition && parent.parent.parent.type === AST_NODE_TYPES.ClassDeclaration: return [
|
|
482
|
+
parent.parent.parent,
|
|
483
|
+
parent.parent,
|
|
484
|
+
parent,
|
|
485
|
+
node
|
|
486
|
+
];
|
|
487
|
+
case parent.type === AST_NODE_TYPES.PropertyDefinition && parent.parent.parent.type === AST_NODE_TYPES.ClassDeclaration: return [
|
|
488
|
+
parent.parent.parent,
|
|
489
|
+
parent.parent,
|
|
490
|
+
parent,
|
|
491
|
+
node
|
|
492
|
+
];
|
|
493
|
+
}
|
|
494
|
+
return unit;
|
|
455
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Checks if a specific function call exists in the function initialization path.
|
|
498
|
+
* Useful for detecting HOCs like React.memo, React.forwardRef, etc.
|
|
499
|
+
*
|
|
500
|
+
* @param callName - The name of the call to check for (e.g., "memo", "forwardRef")
|
|
501
|
+
* @param initPath - The function initialization path to search in
|
|
502
|
+
* @returns True if the call exists in the path, false otherwise
|
|
503
|
+
*/
|
|
504
|
+
function hasCallInFunctionInitPath(callName, initPath) {
|
|
505
|
+
return initPath.some((node) => {
|
|
506
|
+
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
507
|
+
const { callee } = node;
|
|
508
|
+
if (callee.type === AST_NODE_TYPES.Identifier) return callee.name === callName;
|
|
509
|
+
if (callee.type === AST_NODE_TYPES.MemberExpression && "name" in callee.property) return callee.property.name === callName;
|
|
510
|
+
return false;
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
//#endregion
|
|
515
|
+
//#region src/function-is.ts
|
|
516
|
+
function isFunctionEmpty(node) {
|
|
517
|
+
return node.body.type === AST_NODE_TYPES.BlockStatement && node.body.body.length === 0;
|
|
518
|
+
}
|
|
519
|
+
function isFunctionImmediatelyInvoked(node) {
|
|
520
|
+
return node.type !== AST_NODE_TYPES.FunctionDeclaration && node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
//#endregion
|
|
524
|
+
//#region src/literal.ts
|
|
456
525
|
function isLiteral(node, type) {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
case "regexp":
|
|
467
|
-
return "regex" in node;
|
|
468
|
-
case "string":
|
|
469
|
-
return typeof node.value === "string";
|
|
470
|
-
}
|
|
526
|
+
if (node.type !== AST_NODE_TYPES.Literal) return false;
|
|
527
|
+
if (type == null) return true;
|
|
528
|
+
switch (type) {
|
|
529
|
+
case "boolean": return typeof node.value === "boolean";
|
|
530
|
+
case "null": return node.value === null;
|
|
531
|
+
case "number": return typeof node.value === "number";
|
|
532
|
+
case "regexp": return "regex" in node;
|
|
533
|
+
case "string": return typeof node.value === "string";
|
|
534
|
+
}
|
|
471
535
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
515
|
-
return isNodeEqual(a.value, b.value);
|
|
516
|
-
}
|
|
517
|
-
case (a.type === AST_NODE_TYPES.ThisExpression && b.type === AST_NODE_TYPES.ThisExpression):
|
|
518
|
-
return true;
|
|
519
|
-
default:
|
|
520
|
-
return false;
|
|
521
|
-
}
|
|
522
|
-
});
|
|
536
|
+
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region src/misc.ts
|
|
539
|
+
/**
|
|
540
|
+
* Check if a node is multiline
|
|
541
|
+
* @param node The AST node to check
|
|
542
|
+
* @returns `true` if the node is multiline
|
|
543
|
+
*/
|
|
544
|
+
function isMultiLine(node) {
|
|
545
|
+
return node.loc.start.line !== node.loc.end.line;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Check if a node is a line break
|
|
549
|
+
* @param node The AST node to check
|
|
550
|
+
* @returns boolean
|
|
551
|
+
*/
|
|
552
|
+
function isLineBreak(node) {
|
|
553
|
+
return isOneOf([AST_NODE_TYPES.Literal, AST_NODE_TYPES.JSXText])(node) && typeof node.value === "string" && node.value.trim() === "" && isMultiLine(node);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
//#endregion
|
|
557
|
+
//#region src/node-selectors.ts
|
|
558
|
+
const SEL_IMPLICIT_RETURN_ARROW_FUNCTION_EXPRESSION = "ArrowFunctionExpression[body.type!='BlockStatement']";
|
|
559
|
+
const SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR = [
|
|
560
|
+
"VariableDeclarator",
|
|
561
|
+
"[id.type='ObjectPattern']",
|
|
562
|
+
"[init.type='Identifier']"
|
|
563
|
+
].join("");
|
|
564
|
+
const SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION = [
|
|
565
|
+
"AssignmentExpression",
|
|
566
|
+
"[operator='=']",
|
|
567
|
+
"[left.type='MemberExpression']",
|
|
568
|
+
"[left.property.name='displayName']"
|
|
569
|
+
].join("");
|
|
570
|
+
|
|
571
|
+
//#endregion
|
|
572
|
+
//#region src/process-env-node-env.ts
|
|
573
|
+
/**
|
|
574
|
+
* Check if the given node is a member expression that accesses `process.env.NODE_ENV`
|
|
575
|
+
* @param node The AST node
|
|
576
|
+
* @returns True if the node is a member expression that accesses `process.env.NODE_ENV`, false otherwise
|
|
577
|
+
*/
|
|
523
578
|
function isProcessEnvNodeEnv(node) {
|
|
524
|
-
|
|
579
|
+
return node != null && node.type === AST_NODE_TYPES.MemberExpression && node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && node.object.object.name === "process" && node.object.property.type === AST_NODE_TYPES.Identifier && node.object.property.name === "env" && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === "NODE_ENV";
|
|
525
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Check if the given node is a binary expression that compares `process.env.NODE_ENV` with a string literal.
|
|
583
|
+
* @param node The AST node
|
|
584
|
+
* @param operator The operator used in the comparison
|
|
585
|
+
* @param value The string literal value to compare against
|
|
586
|
+
* @returns True if the node is a binary expression that compares `process.env.NODE_ENV` with the specified value, false otherwise
|
|
587
|
+
*/
|
|
526
588
|
function isProcessEnvNodeEnvCompare(node, operator, value) {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
if (isLiteral(node.left, "string") && isProcessEnvNodeEnv(node.right)) {
|
|
534
|
-
return node.left.value === value;
|
|
535
|
-
}
|
|
536
|
-
return false;
|
|
589
|
+
if (node == null) return false;
|
|
590
|
+
if (node.type !== AST_NODE_TYPES.BinaryExpression) return false;
|
|
591
|
+
if (node.operator !== operator) return false;
|
|
592
|
+
if (isProcessEnvNodeEnv(node.left) && isLiteral(node.right, "string")) return node.right.value === value;
|
|
593
|
+
if (isLiteral(node.left, "string") && isProcessEnvNodeEnv(node.right)) return node.left.value === value;
|
|
594
|
+
return false;
|
|
537
595
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
return node.name;
|
|
544
|
-
}
|
|
545
|
-
if (node.type === AST_NODE_TYPES.Literal) {
|
|
546
|
-
return String(node.value);
|
|
547
|
-
}
|
|
548
|
-
if (node.type === AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0) {
|
|
549
|
-
return node.quasis[0]?.value.raw;
|
|
550
|
-
}
|
|
551
|
-
return _;
|
|
596
|
+
|
|
597
|
+
//#endregion
|
|
598
|
+
//#region src/promise-then.ts
|
|
599
|
+
function isThenCall(node) {
|
|
600
|
+
return node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "then";
|
|
552
601
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
602
|
+
|
|
603
|
+
//#endregion
|
|
604
|
+
//#region src/property-name.ts
|
|
605
|
+
function getPropertyName(node) {
|
|
606
|
+
if (isTypeExpression(node)) return getPropertyName(getUnderlyingExpression(node));
|
|
607
|
+
if (node.type === AST_NODE_TYPES.Identifier || node.type === AST_NODE_TYPES.PrivateIdentifier) return node.name;
|
|
608
|
+
if (node.type === AST_NODE_TYPES.Literal) return String(node.value);
|
|
609
|
+
if (node.type === AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0) return node.quasis[0]?.value.raw;
|
|
610
|
+
return unit;
|
|
556
611
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
612
|
+
|
|
613
|
+
//#endregion
|
|
614
|
+
//#region src/vitest-mock.ts
|
|
615
|
+
/**
|
|
616
|
+
* Checks if the given node is a `vi.mock`.
|
|
617
|
+
* @param node The node to check
|
|
618
|
+
* @returns `true` if the node is a `vi.mock`, otherwise `false`.
|
|
619
|
+
* @internal
|
|
620
|
+
*/
|
|
621
|
+
function isViMock(node) {
|
|
622
|
+
return node != null && node.type === AST_NODE_TYPES.MemberExpression && node.object.type === AST_NODE_TYPES.Identifier && node.object.name === "vi" && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === "mock";
|
|
568
623
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
return `${toString(node.object, getText)}.${toString(node.property, getText)}`;
|
|
578
|
-
case AST_NODE_TYPES.JSXNamespacedName:
|
|
579
|
-
return `${node.namespace.name}:${node.name.name}`;
|
|
580
|
-
case AST_NODE_TYPES.JSXText:
|
|
581
|
-
return node.value;
|
|
582
|
-
case AST_NODE_TYPES.Literal:
|
|
583
|
-
return node.raw;
|
|
584
|
-
default:
|
|
585
|
-
return getText(node);
|
|
586
|
-
}
|
|
624
|
+
/**
|
|
625
|
+
* Checks if the given node is a `vi.mock` callback.
|
|
626
|
+
* @param node The node to check
|
|
627
|
+
* @returns `true` if the node is a `vi.mock` callback, otherwise `false`.
|
|
628
|
+
* @internal
|
|
629
|
+
*/
|
|
630
|
+
function isViMockCallback(node) {
|
|
631
|
+
return node != null && isFunction(node) && node.parent.type === AST_NODE_TYPES.CallExpression && isViMock(node.parent.callee) && node.parent.arguments[1] === node;
|
|
587
632
|
}
|
|
588
633
|
|
|
589
|
-
|
|
634
|
+
//#endregion
|
|
635
|
+
export { SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION, SEL_IMPLICIT_RETURN_ARROW_FUNCTION_EXPRESSION, SEL_OBJECT_DESTRUCTURING_VARIABLE_DECLARATOR, findParentNode, getArrayMethodCallbackIndexParamPosition, getClassId, getFunctionId, getFunctionInitPath, getNestedCallExpressions, getNestedExpressionsOfType, getNestedIdentifiers, getNestedNewExpressions, getNestedReturnStatements, getPropertyName, getUnderlyingExpression, hasCallInFunctionInitPath, is, isArrayFromCall, isArrayMapCall, isClass, isFunction, isFunctionEmpty, isFunctionImmediatelyInvoked, isFunctionType, isJSX, isJSXElement, isJSXFragment, isJSXTagNameExpression, isLineBreak, isLiteral, isLoop, isMethodOrProperty, isMultiLine, isNodeEqual, isOneOf, isProcessEnvNodeEnv, isProcessEnvNodeEnvCompare, isProperty, isThenCall, isThisExpression, isTypeAssertionExpression, isTypeExpression, isViMock, isViMockCallback, toDelimiterFormat, toStringFormat };
|