@zayne-labs/eslint-config 0.9.17 → 0.9.18
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/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +357 -320
- package/dist/index.js +68 -59
- package/dist/index.js.map +1 -1
- package/dist/src-DwSufEpw.js +1769 -0
- package/dist/src-DwSufEpw.js.map +1 -0
- package/package.json +46 -42
|
@@ -0,0 +1,1769 @@
|
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
|
|
3
|
+
//#region rolldown:runtime
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __commonJS = (cb, mod) => function() {
|
|
11
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
15
|
+
key = keys[i];
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
17
|
+
get: ((k) => from[k]).bind(null, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region ../../node_modules/.pnpm/eslint-visitor-keys@2.1.0/node_modules/eslint-visitor-keys/lib/visitor-keys.json
|
|
30
|
+
var require_visitor_keys = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/eslint-visitor-keys@2.1.0/node_modules/eslint-visitor-keys/lib/visitor-keys.json": ((exports, module) => {
|
|
31
|
+
module.exports = {
|
|
32
|
+
"AssignmentExpression": ["left", "right"],
|
|
33
|
+
"AssignmentPattern": ["left", "right"],
|
|
34
|
+
"ArrayExpression": ["elements"],
|
|
35
|
+
"ArrayPattern": ["elements"],
|
|
36
|
+
"ArrowFunctionExpression": ["params", "body"],
|
|
37
|
+
"AwaitExpression": ["argument"],
|
|
38
|
+
"BlockStatement": ["body"],
|
|
39
|
+
"BinaryExpression": ["left", "right"],
|
|
40
|
+
"BreakStatement": ["label"],
|
|
41
|
+
"CallExpression": ["callee", "arguments"],
|
|
42
|
+
"CatchClause": ["param", "body"],
|
|
43
|
+
"ChainExpression": ["expression"],
|
|
44
|
+
"ClassBody": ["body"],
|
|
45
|
+
"ClassDeclaration": [
|
|
46
|
+
"id",
|
|
47
|
+
"superClass",
|
|
48
|
+
"body"
|
|
49
|
+
],
|
|
50
|
+
"ClassExpression": [
|
|
51
|
+
"id",
|
|
52
|
+
"superClass",
|
|
53
|
+
"body"
|
|
54
|
+
],
|
|
55
|
+
"ConditionalExpression": [
|
|
56
|
+
"test",
|
|
57
|
+
"consequent",
|
|
58
|
+
"alternate"
|
|
59
|
+
],
|
|
60
|
+
"ContinueStatement": ["label"],
|
|
61
|
+
"DebuggerStatement": [],
|
|
62
|
+
"DoWhileStatement": ["body", "test"],
|
|
63
|
+
"EmptyStatement": [],
|
|
64
|
+
"ExportAllDeclaration": ["exported", "source"],
|
|
65
|
+
"ExportDefaultDeclaration": ["declaration"],
|
|
66
|
+
"ExportNamedDeclaration": [
|
|
67
|
+
"declaration",
|
|
68
|
+
"specifiers",
|
|
69
|
+
"source"
|
|
70
|
+
],
|
|
71
|
+
"ExportSpecifier": ["exported", "local"],
|
|
72
|
+
"ExpressionStatement": ["expression"],
|
|
73
|
+
"ExperimentalRestProperty": ["argument"],
|
|
74
|
+
"ExperimentalSpreadProperty": ["argument"],
|
|
75
|
+
"ForStatement": [
|
|
76
|
+
"init",
|
|
77
|
+
"test",
|
|
78
|
+
"update",
|
|
79
|
+
"body"
|
|
80
|
+
],
|
|
81
|
+
"ForInStatement": [
|
|
82
|
+
"left",
|
|
83
|
+
"right",
|
|
84
|
+
"body"
|
|
85
|
+
],
|
|
86
|
+
"ForOfStatement": [
|
|
87
|
+
"left",
|
|
88
|
+
"right",
|
|
89
|
+
"body"
|
|
90
|
+
],
|
|
91
|
+
"FunctionDeclaration": [
|
|
92
|
+
"id",
|
|
93
|
+
"params",
|
|
94
|
+
"body"
|
|
95
|
+
],
|
|
96
|
+
"FunctionExpression": [
|
|
97
|
+
"id",
|
|
98
|
+
"params",
|
|
99
|
+
"body"
|
|
100
|
+
],
|
|
101
|
+
"Identifier": [],
|
|
102
|
+
"IfStatement": [
|
|
103
|
+
"test",
|
|
104
|
+
"consequent",
|
|
105
|
+
"alternate"
|
|
106
|
+
],
|
|
107
|
+
"ImportDeclaration": ["specifiers", "source"],
|
|
108
|
+
"ImportDefaultSpecifier": ["local"],
|
|
109
|
+
"ImportExpression": ["source"],
|
|
110
|
+
"ImportNamespaceSpecifier": ["local"],
|
|
111
|
+
"ImportSpecifier": ["imported", "local"],
|
|
112
|
+
"JSXAttribute": ["name", "value"],
|
|
113
|
+
"JSXClosingElement": ["name"],
|
|
114
|
+
"JSXElement": [
|
|
115
|
+
"openingElement",
|
|
116
|
+
"children",
|
|
117
|
+
"closingElement"
|
|
118
|
+
],
|
|
119
|
+
"JSXEmptyExpression": [],
|
|
120
|
+
"JSXExpressionContainer": ["expression"],
|
|
121
|
+
"JSXIdentifier": [],
|
|
122
|
+
"JSXMemberExpression": ["object", "property"],
|
|
123
|
+
"JSXNamespacedName": ["namespace", "name"],
|
|
124
|
+
"JSXOpeningElement": ["name", "attributes"],
|
|
125
|
+
"JSXSpreadAttribute": ["argument"],
|
|
126
|
+
"JSXText": [],
|
|
127
|
+
"JSXFragment": [
|
|
128
|
+
"openingFragment",
|
|
129
|
+
"children",
|
|
130
|
+
"closingFragment"
|
|
131
|
+
],
|
|
132
|
+
"Literal": [],
|
|
133
|
+
"LabeledStatement": ["label", "body"],
|
|
134
|
+
"LogicalExpression": ["left", "right"],
|
|
135
|
+
"MemberExpression": ["object", "property"],
|
|
136
|
+
"MetaProperty": ["meta", "property"],
|
|
137
|
+
"MethodDefinition": ["key", "value"],
|
|
138
|
+
"NewExpression": ["callee", "arguments"],
|
|
139
|
+
"ObjectExpression": ["properties"],
|
|
140
|
+
"ObjectPattern": ["properties"],
|
|
141
|
+
"PrivateIdentifier": [],
|
|
142
|
+
"Program": ["body"],
|
|
143
|
+
"Property": ["key", "value"],
|
|
144
|
+
"PropertyDefinition": ["key", "value"],
|
|
145
|
+
"RestElement": ["argument"],
|
|
146
|
+
"ReturnStatement": ["argument"],
|
|
147
|
+
"SequenceExpression": ["expressions"],
|
|
148
|
+
"SpreadElement": ["argument"],
|
|
149
|
+
"Super": [],
|
|
150
|
+
"SwitchStatement": ["discriminant", "cases"],
|
|
151
|
+
"SwitchCase": ["test", "consequent"],
|
|
152
|
+
"TaggedTemplateExpression": ["tag", "quasi"],
|
|
153
|
+
"TemplateElement": [],
|
|
154
|
+
"TemplateLiteral": ["quasis", "expressions"],
|
|
155
|
+
"ThisExpression": [],
|
|
156
|
+
"ThrowStatement": ["argument"],
|
|
157
|
+
"TryStatement": [
|
|
158
|
+
"block",
|
|
159
|
+
"handler",
|
|
160
|
+
"finalizer"
|
|
161
|
+
],
|
|
162
|
+
"UnaryExpression": ["argument"],
|
|
163
|
+
"UpdateExpression": ["argument"],
|
|
164
|
+
"VariableDeclaration": ["declarations"],
|
|
165
|
+
"VariableDeclarator": ["id", "init"],
|
|
166
|
+
"WhileStatement": ["test", "body"],
|
|
167
|
+
"WithStatement": ["object", "body"],
|
|
168
|
+
"YieldExpression": ["argument"]
|
|
169
|
+
};
|
|
170
|
+
}) });
|
|
171
|
+
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region ../../node_modules/.pnpm/eslint-visitor-keys@2.1.0/node_modules/eslint-visitor-keys/lib/index.js
|
|
174
|
+
var require_lib = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/eslint-visitor-keys@2.1.0/node_modules/eslint-visitor-keys/lib/index.js": ((exports, module) => {
|
|
175
|
+
const KEYS = require_visitor_keys();
|
|
176
|
+
const NODE_TYPES = Object.freeze(Object.keys(KEYS));
|
|
177
|
+
for (const type of NODE_TYPES) Object.freeze(KEYS[type]);
|
|
178
|
+
Object.freeze(KEYS);
|
|
179
|
+
const KEY_BLACKLIST = new Set([
|
|
180
|
+
"parent",
|
|
181
|
+
"leadingComments",
|
|
182
|
+
"trailingComments"
|
|
183
|
+
]);
|
|
184
|
+
/**
|
|
185
|
+
* Check whether a given key should be used or not.
|
|
186
|
+
* @param {string} key The key to check.
|
|
187
|
+
* @returns {boolean} `true` if the key should be used.
|
|
188
|
+
*/
|
|
189
|
+
function filterKey(key) {
|
|
190
|
+
return !KEY_BLACKLIST.has(key) && key[0] !== "_";
|
|
191
|
+
}
|
|
192
|
+
module.exports = Object.freeze({
|
|
193
|
+
KEYS,
|
|
194
|
+
getKeys(node) {
|
|
195
|
+
return Object.keys(node).filter(filterKey);
|
|
196
|
+
},
|
|
197
|
+
unionWith(additionalKeys) {
|
|
198
|
+
const retv = Object.assign({}, KEYS);
|
|
199
|
+
for (const type of Object.keys(additionalKeys)) if (retv.hasOwnProperty(type)) {
|
|
200
|
+
const keys = new Set(additionalKeys[type]);
|
|
201
|
+
for (const key of retv[type]) keys.add(key);
|
|
202
|
+
retv[type] = Object.freeze(Array.from(keys));
|
|
203
|
+
} else retv[type] = Object.freeze(Array.from(additionalKeys[type]));
|
|
204
|
+
return Object.freeze(retv);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}) });
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region ../../node_modules/.pnpm/eslint-utils@3.0.0_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-utils/index.mjs
|
|
211
|
+
var import_lib = /* @__PURE__ */ __toESM(require_lib(), 1);
|
|
212
|
+
/**
|
|
213
|
+
* Get the innermost scope which contains a given location.
|
|
214
|
+
* @param {Scope} initialScope The initial scope to search.
|
|
215
|
+
* @param {Node} node The location to search.
|
|
216
|
+
* @returns {Scope} The innermost scope.
|
|
217
|
+
*/
|
|
218
|
+
function getInnermostScope(initialScope, node) {
|
|
219
|
+
const location = node.range[0];
|
|
220
|
+
let scope = initialScope;
|
|
221
|
+
let found = false;
|
|
222
|
+
do {
|
|
223
|
+
found = false;
|
|
224
|
+
for (const childScope of scope.childScopes) {
|
|
225
|
+
const range = childScope.block.range;
|
|
226
|
+
if (range[0] <= location && location < range[1]) {
|
|
227
|
+
scope = childScope;
|
|
228
|
+
found = true;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} while (found);
|
|
233
|
+
return scope;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Find the variable of a given name.
|
|
237
|
+
* @param {Scope} initialScope The scope to start finding.
|
|
238
|
+
* @param {string|Node} nameOrNode The variable name to find. If this is a Node object then it should be an Identifier node.
|
|
239
|
+
* @returns {Variable|null} The found variable or null.
|
|
240
|
+
*/
|
|
241
|
+
function findVariable(initialScope, nameOrNode) {
|
|
242
|
+
let name = "";
|
|
243
|
+
let scope = initialScope;
|
|
244
|
+
if (typeof nameOrNode === "string") name = nameOrNode;
|
|
245
|
+
else {
|
|
246
|
+
name = nameOrNode.name;
|
|
247
|
+
scope = getInnermostScope(scope, nameOrNode);
|
|
248
|
+
}
|
|
249
|
+
while (scope != null) {
|
|
250
|
+
const variable = scope.set.get(name);
|
|
251
|
+
if (variable != null) return variable;
|
|
252
|
+
scope = scope.upper;
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Negate the result of `this` calling.
|
|
258
|
+
* @param {Token} token The token to check.
|
|
259
|
+
* @returns {boolean} `true` if the result of `this(token)` is `false`.
|
|
260
|
+
*/
|
|
261
|
+
function negate0(token) {
|
|
262
|
+
return !this(token);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Creates the negate function of the given function.
|
|
266
|
+
* @param {function(Token):boolean} f - The function to negate.
|
|
267
|
+
* @returns {function(Token):boolean} Negated function.
|
|
268
|
+
*/
|
|
269
|
+
function negate(f) {
|
|
270
|
+
return negate0.bind(f);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Checks if the given token is a PunctuatorToken with the given value
|
|
274
|
+
* @param {Token} token - The token to check.
|
|
275
|
+
* @param {string} value - The value to check.
|
|
276
|
+
* @returns {boolean} `true` if the token is a PunctuatorToken with the given value.
|
|
277
|
+
*/
|
|
278
|
+
function isPunctuatorTokenWithValue(token, value) {
|
|
279
|
+
return token.type === "Punctuator" && token.value === value;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Checks if the given token is an arrow token or not.
|
|
283
|
+
* @param {Token} token - The token to check.
|
|
284
|
+
* @returns {boolean} `true` if the token is an arrow token.
|
|
285
|
+
*/
|
|
286
|
+
function isArrowToken(token) {
|
|
287
|
+
return isPunctuatorTokenWithValue(token, "=>");
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Checks if the given token is a comma token or not.
|
|
291
|
+
* @param {Token} token - The token to check.
|
|
292
|
+
* @returns {boolean} `true` if the token is a comma token.
|
|
293
|
+
*/
|
|
294
|
+
function isCommaToken(token) {
|
|
295
|
+
return isPunctuatorTokenWithValue(token, ",");
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Checks if the given token is a semicolon token or not.
|
|
299
|
+
* @param {Token} token - The token to check.
|
|
300
|
+
* @returns {boolean} `true` if the token is a semicolon token.
|
|
301
|
+
*/
|
|
302
|
+
function isSemicolonToken(token) {
|
|
303
|
+
return isPunctuatorTokenWithValue(token, ";");
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Checks if the given token is a colon token or not.
|
|
307
|
+
* @param {Token} token - The token to check.
|
|
308
|
+
* @returns {boolean} `true` if the token is a colon token.
|
|
309
|
+
*/
|
|
310
|
+
function isColonToken(token) {
|
|
311
|
+
return isPunctuatorTokenWithValue(token, ":");
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Checks if the given token is an opening parenthesis token or not.
|
|
315
|
+
* @param {Token} token - The token to check.
|
|
316
|
+
* @returns {boolean} `true` if the token is an opening parenthesis token.
|
|
317
|
+
*/
|
|
318
|
+
function isOpeningParenToken(token) {
|
|
319
|
+
return isPunctuatorTokenWithValue(token, "(");
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Checks if the given token is a closing parenthesis token or not.
|
|
323
|
+
* @param {Token} token - The token to check.
|
|
324
|
+
* @returns {boolean} `true` if the token is a closing parenthesis token.
|
|
325
|
+
*/
|
|
326
|
+
function isClosingParenToken(token) {
|
|
327
|
+
return isPunctuatorTokenWithValue(token, ")");
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Checks if the given token is an opening square bracket token or not.
|
|
331
|
+
* @param {Token} token - The token to check.
|
|
332
|
+
* @returns {boolean} `true` if the token is an opening square bracket token.
|
|
333
|
+
*/
|
|
334
|
+
function isOpeningBracketToken(token) {
|
|
335
|
+
return isPunctuatorTokenWithValue(token, "[");
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Checks if the given token is a closing square bracket token or not.
|
|
339
|
+
* @param {Token} token - The token to check.
|
|
340
|
+
* @returns {boolean} `true` if the token is a closing square bracket token.
|
|
341
|
+
*/
|
|
342
|
+
function isClosingBracketToken(token) {
|
|
343
|
+
return isPunctuatorTokenWithValue(token, "]");
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Checks if the given token is an opening brace token or not.
|
|
347
|
+
* @param {Token} token - The token to check.
|
|
348
|
+
* @returns {boolean} `true` if the token is an opening brace token.
|
|
349
|
+
*/
|
|
350
|
+
function isOpeningBraceToken(token) {
|
|
351
|
+
return isPunctuatorTokenWithValue(token, "{");
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Checks if the given token is a closing brace token or not.
|
|
355
|
+
* @param {Token} token - The token to check.
|
|
356
|
+
* @returns {boolean} `true` if the token is a closing brace token.
|
|
357
|
+
*/
|
|
358
|
+
function isClosingBraceToken(token) {
|
|
359
|
+
return isPunctuatorTokenWithValue(token, "}");
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Checks if the given token is a comment token or not.
|
|
363
|
+
* @param {Token} token - The token to check.
|
|
364
|
+
* @returns {boolean} `true` if the token is a comment token.
|
|
365
|
+
*/
|
|
366
|
+
function isCommentToken(token) {
|
|
367
|
+
return [
|
|
368
|
+
"Block",
|
|
369
|
+
"Line",
|
|
370
|
+
"Shebang"
|
|
371
|
+
].includes(token.type);
|
|
372
|
+
}
|
|
373
|
+
const isNotArrowToken = negate(isArrowToken);
|
|
374
|
+
const isNotCommaToken = negate(isCommaToken);
|
|
375
|
+
const isNotSemicolonToken = negate(isSemicolonToken);
|
|
376
|
+
const isNotColonToken = negate(isColonToken);
|
|
377
|
+
const isNotOpeningParenToken = negate(isOpeningParenToken);
|
|
378
|
+
const isNotClosingParenToken = negate(isClosingParenToken);
|
|
379
|
+
const isNotOpeningBracketToken = negate(isOpeningBracketToken);
|
|
380
|
+
const isNotClosingBracketToken = negate(isClosingBracketToken);
|
|
381
|
+
const isNotOpeningBraceToken = negate(isOpeningBraceToken);
|
|
382
|
+
const isNotClosingBraceToken = negate(isClosingBraceToken);
|
|
383
|
+
const isNotCommentToken = negate(isCommentToken);
|
|
384
|
+
const globalObject = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {};
|
|
385
|
+
const builtinNames = Object.freeze(new Set([
|
|
386
|
+
"Array",
|
|
387
|
+
"ArrayBuffer",
|
|
388
|
+
"BigInt",
|
|
389
|
+
"BigInt64Array",
|
|
390
|
+
"BigUint64Array",
|
|
391
|
+
"Boolean",
|
|
392
|
+
"DataView",
|
|
393
|
+
"Date",
|
|
394
|
+
"decodeURI",
|
|
395
|
+
"decodeURIComponent",
|
|
396
|
+
"encodeURI",
|
|
397
|
+
"encodeURIComponent",
|
|
398
|
+
"escape",
|
|
399
|
+
"Float32Array",
|
|
400
|
+
"Float64Array",
|
|
401
|
+
"Function",
|
|
402
|
+
"Infinity",
|
|
403
|
+
"Int16Array",
|
|
404
|
+
"Int32Array",
|
|
405
|
+
"Int8Array",
|
|
406
|
+
"isFinite",
|
|
407
|
+
"isNaN",
|
|
408
|
+
"isPrototypeOf",
|
|
409
|
+
"JSON",
|
|
410
|
+
"Map",
|
|
411
|
+
"Math",
|
|
412
|
+
"NaN",
|
|
413
|
+
"Number",
|
|
414
|
+
"Object",
|
|
415
|
+
"parseFloat",
|
|
416
|
+
"parseInt",
|
|
417
|
+
"Promise",
|
|
418
|
+
"Proxy",
|
|
419
|
+
"Reflect",
|
|
420
|
+
"RegExp",
|
|
421
|
+
"Set",
|
|
422
|
+
"String",
|
|
423
|
+
"Symbol",
|
|
424
|
+
"Uint16Array",
|
|
425
|
+
"Uint32Array",
|
|
426
|
+
"Uint8Array",
|
|
427
|
+
"Uint8ClampedArray",
|
|
428
|
+
"undefined",
|
|
429
|
+
"unescape",
|
|
430
|
+
"WeakMap",
|
|
431
|
+
"WeakSet"
|
|
432
|
+
]));
|
|
433
|
+
const callAllowed = new Set([
|
|
434
|
+
Array.isArray,
|
|
435
|
+
typeof BigInt === "function" ? BigInt : void 0,
|
|
436
|
+
Boolean,
|
|
437
|
+
Date,
|
|
438
|
+
Date.parse,
|
|
439
|
+
decodeURI,
|
|
440
|
+
decodeURIComponent,
|
|
441
|
+
encodeURI,
|
|
442
|
+
encodeURIComponent,
|
|
443
|
+
escape,
|
|
444
|
+
isFinite,
|
|
445
|
+
isNaN,
|
|
446
|
+
isPrototypeOf,
|
|
447
|
+
...Object.getOwnPropertyNames(Math).map((k) => Math[k]).filter((f) => typeof f === "function"),
|
|
448
|
+
Number,
|
|
449
|
+
Number.isFinite,
|
|
450
|
+
Number.isNaN,
|
|
451
|
+
Number.parseFloat,
|
|
452
|
+
Number.parseInt,
|
|
453
|
+
Object,
|
|
454
|
+
Object.entries,
|
|
455
|
+
Object.is,
|
|
456
|
+
Object.isExtensible,
|
|
457
|
+
Object.isFrozen,
|
|
458
|
+
Object.isSealed,
|
|
459
|
+
Object.keys,
|
|
460
|
+
Object.values,
|
|
461
|
+
parseFloat,
|
|
462
|
+
parseInt,
|
|
463
|
+
RegExp,
|
|
464
|
+
String,
|
|
465
|
+
String.fromCharCode,
|
|
466
|
+
String.fromCodePoint,
|
|
467
|
+
String.raw,
|
|
468
|
+
Symbol.for,
|
|
469
|
+
Symbol.keyFor,
|
|
470
|
+
unescape
|
|
471
|
+
].filter((f) => typeof f === "function"));
|
|
472
|
+
const callPassThrough = new Set([
|
|
473
|
+
Object.freeze,
|
|
474
|
+
Object.preventExtensions,
|
|
475
|
+
Object.seal
|
|
476
|
+
]);
|
|
477
|
+
/**
|
|
478
|
+
* Get the property descriptor.
|
|
479
|
+
* @param {object} object The object to get.
|
|
480
|
+
* @param {string|number|symbol} name The property name to get.
|
|
481
|
+
*/
|
|
482
|
+
function getPropertyDescriptor(object, name) {
|
|
483
|
+
let x = object;
|
|
484
|
+
while ((typeof x === "object" || typeof x === "function") && x !== null) {
|
|
485
|
+
const d = Object.getOwnPropertyDescriptor(x, name);
|
|
486
|
+
if (d) return d;
|
|
487
|
+
x = Object.getPrototypeOf(x);
|
|
488
|
+
}
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Check if a property is getter or not.
|
|
493
|
+
* @param {object} object The object to check.
|
|
494
|
+
* @param {string|number|symbol} name The property name to check.
|
|
495
|
+
*/
|
|
496
|
+
function isGetter(object, name) {
|
|
497
|
+
const d = getPropertyDescriptor(object, name);
|
|
498
|
+
return d != null && d.get != null;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Get the element values of a given node list.
|
|
502
|
+
* @param {Node[]} nodeList The node list to get values.
|
|
503
|
+
* @param {Scope|undefined} initialScope The initial scope to find variables.
|
|
504
|
+
* @returns {any[]|null} The value list if all nodes are constant. Otherwise, null.
|
|
505
|
+
*/
|
|
506
|
+
function getElementValues(nodeList, initialScope) {
|
|
507
|
+
const valueList = [];
|
|
508
|
+
for (let i = 0; i < nodeList.length; ++i) {
|
|
509
|
+
const elementNode = nodeList[i];
|
|
510
|
+
if (elementNode == null) valueList.length = i + 1;
|
|
511
|
+
else if (elementNode.type === "SpreadElement") {
|
|
512
|
+
const argument = getStaticValueR(elementNode.argument, initialScope);
|
|
513
|
+
if (argument == null) return null;
|
|
514
|
+
valueList.push(...argument.value);
|
|
515
|
+
} else {
|
|
516
|
+
const element = getStaticValueR(elementNode, initialScope);
|
|
517
|
+
if (element == null) return null;
|
|
518
|
+
valueList.push(element.value);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return valueList;
|
|
522
|
+
}
|
|
523
|
+
const operations = Object.freeze({
|
|
524
|
+
ArrayExpression(node, initialScope) {
|
|
525
|
+
const elements = getElementValues(node.elements, initialScope);
|
|
526
|
+
return elements != null ? { value: elements } : null;
|
|
527
|
+
},
|
|
528
|
+
AssignmentExpression(node, initialScope) {
|
|
529
|
+
if (node.operator === "=") return getStaticValueR(node.right, initialScope);
|
|
530
|
+
return null;
|
|
531
|
+
},
|
|
532
|
+
BinaryExpression(node, initialScope) {
|
|
533
|
+
if (node.operator === "in" || node.operator === "instanceof") return null;
|
|
534
|
+
const left = getStaticValueR(node.left, initialScope);
|
|
535
|
+
const right = getStaticValueR(node.right, initialScope);
|
|
536
|
+
if (left != null && right != null) switch (node.operator) {
|
|
537
|
+
case "==": return { value: left.value == right.value };
|
|
538
|
+
case "!=": return { value: left.value != right.value };
|
|
539
|
+
case "===": return { value: left.value === right.value };
|
|
540
|
+
case "!==": return { value: left.value !== right.value };
|
|
541
|
+
case "<": return { value: left.value < right.value };
|
|
542
|
+
case "<=": return { value: left.value <= right.value };
|
|
543
|
+
case ">": return { value: left.value > right.value };
|
|
544
|
+
case ">=": return { value: left.value >= right.value };
|
|
545
|
+
case "<<": return { value: left.value << right.value };
|
|
546
|
+
case ">>": return { value: left.value >> right.value };
|
|
547
|
+
case ">>>": return { value: left.value >>> right.value };
|
|
548
|
+
case "+": return { value: left.value + right.value };
|
|
549
|
+
case "-": return { value: left.value - right.value };
|
|
550
|
+
case "*": return { value: left.value * right.value };
|
|
551
|
+
case "/": return { value: left.value / right.value };
|
|
552
|
+
case "%": return { value: left.value % right.value };
|
|
553
|
+
case "**": return { value: Math.pow(left.value, right.value) };
|
|
554
|
+
case "|": return { value: left.value | right.value };
|
|
555
|
+
case "^": return { value: left.value ^ right.value };
|
|
556
|
+
case "&": return { value: left.value & right.value };
|
|
557
|
+
}
|
|
558
|
+
return null;
|
|
559
|
+
},
|
|
560
|
+
CallExpression(node, initialScope) {
|
|
561
|
+
const calleeNode = node.callee;
|
|
562
|
+
const args = getElementValues(node.arguments, initialScope);
|
|
563
|
+
if (args != null) if (calleeNode.type === "MemberExpression") {
|
|
564
|
+
if (calleeNode.property.type === "PrivateIdentifier") return null;
|
|
565
|
+
const object = getStaticValueR(calleeNode.object, initialScope);
|
|
566
|
+
if (object != null) {
|
|
567
|
+
if (object.value == null && (object.optional || node.optional)) return {
|
|
568
|
+
value: void 0,
|
|
569
|
+
optional: true
|
|
570
|
+
};
|
|
571
|
+
const property = getStaticPropertyNameValue(calleeNode, initialScope);
|
|
572
|
+
if (property != null) {
|
|
573
|
+
const receiver = object.value;
|
|
574
|
+
const methodName = property.value;
|
|
575
|
+
if (callAllowed.has(receiver[methodName])) return { value: receiver[methodName](...args) };
|
|
576
|
+
if (callPassThrough.has(receiver[methodName])) return { value: args[0] };
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
} else {
|
|
580
|
+
const callee = getStaticValueR(calleeNode, initialScope);
|
|
581
|
+
if (callee != null) {
|
|
582
|
+
if (callee.value == null && node.optional) return {
|
|
583
|
+
value: void 0,
|
|
584
|
+
optional: true
|
|
585
|
+
};
|
|
586
|
+
const func = callee.value;
|
|
587
|
+
if (callAllowed.has(func)) return { value: func(...args) };
|
|
588
|
+
if (callPassThrough.has(func)) return { value: args[0] };
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return null;
|
|
592
|
+
},
|
|
593
|
+
ConditionalExpression(node, initialScope) {
|
|
594
|
+
const test = getStaticValueR(node.test, initialScope);
|
|
595
|
+
if (test != null) return test.value ? getStaticValueR(node.consequent, initialScope) : getStaticValueR(node.alternate, initialScope);
|
|
596
|
+
return null;
|
|
597
|
+
},
|
|
598
|
+
ExpressionStatement(node, initialScope) {
|
|
599
|
+
return getStaticValueR(node.expression, initialScope);
|
|
600
|
+
},
|
|
601
|
+
Identifier(node, initialScope) {
|
|
602
|
+
if (initialScope != null) {
|
|
603
|
+
const variable = findVariable(initialScope, node);
|
|
604
|
+
if (variable != null && variable.defs.length === 0 && builtinNames.has(variable.name) && variable.name in globalObject) return { value: globalObject[variable.name] };
|
|
605
|
+
if (variable != null && variable.defs.length === 1) {
|
|
606
|
+
const def = variable.defs[0];
|
|
607
|
+
if (def.parent && def.parent.kind === "const" && def.node.id.type === "Identifier") return getStaticValueR(def.node.init, initialScope);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return null;
|
|
611
|
+
},
|
|
612
|
+
Literal(node) {
|
|
613
|
+
//istanbul ignore if : this is implementation-specific behavior.
|
|
614
|
+
if ((node.regex != null || node.bigint != null) && node.value == null) return null;
|
|
615
|
+
return { value: node.value };
|
|
616
|
+
},
|
|
617
|
+
LogicalExpression(node, initialScope) {
|
|
618
|
+
const left = getStaticValueR(node.left, initialScope);
|
|
619
|
+
if (left != null) {
|
|
620
|
+
if (node.operator === "||" && Boolean(left.value) === true || node.operator === "&&" && Boolean(left.value) === false || node.operator === "??" && left.value != null) return left;
|
|
621
|
+
const right = getStaticValueR(node.right, initialScope);
|
|
622
|
+
if (right != null) return right;
|
|
623
|
+
}
|
|
624
|
+
return null;
|
|
625
|
+
},
|
|
626
|
+
MemberExpression(node, initialScope) {
|
|
627
|
+
if (node.property.type === "PrivateIdentifier") return null;
|
|
628
|
+
const object = getStaticValueR(node.object, initialScope);
|
|
629
|
+
if (object != null) {
|
|
630
|
+
if (object.value == null && (object.optional || node.optional)) return {
|
|
631
|
+
value: void 0,
|
|
632
|
+
optional: true
|
|
633
|
+
};
|
|
634
|
+
const property = getStaticPropertyNameValue(node, initialScope);
|
|
635
|
+
if (property != null && !isGetter(object.value, property.value)) return { value: object.value[property.value] };
|
|
636
|
+
}
|
|
637
|
+
return null;
|
|
638
|
+
},
|
|
639
|
+
ChainExpression(node, initialScope) {
|
|
640
|
+
const expression = getStaticValueR(node.expression, initialScope);
|
|
641
|
+
if (expression != null) return { value: expression.value };
|
|
642
|
+
return null;
|
|
643
|
+
},
|
|
644
|
+
NewExpression(node, initialScope) {
|
|
645
|
+
const callee = getStaticValueR(node.callee, initialScope);
|
|
646
|
+
const args = getElementValues(node.arguments, initialScope);
|
|
647
|
+
if (callee != null && args != null) {
|
|
648
|
+
const Func = callee.value;
|
|
649
|
+
if (callAllowed.has(Func)) return { value: new Func(...args) };
|
|
650
|
+
}
|
|
651
|
+
return null;
|
|
652
|
+
},
|
|
653
|
+
ObjectExpression(node, initialScope) {
|
|
654
|
+
const object = {};
|
|
655
|
+
for (const propertyNode of node.properties) if (propertyNode.type === "Property") {
|
|
656
|
+
if (propertyNode.kind !== "init") return null;
|
|
657
|
+
const key = getStaticPropertyNameValue(propertyNode, initialScope);
|
|
658
|
+
const value = getStaticValueR(propertyNode.value, initialScope);
|
|
659
|
+
if (key == null || value == null) return null;
|
|
660
|
+
object[key.value] = value.value;
|
|
661
|
+
} else if (propertyNode.type === "SpreadElement" || propertyNode.type === "ExperimentalSpreadProperty") {
|
|
662
|
+
const argument = getStaticValueR(propertyNode.argument, initialScope);
|
|
663
|
+
if (argument == null) return null;
|
|
664
|
+
Object.assign(object, argument.value);
|
|
665
|
+
} else return null;
|
|
666
|
+
return { value: object };
|
|
667
|
+
},
|
|
668
|
+
SequenceExpression(node, initialScope) {
|
|
669
|
+
const last = node.expressions[node.expressions.length - 1];
|
|
670
|
+
return getStaticValueR(last, initialScope);
|
|
671
|
+
},
|
|
672
|
+
TaggedTemplateExpression(node, initialScope) {
|
|
673
|
+
const tag = getStaticValueR(node.tag, initialScope);
|
|
674
|
+
const expressions = getElementValues(node.quasi.expressions, initialScope);
|
|
675
|
+
if (tag != null && expressions != null) {
|
|
676
|
+
const func = tag.value;
|
|
677
|
+
const strings = node.quasi.quasis.map((q) => q.value.cooked);
|
|
678
|
+
strings.raw = node.quasi.quasis.map((q) => q.value.raw);
|
|
679
|
+
if (func === String.raw) return { value: func(strings, ...expressions) };
|
|
680
|
+
}
|
|
681
|
+
return null;
|
|
682
|
+
},
|
|
683
|
+
TemplateLiteral(node, initialScope) {
|
|
684
|
+
const expressions = getElementValues(node.expressions, initialScope);
|
|
685
|
+
if (expressions != null) {
|
|
686
|
+
let value = node.quasis[0].value.cooked;
|
|
687
|
+
for (let i = 0; i < expressions.length; ++i) {
|
|
688
|
+
value += expressions[i];
|
|
689
|
+
value += node.quasis[i + 1].value.cooked;
|
|
690
|
+
}
|
|
691
|
+
return { value };
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
},
|
|
695
|
+
UnaryExpression(node, initialScope) {
|
|
696
|
+
if (node.operator === "delete") return null;
|
|
697
|
+
if (node.operator === "void") return { value: void 0 };
|
|
698
|
+
const arg = getStaticValueR(node.argument, initialScope);
|
|
699
|
+
if (arg != null) switch (node.operator) {
|
|
700
|
+
case "-": return { value: -arg.value };
|
|
701
|
+
case "+": return { value: +arg.value };
|
|
702
|
+
case "!": return { value: !arg.value };
|
|
703
|
+
case "~": return { value: ~arg.value };
|
|
704
|
+
case "typeof": return { value: typeof arg.value };
|
|
705
|
+
}
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
/**
|
|
710
|
+
* Get the value of a given node if it's a static value.
|
|
711
|
+
* @param {Node} node The node to get.
|
|
712
|
+
* @param {Scope|undefined} initialScope The scope to start finding variable.
|
|
713
|
+
* @returns {{value:any}|{value:undefined,optional?:true}|null} The static value of the node, or `null`.
|
|
714
|
+
*/
|
|
715
|
+
function getStaticValueR(node, initialScope) {
|
|
716
|
+
if (node != null && Object.hasOwnProperty.call(operations, node.type)) return operations[node.type](node, initialScope);
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Get the static value of property name from a MemberExpression node or a Property node.
|
|
721
|
+
* @param {Node} node The node to get.
|
|
722
|
+
* @param {Scope} [initialScope] The scope to start finding variable. Optional. If the node is a computed property node and this scope was given, this checks the computed property name by the `getStringIfConstant` function with the scope, and returns the value of it.
|
|
723
|
+
* @returns {{value:any}|{value:undefined,optional?:true}|null} The static value of the property name of the node, or `null`.
|
|
724
|
+
*/
|
|
725
|
+
function getStaticPropertyNameValue(node, initialScope) {
|
|
726
|
+
const nameNode = node.type === "Property" ? node.key : node.property;
|
|
727
|
+
if (node.computed) return getStaticValueR(nameNode, initialScope);
|
|
728
|
+
if (nameNode.type === "Identifier") return { value: nameNode.name };
|
|
729
|
+
if (nameNode.type === "Literal") {
|
|
730
|
+
if (nameNode.bigint) return { value: nameNode.bigint };
|
|
731
|
+
return { value: String(nameNode.value) };
|
|
732
|
+
}
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Get the value of a given node if it's a static value.
|
|
737
|
+
* @param {Node} node The node to get.
|
|
738
|
+
* @param {Scope} [initialScope] The scope to start finding variable. Optional. If this scope was given, this tries to resolve identifier references which are in the given node as much as possible.
|
|
739
|
+
* @returns {{value:any}|{value:undefined,optional?:true}|null} The static value of the node, or `null`.
|
|
740
|
+
*/
|
|
741
|
+
function getStaticValue(node, initialScope = null) {
|
|
742
|
+
try {
|
|
743
|
+
return getStaticValueR(node, initialScope);
|
|
744
|
+
} catch (_error) {
|
|
745
|
+
return null;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Get the value of a given node if it's a literal or a template literal.
|
|
750
|
+
* @param {Node} node The node to get.
|
|
751
|
+
* @param {Scope} [initialScope] The scope to start finding variable. Optional. If the node is an Identifier node and this scope was given, this checks the variable of the identifier, and returns the value of it if the variable is a constant.
|
|
752
|
+
* @returns {string|null} The value of the node, or `null`.
|
|
753
|
+
*/
|
|
754
|
+
function getStringIfConstant(node, initialScope = null) {
|
|
755
|
+
if (node && node.type === "Literal" && node.value === null) {
|
|
756
|
+
if (node.regex) return `/${node.regex.pattern}/${node.regex.flags}`;
|
|
757
|
+
if (node.bigint) return node.bigint;
|
|
758
|
+
}
|
|
759
|
+
const evaluated = getStaticValue(node, initialScope);
|
|
760
|
+
return evaluated && String(evaluated.value);
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Get the property name from a MemberExpression node or a Property node.
|
|
764
|
+
* @param {Node} node The node to get.
|
|
765
|
+
* @param {Scope} [initialScope] The scope to start finding variable. Optional. If the node is a computed property node and this scope was given, this checks the computed property name by the `getStringIfConstant` function with the scope, and returns the value of it.
|
|
766
|
+
* @returns {string|null} The property name of the node.
|
|
767
|
+
*/
|
|
768
|
+
function getPropertyName(node, initialScope) {
|
|
769
|
+
switch (node.type) {
|
|
770
|
+
case "MemberExpression":
|
|
771
|
+
if (node.computed) return getStringIfConstant(node.property, initialScope);
|
|
772
|
+
if (node.property.type === "PrivateIdentifier") return null;
|
|
773
|
+
return node.property.name;
|
|
774
|
+
case "Property":
|
|
775
|
+
case "MethodDefinition":
|
|
776
|
+
case "PropertyDefinition":
|
|
777
|
+
if (node.computed) return getStringIfConstant(node.key, initialScope);
|
|
778
|
+
if (node.key.type === "Literal") return String(node.key.value);
|
|
779
|
+
if (node.key.type === "PrivateIdentifier") return null;
|
|
780
|
+
return node.key.name;
|
|
781
|
+
}
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
const typeConversionBinaryOps = Object.freeze(new Set([
|
|
785
|
+
"==",
|
|
786
|
+
"!=",
|
|
787
|
+
"<",
|
|
788
|
+
"<=",
|
|
789
|
+
">",
|
|
790
|
+
">=",
|
|
791
|
+
"<<",
|
|
792
|
+
">>",
|
|
793
|
+
">>>",
|
|
794
|
+
"+",
|
|
795
|
+
"-",
|
|
796
|
+
"*",
|
|
797
|
+
"/",
|
|
798
|
+
"%",
|
|
799
|
+
"|",
|
|
800
|
+
"^",
|
|
801
|
+
"&",
|
|
802
|
+
"in"
|
|
803
|
+
]));
|
|
804
|
+
const typeConversionUnaryOps = Object.freeze(new Set([
|
|
805
|
+
"-",
|
|
806
|
+
"+",
|
|
807
|
+
"!",
|
|
808
|
+
"~"
|
|
809
|
+
]));
|
|
810
|
+
/**
|
|
811
|
+
* Check whether the given value is an ASTNode or not.
|
|
812
|
+
* @param {any} x The value to check.
|
|
813
|
+
* @returns {boolean} `true` if the value is an ASTNode.
|
|
814
|
+
*/
|
|
815
|
+
function isNode(x) {
|
|
816
|
+
return x !== null && typeof x === "object" && typeof x.type === "string";
|
|
817
|
+
}
|
|
818
|
+
const visitor = Object.freeze(Object.assign(Object.create(null), {
|
|
819
|
+
$visit(node, options, visitorKeys) {
|
|
820
|
+
const { type } = node;
|
|
821
|
+
if (typeof this[type] === "function") return this[type](node, options, visitorKeys);
|
|
822
|
+
return this.$visitChildren(node, options, visitorKeys);
|
|
823
|
+
},
|
|
824
|
+
$visitChildren(node, options, visitorKeys) {
|
|
825
|
+
const { type } = node;
|
|
826
|
+
for (const key of visitorKeys[type] || import_lib.default.getKeys(node)) {
|
|
827
|
+
const value = node[key];
|
|
828
|
+
if (Array.isArray(value)) {
|
|
829
|
+
for (const element of value) if (isNode(element) && this.$visit(element, options, visitorKeys)) return true;
|
|
830
|
+
} else if (isNode(value) && this.$visit(value, options, visitorKeys)) return true;
|
|
831
|
+
}
|
|
832
|
+
return false;
|
|
833
|
+
},
|
|
834
|
+
ArrowFunctionExpression() {
|
|
835
|
+
return false;
|
|
836
|
+
},
|
|
837
|
+
AssignmentExpression() {
|
|
838
|
+
return true;
|
|
839
|
+
},
|
|
840
|
+
AwaitExpression() {
|
|
841
|
+
return true;
|
|
842
|
+
},
|
|
843
|
+
BinaryExpression(node, options, visitorKeys) {
|
|
844
|
+
if (options.considerImplicitTypeConversion && typeConversionBinaryOps.has(node.operator) && (node.left.type !== "Literal" || node.right.type !== "Literal")) return true;
|
|
845
|
+
return this.$visitChildren(node, options, visitorKeys);
|
|
846
|
+
},
|
|
847
|
+
CallExpression() {
|
|
848
|
+
return true;
|
|
849
|
+
},
|
|
850
|
+
FunctionExpression() {
|
|
851
|
+
return false;
|
|
852
|
+
},
|
|
853
|
+
ImportExpression() {
|
|
854
|
+
return true;
|
|
855
|
+
},
|
|
856
|
+
MemberExpression(node, options, visitorKeys) {
|
|
857
|
+
if (options.considerGetters) return true;
|
|
858
|
+
if (options.considerImplicitTypeConversion && node.computed && node.property.type !== "Literal") return true;
|
|
859
|
+
return this.$visitChildren(node, options, visitorKeys);
|
|
860
|
+
},
|
|
861
|
+
MethodDefinition(node, options, visitorKeys) {
|
|
862
|
+
if (options.considerImplicitTypeConversion && node.computed && node.key.type !== "Literal") return true;
|
|
863
|
+
return this.$visitChildren(node, options, visitorKeys);
|
|
864
|
+
},
|
|
865
|
+
NewExpression() {
|
|
866
|
+
return true;
|
|
867
|
+
},
|
|
868
|
+
Property(node, options, visitorKeys) {
|
|
869
|
+
if (options.considerImplicitTypeConversion && node.computed && node.key.type !== "Literal") return true;
|
|
870
|
+
return this.$visitChildren(node, options, visitorKeys);
|
|
871
|
+
},
|
|
872
|
+
PropertyDefinition(node, options, visitorKeys) {
|
|
873
|
+
if (options.considerImplicitTypeConversion && node.computed && node.key.type !== "Literal") return true;
|
|
874
|
+
return this.$visitChildren(node, options, visitorKeys);
|
|
875
|
+
},
|
|
876
|
+
UnaryExpression(node, options, visitorKeys) {
|
|
877
|
+
if (node.operator === "delete") return true;
|
|
878
|
+
if (options.considerImplicitTypeConversion && typeConversionUnaryOps.has(node.operator) && node.argument.type !== "Literal") return true;
|
|
879
|
+
return this.$visitChildren(node, options, visitorKeys);
|
|
880
|
+
},
|
|
881
|
+
UpdateExpression() {
|
|
882
|
+
return true;
|
|
883
|
+
},
|
|
884
|
+
YieldExpression() {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
}));
|
|
888
|
+
/**
|
|
889
|
+
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
890
|
+
* See LICENSE file in root directory for full license.
|
|
891
|
+
*/
|
|
892
|
+
const placeholder = /\$(?:[$&`']|[1-9][0-9]?)/gu;
|
|
893
|
+
/** @type {WeakMap<PatternMatcher, {pattern:RegExp,escaped:boolean}>} */
|
|
894
|
+
const internal = /* @__PURE__ */ new WeakMap();
|
|
895
|
+
/**
|
|
896
|
+
* Check whether a given character is escaped or not.
|
|
897
|
+
* @param {string} str The string to check.
|
|
898
|
+
* @param {number} index The location of the character to check.
|
|
899
|
+
* @returns {boolean} `true` if the character is escaped.
|
|
900
|
+
*/
|
|
901
|
+
function isEscaped(str, index) {
|
|
902
|
+
let escaped = false;
|
|
903
|
+
for (let i = index - 1; i >= 0 && str.charCodeAt(i) === 92; --i) escaped = !escaped;
|
|
904
|
+
return escaped;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Replace a given string by a given matcher.
|
|
908
|
+
* @param {PatternMatcher} matcher The pattern matcher.
|
|
909
|
+
* @param {string} str The string to be replaced.
|
|
910
|
+
* @param {string} replacement The new substring to replace each matched part.
|
|
911
|
+
* @returns {string} The replaced string.
|
|
912
|
+
*/
|
|
913
|
+
function replaceS(matcher, str, replacement) {
|
|
914
|
+
const chunks = [];
|
|
915
|
+
let index = 0;
|
|
916
|
+
/** @type {RegExpExecArray} */
|
|
917
|
+
let match = null;
|
|
918
|
+
/**
|
|
919
|
+
* @param {string} key The placeholder.
|
|
920
|
+
* @returns {string} The replaced string.
|
|
921
|
+
*/
|
|
922
|
+
function replacer(key) {
|
|
923
|
+
switch (key) {
|
|
924
|
+
case "$$": return "$";
|
|
925
|
+
case "$&": return match[0];
|
|
926
|
+
case "$`": return str.slice(0, match.index);
|
|
927
|
+
case "$'": return str.slice(match.index + match[0].length);
|
|
928
|
+
default: {
|
|
929
|
+
const i = key.slice(1);
|
|
930
|
+
if (i in match) return match[i];
|
|
931
|
+
return key;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
for (match of matcher.execAll(str)) {
|
|
936
|
+
chunks.push(str.slice(index, match.index));
|
|
937
|
+
chunks.push(replacement.replace(placeholder, replacer));
|
|
938
|
+
index = match.index + match[0].length;
|
|
939
|
+
}
|
|
940
|
+
chunks.push(str.slice(index));
|
|
941
|
+
return chunks.join("");
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Replace a given string by a given matcher.
|
|
945
|
+
* @param {PatternMatcher} matcher The pattern matcher.
|
|
946
|
+
* @param {string} str The string to be replaced.
|
|
947
|
+
* @param {(...strs[])=>string} replace The function to replace each matched part.
|
|
948
|
+
* @returns {string} The replaced string.
|
|
949
|
+
*/
|
|
950
|
+
function replaceF(matcher, str, replace) {
|
|
951
|
+
const chunks = [];
|
|
952
|
+
let index = 0;
|
|
953
|
+
for (const match of matcher.execAll(str)) {
|
|
954
|
+
chunks.push(str.slice(index, match.index));
|
|
955
|
+
chunks.push(String(replace(...match, match.index, match.input)));
|
|
956
|
+
index = match.index + match[0].length;
|
|
957
|
+
}
|
|
958
|
+
chunks.push(str.slice(index));
|
|
959
|
+
return chunks.join("");
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* The class to find patterns as considering escape sequences.
|
|
963
|
+
*/
|
|
964
|
+
var PatternMatcher = class {
|
|
965
|
+
/**
|
|
966
|
+
* Initialize this matcher.
|
|
967
|
+
* @param {RegExp} pattern The pattern to match.
|
|
968
|
+
* @param {{escaped:boolean}} options The options.
|
|
969
|
+
*/
|
|
970
|
+
constructor(pattern, { escaped = false } = {}) {
|
|
971
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("'pattern' should be a RegExp instance.");
|
|
972
|
+
if (!pattern.flags.includes("g")) throw new Error("'pattern' should contains 'g' flag.");
|
|
973
|
+
internal.set(this, {
|
|
974
|
+
pattern: new RegExp(pattern.source, pattern.flags),
|
|
975
|
+
escaped: Boolean(escaped)
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Find the pattern in a given string.
|
|
980
|
+
* @param {string} str The string to find.
|
|
981
|
+
* @returns {IterableIterator<RegExpExecArray>} The iterator which iterate the matched information.
|
|
982
|
+
*/
|
|
983
|
+
*execAll(str) {
|
|
984
|
+
const { pattern, escaped } = internal.get(this);
|
|
985
|
+
let match = null;
|
|
986
|
+
let lastIndex = 0;
|
|
987
|
+
pattern.lastIndex = 0;
|
|
988
|
+
while ((match = pattern.exec(str)) != null) if (escaped || !isEscaped(str, match.index)) {
|
|
989
|
+
lastIndex = pattern.lastIndex;
|
|
990
|
+
yield match;
|
|
991
|
+
pattern.lastIndex = lastIndex;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Check whether the pattern is found in a given string.
|
|
996
|
+
* @param {string} str The string to check.
|
|
997
|
+
* @returns {boolean} `true` if the pattern was found in the string.
|
|
998
|
+
*/
|
|
999
|
+
test(str) {
|
|
1000
|
+
return !this.execAll(str).next().done;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Replace a given string.
|
|
1004
|
+
* @param {string} str The string to be replaced.
|
|
1005
|
+
* @param {(string|((...strs:string[])=>string))} replacer The string or function to replace. This is the same as the 2nd argument of `String.prototype.replace`.
|
|
1006
|
+
* @returns {string} The replaced string.
|
|
1007
|
+
*/
|
|
1008
|
+
[Symbol.replace](str, replacer) {
|
|
1009
|
+
return typeof replacer === "function" ? replaceF(this, String(str), replacer) : replaceS(this, String(str), String(replacer));
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
const IMPORT_TYPE = /^(?:Import|Export(?:All|Default|Named))Declaration$/u;
|
|
1013
|
+
const has = Function.call.bind(Object.hasOwnProperty);
|
|
1014
|
+
const READ = Symbol("read");
|
|
1015
|
+
const CALL = Symbol("call");
|
|
1016
|
+
const CONSTRUCT = Symbol("construct");
|
|
1017
|
+
const ESM = Symbol("esm");
|
|
1018
|
+
const requireCall = { require: { [CALL]: true } };
|
|
1019
|
+
/**
|
|
1020
|
+
* Check whether a given variable is modified or not.
|
|
1021
|
+
* @param {Variable} variable The variable to check.
|
|
1022
|
+
* @returns {boolean} `true` if the variable is modified.
|
|
1023
|
+
*/
|
|
1024
|
+
function isModifiedGlobal(variable) {
|
|
1025
|
+
return variable == null || variable.defs.length !== 0 || variable.references.some((r) => r.isWrite());
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Check if the value of a given node is passed through to the parent syntax as-is.
|
|
1029
|
+
* For example, `a` and `b` in (`a || b` and `c ? a : b`) are passed through.
|
|
1030
|
+
* @param {Node} node A node to check.
|
|
1031
|
+
* @returns {boolean} `true` if the node is passed through.
|
|
1032
|
+
*/
|
|
1033
|
+
function isPassThrough(node) {
|
|
1034
|
+
const parent = node.parent;
|
|
1035
|
+
switch (parent && parent.type) {
|
|
1036
|
+
case "ConditionalExpression": return parent.consequent === node || parent.alternate === node;
|
|
1037
|
+
case "LogicalExpression": return true;
|
|
1038
|
+
case "SequenceExpression": return parent.expressions[parent.expressions.length - 1] === node;
|
|
1039
|
+
case "ChainExpression": return true;
|
|
1040
|
+
default: return false;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* The reference tracker.
|
|
1045
|
+
*/
|
|
1046
|
+
var ReferenceTracker = class {
|
|
1047
|
+
/**
|
|
1048
|
+
* Initialize this tracker.
|
|
1049
|
+
* @param {Scope} globalScope The global scope.
|
|
1050
|
+
* @param {object} [options] The options.
|
|
1051
|
+
* @param {"legacy"|"strict"} [options.mode="strict"] The mode to determine the ImportDeclaration's behavior for CJS modules.
|
|
1052
|
+
* @param {string[]} [options.globalObjectNames=["global","globalThis","self","window"]] The variable names for Global Object.
|
|
1053
|
+
*/
|
|
1054
|
+
constructor(globalScope, { mode = "strict", globalObjectNames = [
|
|
1055
|
+
"global",
|
|
1056
|
+
"globalThis",
|
|
1057
|
+
"self",
|
|
1058
|
+
"window"
|
|
1059
|
+
] } = {}) {
|
|
1060
|
+
this.variableStack = [];
|
|
1061
|
+
this.globalScope = globalScope;
|
|
1062
|
+
this.mode = mode;
|
|
1063
|
+
this.globalObjectNames = globalObjectNames.slice(0);
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Iterate the references of global variables.
|
|
1067
|
+
* @param {object} traceMap The trace map.
|
|
1068
|
+
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
|
|
1069
|
+
*/
|
|
1070
|
+
*iterateGlobalReferences(traceMap) {
|
|
1071
|
+
for (const key of Object.keys(traceMap)) {
|
|
1072
|
+
const nextTraceMap = traceMap[key];
|
|
1073
|
+
const path = [key];
|
|
1074
|
+
const variable = this.globalScope.set.get(key);
|
|
1075
|
+
if (isModifiedGlobal(variable)) continue;
|
|
1076
|
+
yield* this._iterateVariableReferences(variable, path, nextTraceMap, true);
|
|
1077
|
+
}
|
|
1078
|
+
for (const key of this.globalObjectNames) {
|
|
1079
|
+
const path = [];
|
|
1080
|
+
const variable = this.globalScope.set.get(key);
|
|
1081
|
+
if (isModifiedGlobal(variable)) continue;
|
|
1082
|
+
yield* this._iterateVariableReferences(variable, path, traceMap, false);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Iterate the references of CommonJS modules.
|
|
1087
|
+
* @param {object} traceMap The trace map.
|
|
1088
|
+
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
|
|
1089
|
+
*/
|
|
1090
|
+
*iterateCjsReferences(traceMap) {
|
|
1091
|
+
for (const { node } of this.iterateGlobalReferences(requireCall)) {
|
|
1092
|
+
const key = getStringIfConstant(node.arguments[0]);
|
|
1093
|
+
if (key == null || !has(traceMap, key)) continue;
|
|
1094
|
+
const nextTraceMap = traceMap[key];
|
|
1095
|
+
const path = [key];
|
|
1096
|
+
if (nextTraceMap[READ]) yield {
|
|
1097
|
+
node,
|
|
1098
|
+
path,
|
|
1099
|
+
type: READ,
|
|
1100
|
+
info: nextTraceMap[READ]
|
|
1101
|
+
};
|
|
1102
|
+
yield* this._iteratePropertyReferences(node, path, nextTraceMap);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Iterate the references of ES modules.
|
|
1107
|
+
* @param {object} traceMap The trace map.
|
|
1108
|
+
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
|
|
1109
|
+
*/
|
|
1110
|
+
*iterateEsmReferences(traceMap) {
|
|
1111
|
+
const programNode = this.globalScope.block;
|
|
1112
|
+
for (const node of programNode.body) {
|
|
1113
|
+
if (!IMPORT_TYPE.test(node.type) || node.source == null) continue;
|
|
1114
|
+
const moduleId = node.source.value;
|
|
1115
|
+
if (!has(traceMap, moduleId)) continue;
|
|
1116
|
+
const nextTraceMap = traceMap[moduleId];
|
|
1117
|
+
const path = [moduleId];
|
|
1118
|
+
if (nextTraceMap[READ]) yield {
|
|
1119
|
+
node,
|
|
1120
|
+
path,
|
|
1121
|
+
type: READ,
|
|
1122
|
+
info: nextTraceMap[READ]
|
|
1123
|
+
};
|
|
1124
|
+
if (node.type === "ExportAllDeclaration") for (const key of Object.keys(nextTraceMap)) {
|
|
1125
|
+
const exportTraceMap = nextTraceMap[key];
|
|
1126
|
+
if (exportTraceMap[READ]) yield {
|
|
1127
|
+
node,
|
|
1128
|
+
path: path.concat(key),
|
|
1129
|
+
type: READ,
|
|
1130
|
+
info: exportTraceMap[READ]
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
else for (const specifier of node.specifiers) {
|
|
1134
|
+
const esm = has(nextTraceMap, ESM);
|
|
1135
|
+
const it = this._iterateImportReferences(specifier, path, esm ? nextTraceMap : this.mode === "legacy" ? {
|
|
1136
|
+
default: nextTraceMap,
|
|
1137
|
+
...nextTraceMap
|
|
1138
|
+
} : { default: nextTraceMap });
|
|
1139
|
+
if (esm) yield* it;
|
|
1140
|
+
else for (const report of it) {
|
|
1141
|
+
report.path = report.path.filter(exceptDefault);
|
|
1142
|
+
if (report.path.length >= 2 || report.type !== READ) yield report;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Iterate the references for a given variable.
|
|
1149
|
+
* @param {Variable} variable The variable to iterate that references.
|
|
1150
|
+
* @param {string[]} path The current path.
|
|
1151
|
+
* @param {object} traceMap The trace map.
|
|
1152
|
+
* @param {boolean} shouldReport = The flag to report those references.
|
|
1153
|
+
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
|
|
1154
|
+
*/
|
|
1155
|
+
*_iterateVariableReferences(variable, path, traceMap, shouldReport) {
|
|
1156
|
+
if (this.variableStack.includes(variable)) return;
|
|
1157
|
+
this.variableStack.push(variable);
|
|
1158
|
+
try {
|
|
1159
|
+
for (const reference of variable.references) {
|
|
1160
|
+
if (!reference.isRead()) continue;
|
|
1161
|
+
const node = reference.identifier;
|
|
1162
|
+
if (shouldReport && traceMap[READ]) yield {
|
|
1163
|
+
node,
|
|
1164
|
+
path,
|
|
1165
|
+
type: READ,
|
|
1166
|
+
info: traceMap[READ]
|
|
1167
|
+
};
|
|
1168
|
+
yield* this._iteratePropertyReferences(node, path, traceMap);
|
|
1169
|
+
}
|
|
1170
|
+
} finally {
|
|
1171
|
+
this.variableStack.pop();
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Iterate the references for a given AST node.
|
|
1176
|
+
* @param rootNode The AST node to iterate references.
|
|
1177
|
+
* @param {string[]} path The current path.
|
|
1178
|
+
* @param {object} traceMap The trace map.
|
|
1179
|
+
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
|
|
1180
|
+
*/
|
|
1181
|
+
*_iteratePropertyReferences(rootNode, path, traceMap) {
|
|
1182
|
+
let node = rootNode;
|
|
1183
|
+
while (isPassThrough(node)) node = node.parent;
|
|
1184
|
+
const parent = node.parent;
|
|
1185
|
+
if (parent.type === "MemberExpression") {
|
|
1186
|
+
if (parent.object === node) {
|
|
1187
|
+
const key = getPropertyName(parent);
|
|
1188
|
+
if (key == null || !has(traceMap, key)) return;
|
|
1189
|
+
path = path.concat(key);
|
|
1190
|
+
const nextTraceMap = traceMap[key];
|
|
1191
|
+
if (nextTraceMap[READ]) yield {
|
|
1192
|
+
node: parent,
|
|
1193
|
+
path,
|
|
1194
|
+
type: READ,
|
|
1195
|
+
info: nextTraceMap[READ]
|
|
1196
|
+
};
|
|
1197
|
+
yield* this._iteratePropertyReferences(parent, path, nextTraceMap);
|
|
1198
|
+
}
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
if (parent.type === "CallExpression") {
|
|
1202
|
+
if (parent.callee === node && traceMap[CALL]) yield {
|
|
1203
|
+
node: parent,
|
|
1204
|
+
path,
|
|
1205
|
+
type: CALL,
|
|
1206
|
+
info: traceMap[CALL]
|
|
1207
|
+
};
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
if (parent.type === "NewExpression") {
|
|
1211
|
+
if (parent.callee === node && traceMap[CONSTRUCT]) yield {
|
|
1212
|
+
node: parent,
|
|
1213
|
+
path,
|
|
1214
|
+
type: CONSTRUCT,
|
|
1215
|
+
info: traceMap[CONSTRUCT]
|
|
1216
|
+
};
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
if (parent.type === "AssignmentExpression") {
|
|
1220
|
+
if (parent.right === node) {
|
|
1221
|
+
yield* this._iterateLhsReferences(parent.left, path, traceMap);
|
|
1222
|
+
yield* this._iteratePropertyReferences(parent, path, traceMap);
|
|
1223
|
+
}
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
if (parent.type === "AssignmentPattern") {
|
|
1227
|
+
if (parent.right === node) yield* this._iterateLhsReferences(parent.left, path, traceMap);
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
if (parent.type === "VariableDeclarator") {
|
|
1231
|
+
if (parent.init === node) yield* this._iterateLhsReferences(parent.id, path, traceMap);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Iterate the references for a given Pattern node.
|
|
1236
|
+
* @param {Node} patternNode The Pattern node to iterate references.
|
|
1237
|
+
* @param {string[]} path The current path.
|
|
1238
|
+
* @param {object} traceMap The trace map.
|
|
1239
|
+
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
|
|
1240
|
+
*/
|
|
1241
|
+
*_iterateLhsReferences(patternNode, path, traceMap) {
|
|
1242
|
+
if (patternNode.type === "Identifier") {
|
|
1243
|
+
const variable = findVariable(this.globalScope, patternNode);
|
|
1244
|
+
if (variable != null) yield* this._iterateVariableReferences(variable, path, traceMap, false);
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
if (patternNode.type === "ObjectPattern") {
|
|
1248
|
+
for (const property of patternNode.properties) {
|
|
1249
|
+
const key = getPropertyName(property);
|
|
1250
|
+
if (key == null || !has(traceMap, key)) continue;
|
|
1251
|
+
const nextPath = path.concat(key);
|
|
1252
|
+
const nextTraceMap = traceMap[key];
|
|
1253
|
+
if (nextTraceMap[READ]) yield {
|
|
1254
|
+
node: property,
|
|
1255
|
+
path: nextPath,
|
|
1256
|
+
type: READ,
|
|
1257
|
+
info: nextTraceMap[READ]
|
|
1258
|
+
};
|
|
1259
|
+
yield* this._iterateLhsReferences(property.value, nextPath, nextTraceMap);
|
|
1260
|
+
}
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
if (patternNode.type === "AssignmentPattern") yield* this._iterateLhsReferences(patternNode.left, path, traceMap);
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Iterate the references for a given ModuleSpecifier node.
|
|
1267
|
+
* @param {Node} specifierNode The ModuleSpecifier node to iterate references.
|
|
1268
|
+
* @param {string[]} path The current path.
|
|
1269
|
+
* @param {object} traceMap The trace map.
|
|
1270
|
+
* @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
|
|
1271
|
+
*/
|
|
1272
|
+
*_iterateImportReferences(specifierNode, path, traceMap) {
|
|
1273
|
+
const type = specifierNode.type;
|
|
1274
|
+
if (type === "ImportSpecifier" || type === "ImportDefaultSpecifier") {
|
|
1275
|
+
const key = type === "ImportDefaultSpecifier" ? "default" : specifierNode.imported.name;
|
|
1276
|
+
if (!has(traceMap, key)) return;
|
|
1277
|
+
path = path.concat(key);
|
|
1278
|
+
const nextTraceMap = traceMap[key];
|
|
1279
|
+
if (nextTraceMap[READ]) yield {
|
|
1280
|
+
node: specifierNode,
|
|
1281
|
+
path,
|
|
1282
|
+
type: READ,
|
|
1283
|
+
info: nextTraceMap[READ]
|
|
1284
|
+
};
|
|
1285
|
+
yield* this._iterateVariableReferences(findVariable(this.globalScope, specifierNode.local), path, nextTraceMap, false);
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
if (type === "ImportNamespaceSpecifier") {
|
|
1289
|
+
yield* this._iterateVariableReferences(findVariable(this.globalScope, specifierNode.local), path, traceMap, false);
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (type === "ExportSpecifier") {
|
|
1293
|
+
const key = specifierNode.local.name;
|
|
1294
|
+
if (!has(traceMap, key)) return;
|
|
1295
|
+
path = path.concat(key);
|
|
1296
|
+
const nextTraceMap = traceMap[key];
|
|
1297
|
+
if (nextTraceMap[READ]) yield {
|
|
1298
|
+
node: specifierNode,
|
|
1299
|
+
path,
|
|
1300
|
+
type: READ,
|
|
1301
|
+
info: nextTraceMap[READ]
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
ReferenceTracker.READ = READ;
|
|
1307
|
+
ReferenceTracker.CALL = CALL;
|
|
1308
|
+
ReferenceTracker.CONSTRUCT = CONSTRUCT;
|
|
1309
|
+
ReferenceTracker.ESM = ESM;
|
|
1310
|
+
/**
|
|
1311
|
+
* This is a predicate function for Array#filter.
|
|
1312
|
+
* @param {string} name A name part.
|
|
1313
|
+
* @param {number} index The index of the name.
|
|
1314
|
+
* @returns {boolean} `false` if it's default.
|
|
1315
|
+
*/
|
|
1316
|
+
function exceptDefault(name, index) {
|
|
1317
|
+
return !(index === 1 && name === "default");
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
//#endregion
|
|
1321
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/util/ast.js
|
|
1322
|
+
const traverse = (context, node, visit, visited = /* @__PURE__ */ new Set()) => {
|
|
1323
|
+
if (visited.has(node)) return;
|
|
1324
|
+
visited.add(node);
|
|
1325
|
+
visit(node);
|
|
1326
|
+
(context.sourceCode.visitorKeys[node.type] || []).map((key) => node[key]).filter(Boolean).flatMap((child) => Array.isArray(child) ? child : [child]).filter(Boolean).filter((child) => typeof child.type === "string").forEach((child) => traverse(context, child, visit, visited));
|
|
1327
|
+
};
|
|
1328
|
+
const findDownstreamNodes = (context, topNode, type) => {
|
|
1329
|
+
const nodes = [];
|
|
1330
|
+
traverse(context, topNode, (node) => {
|
|
1331
|
+
if (node.type === type) nodes.push(node);
|
|
1332
|
+
});
|
|
1333
|
+
return nodes;
|
|
1334
|
+
};
|
|
1335
|
+
const getUpstreamVariables = (context, variable, filter, visited = /* @__PURE__ */ new Set()) => {
|
|
1336
|
+
if (visited.has(variable)) return [];
|
|
1337
|
+
visited.add(variable);
|
|
1338
|
+
const upstreamVariables = variable.defs.filter((def) => !!def.node.init).filter((def) => filter(def.node)).flatMap((def) => getDownstreamRefs(context, def.node.init)).map((ref) => ref.resolved).filter(Boolean).flatMap((variable$1) => getUpstreamVariables(context, variable$1, filter, visited));
|
|
1339
|
+
return upstreamVariables.length === 0 ? [variable] : upstreamVariables;
|
|
1340
|
+
};
|
|
1341
|
+
const getDownstreamRefs = (context, node) => findDownstreamNodes(context, node, "Identifier").map((identifier) => getRef(context, identifier)).filter(Boolean);
|
|
1342
|
+
const getRef = (context, identifier) => findVariable(context.sourceCode.getScope(identifier), identifier)?.references.find((ref) => ref.identifier === identifier);
|
|
1343
|
+
const getCallExpr = (ref, current = ref.identifier.parent) => {
|
|
1344
|
+
if (current.type === "CallExpression") {
|
|
1345
|
+
let node = ref.identifier;
|
|
1346
|
+
while (node.parent.type === "MemberExpression") node = node.parent;
|
|
1347
|
+
if (current.callee === node) return current;
|
|
1348
|
+
}
|
|
1349
|
+
if (current.type === "MemberExpression") return getCallExpr(ref, current.parent);
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
//#endregion
|
|
1353
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/util/react.js
|
|
1354
|
+
const isReactFunctionalComponent = (node) => (node.type === "FunctionDeclaration" || node.type === "VariableDeclarator" && (node.init.type === "ArrowFunctionExpression" || node.init.type === "CallExpression")) && node.id.type === "Identifier" && node.id.name[0].toUpperCase() === node.id.name[0];
|
|
1355
|
+
const isReactFunctionalHOC = (node) => node.type === "VariableDeclarator" && node.init && node.init.type === "CallExpression" && node.init.callee.type === "Identifier" && !["memo", "forwardRef"].includes(node.init.callee.name) && node.init.arguments.length > 0 && (node.init.arguments[0].type === "ArrowFunctionExpression" || node.init.arguments[0].type === "FunctionExpression") && node.id.type === "Identifier" && node.id.name[0].toUpperCase() === node.id.name[0];
|
|
1356
|
+
const isCustomHook = (node) => (node.type === "FunctionDeclaration" || node.type === "VariableDeclarator" && node.init && (node.init.type === "ArrowFunctionExpression" || node.init.type === "FunctionExpression")) && node.id.type === "Identifier" && node.id.name.startsWith("use") && node.id.name[3] === node.id.name[3].toUpperCase();
|
|
1357
|
+
const isUseState = (node) => node.type === "VariableDeclarator" && node.init && node.init.type === "CallExpression" && node.init.callee.name === "useState" && node.id.type === "ArrayPattern" && (node.id.elements.length === 1 || node.id.elements.length === 2) && node.id.elements.every((el) => {
|
|
1358
|
+
return !el || el.type === "Identifier";
|
|
1359
|
+
});
|
|
1360
|
+
const isPropDef = (def) => {
|
|
1361
|
+
const declaringNode = def.node.type === "ArrowFunctionExpression" ? def.node.parent.type === "CallExpression" ? def.node.parent.parent : def.node.parent : def.node;
|
|
1362
|
+
return def.type === "Parameter" && (isReactFunctionalComponent(declaringNode) && !isReactFunctionalHOC(declaringNode) || isCustomHook(declaringNode));
|
|
1363
|
+
};
|
|
1364
|
+
const isUseRef = (node) => node.type === "VariableDeclarator" && node.init && node.init.type === "CallExpression" && node.init.callee.name === "useRef" && node.id.type === "Identifier";
|
|
1365
|
+
const isUseEffect = (node) => node.type === "CallExpression" && (node.callee.type === "Identifier" && node.callee.name === "useEffect" || node.callee.type === "MemberExpression" && node.callee.object.name === "React" && node.callee.property.name === "useEffect");
|
|
1366
|
+
const getEffectFnRefs = (context, node) => {
|
|
1367
|
+
if (!isUseEffect(node) || node.arguments.length < 1) return;
|
|
1368
|
+
const effectFn = node.arguments[0];
|
|
1369
|
+
if (effectFn.type !== "ArrowFunctionExpression" && effectFn.type !== "FunctionExpression") return;
|
|
1370
|
+
return getDownstreamRefs(context, effectFn);
|
|
1371
|
+
};
|
|
1372
|
+
function getEffectDepsRefs(context, node) {
|
|
1373
|
+
if (!isUseEffect(node) || node.arguments.length < 2) return;
|
|
1374
|
+
const depsArr = node.arguments[1];
|
|
1375
|
+
if (depsArr.type !== "ArrayExpression") return;
|
|
1376
|
+
return getDownstreamRefs(context, depsArr);
|
|
1377
|
+
}
|
|
1378
|
+
const isStateSetter = (context, ref) => getCallExpr(ref) !== void 0 && isState(context, ref);
|
|
1379
|
+
const isPropCallback = (context, ref) => getCallExpr(ref) !== void 0 && isProp(context, ref);
|
|
1380
|
+
const isState = (context, ref) => getUpstreamReactVariables(context, ref.resolved).notEmptyEvery((variable) => variable.defs.some((def) => isUseState(def.node)));
|
|
1381
|
+
const isProp = (context, ref) => getUpstreamReactVariables(context, ref.resolved).notEmptyEvery((variable) => variable.defs.some((def) => isPropDef(def)));
|
|
1382
|
+
const isRef = (context, ref) => getUpstreamReactVariables(context, ref.resolved).notEmptyEvery((variable) => variable.defs.some((def) => isUseRef(def.node)));
|
|
1383
|
+
const getUseStateNode = (context, ref) => {
|
|
1384
|
+
return getUpstreamReactVariables(context, ref.resolved).find((variable) => variable.defs.some((def) => isUseState(def.node)))?.defs.find((def) => isUseState(def.node))?.node;
|
|
1385
|
+
};
|
|
1386
|
+
/**
|
|
1387
|
+
* Walks up the AST until a `useEffect` call, returning `false` if never found, or finds any of the following on the way:
|
|
1388
|
+
* - An async function
|
|
1389
|
+
* - A function declaration, which may be called at an arbitrary later time
|
|
1390
|
+
* - A function passed as a callback to another function or `new` - event handler, `setTimeout`, `Promise.then()` `new ResizeObserver()`, etc.
|
|
1391
|
+
*
|
|
1392
|
+
* Otherwise returns `true`.
|
|
1393
|
+
*
|
|
1394
|
+
* Inspired by https://eslint-react.xyz/docs/rules/hooks-extra-no-direct-set-state-in-use-effect
|
|
1395
|
+
*/
|
|
1396
|
+
const isImmediateCall = (node) => {
|
|
1397
|
+
if (!node.parent) return false;
|
|
1398
|
+
else if (isUseEffect(node.parent)) return true;
|
|
1399
|
+
else if (node.async || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") return false;
|
|
1400
|
+
else return isImmediateCall(node.parent);
|
|
1401
|
+
};
|
|
1402
|
+
const isArgsAllLiterals = (context, callExpr) => callExpr.arguments.flatMap((arg) => getDownstreamRefs(context, arg)).flatMap((ref) => getUpstreamReactVariables(context, ref.resolved)).length === 0;
|
|
1403
|
+
const getUpstreamReactVariables = (context, variable) => getUpstreamVariables(context, variable, (node) => !isUseState(node)).filter((variable$1) => variable$1.defs.every((def) => isPropDef(def) || def.type !== "Parameter"));
|
|
1404
|
+
|
|
1405
|
+
//#endregion
|
|
1406
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-empty-effect.js
|
|
1407
|
+
/**
|
|
1408
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1409
|
+
*/
|
|
1410
|
+
var no_empty_effect_default = {
|
|
1411
|
+
meta: {
|
|
1412
|
+
type: "suggestion",
|
|
1413
|
+
docs: { description: "Disallow empty effects." },
|
|
1414
|
+
schema: [],
|
|
1415
|
+
messages: { avoidEmptyEffect: "This effect is empty and could be removed." }
|
|
1416
|
+
},
|
|
1417
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1418
|
+
if (!isUseEffect(node)) return;
|
|
1419
|
+
if (node.arguments?.length === 0 || getEffectFnRefs(context, node)?.length === 0) context.report({
|
|
1420
|
+
node,
|
|
1421
|
+
messageId: "avoidEmptyEffect"
|
|
1422
|
+
});
|
|
1423
|
+
} })
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
//#endregion
|
|
1427
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-adjust-state-on-prop-change.js
|
|
1428
|
+
/**
|
|
1429
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1430
|
+
*/
|
|
1431
|
+
var no_adjust_state_on_prop_change_default = {
|
|
1432
|
+
meta: {
|
|
1433
|
+
type: "suggestion",
|
|
1434
|
+
docs: {
|
|
1435
|
+
description: "Disallow adjusting state in an effect when a prop changes.",
|
|
1436
|
+
url: "https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes"
|
|
1437
|
+
},
|
|
1438
|
+
schema: [],
|
|
1439
|
+
messages: { avoidAdjustingStateWhenAPropChanges: "Avoid adjusting state when a prop changes. Instead, adjust the state directly during render, or refactor your state to avoid this need entirely." }
|
|
1440
|
+
},
|
|
1441
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1442
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1443
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1444
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1445
|
+
const isAllDepsProps = depsRefs.notEmptyEvery((ref) => isProp(context, ref));
|
|
1446
|
+
effectFnRefs.filter((ref) => isStateSetter(context, ref)).filter((ref) => isImmediateCall(ref.identifier)).forEach((ref) => {
|
|
1447
|
+
const callExpr = getCallExpr(ref);
|
|
1448
|
+
if (isAllDepsProps && isArgsAllLiterals(context, callExpr)) context.report({
|
|
1449
|
+
node: callExpr,
|
|
1450
|
+
messageId: "avoidAdjustingStateWhenAPropChanges"
|
|
1451
|
+
});
|
|
1452
|
+
});
|
|
1453
|
+
} })
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
//#endregion
|
|
1457
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-reset-all-state-on-prop-change.js
|
|
1458
|
+
/**
|
|
1459
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1460
|
+
*/
|
|
1461
|
+
var no_reset_all_state_on_prop_change_default = {
|
|
1462
|
+
meta: {
|
|
1463
|
+
type: "suggestion",
|
|
1464
|
+
docs: {
|
|
1465
|
+
description: "Disallow resetting all state in an effect when a prop changes.",
|
|
1466
|
+
url: "https://react.dev/learn/you-might-not-need-an-effect#resetting-all-state-when-a-prop-changes"
|
|
1467
|
+
},
|
|
1468
|
+
schema: [],
|
|
1469
|
+
messages: { avoidResettingAllStateWhenAPropChanges: "Avoid resetting all state when a prop changes. If \"{{prop}}\" is a key, pass it as `key` instead so React will reset the component." }
|
|
1470
|
+
},
|
|
1471
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1472
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1473
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1474
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1475
|
+
const propUsedToResetAllState = findPropUsedToResetAllState(context, effectFnRefs, depsRefs, node);
|
|
1476
|
+
if (propUsedToResetAllState) context.report({
|
|
1477
|
+
node,
|
|
1478
|
+
messageId: "avoidResettingAllStateWhenAPropChanges",
|
|
1479
|
+
data: { prop: propUsedToResetAllState.identifier.name }
|
|
1480
|
+
});
|
|
1481
|
+
} })
|
|
1482
|
+
};
|
|
1483
|
+
const findPropUsedToResetAllState = (context, effectFnRefs, depsRefs, useEffectNode) => {
|
|
1484
|
+
const stateSetterRefs = effectFnRefs.filter((ref) => isStateSetter(context, ref));
|
|
1485
|
+
return stateSetterRefs.length > 0 && stateSetterRefs.every((ref) => isSetStateToInitialValue(context, ref)) && stateSetterRefs.length === countUseStates(context, findContainingNode(useEffectNode)) ? depsRefs.find((ref) => isProp(context, ref)) : void 0;
|
|
1486
|
+
};
|
|
1487
|
+
const isSetStateToInitialValue = (context, setterRef) => {
|
|
1488
|
+
const setStateToValue = getCallExpr(setterRef).arguments[0];
|
|
1489
|
+
const stateInitialValue = getUseStateNode(context, setterRef).init.arguments[0];
|
|
1490
|
+
const isUndefined = (node) => node === void 0 || node.name === "undefined";
|
|
1491
|
+
if (isUndefined(setStateToValue) && isUndefined(stateInitialValue)) return true;
|
|
1492
|
+
if (setStateToValue === null && stateInitialValue === null) return true;
|
|
1493
|
+
else if (setStateToValue && !stateInitialValue || !setStateToValue && stateInitialValue) return false;
|
|
1494
|
+
return context.sourceCode.getText(setStateToValue) === context.sourceCode.getText(stateInitialValue);
|
|
1495
|
+
};
|
|
1496
|
+
const countUseStates = (context, componentNode) => {
|
|
1497
|
+
if (!componentNode) return 0;
|
|
1498
|
+
let count = 0;
|
|
1499
|
+
traverse(context, componentNode, (node) => {
|
|
1500
|
+
if (isUseState(node)) count++;
|
|
1501
|
+
});
|
|
1502
|
+
return count;
|
|
1503
|
+
};
|
|
1504
|
+
const findContainingNode = (node) => {
|
|
1505
|
+
if (!node) return;
|
|
1506
|
+
else if (isReactFunctionalComponent(node) || isReactFunctionalHOC(node) || isCustomHook(node)) return node;
|
|
1507
|
+
else return findContainingNode(node.parent);
|
|
1508
|
+
};
|
|
1509
|
+
|
|
1510
|
+
//#endregion
|
|
1511
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-event-handler.js
|
|
1512
|
+
/**
|
|
1513
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1514
|
+
*/
|
|
1515
|
+
var no_event_handler_default = {
|
|
1516
|
+
meta: {
|
|
1517
|
+
type: "suggestion",
|
|
1518
|
+
docs: {
|
|
1519
|
+
description: "Disallow using state and an effect as an event handler.",
|
|
1520
|
+
url: "https://react.dev/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers"
|
|
1521
|
+
},
|
|
1522
|
+
schema: [],
|
|
1523
|
+
messages: { avoidEventHandler: "Avoid using state and effects as an event handler. Instead, call the event handling code directly when the event occurs." }
|
|
1524
|
+
},
|
|
1525
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1526
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1527
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1528
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1529
|
+
findDownstreamNodes(context, node, "IfStatement").filter((ifNode) => !ifNode.alternate).filter((ifNode) => getDownstreamRefs(context, ifNode.test).notEmptyEvery((ref) => isState(context, ref))).forEach((ifNode) => {
|
|
1530
|
+
context.report({
|
|
1531
|
+
node: ifNode.test,
|
|
1532
|
+
messageId: "avoidEventHandler"
|
|
1533
|
+
});
|
|
1534
|
+
});
|
|
1535
|
+
} })
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
//#endregion
|
|
1539
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-pass-live-state-to-parent.js
|
|
1540
|
+
/**
|
|
1541
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1542
|
+
*/
|
|
1543
|
+
var no_pass_live_state_to_parent_default = {
|
|
1544
|
+
meta: {
|
|
1545
|
+
type: "suggestion",
|
|
1546
|
+
docs: {
|
|
1547
|
+
description: "Disallow passing live state to parent components in an effect.",
|
|
1548
|
+
url: "https://react.dev/learn/you-might-not-need-an-effect#notifying-parent-components-about-state-changes"
|
|
1549
|
+
},
|
|
1550
|
+
schema: [],
|
|
1551
|
+
messages: { avoidPassingLiveStateToParent: "Avoid passing live state to parents in an effect. Instead, lift the state to the parent and pass it down to the child as a prop." }
|
|
1552
|
+
},
|
|
1553
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1554
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1555
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1556
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1557
|
+
effectFnRefs.filter((ref) => isPropCallback(context, ref)).filter((ref) => isImmediateCall(ref.identifier)).forEach((ref) => {
|
|
1558
|
+
const callExpr = getCallExpr(ref);
|
|
1559
|
+
if (callExpr.arguments.flatMap((arg) => getDownstreamRefs(context, arg)).some((ref$1) => isState(context, ref$1))) context.report({
|
|
1560
|
+
node: callExpr,
|
|
1561
|
+
messageId: "avoidPassingLiveStateToParent"
|
|
1562
|
+
});
|
|
1563
|
+
});
|
|
1564
|
+
} })
|
|
1565
|
+
};
|
|
1566
|
+
|
|
1567
|
+
//#endregion
|
|
1568
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-initialize-state.js
|
|
1569
|
+
/**
|
|
1570
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1571
|
+
*/
|
|
1572
|
+
var no_initialize_state_default = {
|
|
1573
|
+
meta: {
|
|
1574
|
+
type: "suggestion",
|
|
1575
|
+
docs: { description: "Disallow initializing state in an effect." },
|
|
1576
|
+
schema: [],
|
|
1577
|
+
messages: { avoidInitializingState: "Avoid initializing state in an effect. Instead, pass \"{{state}}\"'s initial value to its `useState`." }
|
|
1578
|
+
},
|
|
1579
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1580
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1581
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1582
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1583
|
+
if (depsRefs.length > 0) return;
|
|
1584
|
+
effectFnRefs.filter((ref) => isStateSetter(context, ref)).filter((ref) => isImmediateCall(ref.identifier)).forEach((ref) => {
|
|
1585
|
+
const useStateNode = getUseStateNode(context, ref);
|
|
1586
|
+
const stateName = (useStateNode.id.elements[0] ?? useStateNode.id.elements[1])?.name;
|
|
1587
|
+
context.report({
|
|
1588
|
+
node: getCallExpr(ref),
|
|
1589
|
+
messageId: "avoidInitializingState",
|
|
1590
|
+
data: { state: stateName }
|
|
1591
|
+
});
|
|
1592
|
+
});
|
|
1593
|
+
} })
|
|
1594
|
+
};
|
|
1595
|
+
|
|
1596
|
+
//#endregion
|
|
1597
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-chain-state-updates.js
|
|
1598
|
+
/**
|
|
1599
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1600
|
+
*/
|
|
1601
|
+
var no_chain_state_updates_default = {
|
|
1602
|
+
meta: {
|
|
1603
|
+
type: "suggestion",
|
|
1604
|
+
docs: {
|
|
1605
|
+
description: "Disallow chaining state changes in an effect.",
|
|
1606
|
+
url: "https://react.dev/learn/you-might-not-need-an-effect#chains-of-computations"
|
|
1607
|
+
},
|
|
1608
|
+
schema: [],
|
|
1609
|
+
messages: { avoidChainingStateUpdates: "Avoid chaining state changes. When possible, update all relevant state simultaneously." }
|
|
1610
|
+
},
|
|
1611
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1612
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1613
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1614
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1615
|
+
const isAllDepsState = depsRefs.notEmptyEvery((ref) => isState(context, ref));
|
|
1616
|
+
effectFnRefs.filter((ref) => isStateSetter(context, ref)).filter((ref) => isImmediateCall(ref.identifier)).forEach((ref) => {
|
|
1617
|
+
const callExpr = getCallExpr(ref);
|
|
1618
|
+
if (isAllDepsState && isArgsAllLiterals(context, callExpr)) context.report({
|
|
1619
|
+
node: callExpr,
|
|
1620
|
+
messageId: "avoidChainingStateUpdates"
|
|
1621
|
+
});
|
|
1622
|
+
});
|
|
1623
|
+
} })
|
|
1624
|
+
};
|
|
1625
|
+
|
|
1626
|
+
//#endregion
|
|
1627
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-derived-state.js
|
|
1628
|
+
/**
|
|
1629
|
+
* @type {import('eslint').Rule.RuleModule}
|
|
1630
|
+
*/
|
|
1631
|
+
var no_derived_state_default = {
|
|
1632
|
+
meta: {
|
|
1633
|
+
type: "suggestion",
|
|
1634
|
+
docs: {
|
|
1635
|
+
description: "Disallow storing derived state in an effect.",
|
|
1636
|
+
url: "https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state"
|
|
1637
|
+
},
|
|
1638
|
+
schema: [],
|
|
1639
|
+
messages: { avoidDerivedState: "Avoid storing derived state. Compute \"{{state}}\" directly during render, optionally with `useMemo` if it's expensive." }
|
|
1640
|
+
},
|
|
1641
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1642
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1643
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1644
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1645
|
+
effectFnRefs.filter((ref) => isStateSetter(context, ref)).filter((ref) => isImmediateCall(ref.identifier)).forEach((ref) => {
|
|
1646
|
+
const callExpr = getCallExpr(ref);
|
|
1647
|
+
const useStateNode = getUseStateNode(context, ref);
|
|
1648
|
+
const stateName = (useStateNode.id.elements[0] ?? useStateNode.id.elements[1])?.name;
|
|
1649
|
+
const argsRefs = callExpr.arguments.flatMap((arg) => getDownstreamRefs(context, arg));
|
|
1650
|
+
const isAllArgsInternal = argsRefs.notEmptyEvery((ref$1) => isState(context, ref$1) || isProp(context, ref$1));
|
|
1651
|
+
const argsUpstreamVars = argsRefs.flatMap((ref$1) => getUpstreamReactVariables(context, ref$1.resolved));
|
|
1652
|
+
const depsUpstreamVars = depsRefs.flatMap((ref$1) => getUpstreamReactVariables(context, ref$1.resolved));
|
|
1653
|
+
const isValueAlwaysInSync = argsUpstreamVars.notEmptyEvery((argVar) => depsUpstreamVars.some((depVar) => argVar.name === depVar.name)) && countCalls(ref) === 1;
|
|
1654
|
+
if (isAllArgsInternal || isValueAlwaysInSync) context.report({
|
|
1655
|
+
node: callExpr,
|
|
1656
|
+
messageId: "avoidDerivedState",
|
|
1657
|
+
data: { state: stateName }
|
|
1658
|
+
});
|
|
1659
|
+
});
|
|
1660
|
+
} })
|
|
1661
|
+
};
|
|
1662
|
+
const countCalls = (ref) => ref.resolved.references.filter((ref$1) => ref$1.identifier.parent.type === "CallExpression").length;
|
|
1663
|
+
|
|
1664
|
+
//#endregion
|
|
1665
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-pass-data-to-parent.js
|
|
1666
|
+
/**
|
|
1667
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1668
|
+
*/
|
|
1669
|
+
var no_pass_data_to_parent_default = {
|
|
1670
|
+
meta: {
|
|
1671
|
+
type: "suggestion",
|
|
1672
|
+
docs: {
|
|
1673
|
+
description: "Disallow passing data to parents in an effect.",
|
|
1674
|
+
url: "https://react.dev/learn/you-might-not-need-an-effect#passing-data-to-the-parent"
|
|
1675
|
+
},
|
|
1676
|
+
schema: [],
|
|
1677
|
+
messages: { avoidPassingDataToParent: "Avoid passing data to parents in an effect. Instead, let the parent fetch the data itself and pass it down to the child as a prop." }
|
|
1678
|
+
},
|
|
1679
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1680
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1681
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1682
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1683
|
+
effectFnRefs.filter((ref) => isPropCallback(context, ref)).forEach((ref) => {
|
|
1684
|
+
const callExpr = getCallExpr(ref);
|
|
1685
|
+
if (callExpr.arguments.flatMap((arg) => getDownstreamRefs(context, arg)).notEmptyEvery((ref$1) => !isState(context, ref$1) && !isProp(context, ref$1) && !isRef(context, ref$1))) context.report({
|
|
1686
|
+
node: callExpr,
|
|
1687
|
+
messageId: "avoidPassingDataToParent"
|
|
1688
|
+
});
|
|
1689
|
+
});
|
|
1690
|
+
} })
|
|
1691
|
+
};
|
|
1692
|
+
|
|
1693
|
+
//#endregion
|
|
1694
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/no-manage-parent.js
|
|
1695
|
+
/**
|
|
1696
|
+
* @type {import("eslint").Rule.RuleModule}
|
|
1697
|
+
*/
|
|
1698
|
+
var no_manage_parent_default = {
|
|
1699
|
+
meta: {
|
|
1700
|
+
type: "problem",
|
|
1701
|
+
docs: { description: "Disallow effects that only use props." },
|
|
1702
|
+
schema: [],
|
|
1703
|
+
messages: { avoidManagingParent: "This effect only uses props. Consider lifting the logic up to the parent." }
|
|
1704
|
+
},
|
|
1705
|
+
create: (context) => ({ CallExpression: (node) => {
|
|
1706
|
+
const effectFnRefs = getEffectFnRefs(context, node);
|
|
1707
|
+
const depsRefs = getEffectDepsRefs(context, node);
|
|
1708
|
+
if (!effectFnRefs || !depsRefs) return;
|
|
1709
|
+
if (effectFnRefs.length === 0) return;
|
|
1710
|
+
if (effectFnRefs.concat(depsRefs).every((ref) => isProp(context, ref))) context.report({
|
|
1711
|
+
node,
|
|
1712
|
+
messageId: "avoidManagingParent"
|
|
1713
|
+
});
|
|
1714
|
+
} })
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1717
|
+
//#endregion
|
|
1718
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/util/javascript.js
|
|
1719
|
+
Array.prototype.notEmptyEvery = function(predicate) {
|
|
1720
|
+
return this.length > 0 && this.every(predicate);
|
|
1721
|
+
};
|
|
1722
|
+
|
|
1723
|
+
//#endregion
|
|
1724
|
+
//#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.5.3_eslint@9.36.0_jiti@2.5.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/index.js
|
|
1725
|
+
/**
|
|
1726
|
+
* @type {import("eslint").ESLint.Plugin}
|
|
1727
|
+
*/
|
|
1728
|
+
const plugin = {
|
|
1729
|
+
meta: { name: "react-you-might-not-need-an-effect" },
|
|
1730
|
+
configs: {},
|
|
1731
|
+
rules: {
|
|
1732
|
+
"no-empty-effect": no_empty_effect_default,
|
|
1733
|
+
"no-adjust-state-on-prop-change": no_adjust_state_on_prop_change_default,
|
|
1734
|
+
"no-reset-all-state-on-prop-change": no_reset_all_state_on_prop_change_default,
|
|
1735
|
+
"no-event-handler": no_event_handler_default,
|
|
1736
|
+
"no-pass-live-state-to-parent": no_pass_live_state_to_parent_default,
|
|
1737
|
+
"no-pass-data-to-parent": no_pass_data_to_parent_default,
|
|
1738
|
+
"no-manage-parent": no_manage_parent_default,
|
|
1739
|
+
"no-initialize-state": no_initialize_state_default,
|
|
1740
|
+
"no-chain-state-updates": no_chain_state_updates_default,
|
|
1741
|
+
"no-derived-state": no_derived_state_default
|
|
1742
|
+
}
|
|
1743
|
+
};
|
|
1744
|
+
const recommendedRules = Object.keys(plugin.rules).reduce((acc, ruleName) => {
|
|
1745
|
+
acc[plugin.meta.name + "/" + ruleName] = "warn";
|
|
1746
|
+
return acc;
|
|
1747
|
+
}, {});
|
|
1748
|
+
const languageOptions = {
|
|
1749
|
+
globals: { ...globals.browser },
|
|
1750
|
+
parserOptions: { ecmaFeatures: { jsx: true } }
|
|
1751
|
+
};
|
|
1752
|
+
Object.assign(plugin.configs, {
|
|
1753
|
+
recommended: {
|
|
1754
|
+
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"],
|
|
1755
|
+
plugins: { [plugin.meta.name]: plugin },
|
|
1756
|
+
rules: recommendedRules,
|
|
1757
|
+
languageOptions
|
|
1758
|
+
},
|
|
1759
|
+
"legacy-recommended": {
|
|
1760
|
+
plugins: [plugin.meta.name],
|
|
1761
|
+
rules: recommendedRules,
|
|
1762
|
+
...languageOptions
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1765
|
+
var src_default = plugin;
|
|
1766
|
+
|
|
1767
|
+
//#endregion
|
|
1768
|
+
export { src_default as default };
|
|
1769
|
+
//# sourceMappingURL=src-DwSufEpw.js.map
|