eslint-plugin-react-x 2.14.0-next.0 → 3.0.0-next.0
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.js +1268 -526
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, coerceSettings, defineRuleListener, getConfigAdapters, getSettingsFromContext, report, toRegExp } from "@eslint-react/shared";
|
|
2
|
-
import
|
|
2
|
+
import * as ast from "@eslint-react/ast";
|
|
3
|
+
import * as core from "@eslint-react/core";
|
|
3
4
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
4
5
|
import { P, isMatching, match } from "ts-pattern";
|
|
5
6
|
import ts from "typescript";
|
|
6
|
-
import
|
|
7
|
-
import * as ast from "@eslint-react/ast";
|
|
7
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
8
8
|
import { findEnclosingAssignmentTarget, findVariable, getChildScopes, getObjectType, getVariableDefinitionNode, isAssignmentTargetEqual } from "@eslint-react/var";
|
|
9
|
-
import {
|
|
9
|
+
import { DefinitionType } from "@typescript-eslint/scope-manager";
|
|
10
|
+
import { constFalse, constTrue, constVoid, flow, getOrElseUpdate, identity, not, unit } from "@eslint-react/eff";
|
|
10
11
|
import { compare } from "compare-versions";
|
|
11
12
|
import { getConstrainedTypeAtLocation, isTypeReadonly } from "@typescript-eslint/type-utils";
|
|
12
13
|
import { isPropertyReadonlyInType, unionConstituents } from "ts-api-utils";
|
|
@@ -42,10 +43,8 @@ const rules$8 = {
|
|
|
42
43
|
"react-x/no-duplicate-key": "off",
|
|
43
44
|
"react-x/no-implicit-key": "off",
|
|
44
45
|
"react-x/no-misused-capture-owner-stack": "off",
|
|
45
|
-
"react-x/no-unnecessary-key": "off",
|
|
46
46
|
"react-x/no-unnecessary-use-callback": "off",
|
|
47
47
|
"react-x/no-unnecessary-use-memo": "off",
|
|
48
|
-
"react-x/no-unnecessary-use-ref": "off",
|
|
49
48
|
"react-x/no-unused-props": "off",
|
|
50
49
|
"react-x/prefer-read-only-props": "off"
|
|
51
50
|
};
|
|
@@ -67,7 +66,7 @@ const rules$7 = {
|
|
|
67
66
|
//#endregion
|
|
68
67
|
//#region package.json
|
|
69
68
|
var name$6 = "eslint-plugin-react-x";
|
|
70
|
-
var version = "
|
|
69
|
+
var version = "3.0.0-next.0";
|
|
71
70
|
|
|
72
71
|
//#endregion
|
|
73
72
|
//#region src/utils/create-rule.ts
|
|
@@ -220,9 +219,512 @@ function getTypeVariants(types) {
|
|
|
220
219
|
return variants;
|
|
221
220
|
}
|
|
222
221
|
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/rules/component-hook-factories.ts
|
|
224
|
+
const RULE_NAME$63 = "component-hook-factories";
|
|
225
|
+
var component_hook_factories_default = createRule({
|
|
226
|
+
meta: {
|
|
227
|
+
type: "problem",
|
|
228
|
+
docs: { description: "Disallows higher order functions that define components or hooks inside them." },
|
|
229
|
+
messages: {
|
|
230
|
+
component: "Do not define component '{{name}}' inside a function. Components should be defined at the module level. Move it to the top level.",
|
|
231
|
+
hook: "Do not define hook '{{name}}' inside a function. Hooks should be defined at the module level. Move it to the top level."
|
|
232
|
+
},
|
|
233
|
+
schema: []
|
|
234
|
+
},
|
|
235
|
+
name: RULE_NAME$63,
|
|
236
|
+
create: create$63,
|
|
237
|
+
defaultOptions: []
|
|
238
|
+
});
|
|
239
|
+
function create$63(context) {
|
|
240
|
+
const hint = core.ComponentDetectionHint.DoNotIncludeJsxWithNumberValue | core.ComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | core.ComponentDetectionHint.DoNotIncludeJsxWithNullValue | core.ComponentDetectionHint.DoNotIncludeJsxWithStringValue | core.ComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | core.ComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx | core.ComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | core.ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayPattern | core.ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayExpression | core.ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback;
|
|
241
|
+
const fCollector = core.useComponentCollector(context, { hint });
|
|
242
|
+
const cCollector = core.useComponentCollectorLegacy(context);
|
|
243
|
+
const hCollector = core.useHookCollector(context);
|
|
244
|
+
const reported = /* @__PURE__ */ new Set();
|
|
245
|
+
return defineRuleListener(fCollector.visitor, cCollector.visitor, hCollector.visitor, { "Program:exit"(program) {
|
|
246
|
+
const fComponents = [...fCollector.ctx.getAllComponents(program)];
|
|
247
|
+
const cComponents = [...cCollector.ctx.getAllComponents(program)];
|
|
248
|
+
const hooks = [...hCollector.ctx.getAllHooks(program)];
|
|
249
|
+
for (const { name, node } of fComponents) {
|
|
250
|
+
if (name == null) continue;
|
|
251
|
+
if (ast.findParentNode(node, ast.isFunction) == null) continue;
|
|
252
|
+
if (reported.has(node)) continue;
|
|
253
|
+
context.report({
|
|
254
|
+
messageId: "component",
|
|
255
|
+
node,
|
|
256
|
+
data: { name }
|
|
257
|
+
});
|
|
258
|
+
reported.add(node);
|
|
259
|
+
}
|
|
260
|
+
for (const { name = "unknown", node } of cComponents) {
|
|
261
|
+
if (ast.findParentNode(node, ast.isFunction) == null) continue;
|
|
262
|
+
context.report({
|
|
263
|
+
messageId: "component",
|
|
264
|
+
node,
|
|
265
|
+
data: { name }
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
for (const { name, node } of hooks) {
|
|
269
|
+
if (ast.findParentNode(node, ast.isFunction) == null) continue;
|
|
270
|
+
if (reported.has(node)) continue;
|
|
271
|
+
context.report({
|
|
272
|
+
messageId: "hook",
|
|
273
|
+
node,
|
|
274
|
+
data: { name }
|
|
275
|
+
});
|
|
276
|
+
reported.add(node);
|
|
277
|
+
}
|
|
278
|
+
} });
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/rules/error-boundaries.ts
|
|
283
|
+
const RULE_NAME$62 = "error-boundaries";
|
|
284
|
+
var error_boundaries_default = createRule({
|
|
285
|
+
meta: {
|
|
286
|
+
type: "problem",
|
|
287
|
+
docs: { description: "Validates usage of Error Boundaries instead of try/catch for errors in child components." },
|
|
288
|
+
messages: {
|
|
289
|
+
tryCatchWithJsx: "Use an Error Boundary to catch errors in child components. Try/catch can't catch errors during React's rendering process.",
|
|
290
|
+
tryCatchWithUse: "Use an Error Boundary instead of try/catch around the 'use' hook. The 'use' hook suspends the component, and its errors can only be caught by Error Boundaries."
|
|
291
|
+
},
|
|
292
|
+
schema: []
|
|
293
|
+
},
|
|
294
|
+
name: RULE_NAME$62,
|
|
295
|
+
create: create$62,
|
|
296
|
+
defaultOptions: []
|
|
297
|
+
});
|
|
298
|
+
function create$62(context) {
|
|
299
|
+
if (!context.sourceCode.text.includes("try")) return {};
|
|
300
|
+
const { ctx, visitor } = core.useComponentCollector(context);
|
|
301
|
+
const reported = /* @__PURE__ */ new Set();
|
|
302
|
+
return defineRuleListener(visitor, {
|
|
303
|
+
CallExpression(node) {
|
|
304
|
+
if (!core.isUseCall(node)) return;
|
|
305
|
+
const stmt = ast.findParentNode(node, ast.is(AST_NODE_TYPES.TryStatement));
|
|
306
|
+
if (stmt != null && !reported.has(stmt)) {
|
|
307
|
+
context.report({
|
|
308
|
+
messageId: "tryCatchWithUse",
|
|
309
|
+
node
|
|
310
|
+
});
|
|
311
|
+
reported.add(stmt);
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
"Program:exit"(node) {
|
|
315
|
+
for (const { rets } of ctx.getAllComponents(node)) for (const ret of rets) {
|
|
316
|
+
if (ret == null) continue;
|
|
317
|
+
const stmt = ast.findParentNode(ret, ast.is(AST_NODE_TYPES.TryStatement));
|
|
318
|
+
if (stmt != null && !reported.has(stmt)) {
|
|
319
|
+
context.report({
|
|
320
|
+
messageId: "tryCatchWithJsx",
|
|
321
|
+
node: stmt
|
|
322
|
+
});
|
|
323
|
+
reported.add(stmt);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
//#endregion
|
|
331
|
+
//#region src/rules/exhaustive-deps.ts
|
|
332
|
+
const RULE_NAME$61 = "exhaustive-deps";
|
|
333
|
+
/**
|
|
334
|
+
* Built-in hooks that accept dependency arrays.
|
|
335
|
+
* Maps hook name to the index of the callback argument.
|
|
336
|
+
*/
|
|
337
|
+
const HOOKS_WITH_DEPS = {
|
|
338
|
+
useCallback: 0,
|
|
339
|
+
useEffect: 0,
|
|
340
|
+
useImperativeHandle: 1,
|
|
341
|
+
useInsertionEffect: 0,
|
|
342
|
+
useLayoutEffect: 0,
|
|
343
|
+
useMemo: 0
|
|
344
|
+
};
|
|
345
|
+
/**
|
|
346
|
+
* Hooks whose return values (at specific destructuring indices) are stable.
|
|
347
|
+
*/
|
|
348
|
+
const STABLE_HOOK_PATTERNS = {
|
|
349
|
+
useReducer: 1,
|
|
350
|
+
useRef: "all",
|
|
351
|
+
useState: 1,
|
|
352
|
+
useTransition: 1
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Get the name of a hook from a call expression.
|
|
356
|
+
* @param node - the call expression node
|
|
357
|
+
*/
|
|
358
|
+
function getHookName$1(node) {
|
|
359
|
+
if (node.callee.type === AST_NODE_TYPES.Identifier) return node.callee.name;
|
|
360
|
+
if (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier) return node.callee.property.name;
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Check if a hook name is one of the built-in hooks with dependency arrays.
|
|
365
|
+
* @param name - the hook name to check
|
|
366
|
+
*/
|
|
367
|
+
function isBuiltInHookWithDeps(name) {
|
|
368
|
+
return name in HOOKS_WITH_DEPS;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Get the callback argument index for a given hook.
|
|
372
|
+
* @param hookName - the hook name to look up
|
|
373
|
+
*/
|
|
374
|
+
function getCallbackIndex(hookName) {
|
|
375
|
+
return HOOKS_WITH_DEPS[hookName] ?? 0;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Get the text representation of a member expression chain.
|
|
379
|
+
* Handles both regular (obj.prop) and optional (obj?.prop) member expressions.
|
|
380
|
+
* @param node - the member expression node
|
|
381
|
+
*/
|
|
382
|
+
function getMemberExpressionText(node) {
|
|
383
|
+
const parts = [];
|
|
384
|
+
let current = node;
|
|
385
|
+
while (current.type === AST_NODE_TYPES.MemberExpression) {
|
|
386
|
+
const memberExpr = current;
|
|
387
|
+
if (memberExpr.computed) return null;
|
|
388
|
+
if (memberExpr.property.type !== AST_NODE_TYPES.Identifier) return null;
|
|
389
|
+
const sep = memberExpr.optional ? "?." : ".";
|
|
390
|
+
parts.unshift(`${sep}${memberExpr.property.name}`);
|
|
391
|
+
current = memberExpr.object;
|
|
392
|
+
}
|
|
393
|
+
if (current.type !== AST_NODE_TYPES.Identifier) return null;
|
|
394
|
+
parts.unshift(current.name);
|
|
395
|
+
return parts.join("");
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Check if a variable is defined at module level (outside any function).
|
|
399
|
+
* @param variable - the variable to check
|
|
400
|
+
*/
|
|
401
|
+
function isModuleLevelVariable(variable) {
|
|
402
|
+
for (const def of variable.defs) {
|
|
403
|
+
let node = def.name.parent;
|
|
404
|
+
while (node != null) {
|
|
405
|
+
if (ast.isFunction(node)) return false;
|
|
406
|
+
node = node.parent;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Check if a variable is an import.
|
|
413
|
+
* @param variable - the variable to check
|
|
414
|
+
*/
|
|
415
|
+
function isImportVariable(variable) {
|
|
416
|
+
return variable.defs.length > 0 && variable.defs.every((def) => def.type === DefinitionType.ImportBinding);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Check if a variable is a stable value from a known React hook pattern.
|
|
420
|
+
* E.g., setState from useState, dispatch from useReducer, ref from useRef,
|
|
421
|
+
* startTransition from useTransition.
|
|
422
|
+
* @param variable - the variable to check
|
|
423
|
+
*/
|
|
424
|
+
function isStableHookValue(variable) {
|
|
425
|
+
if (variable.defs.length === 0) return false;
|
|
426
|
+
const def = variable.defs[0];
|
|
427
|
+
if (def == null) return false;
|
|
428
|
+
if (def.type !== DefinitionType.Variable) return false;
|
|
429
|
+
const defNode = def.node;
|
|
430
|
+
const init = defNode.init;
|
|
431
|
+
if (init == null || init.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
432
|
+
const hookName = getHookName$1(init);
|
|
433
|
+
if (hookName == null) return false;
|
|
434
|
+
const stablePattern = STABLE_HOOK_PATTERNS[hookName];
|
|
435
|
+
if (stablePattern == null) return false;
|
|
436
|
+
if (stablePattern === "all") return true;
|
|
437
|
+
const id = defNode.id;
|
|
438
|
+
if (id.type !== AST_NODE_TYPES.ArrayPattern) return false;
|
|
439
|
+
const stableIndex = stablePattern;
|
|
440
|
+
const element = id.elements[stableIndex];
|
|
441
|
+
if (element == null || element.type !== AST_NODE_TYPES.Identifier) return false;
|
|
442
|
+
return element.name === variable.name;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Check if a variable is stable (should not be required in dependency arrays).
|
|
446
|
+
* @param variable - the variable to check
|
|
447
|
+
*/
|
|
448
|
+
function isStableVariable(variable) {
|
|
449
|
+
return isModuleLevelVariable(variable) || isImportVariable(variable) || isStableHookValue(variable);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Find the enclosing component or hook function for a node.
|
|
453
|
+
* @param node - the node to start searching from
|
|
454
|
+
*/
|
|
455
|
+
function findComponentOrHookScope(node) {
|
|
456
|
+
let current = node.parent;
|
|
457
|
+
while (current != null) {
|
|
458
|
+
if (ast.isFunction(current)) {
|
|
459
|
+
const id = ast.getFunctionId(current);
|
|
460
|
+
if (id != null && id.type === AST_NODE_TYPES.Identifier) {
|
|
461
|
+
if (core.isHookName(id.name) || /^[A-Z]/.test(id.name)) return current;
|
|
462
|
+
}
|
|
463
|
+
if (id != null && id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) {
|
|
464
|
+
if (core.isHookName(id.property.name) || /^[A-Z]/.test(id.property.name)) return current;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
current = current.parent;
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Check if a variable is defined within the given function scope (reactive).
|
|
473
|
+
* @param variable - the variable to check
|
|
474
|
+
* @param scopeNode - the function scope to check against
|
|
475
|
+
*/
|
|
476
|
+
function isDefinedInScope(variable, scopeNode) {
|
|
477
|
+
for (const def of variable.defs) {
|
|
478
|
+
let node = def.name;
|
|
479
|
+
for (;;) {
|
|
480
|
+
if (node === scopeNode) return true;
|
|
481
|
+
if (node.parent == null) break;
|
|
482
|
+
node = node.parent;
|
|
483
|
+
}
|
|
484
|
+
if (def.type === DefinitionType.Parameter) {
|
|
485
|
+
let paramNode = def.node;
|
|
486
|
+
for (;;) {
|
|
487
|
+
if (paramNode === scopeNode) return true;
|
|
488
|
+
if (paramNode.parent == null) break;
|
|
489
|
+
paramNode = paramNode.parent;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
var exhaustive_deps_default = createRule({
|
|
496
|
+
meta: {
|
|
497
|
+
type: "problem",
|
|
498
|
+
docs: { description: "Enforces that React hook dependency arrays contain all reactive values used in the callback." },
|
|
499
|
+
fixable: "code",
|
|
500
|
+
messages: {
|
|
501
|
+
missingDeps: "React Hook '{{hookName}}' has missing dependencies: {{deps}}. Either include them or remove the dependency array.",
|
|
502
|
+
nonLiteralDeps: "React Hook '{{hookName}}' was passed a dependency list that is not an array literal. This means we can't statically verify whether you've passed the correct dependencies.",
|
|
503
|
+
unnecessaryDeps: "React Hook '{{hookName}}' has unnecessary dependencies: {{deps}}. Either exclude them or remove the dependency array."
|
|
504
|
+
},
|
|
505
|
+
schema: [{
|
|
506
|
+
type: "object",
|
|
507
|
+
additionalProperties: false,
|
|
508
|
+
properties: { additionalHooks: { type: "string" } }
|
|
509
|
+
}]
|
|
510
|
+
},
|
|
511
|
+
name: RULE_NAME$61,
|
|
512
|
+
create: create$61,
|
|
513
|
+
defaultOptions: [{}]
|
|
514
|
+
});
|
|
515
|
+
function create$61(context) {
|
|
516
|
+
const additionalHooks = context.options[0]?.additionalHooks;
|
|
517
|
+
const additionalHooksRegex = additionalHooks != null && additionalHooks.length > 0 ? new RegExp(additionalHooks) : null;
|
|
518
|
+
/** Collected hook calls for later analysis. */
|
|
519
|
+
const collectedHookCalls = [];
|
|
520
|
+
const getText = (n) => context.sourceCode.getText(n);
|
|
521
|
+
/**
|
|
522
|
+
* Check if a hook name matches the additionalHooks regex option.
|
|
523
|
+
* @param name - the hook name to check
|
|
524
|
+
*/
|
|
525
|
+
function isAdditionalHook(name) {
|
|
526
|
+
return additionalHooksRegex != null && additionalHooksRegex.test(name);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Check if a call expression is a hook call that we should check for deps.
|
|
530
|
+
* @param node - the call expression to check
|
|
531
|
+
*/
|
|
532
|
+
function isHookWithDeps(node) {
|
|
533
|
+
const name = getHookName$1(node);
|
|
534
|
+
if (name == null) return false;
|
|
535
|
+
return isBuiltInHookWithDeps(name) || isAdditionalHook(name);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Extract the callback and dependency array from a hook call.
|
|
539
|
+
* @param node - the hook call expression
|
|
540
|
+
* @param hookName - the resolved hook name
|
|
541
|
+
*/
|
|
542
|
+
function extractCallbackAndDeps(node, hookName) {
|
|
543
|
+
const args = node.arguments;
|
|
544
|
+
if (args.length === 0) return null;
|
|
545
|
+
const callbackIndex = getCallbackIndex(hookName);
|
|
546
|
+
const callback = args[callbackIndex];
|
|
547
|
+
if (callback == null) return null;
|
|
548
|
+
const depsArgIndex = callbackIndex + 1;
|
|
549
|
+
if (args.length <= depsArgIndex) return null;
|
|
550
|
+
const depsArg = args[args.length - 1];
|
|
551
|
+
if (depsArg == null) return null;
|
|
552
|
+
if (depsArg.type === AST_NODE_TYPES.ArrayExpression) return {
|
|
553
|
+
callback,
|
|
554
|
+
depsArgNode: depsArg,
|
|
555
|
+
depsNode: depsArg
|
|
556
|
+
};
|
|
557
|
+
return {
|
|
558
|
+
callback,
|
|
559
|
+
depsArgNode: depsArg,
|
|
560
|
+
depsNode: null
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Collect all reactive dependency candidates from a callback node.
|
|
565
|
+
* Walks the callback body, finds all identifier references and member expressions,
|
|
566
|
+
* resolves them via scope analysis, and classifies them as reactive or stable.
|
|
567
|
+
* @param callbackNode - the callback argument node
|
|
568
|
+
* @param componentScope - the enclosing component or hook function
|
|
569
|
+
*/
|
|
570
|
+
function collectReactiveDeps(callbackNode, componentScope) {
|
|
571
|
+
const reactiveDeps = /* @__PURE__ */ new Set();
|
|
572
|
+
const callbackScope = context.sourceCode.getScope(callbackNode);
|
|
573
|
+
const references = collectScopeReferences(callbackScope);
|
|
574
|
+
for (const ref of references) {
|
|
575
|
+
const identifier = ref.identifier;
|
|
576
|
+
if (identifier.type !== AST_NODE_TYPES.Identifier) continue;
|
|
577
|
+
const memberExprText = getEnclosingMemberExpressionText(identifier);
|
|
578
|
+
if (memberExprText != null) {
|
|
579
|
+
const variable = findVariable(identifier.name, callbackScope);
|
|
580
|
+
if (variable == null) continue;
|
|
581
|
+
if (isStableVariable(variable)) continue;
|
|
582
|
+
if (!isDefinedInScope(variable, componentScope)) continue;
|
|
583
|
+
reactiveDeps.add(memberExprText);
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
const variable = findVariable(identifier.name, callbackScope);
|
|
587
|
+
if (variable == null) continue;
|
|
588
|
+
if (isStableVariable(variable)) continue;
|
|
589
|
+
if (!isDefinedInScope(variable, componentScope)) continue;
|
|
590
|
+
reactiveDeps.add(identifier.name);
|
|
591
|
+
}
|
|
592
|
+
return reactiveDeps;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Recursively collect all references from a scope and its child scopes,
|
|
596
|
+
* but stop at function boundaries that are not the callback itself.
|
|
597
|
+
* @param scope - the scope to collect references from
|
|
598
|
+
*/
|
|
599
|
+
function collectScopeReferences(scope) {
|
|
600
|
+
const refs = [];
|
|
601
|
+
for (const ref of scope.references) {
|
|
602
|
+
if (ref.isWriteOnly()) continue;
|
|
603
|
+
refs.push(ref);
|
|
604
|
+
}
|
|
605
|
+
for (const childScope of scope.childScopes) refs.push(...collectScopeReferences(childScope));
|
|
606
|
+
return refs;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* If an identifier is the root of a member expression chain,
|
|
610
|
+
* return the full text of that member expression.
|
|
611
|
+
* @param identifier - the identifier node to check
|
|
612
|
+
*/
|
|
613
|
+
function getEnclosingMemberExpressionText(identifier) {
|
|
614
|
+
const { parent } = identifier;
|
|
615
|
+
if (parent.type !== AST_NODE_TYPES.MemberExpression) return null;
|
|
616
|
+
if (parent.object !== identifier) return null;
|
|
617
|
+
let outermost = parent;
|
|
618
|
+
let current = parent;
|
|
619
|
+
while (current.parent.type === AST_NODE_TYPES.MemberExpression && current.parent.object === current && !current.parent.computed) {
|
|
620
|
+
outermost = current.parent;
|
|
621
|
+
current = current.parent;
|
|
622
|
+
}
|
|
623
|
+
return getMemberExpressionText(outermost);
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Get the set of declared dependencies from a dependency array node.
|
|
627
|
+
* @param depsNode - the array expression node
|
|
628
|
+
*/
|
|
629
|
+
function getDeclaredDeps(depsNode) {
|
|
630
|
+
const deps = /* @__PURE__ */ new Set();
|
|
631
|
+
for (const element of depsNode.elements) {
|
|
632
|
+
if (element == null) continue;
|
|
633
|
+
if (element.type === AST_NODE_TYPES.SpreadElement) continue;
|
|
634
|
+
deps.add(getText(element));
|
|
635
|
+
}
|
|
636
|
+
return deps;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Generate a fix that produces a corrected dependency array.
|
|
640
|
+
* Removes unnecessary deps, adds missing deps, and sorts all alphabetically.
|
|
641
|
+
* @param depsNode - the dependency array node
|
|
642
|
+
* @param missing - set of missing dependency names
|
|
643
|
+
* @param unnecessary - set of unnecessary dependency names
|
|
644
|
+
*/
|
|
645
|
+
function generateFix(depsNode, missing, unnecessary) {
|
|
646
|
+
return (fixer) => {
|
|
647
|
+
const allDeps = [...depsNode.elements.filter((el) => el != null && el.type !== AST_NODE_TYPES.SpreadElement).map((el) => getText(el)).filter((text) => !unnecessary.has(text)), ...missing].toSorted();
|
|
648
|
+
return fixer.replaceText(depsNode, `[${allDeps.join(", ")}]`);
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Analyze a collected hook call and report missing/unnecessary dependencies.
|
|
653
|
+
* @param hookCall - the collected hook call to analyze
|
|
654
|
+
*/
|
|
655
|
+
function analyzeHookCall(hookCall) {
|
|
656
|
+
const { node, callback, depsNode, hookName } = hookCall;
|
|
657
|
+
if (depsNode == null) return;
|
|
658
|
+
const componentScope = findComponentOrHookScope(node);
|
|
659
|
+
if (componentScope == null) return;
|
|
660
|
+
const reactiveDeps = collectReactiveDeps(callback, componentScope);
|
|
661
|
+
const declaredDeps = getDeclaredDeps(depsNode);
|
|
662
|
+
const missingDeps = /* @__PURE__ */ new Set();
|
|
663
|
+
for (const dep of reactiveDeps) if (!declaredDeps.has(dep)) missingDeps.add(dep);
|
|
664
|
+
const unnecessaryDeps = /* @__PURE__ */ new Set();
|
|
665
|
+
for (const dep of declaredDeps) if (!reactiveDeps.has(dep)) unnecessaryDeps.add(dep);
|
|
666
|
+
const hasMissing = missingDeps.size > 0;
|
|
667
|
+
const hasUnnecessary = unnecessaryDeps.size > 0;
|
|
668
|
+
if (!hasMissing && !hasUnnecessary) return;
|
|
669
|
+
const fix = generateFix(depsNode, missingDeps, unnecessaryDeps);
|
|
670
|
+
if (hasMissing) {
|
|
671
|
+
const depsList = [...missingDeps].toSorted().map((d) => `'${d}'`).join(", ");
|
|
672
|
+
context.report({
|
|
673
|
+
messageId: "missingDeps",
|
|
674
|
+
node: depsNode,
|
|
675
|
+
data: {
|
|
676
|
+
deps: depsList,
|
|
677
|
+
hookName
|
|
678
|
+
},
|
|
679
|
+
fix
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
if (hasUnnecessary) {
|
|
683
|
+
const depsList = [...unnecessaryDeps].toSorted().map((d) => `'${d}'`).join(", ");
|
|
684
|
+
context.report({
|
|
685
|
+
messageId: "unnecessaryDeps",
|
|
686
|
+
node: depsNode,
|
|
687
|
+
data: {
|
|
688
|
+
deps: depsList,
|
|
689
|
+
hookName
|
|
690
|
+
},
|
|
691
|
+
...!hasMissing ? { fix } : {}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return {
|
|
696
|
+
CallExpression(node) {
|
|
697
|
+
if (!isHookWithDeps(node)) return;
|
|
698
|
+
const hookName = getHookName$1(node);
|
|
699
|
+
if (hookName == null) return;
|
|
700
|
+
const result = extractCallbackAndDeps(node, hookName);
|
|
701
|
+
if (result == null) return;
|
|
702
|
+
const { callback, depsArgNode, depsNode } = result;
|
|
703
|
+
if (depsNode == null && depsArgNode != null) {
|
|
704
|
+
context.report({
|
|
705
|
+
messageId: "nonLiteralDeps",
|
|
706
|
+
node: depsArgNode,
|
|
707
|
+
data: { hookName }
|
|
708
|
+
});
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
collectedHookCalls.push({
|
|
712
|
+
node,
|
|
713
|
+
callback,
|
|
714
|
+
depsArgNode,
|
|
715
|
+
depsNode,
|
|
716
|
+
hookName
|
|
717
|
+
});
|
|
718
|
+
},
|
|
719
|
+
"Program:exit"() {
|
|
720
|
+
for (const hookCall of collectedHookCalls) analyzeHookCall(hookCall);
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
223
725
|
//#endregion
|
|
224
726
|
//#region src/rules/jsx-dollar.ts
|
|
225
|
-
const RULE_NAME$
|
|
727
|
+
const RULE_NAME$60 = "jsx-dollar";
|
|
226
728
|
var jsx_dollar_default = createRule({
|
|
227
729
|
meta: {
|
|
228
730
|
type: "problem",
|
|
@@ -235,11 +737,11 @@ var jsx_dollar_default = createRule({
|
|
|
235
737
|
},
|
|
236
738
|
schema: []
|
|
237
739
|
},
|
|
238
|
-
name: RULE_NAME$
|
|
239
|
-
create: create$
|
|
740
|
+
name: RULE_NAME$60,
|
|
741
|
+
create: create$60,
|
|
240
742
|
defaultOptions: []
|
|
241
743
|
});
|
|
242
|
-
function create$
|
|
744
|
+
function create$60(context) {
|
|
243
745
|
/**
|
|
244
746
|
* Visitor function for JSXElement and JSXFragment nodes
|
|
245
747
|
* @param node The JSXElement or JSXFragment node to be checked
|
|
@@ -280,7 +782,7 @@ function create$63(context) {
|
|
|
280
782
|
|
|
281
783
|
//#endregion
|
|
282
784
|
//#region src/rules/jsx-key-before-spread.ts
|
|
283
|
-
const RULE_NAME$
|
|
785
|
+
const RULE_NAME$59 = "jsx-key-before-spread";
|
|
284
786
|
var jsx_key_before_spread_default = createRule({
|
|
285
787
|
meta: {
|
|
286
788
|
type: "problem",
|
|
@@ -288,11 +790,11 @@ var jsx_key_before_spread_default = createRule({
|
|
|
288
790
|
messages: { default: "The 'key' prop must be placed before any spread props when using the new JSX transform." },
|
|
289
791
|
schema: []
|
|
290
792
|
},
|
|
291
|
-
name: RULE_NAME$
|
|
292
|
-
create: create$
|
|
793
|
+
name: RULE_NAME$59,
|
|
794
|
+
create: create$59,
|
|
293
795
|
defaultOptions: []
|
|
294
796
|
});
|
|
295
|
-
function create$
|
|
797
|
+
function create$59(context) {
|
|
296
798
|
const { jsx } = {
|
|
297
799
|
...core.getJsxConfigFromContext(context),
|
|
298
800
|
...core.getJsxConfigFromAnnotation(context)
|
|
@@ -316,7 +818,7 @@ function create$62(context) {
|
|
|
316
818
|
|
|
317
819
|
//#endregion
|
|
318
820
|
//#region src/rules/jsx-no-comment-textnodes.ts
|
|
319
|
-
const RULE_NAME$
|
|
821
|
+
const RULE_NAME$58 = "jsx-no-comment-textnodes";
|
|
320
822
|
var jsx_no_comment_textnodes_default = createRule({
|
|
321
823
|
meta: {
|
|
322
824
|
type: "problem",
|
|
@@ -324,11 +826,11 @@ var jsx_no_comment_textnodes_default = createRule({
|
|
|
324
826
|
messages: { default: "Possible misused comment in text node. Comments inside children section of tag should be placed inside braces." },
|
|
325
827
|
schema: []
|
|
326
828
|
},
|
|
327
|
-
name: RULE_NAME$
|
|
328
|
-
create: create$
|
|
829
|
+
name: RULE_NAME$58,
|
|
830
|
+
create: create$58,
|
|
329
831
|
defaultOptions: []
|
|
330
832
|
});
|
|
331
|
-
function create$
|
|
833
|
+
function create$58(context) {
|
|
332
834
|
function hasCommentLike(node) {
|
|
333
835
|
if (ast.isOneOf([AST_NODE_TYPES.JSXAttribute, AST_NODE_TYPES.JSXExpressionContainer])(node.parent)) return false;
|
|
334
836
|
return /^\s*\/(?:\/|\*)/mu.test(context.sourceCode.getText(node));
|
|
@@ -349,7 +851,7 @@ function create$61(context) {
|
|
|
349
851
|
|
|
350
852
|
//#endregion
|
|
351
853
|
//#region src/rules/jsx-no-duplicate-props.ts
|
|
352
|
-
const RULE_NAME$
|
|
854
|
+
const RULE_NAME$57 = "jsx-no-duplicate-props";
|
|
353
855
|
var jsx_no_duplicate_props_default = createRule({
|
|
354
856
|
meta: {
|
|
355
857
|
type: "problem",
|
|
@@ -357,11 +859,11 @@ var jsx_no_duplicate_props_default = createRule({
|
|
|
357
859
|
messages: { default: "This JSX property is assigned multiple times." },
|
|
358
860
|
schema: []
|
|
359
861
|
},
|
|
360
|
-
name: RULE_NAME$
|
|
361
|
-
create: create$
|
|
862
|
+
name: RULE_NAME$57,
|
|
863
|
+
create: create$57,
|
|
362
864
|
defaultOptions: []
|
|
363
865
|
});
|
|
364
|
-
function create$
|
|
866
|
+
function create$57(context) {
|
|
365
867
|
return { JSXOpeningElement(node) {
|
|
366
868
|
const props = [];
|
|
367
869
|
for (const attr of node.attributes) {
|
|
@@ -382,7 +884,7 @@ function create$60(context) {
|
|
|
382
884
|
|
|
383
885
|
//#endregion
|
|
384
886
|
//#region src/rules/jsx-no-iife.ts
|
|
385
|
-
const RULE_NAME$
|
|
887
|
+
const RULE_NAME$56 = "jsx-no-iife";
|
|
386
888
|
var jsx_no_iife_default = createRule({
|
|
387
889
|
meta: {
|
|
388
890
|
type: "problem",
|
|
@@ -390,11 +892,11 @@ var jsx_no_iife_default = createRule({
|
|
|
390
892
|
messages: { default: "Avoid using immediately-invoked function expressions in JSX." },
|
|
391
893
|
schema: []
|
|
392
894
|
},
|
|
393
|
-
name: RULE_NAME$
|
|
394
|
-
create: create$
|
|
895
|
+
name: RULE_NAME$56,
|
|
896
|
+
create: create$56,
|
|
395
897
|
defaultOptions: []
|
|
396
898
|
});
|
|
397
|
-
function create$
|
|
899
|
+
function create$56(context) {
|
|
398
900
|
return {
|
|
399
901
|
"JSXElement :function"(node) {
|
|
400
902
|
if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) context.report({
|
|
@@ -413,7 +915,7 @@ function create$59(context) {
|
|
|
413
915
|
|
|
414
916
|
//#endregion
|
|
415
917
|
//#region src/rules/jsx-no-undef.ts
|
|
416
|
-
const RULE_NAME$
|
|
918
|
+
const RULE_NAME$55 = "jsx-no-undef";
|
|
417
919
|
var jsx_no_undef_default = createRule({
|
|
418
920
|
meta: {
|
|
419
921
|
type: "problem",
|
|
@@ -421,11 +923,11 @@ var jsx_no_undef_default = createRule({
|
|
|
421
923
|
messages: { default: "JSX variable '{{name}}' is not defined." },
|
|
422
924
|
schema: []
|
|
423
925
|
},
|
|
424
|
-
name: RULE_NAME$
|
|
425
|
-
create: create$
|
|
926
|
+
name: RULE_NAME$55,
|
|
927
|
+
create: create$55,
|
|
426
928
|
defaultOptions: []
|
|
427
929
|
});
|
|
428
|
-
function create$
|
|
930
|
+
function create$55(context) {
|
|
429
931
|
return { JSXOpeningElement(node) {
|
|
430
932
|
const name = match(node.name).with({ type: AST_NODE_TYPES.JSXIdentifier }, (n) => n.name).with({
|
|
431
933
|
type: AST_NODE_TYPES.JSXMemberExpression,
|
|
@@ -444,8 +946,8 @@ function create$58(context) {
|
|
|
444
946
|
|
|
445
947
|
//#endregion
|
|
446
948
|
//#region src/rules/jsx-shorthand-boolean.ts
|
|
447
|
-
const RULE_NAME$
|
|
448
|
-
const defaultOptions$
|
|
949
|
+
const RULE_NAME$54 = "jsx-shorthand-boolean";
|
|
950
|
+
const defaultOptions$3 = [1];
|
|
449
951
|
const schema$3 = [{
|
|
450
952
|
type: "integer",
|
|
451
953
|
enum: [-1, 1]
|
|
@@ -458,12 +960,12 @@ var jsx_shorthand_boolean_default = createRule({
|
|
|
458
960
|
messages: { default: "{{message}}" },
|
|
459
961
|
schema: schema$3
|
|
460
962
|
},
|
|
461
|
-
name: RULE_NAME$
|
|
462
|
-
create: create$
|
|
463
|
-
defaultOptions: defaultOptions$
|
|
963
|
+
name: RULE_NAME$54,
|
|
964
|
+
create: create$54,
|
|
965
|
+
defaultOptions: defaultOptions$3
|
|
464
966
|
});
|
|
465
|
-
function create$
|
|
466
|
-
const policy = context.options[0] ?? defaultOptions$
|
|
967
|
+
function create$54(context) {
|
|
968
|
+
const policy = context.options[0] ?? defaultOptions$3[0];
|
|
467
969
|
return { JSXAttribute(node) {
|
|
468
970
|
const { value } = node;
|
|
469
971
|
const propName = core.getJsxAttributeName(context, node);
|
|
@@ -490,8 +992,8 @@ function create$57(context) {
|
|
|
490
992
|
|
|
491
993
|
//#endregion
|
|
492
994
|
//#region src/rules/jsx-shorthand-fragment.ts
|
|
493
|
-
const RULE_NAME$
|
|
494
|
-
const defaultOptions$
|
|
995
|
+
const RULE_NAME$53 = "jsx-shorthand-fragment";
|
|
996
|
+
const defaultOptions$2 = [1];
|
|
495
997
|
const schema$2 = [{
|
|
496
998
|
type: "integer",
|
|
497
999
|
enum: [-1, 1]
|
|
@@ -504,12 +1006,12 @@ var jsx_shorthand_fragment_default = createRule({
|
|
|
504
1006
|
messages: { default: "{{message}}" },
|
|
505
1007
|
schema: schema$2
|
|
506
1008
|
},
|
|
507
|
-
name: RULE_NAME$
|
|
508
|
-
create: create$
|
|
509
|
-
defaultOptions: defaultOptions$
|
|
1009
|
+
name: RULE_NAME$53,
|
|
1010
|
+
create: create$53,
|
|
1011
|
+
defaultOptions: defaultOptions$2
|
|
510
1012
|
});
|
|
511
|
-
function create$
|
|
512
|
-
const policy = context.options[0] ?? defaultOptions$
|
|
1013
|
+
function create$53(context) {
|
|
1014
|
+
const policy = context.options[0] ?? defaultOptions$2[0];
|
|
513
1015
|
const jsxConfig = {
|
|
514
1016
|
...core.getJsxConfigFromContext(context),
|
|
515
1017
|
...core.getJsxConfigFromAnnotation(context)
|
|
@@ -543,7 +1045,7 @@ function create$56(context) {
|
|
|
543
1045
|
|
|
544
1046
|
//#endregion
|
|
545
1047
|
//#region src/rules/jsx-uses-react.ts
|
|
546
|
-
const RULE_NAME$
|
|
1048
|
+
const RULE_NAME$52 = "jsx-uses-react";
|
|
547
1049
|
var jsx_uses_react_default = createRule({
|
|
548
1050
|
meta: {
|
|
549
1051
|
type: "problem",
|
|
@@ -551,11 +1053,11 @@ var jsx_uses_react_default = createRule({
|
|
|
551
1053
|
messages: { default: "Marked {{name}} as used." },
|
|
552
1054
|
schema: []
|
|
553
1055
|
},
|
|
554
|
-
name: RULE_NAME$
|
|
555
|
-
create: create$
|
|
1056
|
+
name: RULE_NAME$52,
|
|
1057
|
+
create: create$52,
|
|
556
1058
|
defaultOptions: []
|
|
557
1059
|
});
|
|
558
|
-
function create$
|
|
1060
|
+
function create$52(context) {
|
|
559
1061
|
const { jsx, jsxFactory, jsxFragmentFactory } = {
|
|
560
1062
|
...core.getJsxConfigFromContext(context),
|
|
561
1063
|
...core.getJsxConfigFromAnnotation(context)
|
|
@@ -586,7 +1088,7 @@ function debugReport(context, node, name) {
|
|
|
586
1088
|
|
|
587
1089
|
//#endregion
|
|
588
1090
|
//#region src/rules/jsx-uses-vars.ts
|
|
589
|
-
const RULE_NAME$
|
|
1091
|
+
const RULE_NAME$51 = "jsx-uses-vars";
|
|
590
1092
|
var jsx_uses_vars_default = createRule({
|
|
591
1093
|
meta: {
|
|
592
1094
|
type: "problem",
|
|
@@ -594,11 +1096,11 @@ var jsx_uses_vars_default = createRule({
|
|
|
594
1096
|
messages: { default: "An identifier in JSX is marked as used." },
|
|
595
1097
|
schema: []
|
|
596
1098
|
},
|
|
597
|
-
name: RULE_NAME$
|
|
598
|
-
create: create$
|
|
1099
|
+
name: RULE_NAME$51,
|
|
1100
|
+
create: create$51,
|
|
599
1101
|
defaultOptions: []
|
|
600
1102
|
});
|
|
601
|
-
function create$
|
|
1103
|
+
function create$51(context) {
|
|
602
1104
|
return { JSXOpeningElement(node) {
|
|
603
1105
|
switch (node.name.type) {
|
|
604
1106
|
case AST_NODE_TYPES.JSXIdentifier:
|
|
@@ -616,7 +1118,7 @@ function create$54(context) {
|
|
|
616
1118
|
|
|
617
1119
|
//#endregion
|
|
618
1120
|
//#region src/rules/no-access-state-in-setstate.ts
|
|
619
|
-
const RULE_NAME$
|
|
1121
|
+
const RULE_NAME$50 = "no-access-state-in-setstate";
|
|
620
1122
|
function isKeyLiteral$2(node, key) {
|
|
621
1123
|
return match(key).with({ type: AST_NODE_TYPES.Literal }, constTrue).with({
|
|
622
1124
|
type: AST_NODE_TYPES.TemplateLiteral,
|
|
@@ -630,11 +1132,11 @@ var no_access_state_in_setstate_default = createRule({
|
|
|
630
1132
|
messages: { default: "Do not access 'this.state' within 'setState'. Use the update function instead." },
|
|
631
1133
|
schema: []
|
|
632
1134
|
},
|
|
633
|
-
name: RULE_NAME$
|
|
634
|
-
create: create$
|
|
1135
|
+
name: RULE_NAME$50,
|
|
1136
|
+
create: create$50,
|
|
635
1137
|
defaultOptions: []
|
|
636
1138
|
});
|
|
637
|
-
function create$
|
|
1139
|
+
function create$50(context) {
|
|
638
1140
|
if (!context.sourceCode.text.includes("setState")) return {};
|
|
639
1141
|
const classStack = [];
|
|
640
1142
|
const methodStack = [];
|
|
@@ -705,7 +1207,7 @@ function create$53(context) {
|
|
|
705
1207
|
|
|
706
1208
|
//#endregion
|
|
707
1209
|
//#region src/rules/no-array-index-key.ts
|
|
708
|
-
const RULE_NAME$
|
|
1210
|
+
const RULE_NAME$49 = "no-array-index-key";
|
|
709
1211
|
const REACT_CHILDREN_METHOD = ["forEach", "map"];
|
|
710
1212
|
function getIndexParamPosition(methodName) {
|
|
711
1213
|
switch (methodName) {
|
|
@@ -764,11 +1266,11 @@ var no_array_index_key_default = createRule({
|
|
|
764
1266
|
messages: { default: "Do not use item index in the array as its key." },
|
|
765
1267
|
schema: []
|
|
766
1268
|
},
|
|
767
|
-
name: RULE_NAME$
|
|
768
|
-
create: create$
|
|
1269
|
+
name: RULE_NAME$49,
|
|
1270
|
+
create: create$49,
|
|
769
1271
|
defaultOptions: []
|
|
770
1272
|
});
|
|
771
|
-
function create$
|
|
1273
|
+
function create$49(context) {
|
|
772
1274
|
const indexParamNames = [];
|
|
773
1275
|
function isArrayIndex(node) {
|
|
774
1276
|
return node.type === AST_NODE_TYPES.Identifier && indexParamNames.some((name) => name != null && name === node.name);
|
|
@@ -834,19 +1336,19 @@ function create$52(context) {
|
|
|
834
1336
|
|
|
835
1337
|
//#endregion
|
|
836
1338
|
//#region src/rules/no-children-count.ts
|
|
837
|
-
const RULE_NAME$
|
|
1339
|
+
const RULE_NAME$48 = "no-children-count";
|
|
838
1340
|
var no_children_count_default = createRule({
|
|
839
1341
|
meta: {
|
|
840
1342
|
type: "problem",
|
|
841
1343
|
docs: { description: "Disallows the use of 'Children.count' from the 'react' package." },
|
|
842
1344
|
messages: { default: "Using 'Children.count' is uncommon and can lead to fragile code. Use alternatives instead." },
|
|
843
1345
|
schema: []
|
|
844
|
-
},
|
|
845
|
-
name: RULE_NAME$
|
|
846
|
-
create: create$
|
|
1346
|
+
},
|
|
1347
|
+
name: RULE_NAME$48,
|
|
1348
|
+
create: create$48,
|
|
847
1349
|
defaultOptions: []
|
|
848
1350
|
});
|
|
849
|
-
function create$
|
|
1351
|
+
function create$48(context) {
|
|
850
1352
|
return { MemberExpression(node) {
|
|
851
1353
|
if (core.isChildrenCount(context, node)) context.report({
|
|
852
1354
|
messageId: "default",
|
|
@@ -857,7 +1359,7 @@ function create$51(context) {
|
|
|
857
1359
|
|
|
858
1360
|
//#endregion
|
|
859
1361
|
//#region src/rules/no-children-for-each.ts
|
|
860
|
-
const RULE_NAME$
|
|
1362
|
+
const RULE_NAME$47 = "no-children-for-each";
|
|
861
1363
|
var no_children_for_each_default = createRule({
|
|
862
1364
|
meta: {
|
|
863
1365
|
type: "problem",
|
|
@@ -865,11 +1367,11 @@ var no_children_for_each_default = createRule({
|
|
|
865
1367
|
messages: { default: "Using 'Children.forEach' is uncommon and can lead to fragile code. Use alternatives instead." },
|
|
866
1368
|
schema: []
|
|
867
1369
|
},
|
|
868
|
-
name: RULE_NAME$
|
|
869
|
-
create: create$
|
|
1370
|
+
name: RULE_NAME$47,
|
|
1371
|
+
create: create$47,
|
|
870
1372
|
defaultOptions: []
|
|
871
1373
|
});
|
|
872
|
-
function create$
|
|
1374
|
+
function create$47(context) {
|
|
873
1375
|
return { MemberExpression(node) {
|
|
874
1376
|
if (core.isChildrenForEach(context, node)) context.report({
|
|
875
1377
|
messageId: "default",
|
|
@@ -880,7 +1382,7 @@ function create$50(context) {
|
|
|
880
1382
|
|
|
881
1383
|
//#endregion
|
|
882
1384
|
//#region src/rules/no-children-map.ts
|
|
883
|
-
const RULE_NAME$
|
|
1385
|
+
const RULE_NAME$46 = "no-children-map";
|
|
884
1386
|
var no_children_map_default = createRule({
|
|
885
1387
|
meta: {
|
|
886
1388
|
type: "problem",
|
|
@@ -888,11 +1390,11 @@ var no_children_map_default = createRule({
|
|
|
888
1390
|
messages: { default: "Using 'Children.map' is uncommon and can lead to fragile code. Use alternatives instead." },
|
|
889
1391
|
schema: []
|
|
890
1392
|
},
|
|
891
|
-
name: RULE_NAME$
|
|
892
|
-
create: create$
|
|
1393
|
+
name: RULE_NAME$46,
|
|
1394
|
+
create: create$46,
|
|
893
1395
|
defaultOptions: []
|
|
894
1396
|
});
|
|
895
|
-
function create$
|
|
1397
|
+
function create$46(context) {
|
|
896
1398
|
return { MemberExpression(node) {
|
|
897
1399
|
if (core.isChildrenMap(context, node)) context.report({
|
|
898
1400
|
messageId: "default",
|
|
@@ -903,7 +1405,7 @@ function create$49(context) {
|
|
|
903
1405
|
|
|
904
1406
|
//#endregion
|
|
905
1407
|
//#region src/rules/no-children-only.ts
|
|
906
|
-
const RULE_NAME$
|
|
1408
|
+
const RULE_NAME$45 = "no-children-only";
|
|
907
1409
|
var no_children_only_default = createRule({
|
|
908
1410
|
meta: {
|
|
909
1411
|
type: "problem",
|
|
@@ -911,11 +1413,11 @@ var no_children_only_default = createRule({
|
|
|
911
1413
|
messages: { default: "Using 'Children.only' is uncommon and can lead to fragile code. Use alternatives instead." },
|
|
912
1414
|
schema: []
|
|
913
1415
|
},
|
|
914
|
-
name: RULE_NAME$
|
|
915
|
-
create: create$
|
|
1416
|
+
name: RULE_NAME$45,
|
|
1417
|
+
create: create$45,
|
|
916
1418
|
defaultOptions: []
|
|
917
1419
|
});
|
|
918
|
-
function create$
|
|
1420
|
+
function create$45(context) {
|
|
919
1421
|
return { MemberExpression(node) {
|
|
920
1422
|
if (core.isChildrenOnly(context, node)) context.report({
|
|
921
1423
|
messageId: "default",
|
|
@@ -926,7 +1428,7 @@ function create$48(context) {
|
|
|
926
1428
|
|
|
927
1429
|
//#endregion
|
|
928
1430
|
//#region src/rules/no-children-prop.ts
|
|
929
|
-
const RULE_NAME$
|
|
1431
|
+
const RULE_NAME$44 = "no-children-prop";
|
|
930
1432
|
var no_children_prop_default = createRule({
|
|
931
1433
|
meta: {
|
|
932
1434
|
type: "problem",
|
|
@@ -934,11 +1436,11 @@ var no_children_prop_default = createRule({
|
|
|
934
1436
|
messages: { default: "Do not pass 'children' as props." },
|
|
935
1437
|
schema: []
|
|
936
1438
|
},
|
|
937
|
-
name: RULE_NAME$
|
|
938
|
-
create: create$
|
|
1439
|
+
name: RULE_NAME$44,
|
|
1440
|
+
create: create$44,
|
|
939
1441
|
defaultOptions: []
|
|
940
1442
|
});
|
|
941
|
-
function create$
|
|
1443
|
+
function create$44(context) {
|
|
942
1444
|
return { JSXElement(node) {
|
|
943
1445
|
const childrenProp = core.getJsxAttribute(context, node)("children");
|
|
944
1446
|
if (childrenProp != null) context.report({
|
|
@@ -950,7 +1452,7 @@ function create$47(context) {
|
|
|
950
1452
|
|
|
951
1453
|
//#endregion
|
|
952
1454
|
//#region src/rules/no-children-to-array.ts
|
|
953
|
-
const RULE_NAME$
|
|
1455
|
+
const RULE_NAME$43 = "no-children-to-array";
|
|
954
1456
|
var no_children_to_array_default = createRule({
|
|
955
1457
|
meta: {
|
|
956
1458
|
type: "problem",
|
|
@@ -958,11 +1460,11 @@ var no_children_to_array_default = createRule({
|
|
|
958
1460
|
messages: { default: "Using 'Children.toArray' is uncommon and can lead to fragile code. Use alternatives instead." },
|
|
959
1461
|
schema: []
|
|
960
1462
|
},
|
|
961
|
-
name: RULE_NAME$
|
|
962
|
-
create: create$
|
|
1463
|
+
name: RULE_NAME$43,
|
|
1464
|
+
create: create$43,
|
|
963
1465
|
defaultOptions: []
|
|
964
1466
|
});
|
|
965
|
-
function create$
|
|
1467
|
+
function create$43(context) {
|
|
966
1468
|
return { MemberExpression(node) {
|
|
967
1469
|
if (core.isChildrenToArray(context, node)) context.report({
|
|
968
1470
|
messageId: "default",
|
|
@@ -973,7 +1475,7 @@ function create$46(context) {
|
|
|
973
1475
|
|
|
974
1476
|
//#endregion
|
|
975
1477
|
//#region src/rules/no-class-component.ts
|
|
976
|
-
const RULE_NAME$
|
|
1478
|
+
const RULE_NAME$42 = "no-class-component";
|
|
977
1479
|
var no_class_component_default = createRule({
|
|
978
1480
|
meta: {
|
|
979
1481
|
type: "problem",
|
|
@@ -981,11 +1483,11 @@ var no_class_component_default = createRule({
|
|
|
981
1483
|
messages: { default: "Avoid using class components. Use function components instead." },
|
|
982
1484
|
schema: []
|
|
983
1485
|
},
|
|
984
|
-
name: RULE_NAME$
|
|
985
|
-
create: create$
|
|
1486
|
+
name: RULE_NAME$42,
|
|
1487
|
+
create: create$42,
|
|
986
1488
|
defaultOptions: []
|
|
987
1489
|
});
|
|
988
|
-
function create$
|
|
1490
|
+
function create$42(context) {
|
|
989
1491
|
if (!context.sourceCode.text.includes("Component")) return {};
|
|
990
1492
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
991
1493
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -1002,7 +1504,7 @@ function create$45(context) {
|
|
|
1002
1504
|
|
|
1003
1505
|
//#endregion
|
|
1004
1506
|
//#region src/rules/no-clone-element.ts
|
|
1005
|
-
const RULE_NAME$
|
|
1507
|
+
const RULE_NAME$41 = "no-clone-element";
|
|
1006
1508
|
var no_clone_element_default = createRule({
|
|
1007
1509
|
meta: {
|
|
1008
1510
|
type: "problem",
|
|
@@ -1010,11 +1512,11 @@ var no_clone_element_default = createRule({
|
|
|
1010
1512
|
messages: { default: "Using 'cloneElement' is uncommon and can lead to fragile code. Use alternatives instead." },
|
|
1011
1513
|
schema: []
|
|
1012
1514
|
},
|
|
1013
|
-
name: RULE_NAME$
|
|
1014
|
-
create: create$
|
|
1515
|
+
name: RULE_NAME$41,
|
|
1516
|
+
create: create$41,
|
|
1015
1517
|
defaultOptions: []
|
|
1016
1518
|
});
|
|
1017
|
-
function create$
|
|
1519
|
+
function create$41(context) {
|
|
1018
1520
|
return { CallExpression(node) {
|
|
1019
1521
|
if (core.isCloneElementCall(context, node)) context.report({
|
|
1020
1522
|
messageId: "default",
|
|
@@ -1025,7 +1527,7 @@ function create$44(context) {
|
|
|
1025
1527
|
|
|
1026
1528
|
//#endregion
|
|
1027
1529
|
//#region src/rules/no-component-will-mount.ts
|
|
1028
|
-
const RULE_NAME$
|
|
1530
|
+
const RULE_NAME$40 = "no-component-will-mount";
|
|
1029
1531
|
var no_component_will_mount_default = createRule({
|
|
1030
1532
|
meta: {
|
|
1031
1533
|
type: "problem",
|
|
@@ -1034,11 +1536,11 @@ var no_component_will_mount_default = createRule({
|
|
|
1034
1536
|
messages: { default: "[Deprecated] Use 'UNSAFE_componentWillMount' instead." },
|
|
1035
1537
|
schema: []
|
|
1036
1538
|
},
|
|
1037
|
-
name: RULE_NAME$
|
|
1038
|
-
create: create$
|
|
1539
|
+
name: RULE_NAME$40,
|
|
1540
|
+
create: create$40,
|
|
1039
1541
|
defaultOptions: []
|
|
1040
1542
|
});
|
|
1041
|
-
function create$
|
|
1543
|
+
function create$40(context) {
|
|
1042
1544
|
if (!context.sourceCode.text.includes("componentWillMount")) return {};
|
|
1043
1545
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
1044
1546
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -1058,7 +1560,7 @@ function create$43(context) {
|
|
|
1058
1560
|
|
|
1059
1561
|
//#endregion
|
|
1060
1562
|
//#region src/rules/no-component-will-receive-props.ts
|
|
1061
|
-
const RULE_NAME$
|
|
1563
|
+
const RULE_NAME$39 = "no-component-will-receive-props";
|
|
1062
1564
|
var no_component_will_receive_props_default = createRule({
|
|
1063
1565
|
meta: {
|
|
1064
1566
|
type: "problem",
|
|
@@ -1067,11 +1569,11 @@ var no_component_will_receive_props_default = createRule({
|
|
|
1067
1569
|
messages: { default: "[Deprecated] Use 'UNSAFE_componentWillReceiveProps' instead." },
|
|
1068
1570
|
schema: []
|
|
1069
1571
|
},
|
|
1070
|
-
name: RULE_NAME$
|
|
1071
|
-
create: create$
|
|
1572
|
+
name: RULE_NAME$39,
|
|
1573
|
+
create: create$39,
|
|
1072
1574
|
defaultOptions: []
|
|
1073
1575
|
});
|
|
1074
|
-
function create$
|
|
1576
|
+
function create$39(context) {
|
|
1075
1577
|
if (!context.sourceCode.text.includes("componentWillReceiveProps")) return {};
|
|
1076
1578
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
1077
1579
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -1091,7 +1593,7 @@ function create$42(context) {
|
|
|
1091
1593
|
|
|
1092
1594
|
//#endregion
|
|
1093
1595
|
//#region src/rules/no-component-will-update.ts
|
|
1094
|
-
const RULE_NAME$
|
|
1596
|
+
const RULE_NAME$38 = "no-component-will-update";
|
|
1095
1597
|
var no_component_will_update_default = createRule({
|
|
1096
1598
|
meta: {
|
|
1097
1599
|
type: "problem",
|
|
@@ -1100,11 +1602,11 @@ var no_component_will_update_default = createRule({
|
|
|
1100
1602
|
messages: { default: "[Deprecated] Use 'UNSAFE_componentWillUpdate' instead." },
|
|
1101
1603
|
schema: []
|
|
1102
1604
|
},
|
|
1103
|
-
name: RULE_NAME$
|
|
1104
|
-
create: create$
|
|
1605
|
+
name: RULE_NAME$38,
|
|
1606
|
+
create: create$38,
|
|
1105
1607
|
defaultOptions: []
|
|
1106
1608
|
});
|
|
1107
|
-
function create$
|
|
1609
|
+
function create$38(context) {
|
|
1108
1610
|
if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
|
|
1109
1611
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
1110
1612
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -1124,7 +1626,7 @@ function create$41(context) {
|
|
|
1124
1626
|
|
|
1125
1627
|
//#endregion
|
|
1126
1628
|
//#region src/rules/no-context-provider.ts
|
|
1127
|
-
const RULE_NAME$
|
|
1629
|
+
const RULE_NAME$37 = "no-context-provider";
|
|
1128
1630
|
var no_context_provider_default = createRule({
|
|
1129
1631
|
meta: {
|
|
1130
1632
|
type: "problem",
|
|
@@ -1133,11 +1635,11 @@ var no_context_provider_default = createRule({
|
|
|
1133
1635
|
messages: { default: "In React 19, you can render '<Context>' as a provider instead of '<Context.Provider>'." },
|
|
1134
1636
|
schema: []
|
|
1135
1637
|
},
|
|
1136
|
-
name: RULE_NAME$
|
|
1137
|
-
create: create$
|
|
1638
|
+
name: RULE_NAME$37,
|
|
1639
|
+
create: create$37,
|
|
1138
1640
|
defaultOptions: []
|
|
1139
1641
|
});
|
|
1140
|
-
function create$
|
|
1642
|
+
function create$37(context) {
|
|
1141
1643
|
if (!context.sourceCode.text.includes("Provider")) return {};
|
|
1142
1644
|
const { version } = getSettingsFromContext(context);
|
|
1143
1645
|
if (compare(version, "19.0.0", "<")) return {};
|
|
@@ -1164,7 +1666,7 @@ function create$40(context) {
|
|
|
1164
1666
|
|
|
1165
1667
|
//#endregion
|
|
1166
1668
|
//#region src/rules/no-create-ref.ts
|
|
1167
|
-
const RULE_NAME$
|
|
1669
|
+
const RULE_NAME$36 = "no-create-ref";
|
|
1168
1670
|
var no_create_ref_default = createRule({
|
|
1169
1671
|
meta: {
|
|
1170
1672
|
type: "problem",
|
|
@@ -1172,11 +1674,11 @@ var no_create_ref_default = createRule({
|
|
|
1172
1674
|
messages: { default: "[Deprecated] Use 'useRef' instead." },
|
|
1173
1675
|
schema: []
|
|
1174
1676
|
},
|
|
1175
|
-
name: RULE_NAME$
|
|
1176
|
-
create: create$
|
|
1677
|
+
name: RULE_NAME$36,
|
|
1678
|
+
create: create$36,
|
|
1177
1679
|
defaultOptions: []
|
|
1178
1680
|
});
|
|
1179
|
-
function create$
|
|
1681
|
+
function create$36(context) {
|
|
1180
1682
|
return { CallExpression(node) {
|
|
1181
1683
|
if (core.isCreateRefCall(context, node) && ast.findParentNode(node, core.isClassComponent) == null) context.report({
|
|
1182
1684
|
messageId: "default",
|
|
@@ -1187,7 +1689,7 @@ function create$39(context) {
|
|
|
1187
1689
|
|
|
1188
1690
|
//#endregion
|
|
1189
1691
|
//#region src/rules/no-direct-mutation-state.ts
|
|
1190
|
-
const RULE_NAME$
|
|
1692
|
+
const RULE_NAME$35 = "no-direct-mutation-state";
|
|
1191
1693
|
function isConstructorFunction(node) {
|
|
1192
1694
|
return ast.isOneOf([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression])(node) && ast.isMethodOrProperty(node.parent) && node.parent.key.type === AST_NODE_TYPES.Identifier && node.parent.key.name === "constructor";
|
|
1193
1695
|
}
|
|
@@ -1198,11 +1700,11 @@ var no_direct_mutation_state_default = createRule({
|
|
|
1198
1700
|
messages: { default: "Do not mutate state directly. Use 'setState()' instead." },
|
|
1199
1701
|
schema: []
|
|
1200
1702
|
},
|
|
1201
|
-
name: RULE_NAME$
|
|
1202
|
-
create: create$
|
|
1703
|
+
name: RULE_NAME$35,
|
|
1704
|
+
create: create$35,
|
|
1203
1705
|
defaultOptions: []
|
|
1204
1706
|
});
|
|
1205
|
-
function create$
|
|
1707
|
+
function create$35(context) {
|
|
1206
1708
|
return { AssignmentExpression(node) {
|
|
1207
1709
|
if (!core.isAssignmentToThisState(node)) return;
|
|
1208
1710
|
const parentClass = ast.findParentNode(node, ast.isOneOf([AST_NODE_TYPES.ClassDeclaration, AST_NODE_TYPES.ClassExpression]));
|
|
@@ -1216,7 +1718,7 @@ function create$38(context) {
|
|
|
1216
1718
|
|
|
1217
1719
|
//#endregion
|
|
1218
1720
|
//#region src/rules/no-duplicate-key.ts
|
|
1219
|
-
const RULE_NAME$
|
|
1721
|
+
const RULE_NAME$34 = "no-duplicate-key";
|
|
1220
1722
|
var no_duplicate_key_default = createRule({
|
|
1221
1723
|
meta: {
|
|
1222
1724
|
type: "problem",
|
|
@@ -1224,11 +1726,11 @@ var no_duplicate_key_default = createRule({
|
|
|
1224
1726
|
messages: { default: "The 'key' prop must be unique to its sibling elements." },
|
|
1225
1727
|
schema: []
|
|
1226
1728
|
},
|
|
1227
|
-
name: RULE_NAME$
|
|
1228
|
-
create: create$
|
|
1729
|
+
name: RULE_NAME$34,
|
|
1730
|
+
create: create$34,
|
|
1229
1731
|
defaultOptions: []
|
|
1230
1732
|
});
|
|
1231
|
-
function create$
|
|
1733
|
+
function create$34(context) {
|
|
1232
1734
|
if (!context.sourceCode.text.includes("key=")) return {};
|
|
1233
1735
|
const keyedEntries = /* @__PURE__ */ new Map();
|
|
1234
1736
|
function isKeyValueEqual(a, b) {
|
|
@@ -1283,7 +1785,7 @@ function create$37(context) {
|
|
|
1283
1785
|
|
|
1284
1786
|
//#endregion
|
|
1285
1787
|
//#region src/rules/no-forward-ref.ts
|
|
1286
|
-
const RULE_NAME$
|
|
1788
|
+
const RULE_NAME$33 = "no-forward-ref";
|
|
1287
1789
|
var no_forward_ref_default = createRule({
|
|
1288
1790
|
meta: {
|
|
1289
1791
|
type: "problem",
|
|
@@ -1292,11 +1794,11 @@ var no_forward_ref_default = createRule({
|
|
|
1292
1794
|
messages: { default: "In React 19, 'forwardRef' is no longer necessary. Pass 'ref' as a prop instead." },
|
|
1293
1795
|
schema: []
|
|
1294
1796
|
},
|
|
1295
|
-
name: RULE_NAME$
|
|
1296
|
-
create: create$
|
|
1797
|
+
name: RULE_NAME$33,
|
|
1798
|
+
create: create$33,
|
|
1297
1799
|
defaultOptions: []
|
|
1298
1800
|
});
|
|
1299
|
-
function create$
|
|
1801
|
+
function create$33(context) {
|
|
1300
1802
|
if (!context.sourceCode.text.includes("forwardRef")) return {};
|
|
1301
1803
|
const { version } = getSettingsFromContext(context);
|
|
1302
1804
|
if (compare(version, "19.0.0", "<")) return {};
|
|
@@ -1391,7 +1893,7 @@ function getComponentPropsFixes(context, fixer, node, typeArguments) {
|
|
|
1391
1893
|
|
|
1392
1894
|
//#endregion
|
|
1393
1895
|
//#region src/rules/no-implicit-key.ts
|
|
1394
|
-
const RULE_NAME$
|
|
1896
|
+
const RULE_NAME$32 = "no-implicit-key";
|
|
1395
1897
|
var no_implicit_key_default = createRule({
|
|
1396
1898
|
meta: {
|
|
1397
1899
|
type: "problem",
|
|
@@ -1399,11 +1901,11 @@ var no_implicit_key_default = createRule({
|
|
|
1399
1901
|
messages: { default: "This spread attribute implicitly passes the 'key' prop to a component, this could lead to unexpected behavior. If you intend to pass the 'key' prop, use 'key={value}'." },
|
|
1400
1902
|
schema: []
|
|
1401
1903
|
},
|
|
1402
|
-
name: RULE_NAME$
|
|
1403
|
-
create: create$
|
|
1904
|
+
name: RULE_NAME$32,
|
|
1905
|
+
create: create$32,
|
|
1404
1906
|
defaultOptions: []
|
|
1405
1907
|
});
|
|
1406
|
-
function create$
|
|
1908
|
+
function create$32(context) {
|
|
1407
1909
|
const services = ESLintUtils.getParserServices(context, false);
|
|
1408
1910
|
const checker = services.program.getTypeChecker();
|
|
1409
1911
|
return { JSXSpreadAttribute(node) {
|
|
@@ -1421,7 +1923,7 @@ function create$35(context) {
|
|
|
1421
1923
|
|
|
1422
1924
|
//#endregion
|
|
1423
1925
|
//#region src/rules/no-leaked-conditional-rendering.ts
|
|
1424
|
-
const RULE_NAME$
|
|
1926
|
+
const RULE_NAME$31 = "no-leaked-conditional-rendering";
|
|
1425
1927
|
var no_leaked_conditional_rendering_default = createRule({
|
|
1426
1928
|
meta: {
|
|
1427
1929
|
type: "problem",
|
|
@@ -1429,11 +1931,11 @@ var no_leaked_conditional_rendering_default = createRule({
|
|
|
1429
1931
|
messages: { default: "Potential leaked value {{value}} that might cause unintentionally rendered values or rendering crashes." },
|
|
1430
1932
|
schema: []
|
|
1431
1933
|
},
|
|
1432
|
-
name: RULE_NAME$
|
|
1433
|
-
create: create$
|
|
1934
|
+
name: RULE_NAME$31,
|
|
1935
|
+
create: create$31,
|
|
1434
1936
|
defaultOptions: []
|
|
1435
1937
|
});
|
|
1436
|
-
function create$
|
|
1938
|
+
function create$31(context) {
|
|
1437
1939
|
if (!context.sourceCode.text.includes("&&")) return {};
|
|
1438
1940
|
const { version } = getSettingsFromContext(context);
|
|
1439
1941
|
const allowedVariants = [
|
|
@@ -1490,7 +1992,7 @@ function create$34(context) {
|
|
|
1490
1992
|
|
|
1491
1993
|
//#endregion
|
|
1492
1994
|
//#region src/rules/no-missing-component-display-name.ts
|
|
1493
|
-
const RULE_NAME$
|
|
1995
|
+
const RULE_NAME$30 = "no-missing-component-display-name";
|
|
1494
1996
|
var no_missing_component_display_name_default = createRule({
|
|
1495
1997
|
meta: {
|
|
1496
1998
|
type: "problem",
|
|
@@ -1498,11 +2000,11 @@ var no_missing_component_display_name_default = createRule({
|
|
|
1498
2000
|
messages: { default: "Add missing 'displayName' for component." },
|
|
1499
2001
|
schema: []
|
|
1500
2002
|
},
|
|
1501
|
-
name: RULE_NAME$
|
|
1502
|
-
create: create$
|
|
2003
|
+
name: RULE_NAME$30,
|
|
2004
|
+
create: create$30,
|
|
1503
2005
|
defaultOptions: []
|
|
1504
2006
|
});
|
|
1505
|
-
function create$
|
|
2007
|
+
function create$30(context) {
|
|
1506
2008
|
if (!context.sourceCode.text.includes("memo") && !context.sourceCode.text.includes("forwardRef")) return {};
|
|
1507
2009
|
const { ctx, visitor } = core.useComponentCollector(context, {
|
|
1508
2010
|
collectDisplayName: true,
|
|
@@ -1524,7 +2026,7 @@ function create$33(context) {
|
|
|
1524
2026
|
|
|
1525
2027
|
//#endregion
|
|
1526
2028
|
//#region src/rules/no-missing-context-display-name.ts
|
|
1527
|
-
const RULE_NAME$
|
|
2029
|
+
const RULE_NAME$29 = "no-missing-context-display-name";
|
|
1528
2030
|
var no_missing_context_display_name_default = createRule({
|
|
1529
2031
|
meta: {
|
|
1530
2032
|
type: "problem",
|
|
@@ -1533,11 +2035,11 @@ var no_missing_context_display_name_default = createRule({
|
|
|
1533
2035
|
messages: { default: "Add missing 'displayName' for context." },
|
|
1534
2036
|
schema: []
|
|
1535
2037
|
},
|
|
1536
|
-
name: RULE_NAME$
|
|
1537
|
-
create: create$
|
|
2038
|
+
name: RULE_NAME$29,
|
|
2039
|
+
create: create$29,
|
|
1538
2040
|
defaultOptions: []
|
|
1539
2041
|
});
|
|
1540
|
-
function create$
|
|
2042
|
+
function create$29(context) {
|
|
1541
2043
|
if (!context.sourceCode.text.includes("createContext")) return {};
|
|
1542
2044
|
const createCalls = [];
|
|
1543
2045
|
const displayNameAssignments = [];
|
|
@@ -1589,7 +2091,7 @@ function create$32(context) {
|
|
|
1589
2091
|
|
|
1590
2092
|
//#endregion
|
|
1591
2093
|
//#region src/rules/no-missing-key.ts
|
|
1592
|
-
const RULE_NAME$
|
|
2094
|
+
const RULE_NAME$28 = "no-missing-key";
|
|
1593
2095
|
var no_missing_key_default = createRule({
|
|
1594
2096
|
meta: {
|
|
1595
2097
|
type: "problem",
|
|
@@ -1600,11 +2102,11 @@ var no_missing_key_default = createRule({
|
|
|
1600
2102
|
},
|
|
1601
2103
|
schema: []
|
|
1602
2104
|
},
|
|
1603
|
-
name: RULE_NAME$
|
|
1604
|
-
create: create$
|
|
2105
|
+
name: RULE_NAME$28,
|
|
2106
|
+
create: create$28,
|
|
1605
2107
|
defaultOptions: []
|
|
1606
2108
|
});
|
|
1607
|
-
function create$
|
|
2109
|
+
function create$28(ctx) {
|
|
1608
2110
|
let inChildrenToArray = false;
|
|
1609
2111
|
function check(node) {
|
|
1610
2112
|
if (node.type === AST_NODE_TYPES.JSXElement) return core.getJsxAttribute(ctx, node)("key") == null ? {
|
|
@@ -1668,7 +2170,7 @@ function create$31(ctx) {
|
|
|
1668
2170
|
|
|
1669
2171
|
//#endregion
|
|
1670
2172
|
//#region src/rules/no-misused-capture-owner-stack.ts
|
|
1671
|
-
const RULE_NAME$
|
|
2173
|
+
const RULE_NAME$27 = "no-misused-capture-owner-stack";
|
|
1672
2174
|
var no_misused_capture_owner_stack_default = createRule({
|
|
1673
2175
|
meta: {
|
|
1674
2176
|
type: "problem",
|
|
@@ -1679,11 +2181,11 @@ var no_misused_capture_owner_stack_default = createRule({
|
|
|
1679
2181
|
},
|
|
1680
2182
|
schema: []
|
|
1681
2183
|
},
|
|
1682
|
-
name: RULE_NAME$
|
|
1683
|
-
create: create$
|
|
2184
|
+
name: RULE_NAME$27,
|
|
2185
|
+
create: create$27,
|
|
1684
2186
|
defaultOptions: []
|
|
1685
2187
|
});
|
|
1686
|
-
function create$
|
|
2188
|
+
function create$27(context) {
|
|
1687
2189
|
if (!context.sourceCode.text.includes("captureOwnerStack")) return {};
|
|
1688
2190
|
const { importSource } = getSettingsFromContext(context);
|
|
1689
2191
|
return {
|
|
@@ -1714,7 +2216,7 @@ function isDevelopmentOnlyCheck(node) {
|
|
|
1714
2216
|
|
|
1715
2217
|
//#endregion
|
|
1716
2218
|
//#region src/rules/no-nested-component-definitions.ts
|
|
1717
|
-
const RULE_NAME$
|
|
2219
|
+
const RULE_NAME$26 = "no-nested-component-definitions";
|
|
1718
2220
|
var no_nested_component_definitions_default = createRule({
|
|
1719
2221
|
meta: {
|
|
1720
2222
|
type: "problem",
|
|
@@ -1722,11 +2224,11 @@ var no_nested_component_definitions_default = createRule({
|
|
|
1722
2224
|
messages: { default: "Do not nest component definitions inside other components or props. {{suggestion}}" },
|
|
1723
2225
|
schema: []
|
|
1724
2226
|
},
|
|
1725
|
-
name: RULE_NAME$
|
|
1726
|
-
create: create$
|
|
2227
|
+
name: RULE_NAME$26,
|
|
2228
|
+
create: create$26,
|
|
1727
2229
|
defaultOptions: []
|
|
1728
2230
|
});
|
|
1729
|
-
function create$
|
|
2231
|
+
function create$26(context) {
|
|
1730
2232
|
const hint = core.ComponentDetectionHint.DoNotIncludeJsxWithNumberValue | core.ComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | core.ComponentDetectionHint.DoNotIncludeJsxWithNullValue | core.ComponentDetectionHint.DoNotIncludeJsxWithStringValue | core.ComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | core.ComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx | core.ComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | core.ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayPattern | core.ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayExpression | core.ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback;
|
|
1731
2233
|
const fCollector = core.useComponentCollector(context, { hint });
|
|
1732
2234
|
const cCollector = core.useComponentCollectorLegacy(context);
|
|
@@ -1831,7 +2333,7 @@ function isInsideCreateElementProps(context, node) {
|
|
|
1831
2333
|
|
|
1832
2334
|
//#endregion
|
|
1833
2335
|
//#region src/rules/no-nested-lazy-component-declarations.ts
|
|
1834
|
-
const RULE_NAME$
|
|
2336
|
+
const RULE_NAME$25 = "no-nested-lazy-component-declarations";
|
|
1835
2337
|
var no_nested_lazy_component_declarations_default = createRule({
|
|
1836
2338
|
meta: {
|
|
1837
2339
|
type: "problem",
|
|
@@ -1839,11 +2341,11 @@ var no_nested_lazy_component_declarations_default = createRule({
|
|
|
1839
2341
|
messages: { default: "Do not declare lazy components inside other components. Instead, always declare them at the top level of your module." },
|
|
1840
2342
|
schema: []
|
|
1841
2343
|
},
|
|
1842
|
-
name: RULE_NAME$
|
|
1843
|
-
create: create$
|
|
2344
|
+
name: RULE_NAME$25,
|
|
2345
|
+
create: create$25,
|
|
1844
2346
|
defaultOptions: []
|
|
1845
2347
|
});
|
|
1846
|
-
function create$
|
|
2348
|
+
function create$25(context) {
|
|
1847
2349
|
const hint = core.ComponentDetectionHint.None;
|
|
1848
2350
|
const collector = core.useComponentCollector(context, { hint });
|
|
1849
2351
|
const collectorLegacy = core.useComponentCollectorLegacy(context);
|
|
@@ -1872,7 +2374,7 @@ function create$28(context) {
|
|
|
1872
2374
|
|
|
1873
2375
|
//#endregion
|
|
1874
2376
|
//#region src/rules/no-redundant-should-component-update.ts
|
|
1875
|
-
const RULE_NAME$
|
|
2377
|
+
const RULE_NAME$24 = "no-redundant-should-component-update";
|
|
1876
2378
|
function isShouldComponentUpdate(node) {
|
|
1877
2379
|
return ast.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "shouldComponentUpdate";
|
|
1878
2380
|
}
|
|
@@ -1883,11 +2385,11 @@ var no_redundant_should_component_update_default = createRule({
|
|
|
1883
2385
|
messages: { default: "'{{componentName}}' does not need 'shouldComponentUpdate' when extending 'React.PureComponent'." },
|
|
1884
2386
|
schema: []
|
|
1885
2387
|
},
|
|
1886
|
-
name: RULE_NAME$
|
|
1887
|
-
create: create$
|
|
2388
|
+
name: RULE_NAME$24,
|
|
2389
|
+
create: create$24,
|
|
1888
2390
|
defaultOptions: []
|
|
1889
2391
|
});
|
|
1890
|
-
function create$
|
|
2392
|
+
function create$24(context) {
|
|
1891
2393
|
if (!context.sourceCode.text.includes("shouldComponentUpdate")) return {};
|
|
1892
2394
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
1893
2395
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -1905,7 +2407,7 @@ function create$27(context) {
|
|
|
1905
2407
|
|
|
1906
2408
|
//#endregion
|
|
1907
2409
|
//#region src/rules/no-set-state-in-component-did-mount.ts
|
|
1908
|
-
const RULE_NAME$
|
|
2410
|
+
const RULE_NAME$23 = "no-set-state-in-component-did-mount";
|
|
1909
2411
|
var no_set_state_in_component_did_mount_default = createRule({
|
|
1910
2412
|
meta: {
|
|
1911
2413
|
type: "problem",
|
|
@@ -1913,11 +2415,11 @@ var no_set_state_in_component_did_mount_default = createRule({
|
|
|
1913
2415
|
messages: { default: "Do not call `this.setState` in `componentDidMount` outside functions such as callbacks." },
|
|
1914
2416
|
schema: []
|
|
1915
2417
|
},
|
|
1916
|
-
name: RULE_NAME$
|
|
1917
|
-
create: create$
|
|
2418
|
+
name: RULE_NAME$23,
|
|
2419
|
+
create: create$23,
|
|
1918
2420
|
defaultOptions: []
|
|
1919
2421
|
});
|
|
1920
|
-
function create$
|
|
2422
|
+
function create$23(context) {
|
|
1921
2423
|
if (!context.sourceCode.text.includes("componentDidMount")) return {};
|
|
1922
2424
|
return { CallExpression(node) {
|
|
1923
2425
|
if (!core.isThisSetState(node)) return;
|
|
@@ -1935,7 +2437,7 @@ function create$26(context) {
|
|
|
1935
2437
|
|
|
1936
2438
|
//#endregion
|
|
1937
2439
|
//#region src/rules/no-set-state-in-component-did-update.ts
|
|
1938
|
-
const RULE_NAME$
|
|
2440
|
+
const RULE_NAME$22 = "no-set-state-in-component-did-update";
|
|
1939
2441
|
var no_set_state_in_component_did_update_default = createRule({
|
|
1940
2442
|
meta: {
|
|
1941
2443
|
type: "problem",
|
|
@@ -1943,11 +2445,11 @@ var no_set_state_in_component_did_update_default = createRule({
|
|
|
1943
2445
|
messages: { default: "Do not call `this.setState` in `componentDidUpdate` outside functions such as callbacks." },
|
|
1944
2446
|
schema: []
|
|
1945
2447
|
},
|
|
1946
|
-
name: RULE_NAME$
|
|
1947
|
-
create: create$
|
|
2448
|
+
name: RULE_NAME$22,
|
|
2449
|
+
create: create$22,
|
|
1948
2450
|
defaultOptions: []
|
|
1949
2451
|
});
|
|
1950
|
-
function create$
|
|
2452
|
+
function create$22(context) {
|
|
1951
2453
|
if (!context.sourceCode.text.includes("componentDidUpdate")) return {};
|
|
1952
2454
|
return { CallExpression(node) {
|
|
1953
2455
|
if (!core.isThisSetState(node)) return;
|
|
@@ -1965,7 +2467,7 @@ function create$25(context) {
|
|
|
1965
2467
|
|
|
1966
2468
|
//#endregion
|
|
1967
2469
|
//#region src/rules/no-set-state-in-component-will-update.ts
|
|
1968
|
-
const RULE_NAME$
|
|
2470
|
+
const RULE_NAME$21 = "no-set-state-in-component-will-update";
|
|
1969
2471
|
var no_set_state_in_component_will_update_default = createRule({
|
|
1970
2472
|
meta: {
|
|
1971
2473
|
type: "problem",
|
|
@@ -1973,11 +2475,11 @@ var no_set_state_in_component_will_update_default = createRule({
|
|
|
1973
2475
|
messages: { default: "Do not call `this.setState` in `componentWillUpdate` outside functions such as callbacks." },
|
|
1974
2476
|
schema: []
|
|
1975
2477
|
},
|
|
1976
|
-
name: RULE_NAME$
|
|
1977
|
-
create: create$
|
|
2478
|
+
name: RULE_NAME$21,
|
|
2479
|
+
create: create$21,
|
|
1978
2480
|
defaultOptions: []
|
|
1979
2481
|
});
|
|
1980
|
-
function create$
|
|
2482
|
+
function create$21(context) {
|
|
1981
2483
|
if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
|
|
1982
2484
|
return { CallExpression(node) {
|
|
1983
2485
|
if (!core.isThisSetState(node)) return;
|
|
@@ -1993,70 +2495,9 @@ function create$24(context) {
|
|
|
1993
2495
|
} };
|
|
1994
2496
|
}
|
|
1995
2497
|
|
|
1996
|
-
//#endregion
|
|
1997
|
-
//#region src/rules/no-unnecessary-key.ts
|
|
1998
|
-
const RULE_NAME$23 = "no-unnecessary-key";
|
|
1999
|
-
var no_unnecessary_key_default = createRule({
|
|
2000
|
-
meta: {
|
|
2001
|
-
type: "problem",
|
|
2002
|
-
docs: { description: "Disallows unnecessary 'key' props on nested child elements when rendering lists." },
|
|
2003
|
-
messages: { default: "Unnecessary `key` prop on this element. {{reason}}" },
|
|
2004
|
-
schema: []
|
|
2005
|
-
},
|
|
2006
|
-
name: RULE_NAME$23,
|
|
2007
|
-
create: create$23,
|
|
2008
|
-
defaultOptions: []
|
|
2009
|
-
});
|
|
2010
|
-
function create$23(context) {
|
|
2011
|
-
if (!context.sourceCode.text.includes("key=")) return {};
|
|
2012
|
-
const jsxConfig = {
|
|
2013
|
-
...core.getJsxConfigFromContext(context),
|
|
2014
|
-
...core.getJsxConfigFromAnnotation(context)
|
|
2015
|
-
};
|
|
2016
|
-
return { JSXAttribute(node) {
|
|
2017
|
-
if (node.name.name !== "key") return;
|
|
2018
|
-
const jsxElement = node.parent.parent;
|
|
2019
|
-
if (core.isJsxFragmentElement(context, jsxElement, jsxConfig)) return;
|
|
2020
|
-
if (jsxElement.openingElement.attributes.some((attr) => attr.type === AST_NODE_TYPES.JSXSpreadAttribute)) return;
|
|
2021
|
-
if (ast.findParentNode(jsxElement, (n) => core.isRenderFunctionLoose(context, n)) != null) return;
|
|
2022
|
-
const mapCallback = ast.findParentNode(jsxElement, isArrayMethodCallback);
|
|
2023
|
-
if (mapCallback == null || ast.findParentNode(jsxElement, ast.isFunction) !== mapCallback) return;
|
|
2024
|
-
if (context.sourceCode.getScope(mapCallback) !== context.sourceCode.getScope(jsxElement)) return;
|
|
2025
|
-
const keyedElementOrElse = ast.findParentNode(jsxElement, (n) => {
|
|
2026
|
-
if (n === mapCallback) return true;
|
|
2027
|
-
return ast.isJSXElement(n) && core.getJsxAttribute(context, n)("key") != null;
|
|
2028
|
-
});
|
|
2029
|
-
if (keyedElementOrElse == null || keyedElementOrElse === mapCallback) return;
|
|
2030
|
-
context.report({
|
|
2031
|
-
messageId: "default",
|
|
2032
|
-
node,
|
|
2033
|
-
data: { reason: "A parent element already has a `key` prop in the same list rendering context." }
|
|
2034
|
-
});
|
|
2035
|
-
} };
|
|
2036
|
-
}
|
|
2037
|
-
function getArrayMethodCallbackPosition(methodName) {
|
|
2038
|
-
switch (methodName) {
|
|
2039
|
-
case "filter":
|
|
2040
|
-
case "flatMap":
|
|
2041
|
-
case "forEach":
|
|
2042
|
-
case "map":
|
|
2043
|
-
case "reduce":
|
|
2044
|
-
case "reduceRight": return 0;
|
|
2045
|
-
case "from":
|
|
2046
|
-
case "fromAsync": return 1;
|
|
2047
|
-
default: return -1;
|
|
2048
|
-
}
|
|
2049
|
-
}
|
|
2050
|
-
function isArrayMethodCallback(node) {
|
|
2051
|
-
const parent = node.parent;
|
|
2052
|
-
if (parent?.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
2053
|
-
if (parent.callee.type !== AST_NODE_TYPES.MemberExpression || parent.callee.property.type !== AST_NODE_TYPES.Identifier) return false;
|
|
2054
|
-
return parent.arguments[getArrayMethodCallbackPosition(parent.callee.property.name)] === node;
|
|
2055
|
-
}
|
|
2056
|
-
|
|
2057
2498
|
//#endregion
|
|
2058
2499
|
//#region src/rules/no-unnecessary-use-callback.ts
|
|
2059
|
-
const RULE_NAME$
|
|
2500
|
+
const RULE_NAME$20 = "no-unnecessary-use-callback";
|
|
2060
2501
|
var no_unnecessary_use_callback_default = createRule({
|
|
2061
2502
|
meta: {
|
|
2062
2503
|
type: "problem",
|
|
@@ -2067,11 +2508,11 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
2067
2508
|
},
|
|
2068
2509
|
schema: []
|
|
2069
2510
|
},
|
|
2070
|
-
name: RULE_NAME$
|
|
2071
|
-
create: create$
|
|
2511
|
+
name: RULE_NAME$20,
|
|
2512
|
+
create: create$20,
|
|
2072
2513
|
defaultOptions: []
|
|
2073
2514
|
});
|
|
2074
|
-
function create$
|
|
2515
|
+
function create$20(context) {
|
|
2075
2516
|
if (!context.sourceCode.text.includes("useCallback")) return {};
|
|
2076
2517
|
return { VariableDeclarator(node) {
|
|
2077
2518
|
const { id, init } = node;
|
|
@@ -2133,7 +2574,7 @@ function checkForUsageInsideUseEffect$1(sourceCode, node) {
|
|
|
2133
2574
|
|
|
2134
2575
|
//#endregion
|
|
2135
2576
|
//#region src/rules/no-unnecessary-use-memo.ts
|
|
2136
|
-
const RULE_NAME$
|
|
2577
|
+
const RULE_NAME$19 = "no-unnecessary-use-memo";
|
|
2137
2578
|
var no_unnecessary_use_memo_default = createRule({
|
|
2138
2579
|
meta: {
|
|
2139
2580
|
type: "problem",
|
|
@@ -2144,11 +2585,11 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
2144
2585
|
},
|
|
2145
2586
|
schema: []
|
|
2146
2587
|
},
|
|
2147
|
-
name: RULE_NAME$
|
|
2148
|
-
create: create$
|
|
2588
|
+
name: RULE_NAME$19,
|
|
2589
|
+
create: create$19,
|
|
2149
2590
|
defaultOptions: []
|
|
2150
2591
|
});
|
|
2151
|
-
function create$
|
|
2592
|
+
function create$19(context) {
|
|
2152
2593
|
if (!context.sourceCode.text.includes("useMemo")) return {};
|
|
2153
2594
|
return { VariableDeclarator(node) {
|
|
2154
2595
|
const { id, init } = node;
|
|
@@ -2214,7 +2655,7 @@ function checkForUsageInsideUseEffect(sourceCode, node) {
|
|
|
2214
2655
|
|
|
2215
2656
|
//#endregion
|
|
2216
2657
|
//#region src/rules/no-unnecessary-use-prefix.ts
|
|
2217
|
-
const RULE_NAME$
|
|
2658
|
+
const RULE_NAME$18 = "no-unnecessary-use-prefix";
|
|
2218
2659
|
const WELL_KNOWN_HOOKS = ["useMDXComponents"];
|
|
2219
2660
|
function containsUseComments(context, node) {
|
|
2220
2661
|
return context.sourceCode.getCommentsInside(node).some(({ value }) => /use\([\s\S]*?\)/u.test(value) || /use[A-Z0-9]\w*\([\s\S]*?\)/u.test(value));
|
|
@@ -2226,11 +2667,11 @@ var no_unnecessary_use_prefix_default = createRule({
|
|
|
2226
2667
|
messages: { default: "If your function doesn't call any Hooks, avoid the 'use' prefix. Instead, write it as a regular function without the 'use' prefix." },
|
|
2227
2668
|
schema: []
|
|
2228
2669
|
},
|
|
2229
|
-
name: RULE_NAME$
|
|
2230
|
-
create: create$
|
|
2670
|
+
name: RULE_NAME$18,
|
|
2671
|
+
create: create$18,
|
|
2231
2672
|
defaultOptions: []
|
|
2232
2673
|
});
|
|
2233
|
-
function create$
|
|
2674
|
+
function create$18(context) {
|
|
2234
2675
|
const { ctx, visitor } = core.useHookCollector(context);
|
|
2235
2676
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
2236
2677
|
for (const { id, name, node, hookCalls } of ctx.getAllHooks(program)) {
|
|
@@ -2250,7 +2691,7 @@ function create$20(context) {
|
|
|
2250
2691
|
|
|
2251
2692
|
//#endregion
|
|
2252
2693
|
//#region src/rules/no-unsafe-component-will-mount.ts
|
|
2253
|
-
const RULE_NAME$
|
|
2694
|
+
const RULE_NAME$17 = "no-unsafe-component-will-mount";
|
|
2254
2695
|
var no_unsafe_component_will_mount_default = createRule({
|
|
2255
2696
|
meta: {
|
|
2256
2697
|
type: "problem",
|
|
@@ -2258,11 +2699,11 @@ var no_unsafe_component_will_mount_default = createRule({
|
|
|
2258
2699
|
messages: { default: "Do not use 'UNSAFE_componentWillMount'." },
|
|
2259
2700
|
schema: []
|
|
2260
2701
|
},
|
|
2261
|
-
name: RULE_NAME$
|
|
2262
|
-
create: create$
|
|
2702
|
+
name: RULE_NAME$17,
|
|
2703
|
+
create: create$17,
|
|
2263
2704
|
defaultOptions: []
|
|
2264
2705
|
});
|
|
2265
|
-
function create$
|
|
2706
|
+
function create$17(context) {
|
|
2266
2707
|
if (!context.sourceCode.text.includes("UNSAFE_componentWillMount")) return {};
|
|
2267
2708
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
2268
2709
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -2278,7 +2719,7 @@ function create$19(context) {
|
|
|
2278
2719
|
|
|
2279
2720
|
//#endregion
|
|
2280
2721
|
//#region src/rules/no-unsafe-component-will-receive-props.ts
|
|
2281
|
-
const RULE_NAME$
|
|
2722
|
+
const RULE_NAME$16 = "no-unsafe-component-will-receive-props";
|
|
2282
2723
|
var no_unsafe_component_will_receive_props_default = createRule({
|
|
2283
2724
|
meta: {
|
|
2284
2725
|
type: "problem",
|
|
@@ -2286,11 +2727,11 @@ var no_unsafe_component_will_receive_props_default = createRule({
|
|
|
2286
2727
|
messages: { default: "Do not use 'UNSAFE_componentWillReceiveProps'." },
|
|
2287
2728
|
schema: []
|
|
2288
2729
|
},
|
|
2289
|
-
name: RULE_NAME$
|
|
2290
|
-
create: create$
|
|
2730
|
+
name: RULE_NAME$16,
|
|
2731
|
+
create: create$16,
|
|
2291
2732
|
defaultOptions: []
|
|
2292
2733
|
});
|
|
2293
|
-
function create$
|
|
2734
|
+
function create$16(context) {
|
|
2294
2735
|
if (!context.sourceCode.text.includes("UNSAFE_componentWillReceiveProps")) return {};
|
|
2295
2736
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
2296
2737
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -2306,7 +2747,7 @@ function create$18(context) {
|
|
|
2306
2747
|
|
|
2307
2748
|
//#endregion
|
|
2308
2749
|
//#region src/rules/no-unsafe-component-will-update.ts
|
|
2309
|
-
const RULE_NAME$
|
|
2750
|
+
const RULE_NAME$15 = "no-unsafe-component-will-update";
|
|
2310
2751
|
var no_unsafe_component_will_update_default = createRule({
|
|
2311
2752
|
meta: {
|
|
2312
2753
|
type: "problem",
|
|
@@ -2314,11 +2755,11 @@ var no_unsafe_component_will_update_default = createRule({
|
|
|
2314
2755
|
messages: { default: "Do not use 'UNSAFE_componentWillUpdate'." },
|
|
2315
2756
|
schema: []
|
|
2316
2757
|
},
|
|
2317
|
-
name: RULE_NAME$
|
|
2318
|
-
create: create$
|
|
2758
|
+
name: RULE_NAME$15,
|
|
2759
|
+
create: create$15,
|
|
2319
2760
|
defaultOptions: []
|
|
2320
2761
|
});
|
|
2321
|
-
function create$
|
|
2762
|
+
function create$15(context) {
|
|
2322
2763
|
if (!context.sourceCode.text.includes("UNSAFE_componentWillUpdate")) return {};
|
|
2323
2764
|
const { ctx, visitor } = core.useComponentCollectorLegacy(context);
|
|
2324
2765
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -2334,7 +2775,7 @@ function create$17(context) {
|
|
|
2334
2775
|
|
|
2335
2776
|
//#endregion
|
|
2336
2777
|
//#region src/rules/no-unstable-context-value.ts
|
|
2337
|
-
const RULE_NAME$
|
|
2778
|
+
const RULE_NAME$14 = "no-unstable-context-value";
|
|
2338
2779
|
var no_unstable_context_value_default = createRule({
|
|
2339
2780
|
meta: {
|
|
2340
2781
|
type: "problem",
|
|
@@ -2342,13 +2783,13 @@ var no_unstable_context_value_default = createRule({
|
|
|
2342
2783
|
messages: { unstableContextValue: "A/an '{{kind}}' passed as the value prop to the context provider should not be constructed. It will change on every render. {{suggestion}}" },
|
|
2343
2784
|
schema: []
|
|
2344
2785
|
},
|
|
2345
|
-
name: RULE_NAME$
|
|
2346
|
-
create: create$
|
|
2786
|
+
name: RULE_NAME$14,
|
|
2787
|
+
create: create$14,
|
|
2347
2788
|
defaultOptions: []
|
|
2348
2789
|
});
|
|
2349
|
-
function create$
|
|
2350
|
-
|
|
2351
|
-
|
|
2790
|
+
function create$14(context) {
|
|
2791
|
+
const { isCompilerEnabled, version } = getSettingsFromContext(context);
|
|
2792
|
+
if (isCompilerEnabled && ast.isDirectiveInFile(context.sourceCode.ast, "use memo")) return {};
|
|
2352
2793
|
const isReact18OrBelow = compare(version, "19.0.0", "<");
|
|
2353
2794
|
const { ctx, visitor } = core.useComponentCollector(context);
|
|
2354
2795
|
const constructions = /* @__PURE__ */ new WeakMap();
|
|
@@ -2359,6 +2800,7 @@ function create$16(context) {
|
|
|
2359
2800
|
if (!isContextName(selfName, isReact18OrBelow)) return;
|
|
2360
2801
|
const functionEntry = ctx.getCurrentEntry();
|
|
2361
2802
|
if (functionEntry == null) return;
|
|
2803
|
+
if (isCompilerEnabled && ast.isDirectiveInFunction(functionEntry.node, "use memo")) return;
|
|
2362
2804
|
const attribute = node.attributes.find((attribute) => attribute.type === AST_NODE_TYPES.JSXAttribute && attribute.name.name === "value");
|
|
2363
2805
|
if (attribute == null || !("value" in attribute)) return;
|
|
2364
2806
|
const value = attribute.value;
|
|
@@ -2394,8 +2836,8 @@ function isContextName(name, isReact18OrBelow) {
|
|
|
2394
2836
|
|
|
2395
2837
|
//#endregion
|
|
2396
2838
|
//#region src/rules/no-unstable-default-props.ts
|
|
2397
|
-
const RULE_NAME$
|
|
2398
|
-
const defaultOptions$
|
|
2839
|
+
const RULE_NAME$13 = "no-unstable-default-props";
|
|
2840
|
+
const defaultOptions$1 = [{ safeDefaultProps: [] }];
|
|
2399
2841
|
const schema$1 = [{
|
|
2400
2842
|
type: "object",
|
|
2401
2843
|
additionalProperties: false,
|
|
@@ -2411,9 +2853,9 @@ var no_unstable_default_props_default = createRule({
|
|
|
2411
2853
|
messages: { default: "A/an '{{kind}}' as default prop. This could lead to potential infinite render loop in React. Use a variable instead of '{{kind}}'." },
|
|
2412
2854
|
schema: schema$1
|
|
2413
2855
|
},
|
|
2414
|
-
name: RULE_NAME$
|
|
2415
|
-
create: create$
|
|
2416
|
-
defaultOptions: defaultOptions$
|
|
2856
|
+
name: RULE_NAME$13,
|
|
2857
|
+
create: create$13,
|
|
2858
|
+
defaultOptions: defaultOptions$1
|
|
2417
2859
|
});
|
|
2418
2860
|
function extractIdentifier(node) {
|
|
2419
2861
|
if (node.type === AST_NODE_TYPES.NewExpression && node.callee.type === AST_NODE_TYPES.Identifier) return node.callee.name;
|
|
@@ -2423,8 +2865,9 @@ function extractIdentifier(node) {
|
|
|
2423
2865
|
}
|
|
2424
2866
|
return null;
|
|
2425
2867
|
}
|
|
2426
|
-
function create$
|
|
2427
|
-
|
|
2868
|
+
function create$13(context, [options]) {
|
|
2869
|
+
const { isCompilerEnabled } = getSettingsFromContext(context);
|
|
2870
|
+
if (isCompilerEnabled && ast.isDirectiveInFile(context.sourceCode.ast, "use memo")) return {};
|
|
2428
2871
|
const { ctx, visitor } = core.useComponentCollector(context);
|
|
2429
2872
|
const declarators = /* @__PURE__ */ new WeakMap();
|
|
2430
2873
|
const { safeDefaultProps = [] } = options;
|
|
@@ -2467,7 +2910,7 @@ function create$15(context, [options]) {
|
|
|
2467
2910
|
|
|
2468
2911
|
//#endregion
|
|
2469
2912
|
//#region src/rules/no-unused-class-component-members.ts
|
|
2470
|
-
const RULE_NAME$
|
|
2913
|
+
const RULE_NAME$12 = "no-unused-class-component-members";
|
|
2471
2914
|
const LIFECYCLE_METHODS = new Set([
|
|
2472
2915
|
"componentDidCatch",
|
|
2473
2916
|
"componentDidMount",
|
|
@@ -2498,11 +2941,11 @@ var no_unused_class_component_members_default = createRule({
|
|
|
2498
2941
|
messages: { default: "Unused method or property '{{methodName}}'' of class '{{className}}'." },
|
|
2499
2942
|
schema: []
|
|
2500
2943
|
},
|
|
2501
|
-
name: RULE_NAME$
|
|
2502
|
-
create: create$
|
|
2944
|
+
name: RULE_NAME$12,
|
|
2945
|
+
create: create$12,
|
|
2503
2946
|
defaultOptions: []
|
|
2504
2947
|
});
|
|
2505
|
-
function create$
|
|
2948
|
+
function create$12(context) {
|
|
2506
2949
|
const classStack = [];
|
|
2507
2950
|
const methodStack = [];
|
|
2508
2951
|
const propertyDefs = /* @__PURE__ */ new WeakMap();
|
|
@@ -2583,7 +3026,7 @@ function create$14(context) {
|
|
|
2583
3026
|
|
|
2584
3027
|
//#endregion
|
|
2585
3028
|
//#region src/rules/no-unused-props.ts
|
|
2586
|
-
const RULE_NAME$
|
|
3029
|
+
const RULE_NAME$11 = "no-unused-props";
|
|
2587
3030
|
var no_unused_props_default = createRule({
|
|
2588
3031
|
meta: {
|
|
2589
3032
|
type: "problem",
|
|
@@ -2591,11 +3034,11 @@ var no_unused_props_default = createRule({
|
|
|
2591
3034
|
messages: { default: "Prop `{{name}}` is declared but never used" },
|
|
2592
3035
|
schema: []
|
|
2593
3036
|
},
|
|
2594
|
-
name: RULE_NAME$
|
|
2595
|
-
create: create$
|
|
3037
|
+
name: RULE_NAME$11,
|
|
3038
|
+
create: create$11,
|
|
2596
3039
|
defaultOptions: []
|
|
2597
3040
|
});
|
|
2598
|
-
function create$
|
|
3041
|
+
function create$11(context) {
|
|
2599
3042
|
const services = ESLintUtils.getParserServices(context, false);
|
|
2600
3043
|
const { ctx, visitor } = core.useComponentCollector(context);
|
|
2601
3044
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
@@ -2614,7 +3057,7 @@ function create$13(context) {
|
|
|
2614
3057
|
if (usedPropKeys.has(declaredProp.name)) totalUsedProps.add(declaredProp);
|
|
2615
3058
|
}
|
|
2616
3059
|
}
|
|
2617
|
-
const unusedProps =
|
|
3060
|
+
const unusedProps = totalDeclaredProps.difference(totalUsedProps);
|
|
2618
3061
|
for (const unusedProp of unusedProps) reportUnusedProp(context, services, unusedProp);
|
|
2619
3062
|
} });
|
|
2620
3063
|
}
|
|
@@ -2693,7 +3136,7 @@ function reportUnusedProp(context, services, prop) {
|
|
|
2693
3136
|
|
|
2694
3137
|
//#endregion
|
|
2695
3138
|
//#region src/rules/no-unused-state.ts
|
|
2696
|
-
const RULE_NAME$
|
|
3139
|
+
const RULE_NAME$10 = "no-unused-state";
|
|
2697
3140
|
function isKeyLiteral(node, key) {
|
|
2698
3141
|
return match(key).with({ type: AST_NODE_TYPES.Literal }, constTrue).with({
|
|
2699
3142
|
type: AST_NODE_TYPES.TemplateLiteral,
|
|
@@ -2707,11 +3150,11 @@ var no_unused_state_default = createRule({
|
|
|
2707
3150
|
messages: { default: "Unused class component state in '{{className}}'" },
|
|
2708
3151
|
schema: []
|
|
2709
3152
|
},
|
|
2710
|
-
name: RULE_NAME$
|
|
2711
|
-
create: create$
|
|
3153
|
+
name: RULE_NAME$10,
|
|
3154
|
+
create: create$10,
|
|
2712
3155
|
defaultOptions: []
|
|
2713
3156
|
});
|
|
2714
|
-
function create$
|
|
3157
|
+
function create$10(context) {
|
|
2715
3158
|
const classStack = [];
|
|
2716
3159
|
const methodStack = [];
|
|
2717
3160
|
const constructorStack = [];
|
|
@@ -2820,7 +3263,7 @@ function create$12(context) {
|
|
|
2820
3263
|
|
|
2821
3264
|
//#endregion
|
|
2822
3265
|
//#region src/rules/no-use-context.ts
|
|
2823
|
-
const RULE_NAME$
|
|
3266
|
+
const RULE_NAME$9 = "no-use-context";
|
|
2824
3267
|
var no_use_context_default = createRule({
|
|
2825
3268
|
meta: {
|
|
2826
3269
|
type: "problem",
|
|
@@ -2829,11 +3272,11 @@ var no_use_context_default = createRule({
|
|
|
2829
3272
|
messages: { default: "In React 19, 'use' is preferred over 'useContext' because it is more flexible." },
|
|
2830
3273
|
schema: []
|
|
2831
3274
|
},
|
|
2832
|
-
name: RULE_NAME$
|
|
2833
|
-
create: create$
|
|
3275
|
+
name: RULE_NAME$9,
|
|
3276
|
+
create: create$9,
|
|
2834
3277
|
defaultOptions: []
|
|
2835
3278
|
});
|
|
2836
|
-
function create$
|
|
3279
|
+
function create$9(context) {
|
|
2837
3280
|
if (!context.sourceCode.text.includes("useContext")) return {};
|
|
2838
3281
|
const settings = getSettingsFromContext(context);
|
|
2839
3282
|
if (compare(settings.version, "19.0.0", "<")) return {};
|
|
@@ -2898,7 +3341,7 @@ function getCorrelativeTokens(context, node) {
|
|
|
2898
3341
|
|
|
2899
3342
|
//#endregion
|
|
2900
3343
|
//#region src/rules/no-useless-forward-ref.ts
|
|
2901
|
-
const RULE_NAME$
|
|
3344
|
+
const RULE_NAME$8 = "no-useless-forward-ref";
|
|
2902
3345
|
var no_useless_forward_ref_default = createRule({
|
|
2903
3346
|
meta: {
|
|
2904
3347
|
type: "problem",
|
|
@@ -2906,11 +3349,11 @@ var no_useless_forward_ref_default = createRule({
|
|
|
2906
3349
|
messages: { default: "A 'forwardRef' is used with this component but no 'ref' parameter is set." },
|
|
2907
3350
|
schema: []
|
|
2908
3351
|
},
|
|
2909
|
-
name: RULE_NAME$
|
|
2910
|
-
create: create$
|
|
3352
|
+
name: RULE_NAME$8,
|
|
3353
|
+
create: create$8,
|
|
2911
3354
|
defaultOptions: []
|
|
2912
3355
|
});
|
|
2913
|
-
function create$
|
|
3356
|
+
function create$8(context) {
|
|
2914
3357
|
return { CallExpression(node) {
|
|
2915
3358
|
if (!core.isForwardRefCall(context, node)) return;
|
|
2916
3359
|
const [component] = node.arguments;
|
|
@@ -2925,8 +3368,8 @@ function create$10(context) {
|
|
|
2925
3368
|
|
|
2926
3369
|
//#endregion
|
|
2927
3370
|
//#region src/rules/no-useless-fragment.ts
|
|
2928
|
-
const RULE_NAME$
|
|
2929
|
-
const defaultOptions
|
|
3371
|
+
const RULE_NAME$7 = "no-useless-fragment";
|
|
3372
|
+
const defaultOptions = [{
|
|
2930
3373
|
allowEmptyFragment: false,
|
|
2931
3374
|
allowExpressions: true
|
|
2932
3375
|
}];
|
|
@@ -2947,17 +3390,17 @@ const schema = [{
|
|
|
2947
3390
|
var no_useless_fragment_default = createRule({
|
|
2948
3391
|
meta: {
|
|
2949
3392
|
type: "problem",
|
|
2950
|
-
defaultOptions: [...defaultOptions
|
|
3393
|
+
defaultOptions: [...defaultOptions],
|
|
2951
3394
|
docs: { description: "Disallows useless fragment elements." },
|
|
2952
3395
|
fixable: "code",
|
|
2953
3396
|
messages: { default: "A fragment {{reason}} is useless." },
|
|
2954
3397
|
schema
|
|
2955
3398
|
},
|
|
2956
|
-
name: RULE_NAME$
|
|
2957
|
-
create: create$
|
|
2958
|
-
defaultOptions
|
|
3399
|
+
name: RULE_NAME$7,
|
|
3400
|
+
create: create$7,
|
|
3401
|
+
defaultOptions
|
|
2959
3402
|
});
|
|
2960
|
-
function create$
|
|
3403
|
+
function create$7(context, [option]) {
|
|
2961
3404
|
const { allowEmptyFragment = false, allowExpressions = true } = option;
|
|
2962
3405
|
const jsxConfig = {
|
|
2963
3406
|
...core.getJsxConfigFromContext(context),
|
|
@@ -3065,7 +3508,7 @@ function trimLikeReact(text) {
|
|
|
3065
3508
|
|
|
3066
3509
|
//#endregion
|
|
3067
3510
|
//#region src/rules/prefer-destructuring-assignment.ts
|
|
3068
|
-
const RULE_NAME$
|
|
3511
|
+
const RULE_NAME$6 = "prefer-destructuring-assignment";
|
|
3069
3512
|
var prefer_destructuring_assignment_default = createRule({
|
|
3070
3513
|
meta: {
|
|
3071
3514
|
type: "problem",
|
|
@@ -3073,11 +3516,11 @@ var prefer_destructuring_assignment_default = createRule({
|
|
|
3073
3516
|
messages: { default: "Use destructuring assignment for component props." },
|
|
3074
3517
|
schema: []
|
|
3075
3518
|
},
|
|
3076
|
-
name: RULE_NAME$
|
|
3077
|
-
create: create$
|
|
3519
|
+
name: RULE_NAME$6,
|
|
3520
|
+
create: create$6,
|
|
3078
3521
|
defaultOptions: []
|
|
3079
3522
|
});
|
|
3080
|
-
function create$
|
|
3523
|
+
function create$6(context) {
|
|
3081
3524
|
const { ctx, visitor } = core.useComponentCollector(context);
|
|
3082
3525
|
return defineRuleListener(visitor, { "Program:exit"(program) {
|
|
3083
3526
|
for (const component of ctx.getAllComponents(program)) {
|
|
@@ -3101,7 +3544,7 @@ function create$8(context) {
|
|
|
3101
3544
|
|
|
3102
3545
|
//#endregion
|
|
3103
3546
|
//#region src/rules/prefer-namespace-import.ts
|
|
3104
|
-
const RULE_NAME$
|
|
3547
|
+
const RULE_NAME$5 = "prefer-namespace-import";
|
|
3105
3548
|
var prefer_namespace_import_default = createRule({
|
|
3106
3549
|
meta: {
|
|
3107
3550
|
type: "problem",
|
|
@@ -3110,11 +3553,11 @@ var prefer_namespace_import_default = createRule({
|
|
|
3110
3553
|
messages: { default: "Prefer importing React as 'import * as React from \"{{importSource}}\"';" },
|
|
3111
3554
|
schema: []
|
|
3112
3555
|
},
|
|
3113
|
-
name: RULE_NAME$
|
|
3114
|
-
create: create$
|
|
3556
|
+
name: RULE_NAME$5,
|
|
3557
|
+
create: create$5,
|
|
3115
3558
|
defaultOptions: []
|
|
3116
3559
|
});
|
|
3117
|
-
function create$
|
|
3560
|
+
function create$5(context) {
|
|
3118
3561
|
const { importSource } = getSettingsFromContext(context);
|
|
3119
3562
|
return { [`ImportDeclaration[source.value="${importSource}"] ImportDefaultSpecifier`](node) {
|
|
3120
3563
|
const hasOtherSpecifiers = node.parent.specifiers.length > 1;
|
|
@@ -3138,7 +3581,7 @@ function create$7(context) {
|
|
|
3138
3581
|
|
|
3139
3582
|
//#endregion
|
|
3140
3583
|
//#region src/rules/prefer-read-only-props.ts
|
|
3141
|
-
const RULE_NAME$
|
|
3584
|
+
const RULE_NAME$4 = "prefer-read-only-props";
|
|
3142
3585
|
var prefer_read_only_props_default = createRule({
|
|
3143
3586
|
meta: {
|
|
3144
3587
|
type: "problem",
|
|
@@ -3146,11 +3589,11 @@ var prefer_read_only_props_default = createRule({
|
|
|
3146
3589
|
messages: { default: "A function component's props should be read-only." },
|
|
3147
3590
|
schema: []
|
|
3148
3591
|
},
|
|
3149
|
-
name: RULE_NAME$
|
|
3150
|
-
create: create$
|
|
3592
|
+
name: RULE_NAME$4,
|
|
3593
|
+
create: create$4,
|
|
3151
3594
|
defaultOptions: []
|
|
3152
3595
|
});
|
|
3153
|
-
function create$
|
|
3596
|
+
function create$4(context) {
|
|
3154
3597
|
const services = ESLintUtils.getParserServices(context, false);
|
|
3155
3598
|
const checker = services.program.getTypeChecker();
|
|
3156
3599
|
const { ctx, visitor } = core.useComponentCollector(context);
|
|
@@ -3191,7 +3634,7 @@ function isClassOrInterfaceReadonlyLoose(checker, type) {
|
|
|
3191
3634
|
|
|
3192
3635
|
//#endregion
|
|
3193
3636
|
//#region src/rules/prefer-use-state-lazy-initialization.ts
|
|
3194
|
-
const RULE_NAME$
|
|
3637
|
+
const RULE_NAME$3 = "prefer-use-state-lazy-initialization";
|
|
3195
3638
|
const ALLOW_LIST = [
|
|
3196
3639
|
"Boolean",
|
|
3197
3640
|
"String",
|
|
@@ -3204,11 +3647,11 @@ var prefer_use_state_lazy_initialization_default = createRule({
|
|
|
3204
3647
|
messages: { default: "To prevent re-computation, consider using lazy initial state for useState calls that involve function calls. Ex: 'useState(() => getValue())'." },
|
|
3205
3648
|
schema: []
|
|
3206
3649
|
},
|
|
3207
|
-
name: RULE_NAME$
|
|
3208
|
-
create: create$
|
|
3650
|
+
name: RULE_NAME$3,
|
|
3651
|
+
create: create$3,
|
|
3209
3652
|
defaultOptions: []
|
|
3210
3653
|
});
|
|
3211
|
-
function create$
|
|
3654
|
+
function create$3(context) {
|
|
3212
3655
|
return { CallExpression(node) {
|
|
3213
3656
|
if (!core.isUseStateCall(node)) return;
|
|
3214
3657
|
const [useStateInput] = node.arguments;
|
|
@@ -3236,170 +3679,220 @@ function create$5(context) {
|
|
|
3236
3679
|
}
|
|
3237
3680
|
|
|
3238
3681
|
//#endregion
|
|
3239
|
-
//#region src/rules
|
|
3240
|
-
const RULE_NAME$
|
|
3241
|
-
var
|
|
3682
|
+
//#region src/rules/rules-of-hooks.ts
|
|
3683
|
+
const RULE_NAME$2 = "rules-of-hooks";
|
|
3684
|
+
var rules_of_hooks_default = createRule({
|
|
3242
3685
|
meta: {
|
|
3243
3686
|
type: "problem",
|
|
3244
|
-
docs: { description: "
|
|
3245
|
-
messages: {
|
|
3687
|
+
docs: { description: "Enforces the [Rules of Hooks](https://react.dev/reference/rules/rules-of-react#rules-of-hooks)." },
|
|
3688
|
+
messages: {
|
|
3689
|
+
afterEarlyReturn: "React Hook '{{name}}' is called after an early return. React Hooks must be called in the exact same order in every component render.",
|
|
3690
|
+
asyncHook: "React Hook '{{name}}' is called in an async function. React Hooks must be called in a synchronous React function component or custom Hook.",
|
|
3691
|
+
classHook: "React Hook '{{name}}' cannot be called in a class component. React Hooks can only be called in function components or custom Hooks.",
|
|
3692
|
+
conditionalHook: "React Hook '{{name}}' is called conditionally. React Hooks must be called in the exact same order in every component render.",
|
|
3693
|
+
invalidContext: "React Hook '{{name}}' is called in function '{{funcName}}' that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word 'use'.",
|
|
3694
|
+
loopHook: "React Hook '{{name}}' may be executed more than once. React Hooks must be called in the exact same order in every component render.",
|
|
3695
|
+
nestedHook: "React Hook '{{name}}' is called in a nested function. React Hooks must be called at the top level of a React function component or custom Hook.",
|
|
3696
|
+
topLevelHook: "React Hook '{{name}}' cannot be called at the top level. React Hooks must be called in a React function component or custom Hook.",
|
|
3697
|
+
useInTryCatch: "React Hook '{{name}}' cannot be called inside a try/catch block. To handle errors, wrap your component in an error boundary."
|
|
3698
|
+
},
|
|
3246
3699
|
schema: []
|
|
3247
3700
|
},
|
|
3248
|
-
name: RULE_NAME$
|
|
3249
|
-
create: create$
|
|
3701
|
+
name: RULE_NAME$2,
|
|
3702
|
+
create: create$2,
|
|
3250
3703
|
defaultOptions: []
|
|
3251
3704
|
});
|
|
3252
|
-
function
|
|
3253
|
-
if (
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
const { object, property } = node.left;
|
|
3257
|
-
if (object.type !== AST_NODE_TYPES.Identifier) return;
|
|
3258
|
-
if (property.type !== AST_NODE_TYPES.Identifier || property.name !== "defaultProps") return;
|
|
3259
|
-
if (!core.isComponentNameLoose(object.name)) return;
|
|
3260
|
-
const variableNode = getVariableDefinitionNode(findVariable(object.name, context.sourceCode.getScope(node)), 0);
|
|
3261
|
-
if (variableNode == null) return;
|
|
3262
|
-
if (!ast.isFunction(variableNode)) return;
|
|
3263
|
-
context.report({
|
|
3264
|
-
messageId: "default",
|
|
3265
|
-
node: property
|
|
3266
|
-
});
|
|
3267
|
-
} };
|
|
3705
|
+
function getHookName(node) {
|
|
3706
|
+
if (node.callee.type === AST_NODE_TYPES.Identifier) return node.callee.name;
|
|
3707
|
+
if (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier) return node.callee.property.name;
|
|
3708
|
+
return "unknown";
|
|
3268
3709
|
}
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
if (attr.type === AST_NODE_TYPES.JSXSpreadAttribute) continue;
|
|
3337
|
-
const name = attr.name.name;
|
|
3338
|
-
if (typeof name !== "string") continue;
|
|
3339
|
-
for (const forbiddenPropItem of forbid) {
|
|
3340
|
-
if (typeof forbiddenPropItem !== "string" && nodeName != null) {
|
|
3341
|
-
if ("excludedNodes" in forbiddenPropItem && forbiddenPropItem.excludedNodes.includes(nodeName)) continue;
|
|
3342
|
-
if ("includedNodes" in forbiddenPropItem && !forbiddenPropItem.includedNodes.includes(nodeName)) continue;
|
|
3710
|
+
function isUseCall(node) {
|
|
3711
|
+
if (node.callee.type === AST_NODE_TYPES.Identifier) return node.callee.name === "use";
|
|
3712
|
+
if (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier) return node.callee.property.name === "use";
|
|
3713
|
+
return false;
|
|
3714
|
+
}
|
|
3715
|
+
function getFunctionEntryKind(node) {
|
|
3716
|
+
const id = ast.getFunctionId(node);
|
|
3717
|
+
if (id == null) return "other";
|
|
3718
|
+
if (id.type === AST_NODE_TYPES.Identifier) {
|
|
3719
|
+
if (core.isHookName(id.name)) return "hook";
|
|
3720
|
+
if (/^[A-Z]/.test(id.name)) return "component";
|
|
3721
|
+
}
|
|
3722
|
+
if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) {
|
|
3723
|
+
if (core.isHookName(id.property.name)) return "hook";
|
|
3724
|
+
if (/^[A-Z]/.test(id.property.name)) return "component";
|
|
3725
|
+
}
|
|
3726
|
+
return "other";
|
|
3727
|
+
}
|
|
3728
|
+
function isConditionalNode(node) {
|
|
3729
|
+
return node.type === AST_NODE_TYPES.IfStatement || node.type === AST_NODE_TYPES.SwitchStatement || node.type === AST_NODE_TYPES.ConditionalExpression || node.type === AST_NODE_TYPES.LogicalExpression;
|
|
3730
|
+
}
|
|
3731
|
+
function isLoopNode(node) {
|
|
3732
|
+
return node.type === AST_NODE_TYPES.ForStatement || node.type === AST_NODE_TYPES.ForInStatement || node.type === AST_NODE_TYPES.ForOfStatement || node.type === AST_NODE_TYPES.WhileStatement || node.type === AST_NODE_TYPES.DoWhileStatement;
|
|
3733
|
+
}
|
|
3734
|
+
function isTryCatchNode(node) {
|
|
3735
|
+
return node.type === AST_NODE_TYPES.TryStatement;
|
|
3736
|
+
}
|
|
3737
|
+
function create$2(context) {
|
|
3738
|
+
const functionStack = [];
|
|
3739
|
+
function findEnclosingComponentOrHook() {
|
|
3740
|
+
for (let i = functionStack.length - 1; i >= 0; i--) {
|
|
3741
|
+
const entry = functionStack[i];
|
|
3742
|
+
if (entry == null) continue;
|
|
3743
|
+
if (entry.kind === "component" || entry.kind === "hook") return entry;
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
function checkHookCall(node) {
|
|
3747
|
+
const hookName = getHookName(node);
|
|
3748
|
+
const isUse = isUseCall(node);
|
|
3749
|
+
if (functionStack.length === 0) {
|
|
3750
|
+
context.report({
|
|
3751
|
+
messageId: "topLevelHook",
|
|
3752
|
+
node,
|
|
3753
|
+
data: { name: hookName }
|
|
3754
|
+
});
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3757
|
+
const boundary = findEnclosingComponentOrHook();
|
|
3758
|
+
if (boundary == null) {
|
|
3759
|
+
if (ast.findParentNode(node, ast.isClass) != null) {
|
|
3760
|
+
context.report({
|
|
3761
|
+
messageId: "classHook",
|
|
3762
|
+
node,
|
|
3763
|
+
data: { name: hookName }
|
|
3764
|
+
});
|
|
3765
|
+
return;
|
|
3766
|
+
}
|
|
3767
|
+
const currentEntry = functionStack.at(-1);
|
|
3768
|
+
if (currentEntry == null) return;
|
|
3769
|
+
const funcId = ast.getFunctionId(currentEntry.node);
|
|
3770
|
+
const funcName = funcId != null && funcId.type === AST_NODE_TYPES.Identifier ? funcId.name : "anonymous";
|
|
3771
|
+
context.report({
|
|
3772
|
+
messageId: "invalidContext",
|
|
3773
|
+
node,
|
|
3774
|
+
data: {
|
|
3775
|
+
name: hookName,
|
|
3776
|
+
funcName
|
|
3343
3777
|
}
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3778
|
+
});
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3781
|
+
const currentEntry = functionStack.at(-1);
|
|
3782
|
+
if (currentEntry != null && currentEntry.isAsync) {
|
|
3783
|
+
context.report({
|
|
3784
|
+
messageId: "asyncHook",
|
|
3785
|
+
node,
|
|
3786
|
+
data: { name: hookName }
|
|
3787
|
+
});
|
|
3788
|
+
return;
|
|
3789
|
+
}
|
|
3790
|
+
if (boundary.isAsync) {
|
|
3791
|
+
context.report({
|
|
3792
|
+
messageId: "asyncHook",
|
|
3793
|
+
node,
|
|
3794
|
+
data: { name: hookName }
|
|
3795
|
+
});
|
|
3796
|
+
return;
|
|
3797
|
+
}
|
|
3798
|
+
let current = node.parent;
|
|
3799
|
+
while (current != null && current !== boundary.node) {
|
|
3800
|
+
if (ast.isClass(current)) {
|
|
3801
|
+
context.report({
|
|
3802
|
+
messageId: "classHook",
|
|
3803
|
+
node,
|
|
3804
|
+
data: { name: hookName }
|
|
3805
|
+
});
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3808
|
+
if (ast.isFunction(current) && current !== boundary.node) {
|
|
3809
|
+
const nestedKind = getFunctionEntryKind(current);
|
|
3810
|
+
if (nestedKind === "component" || nestedKind === "hook") break;
|
|
3811
|
+
context.report({
|
|
3812
|
+
messageId: "nestedHook",
|
|
3813
|
+
node,
|
|
3814
|
+
data: { name: hookName }
|
|
3815
|
+
});
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
if (!isUse && isConditionalNode(current)) {
|
|
3819
|
+
context.report({
|
|
3820
|
+
messageId: "conditionalHook",
|
|
3821
|
+
node,
|
|
3822
|
+
data: { name: hookName }
|
|
3823
|
+
});
|
|
3824
|
+
return;
|
|
3825
|
+
}
|
|
3826
|
+
if (!isUse && isLoopNode(current)) {
|
|
3827
|
+
context.report({
|
|
3828
|
+
messageId: "loopHook",
|
|
3829
|
+
node,
|
|
3830
|
+
data: { name: hookName }
|
|
3831
|
+
});
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3834
|
+
if (isUse && isTryCatchNode(current)) {
|
|
3835
|
+
context.report({
|
|
3836
|
+
messageId: "useInTryCatch",
|
|
3837
|
+
node,
|
|
3838
|
+
data: { name: hookName }
|
|
3348
3839
|
});
|
|
3840
|
+
return;
|
|
3349
3841
|
}
|
|
3842
|
+
current = current.parent;
|
|
3350
3843
|
}
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
docs: { description: "Disallows 'propTypes' in favor of TypeScript or another type-checking solution." },
|
|
3361
|
-
messages: { default: "[Deprecated] Use TypeScript or another type-checking solution instead." },
|
|
3362
|
-
schema: []
|
|
3363
|
-
},
|
|
3364
|
-
name: RULE_NAME$2,
|
|
3365
|
-
create: create$2,
|
|
3366
|
-
defaultOptions: []
|
|
3367
|
-
});
|
|
3368
|
-
function create$2(context) {
|
|
3369
|
-
if (!context.sourceCode.text.includes("propTypes")) return {};
|
|
3844
|
+
if (boundary.hasEarlyReturn) {
|
|
3845
|
+
context.report({
|
|
3846
|
+
messageId: "afterEarlyReturn",
|
|
3847
|
+
node,
|
|
3848
|
+
data: { name: hookName }
|
|
3849
|
+
});
|
|
3850
|
+
return;
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3370
3853
|
return {
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
if (variableNode != null && (ast.isFunction(variableNode) || core.isClassComponent(variableNode))) context.report({
|
|
3379
|
-
messageId: "default",
|
|
3380
|
-
node: property
|
|
3854
|
+
":function"(node) {
|
|
3855
|
+
const kind = getFunctionEntryKind(node);
|
|
3856
|
+
functionStack.push({
|
|
3857
|
+
kind,
|
|
3858
|
+
node,
|
|
3859
|
+
hasEarlyReturn: false,
|
|
3860
|
+
isAsync: node.async
|
|
3381
3861
|
});
|
|
3382
3862
|
},
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3863
|
+
":function:exit"() {
|
|
3864
|
+
functionStack.pop();
|
|
3865
|
+
},
|
|
3866
|
+
CallExpression(node) {
|
|
3867
|
+
if (!core.isHookCall(node)) return;
|
|
3868
|
+
checkHookCall(node);
|
|
3869
|
+
},
|
|
3870
|
+
ReturnStatement(node) {
|
|
3871
|
+
if (functionStack.length === 0) return;
|
|
3872
|
+
const entry = functionStack.at(-1);
|
|
3873
|
+
if (entry == null) return;
|
|
3874
|
+
const fnNode = entry.node;
|
|
3875
|
+
if (fnNode.body.type !== AST_NODE_TYPES.BlockStatement) return;
|
|
3876
|
+
const body = fnNode.body.body;
|
|
3877
|
+
let stmt = node;
|
|
3878
|
+
while (stmt.parent !== fnNode.body) {
|
|
3879
|
+
if (stmt.parent == null) return;
|
|
3880
|
+
stmt = stmt.parent;
|
|
3881
|
+
}
|
|
3882
|
+
const idx = body.indexOf(stmt);
|
|
3883
|
+
if (idx !== -1 && idx < body.length - 1) entry.hasEarlyReturn = true;
|
|
3390
3884
|
}
|
|
3391
3885
|
};
|
|
3392
3886
|
}
|
|
3393
3887
|
|
|
3394
3888
|
//#endregion
|
|
3395
|
-
//#region src/rules
|
|
3396
|
-
const RULE_NAME$1 = "
|
|
3397
|
-
var
|
|
3889
|
+
//#region src/rules/set-state-in-effect.ts
|
|
3890
|
+
const RULE_NAME$1 = "set-state-in-effect";
|
|
3891
|
+
var set_state_in_effect_default = createRule({
|
|
3398
3892
|
meta: {
|
|
3399
3893
|
type: "problem",
|
|
3400
|
-
docs: { description: "
|
|
3401
|
-
|
|
3402
|
-
messages: { default: "[Deprecated] Use callback refs instead." },
|
|
3894
|
+
docs: { description: "Validates against calling ['setState'](https://react.dev/reference/react/useState#setstate) synchronously in an effect, which can lead to re-renders that degrade performance." },
|
|
3895
|
+
messages: { default: "Do not call the 'set' function '{{name}}' of 'useState' synchronously in an effect. This can lead to unnecessary re-renders and performance issues." },
|
|
3403
3896
|
schema: []
|
|
3404
3897
|
},
|
|
3405
3898
|
name: RULE_NAME$1,
|
|
@@ -3407,56 +3900,203 @@ var no_string_refs_default = createRule({
|
|
|
3407
3900
|
defaultOptions: []
|
|
3408
3901
|
});
|
|
3409
3902
|
function create$1(context) {
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3903
|
+
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
3904
|
+
const { additionalStateHooks } = getSettingsFromContext(context);
|
|
3905
|
+
const functionEntries = [];
|
|
3906
|
+
const setupFnRef = { current: null };
|
|
3907
|
+
const setupFnIds = [];
|
|
3908
|
+
const trackedFnCalls = [];
|
|
3909
|
+
const setStateCallsByFn = /* @__PURE__ */ new WeakMap();
|
|
3910
|
+
const setStateInEffectArg = /* @__PURE__ */ new WeakMap();
|
|
3911
|
+
const setStateInEffectSetup = /* @__PURE__ */ new Map();
|
|
3912
|
+
const setStateInHookCallbacks = /* @__PURE__ */ new WeakMap();
|
|
3913
|
+
const getText = (n) => context.sourceCode.getText(n);
|
|
3914
|
+
const onSetupFunctionEnter = (node) => {
|
|
3915
|
+
setupFnRef.current = node;
|
|
3916
|
+
};
|
|
3917
|
+
const onSetupFunctionExit = (node) => {
|
|
3918
|
+
if (setupFnRef.current === node) setupFnRef.current = null;
|
|
3919
|
+
};
|
|
3920
|
+
function isThenCall(node) {
|
|
3921
|
+
return node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "then";
|
|
3413
3922
|
}
|
|
3414
|
-
function
|
|
3415
|
-
|
|
3923
|
+
function isUseStateCall(node) {
|
|
3924
|
+
return core.isUseStateLikeCall(node, additionalStateHooks);
|
|
3925
|
+
}
|
|
3926
|
+
function isUseEffectSetupCallback(node) {
|
|
3927
|
+
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && core.isUseEffectLikeCall(node.parent);
|
|
3928
|
+
}
|
|
3929
|
+
function getCallName(node) {
|
|
3930
|
+
if (node.type === AST_NODE_TYPES.CallExpression) return ast.getFullyQualifiedName(node.callee, getText);
|
|
3931
|
+
return ast.getFullyQualifiedName(node, getText);
|
|
3932
|
+
}
|
|
3933
|
+
function getCallKind(node) {
|
|
3934
|
+
return match(node).when(isUseStateCall, () => "useState").when(core.isUseEffectLikeCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
3935
|
+
}
|
|
3936
|
+
function getFunctionKind(node) {
|
|
3937
|
+
const parent = ast.findParentNode(node, not(ast.isTypeExpression)) ?? node.parent;
|
|
3938
|
+
switch (true) {
|
|
3939
|
+
case node.async:
|
|
3940
|
+
case parent.type === AST_NODE_TYPES.CallExpression && isThenCall(parent): return "deferred";
|
|
3941
|
+
case node.type !== AST_NODE_TYPES.FunctionDeclaration && parent.type === AST_NODE_TYPES.CallExpression && parent.callee === node: return "immediate";
|
|
3942
|
+
case isUseEffectSetupCallback(node): return "setup";
|
|
3943
|
+
default: return "other";
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
function isIdFromUseStateCall(topLevelId, at) {
|
|
3947
|
+
const variableNode = getVariableDefinitionNode(findVariable(topLevelId, context.sourceCode.getScope(topLevelId)), 0);
|
|
3948
|
+
if (variableNode == null) return false;
|
|
3949
|
+
if (variableNode.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
3950
|
+
if (!isUseStateCall(variableNode)) return false;
|
|
3951
|
+
const variableNodeParent = variableNode.parent;
|
|
3952
|
+
if (!("id" in variableNodeParent) || variableNodeParent.id?.type !== AST_NODE_TYPES.ArrayPattern) return true;
|
|
3953
|
+
return variableNodeParent.id.elements.findIndex((e) => e?.type === AST_NODE_TYPES.Identifier && e.name === topLevelId.name) === at;
|
|
3954
|
+
}
|
|
3955
|
+
function isSetStateCall(node) {
|
|
3956
|
+
switch (node.callee.type) {
|
|
3957
|
+
case AST_NODE_TYPES.CallExpression: {
|
|
3958
|
+
const { callee } = node.callee;
|
|
3959
|
+
if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
3960
|
+
if (!("name" in callee.object)) return false;
|
|
3961
|
+
const isAt = callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "at";
|
|
3962
|
+
const [index] = node.callee.arguments;
|
|
3963
|
+
if (!isAt || index == null) return false;
|
|
3964
|
+
return getStaticValue(index, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(callee.object);
|
|
3965
|
+
}
|
|
3966
|
+
case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(node.callee, 1);
|
|
3967
|
+
case AST_NODE_TYPES.MemberExpression: {
|
|
3968
|
+
if (!("name" in node.callee.object)) return false;
|
|
3969
|
+
const property = node.callee.property;
|
|
3970
|
+
return getStaticValue(property, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(node.callee.object, 1);
|
|
3971
|
+
}
|
|
3972
|
+
default: return false;
|
|
3973
|
+
}
|
|
3416
3974
|
}
|
|
3417
3975
|
return {
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3976
|
+
":function"(node) {
|
|
3977
|
+
const kind = getFunctionKind(node);
|
|
3978
|
+
functionEntries.push({
|
|
3979
|
+
kind,
|
|
3980
|
+
node
|
|
3981
|
+
});
|
|
3982
|
+
if (kind === "setup") onSetupFunctionEnter(node);
|
|
3983
|
+
},
|
|
3984
|
+
":function:exit"(node) {
|
|
3985
|
+
const { kind } = functionEntries.at(-1) ?? {};
|
|
3986
|
+
if (kind === "setup") onSetupFunctionExit(node);
|
|
3987
|
+
functionEntries.pop();
|
|
3988
|
+
},
|
|
3989
|
+
CallExpression(node) {
|
|
3990
|
+
const setupFunction = setupFnRef.current;
|
|
3991
|
+
const entry = functionEntries.at(-1);
|
|
3992
|
+
if (entry == null || entry.node.async) return;
|
|
3993
|
+
match(getCallKind(node)).with("setState", () => {
|
|
3994
|
+
switch (true) {
|
|
3995
|
+
case entry.kind === "deferred":
|
|
3996
|
+
case entry.node.async: break;
|
|
3997
|
+
case entry.node === setupFunction:
|
|
3998
|
+
case entry.kind === "immediate" && ast.findParentNode(entry.node, ast.isFunction) === setupFunction:
|
|
3999
|
+
context.report({
|
|
4000
|
+
messageId: "default",
|
|
4001
|
+
node,
|
|
4002
|
+
data: { name: context.sourceCode.getText(node.callee) }
|
|
4003
|
+
});
|
|
4004
|
+
return;
|
|
4005
|
+
default: {
|
|
4006
|
+
const init = ast.findParentNode(node, isVariableDeclaratorFromHookCall)?.init;
|
|
4007
|
+
if (init == null) getOrElseUpdate(setStateCallsByFn, entry.node, () => []).push(node);
|
|
4008
|
+
else getOrElseUpdate(setStateInHookCallbacks, init, () => []).push(node);
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
}).with("useEffect", () => {
|
|
4012
|
+
if (ast.isFunction(node.arguments.at(0))) return;
|
|
4013
|
+
setupFnIds.push(...ast.getNestedIdentifiers(node));
|
|
4014
|
+
}).with("other", () => {
|
|
4015
|
+
if (entry.node !== setupFunction) return;
|
|
4016
|
+
trackedFnCalls.push(node);
|
|
4017
|
+
}).otherwise(constVoid);
|
|
4018
|
+
},
|
|
4019
|
+
Identifier(node) {
|
|
4020
|
+
if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) return;
|
|
4021
|
+
if (!isIdFromUseStateCall(node, 1)) return;
|
|
4022
|
+
switch (node.parent.type) {
|
|
4023
|
+
case AST_NODE_TYPES.ArrowFunctionExpression: {
|
|
4024
|
+
const parent = node.parent.parent;
|
|
4025
|
+
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
|
|
4026
|
+
if (!core.isUseMemoCall(parent)) break;
|
|
4027
|
+
const init = ast.findParentNode(parent, isVariableDeclaratorFromHookCall)?.init;
|
|
4028
|
+
if (init != null) getOrElseUpdate(setStateInEffectArg, init, () => []).push(node);
|
|
4029
|
+
break;
|
|
4030
|
+
}
|
|
4031
|
+
case AST_NODE_TYPES.CallExpression:
|
|
4032
|
+
if (node !== node.parent.arguments.at(0)) break;
|
|
4033
|
+
if (core.isUseCallbackCall(node.parent)) {
|
|
4034
|
+
const init = ast.findParentNode(node.parent, isVariableDeclaratorFromHookCall)?.init;
|
|
4035
|
+
if (init != null) getOrElseUpdate(setStateInEffectArg, init, () => []).push(node);
|
|
4036
|
+
break;
|
|
4037
|
+
}
|
|
4038
|
+
if (core.isUseEffectLikeCall(node.parent)) getOrElseUpdate(setStateInEffectSetup, node.parent, () => []).push(node);
|
|
4039
|
+
}
|
|
4040
|
+
},
|
|
4041
|
+
"Program:exit"() {
|
|
4042
|
+
const getSetStateCalls = (id, initialScope) => {
|
|
4043
|
+
const node = getVariableDefinitionNode(findVariable(id, initialScope), 0);
|
|
4044
|
+
switch (node?.type) {
|
|
4045
|
+
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
4046
|
+
case AST_NODE_TYPES.FunctionDeclaration:
|
|
4047
|
+
case AST_NODE_TYPES.FunctionExpression: return setStateCallsByFn.get(node) ?? [];
|
|
4048
|
+
case AST_NODE_TYPES.CallExpression: return setStateInHookCallbacks.get(node) ?? setStateInEffectArg.get(node) ?? [];
|
|
3431
4049
|
}
|
|
4050
|
+
return [];
|
|
4051
|
+
};
|
|
4052
|
+
for (const [, calls] of setStateInEffectSetup) for (const call of calls) context.report({
|
|
4053
|
+
messageId: "default",
|
|
4054
|
+
node: call,
|
|
4055
|
+
data: { name: call.name }
|
|
3432
4056
|
});
|
|
4057
|
+
for (const { callee } of trackedFnCalls) {
|
|
4058
|
+
if (!("name" in callee)) continue;
|
|
4059
|
+
const { name } = callee;
|
|
4060
|
+
const setStateCalls = getSetStateCalls(name, context.sourceCode.getScope(callee));
|
|
4061
|
+
for (const setStateCall of setStateCalls) context.report({
|
|
4062
|
+
messageId: "default",
|
|
4063
|
+
node: setStateCall,
|
|
4064
|
+
data: { name: getCallName(setStateCall) }
|
|
4065
|
+
});
|
|
4066
|
+
}
|
|
4067
|
+
for (const id of setupFnIds) {
|
|
4068
|
+
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
4069
|
+
for (const setStateCall of setStateCalls) context.report({
|
|
4070
|
+
messageId: "default",
|
|
4071
|
+
node: setStateCall,
|
|
4072
|
+
data: { name: getCallName(setStateCall) }
|
|
4073
|
+
});
|
|
4074
|
+
}
|
|
3433
4075
|
}
|
|
3434
4076
|
};
|
|
3435
4077
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
function getJsxAttributeValueText(context, node) {
|
|
3443
|
-
if (node == null) return null;
|
|
3444
|
-
switch (true) {
|
|
3445
|
-
case node.type === AST_NODE_TYPES.Literal && typeof node.value === "string": return context.sourceCode.getText(node);
|
|
3446
|
-
case node.type === AST_NODE_TYPES.JSXExpressionContainer && node.expression.type === AST_NODE_TYPES.Literal && typeof node.expression.value === "string": return context.sourceCode.getText(node.expression);
|
|
3447
|
-
case node.type === AST_NODE_TYPES.JSXExpressionContainer && node.expression.type === AST_NODE_TYPES.TemplateLiteral: return context.sourceCode.getText(node.expression);
|
|
3448
|
-
default: return null;
|
|
4078
|
+
function isInitFromHookCall(init) {
|
|
4079
|
+
if (init?.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
4080
|
+
switch (init.callee.type) {
|
|
4081
|
+
case AST_NODE_TYPES.Identifier: return core.isHookName(init.callee.name);
|
|
4082
|
+
case AST_NODE_TYPES.MemberExpression: return init.callee.property.type === AST_NODE_TYPES.Identifier && core.isHookName(init.callee.property.name);
|
|
4083
|
+
default: return false;
|
|
3449
4084
|
}
|
|
3450
4085
|
}
|
|
4086
|
+
function isVariableDeclaratorFromHookCall(node) {
|
|
4087
|
+
if (node.type !== AST_NODE_TYPES.VariableDeclarator) return false;
|
|
4088
|
+
if (node.id.type !== AST_NODE_TYPES.Identifier) return false;
|
|
4089
|
+
return isInitFromHookCall(node.init);
|
|
4090
|
+
}
|
|
3451
4091
|
|
|
3452
4092
|
//#endregion
|
|
3453
|
-
//#region src/rules
|
|
3454
|
-
const RULE_NAME = "
|
|
3455
|
-
var
|
|
4093
|
+
//#region src/rules/set-state-in-render.ts
|
|
4094
|
+
const RULE_NAME = "set-state-in-render";
|
|
4095
|
+
var set_state_in_render_default = createRule({
|
|
3456
4096
|
meta: {
|
|
3457
4097
|
type: "problem",
|
|
3458
|
-
docs: { description: "
|
|
3459
|
-
messages: { default: "
|
|
4098
|
+
docs: { description: "Validates against unconditionally setting state during render, which can trigger additional renders and potential infinite render loops." },
|
|
4099
|
+
messages: { default: "Do not call the 'set' function '{{name}}' unconditionally during render. This will trigger an infinite render loop." },
|
|
3460
4100
|
schema: []
|
|
3461
4101
|
},
|
|
3462
4102
|
name: RULE_NAME,
|
|
@@ -3464,27 +4104,126 @@ var no_unnecessary_use_ref_default = createRule({
|
|
|
3464
4104
|
defaultOptions: []
|
|
3465
4105
|
});
|
|
3466
4106
|
function create(context) {
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
4107
|
+
const { additionalStateHooks } = getSettingsFromContext(context);
|
|
4108
|
+
const functionEntries = [];
|
|
4109
|
+
const componentFnRef = { current: null };
|
|
4110
|
+
const componentHasEarlyReturn = { current: false };
|
|
4111
|
+
function isUseStateCall(node) {
|
|
4112
|
+
return core.isUseStateLikeCall(node, additionalStateHooks);
|
|
4113
|
+
}
|
|
4114
|
+
function isIdFromUseStateCall(topLevelId, at) {
|
|
4115
|
+
const variableNode = getVariableDefinitionNode(findVariable(topLevelId, context.sourceCode.getScope(topLevelId)), 0);
|
|
4116
|
+
if (variableNode == null) return false;
|
|
4117
|
+
if (variableNode.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
4118
|
+
if (!isUseStateCall(variableNode)) return false;
|
|
4119
|
+
const variableNodeParent = variableNode.parent;
|
|
4120
|
+
if (!("id" in variableNodeParent) || variableNodeParent.id?.type !== AST_NODE_TYPES.ArrayPattern) return true;
|
|
4121
|
+
return variableNodeParent.id.elements.findIndex((e) => e?.type === AST_NODE_TYPES.Identifier && e.name === topLevelId.name) === at;
|
|
4122
|
+
}
|
|
4123
|
+
function isSetStateCall(node) {
|
|
4124
|
+
switch (node.callee.type) {
|
|
4125
|
+
case AST_NODE_TYPES.CallExpression: {
|
|
4126
|
+
const { callee } = node.callee;
|
|
4127
|
+
if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
4128
|
+
if (!("name" in callee.object)) return false;
|
|
4129
|
+
const isAt = callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "at";
|
|
4130
|
+
const [index] = node.callee.arguments;
|
|
4131
|
+
if (!isAt || index == null) return false;
|
|
4132
|
+
return getStaticValue(index, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(callee.object);
|
|
4133
|
+
}
|
|
4134
|
+
case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(node.callee, 1);
|
|
4135
|
+
case AST_NODE_TYPES.MemberExpression: {
|
|
4136
|
+
if (!("name" in node.callee.object)) return false;
|
|
4137
|
+
const property = node.callee.property;
|
|
4138
|
+
return getStaticValue(property, context.sourceCode.getScope(node))?.value === 1 && isIdFromUseStateCall(node.callee.object, 1);
|
|
4139
|
+
}
|
|
4140
|
+
default: return false;
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
function isInsideConditional(node, stopAt) {
|
|
4144
|
+
let current = node.parent;
|
|
4145
|
+
while (current != null && current !== stopAt) {
|
|
4146
|
+
switch (current.type) {
|
|
4147
|
+
case AST_NODE_TYPES.IfStatement:
|
|
4148
|
+
case AST_NODE_TYPES.ConditionalExpression:
|
|
4149
|
+
case AST_NODE_TYPES.LogicalExpression:
|
|
4150
|
+
case AST_NODE_TYPES.SwitchStatement:
|
|
4151
|
+
case AST_NODE_TYPES.SwitchCase: return true;
|
|
4152
|
+
default: break;
|
|
4153
|
+
}
|
|
4154
|
+
current = current.parent;
|
|
4155
|
+
}
|
|
4156
|
+
return false;
|
|
4157
|
+
}
|
|
4158
|
+
function isInsideEventHandler(node, stopAt) {
|
|
4159
|
+
let current = node.parent;
|
|
4160
|
+
while (current != null && current !== stopAt) {
|
|
4161
|
+
if (ast.isFunction(current) && current !== stopAt) return true;
|
|
4162
|
+
current = current.parent;
|
|
4163
|
+
}
|
|
4164
|
+
return false;
|
|
4165
|
+
}
|
|
4166
|
+
function isComponentLikeFunction(node) {
|
|
4167
|
+
const id = ast.getFunctionId(node);
|
|
4168
|
+
if (id == null) return false;
|
|
4169
|
+
if (id.type === AST_NODE_TYPES.Identifier) return core.isComponentName(id.name);
|
|
4170
|
+
if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return core.isComponentName(id.property.name);
|
|
4171
|
+
return false;
|
|
4172
|
+
}
|
|
4173
|
+
function getFunctionKind(node) {
|
|
4174
|
+
if (isComponentLikeFunction(node)) return "component";
|
|
4175
|
+
const parent = ast.findParentNode(node, not(ast.isTypeExpression)) ?? node.parent;
|
|
4176
|
+
if (parent.type === AST_NODE_TYPES.CallExpression && parent.callee !== node) return "callback";
|
|
4177
|
+
return "other";
|
|
4178
|
+
}
|
|
4179
|
+
return {
|
|
4180
|
+
":function"(node) {
|
|
4181
|
+
const kind = getFunctionKind(node);
|
|
4182
|
+
functionEntries.push({
|
|
4183
|
+
kind,
|
|
4184
|
+
node
|
|
4185
|
+
});
|
|
4186
|
+
if (kind === "component") {
|
|
4187
|
+
componentFnRef.current = node;
|
|
4188
|
+
componentHasEarlyReturn.current = false;
|
|
4189
|
+
}
|
|
4190
|
+
},
|
|
4191
|
+
":function:exit"(node) {
|
|
4192
|
+
if (functionEntries.at(-1)?.kind === "component" && componentFnRef.current === node) {
|
|
4193
|
+
componentFnRef.current = null;
|
|
4194
|
+
componentHasEarlyReturn.current = false;
|
|
4195
|
+
}
|
|
4196
|
+
functionEntries.pop();
|
|
4197
|
+
},
|
|
4198
|
+
CallExpression(node) {
|
|
4199
|
+
const componentFn = componentFnRef.current;
|
|
4200
|
+
if (componentFn == null) return;
|
|
4201
|
+
if (!isSetStateCall(node)) return;
|
|
4202
|
+
if (isInsideEventHandler(node, componentFn)) return;
|
|
4203
|
+
if (isInsideConditional(node, componentFn)) return;
|
|
4204
|
+
if (componentHasEarlyReturn.current) return;
|
|
4205
|
+
context.report({
|
|
4206
|
+
messageId: "default",
|
|
4207
|
+
node,
|
|
4208
|
+
data: { name: context.sourceCode.getText(node.callee) }
|
|
4209
|
+
});
|
|
4210
|
+
},
|
|
4211
|
+
ReturnStatement(node) {
|
|
4212
|
+
const componentFn = componentFnRef.current;
|
|
4213
|
+
if (componentFn == null) return;
|
|
4214
|
+
const entry = functionEntries.at(-1);
|
|
4215
|
+
if (entry == null || entry.node !== componentFn) return;
|
|
4216
|
+
if (componentFn.body.type !== AST_NODE_TYPES.BlockStatement) return;
|
|
4217
|
+
const body = componentFn.body.body;
|
|
4218
|
+
let stmt = node;
|
|
4219
|
+
while (stmt.parent !== componentFn.body) {
|
|
4220
|
+
if (stmt.parent == null) return;
|
|
4221
|
+
stmt = stmt.parent;
|
|
4222
|
+
}
|
|
4223
|
+
const idx = body.indexOf(stmt);
|
|
4224
|
+
if (idx !== -1 && idx < body.length - 1) componentHasEarlyReturn.current = true;
|
|
4225
|
+
}
|
|
4226
|
+
};
|
|
3488
4227
|
}
|
|
3489
4228
|
|
|
3490
4229
|
//#endregion
|
|
@@ -3495,6 +4234,9 @@ const plugin = {
|
|
|
3495
4234
|
version
|
|
3496
4235
|
},
|
|
3497
4236
|
rules: {
|
|
4237
|
+
"component-hook-factories": component_hook_factories_default,
|
|
4238
|
+
"error-boundaries": error_boundaries_default,
|
|
4239
|
+
"exhaustive-deps": exhaustive_deps_default,
|
|
3498
4240
|
"jsx-dollar": jsx_dollar_default,
|
|
3499
4241
|
"jsx-key-before-spread": jsx_key_before_spread_default,
|
|
3500
4242
|
"jsx-no-comment-textnodes": jsx_no_comment_textnodes_default,
|
|
@@ -3535,7 +4277,6 @@ const plugin = {
|
|
|
3535
4277
|
"no-set-state-in-component-did-mount": no_set_state_in_component_did_mount_default,
|
|
3536
4278
|
"no-set-state-in-component-did-update": no_set_state_in_component_did_update_default,
|
|
3537
4279
|
"no-set-state-in-component-will-update": no_set_state_in_component_will_update_default,
|
|
3538
|
-
"no-unnecessary-key": no_unnecessary_key_default,
|
|
3539
4280
|
"no-unnecessary-use-callback": no_unnecessary_use_callback_default,
|
|
3540
4281
|
"no-unnecessary-use-memo": no_unnecessary_use_memo_default,
|
|
3541
4282
|
"no-unnecessary-use-prefix": no_unnecessary_use_prefix_default,
|
|
@@ -3554,11 +4295,9 @@ const plugin = {
|
|
|
3554
4295
|
"prefer-namespace-import": prefer_namespace_import_default,
|
|
3555
4296
|
"prefer-read-only-props": prefer_read_only_props_default,
|
|
3556
4297
|
"prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default,
|
|
3557
|
-
"
|
|
3558
|
-
"
|
|
3559
|
-
"
|
|
3560
|
-
"no-string-refs": no_string_refs_default,
|
|
3561
|
-
"no-unnecessary-use-ref": no_unnecessary_use_ref_default
|
|
4298
|
+
"rules-of-hooks": rules_of_hooks_default,
|
|
4299
|
+
"set-state-in-effect": set_state_in_effect_default,
|
|
4300
|
+
"set-state-in-render": set_state_in_render_default
|
|
3562
4301
|
}
|
|
3563
4302
|
};
|
|
3564
4303
|
|
|
@@ -3572,6 +4311,9 @@ var recommended_exports = /* @__PURE__ */ __exportAll({
|
|
|
3572
4311
|
});
|
|
3573
4312
|
const name$5 = "react-x/recommended";
|
|
3574
4313
|
const rules$6 = {
|
|
4314
|
+
"react-x/component-hook-factories": "error",
|
|
4315
|
+
"react-x/error-boundaries": "error",
|
|
4316
|
+
"react-x/exhaustive-deps": "warn",
|
|
3575
4317
|
"react-x/jsx-key-before-spread": "warn",
|
|
3576
4318
|
"react-x/jsx-no-comment-textnodes": "warn",
|
|
3577
4319
|
"react-x/jsx-no-duplicate-props": "warn",
|
|
@@ -3590,25 +4332,25 @@ const rules$6 = {
|
|
|
3590
4332
|
"react-x/no-component-will-update": "error",
|
|
3591
4333
|
"react-x/no-context-provider": "warn",
|
|
3592
4334
|
"react-x/no-create-ref": "error",
|
|
3593
|
-
"react-x/no-default-props": "error",
|
|
3594
4335
|
"react-x/no-direct-mutation-state": "error",
|
|
3595
4336
|
"react-x/no-forward-ref": "warn",
|
|
3596
4337
|
"react-x/no-missing-key": "error",
|
|
3597
4338
|
"react-x/no-nested-component-definitions": "error",
|
|
3598
4339
|
"react-x/no-nested-lazy-component-declarations": "error",
|
|
3599
|
-
"react-x/no-prop-types": "error",
|
|
3600
4340
|
"react-x/no-redundant-should-component-update": "error",
|
|
3601
4341
|
"react-x/no-set-state-in-component-did-mount": "warn",
|
|
3602
4342
|
"react-x/no-set-state-in-component-did-update": "warn",
|
|
3603
4343
|
"react-x/no-set-state-in-component-will-update": "warn",
|
|
3604
|
-
"react-x/no-string-refs": "error",
|
|
3605
4344
|
"react-x/no-unnecessary-use-prefix": "warn",
|
|
3606
4345
|
"react-x/no-unsafe-component-will-mount": "warn",
|
|
3607
4346
|
"react-x/no-unsafe-component-will-receive-props": "warn",
|
|
3608
4347
|
"react-x/no-unsafe-component-will-update": "warn",
|
|
3609
4348
|
"react-x/no-use-context": "warn",
|
|
3610
4349
|
"react-x/no-useless-forward-ref": "warn",
|
|
3611
|
-
"react-x/prefer-use-state-lazy-initialization": "warn"
|
|
4350
|
+
"react-x/prefer-use-state-lazy-initialization": "warn",
|
|
4351
|
+
"react-x/rules-of-hooks": "error",
|
|
4352
|
+
"react-x/set-state-in-effect": "warn",
|
|
4353
|
+
"react-x/set-state-in-render": "error"
|
|
3612
4354
|
};
|
|
3613
4355
|
const plugins$5 = { "react-x": plugin };
|
|
3614
4356
|
const settings$5 = { "react-x": DEFAULT_ESLINT_REACT_SETTINGS };
|