oxlint-plugin-react-doctor 0.7.7-dev.04c7e36 → 0.7.7-dev.12e7193

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +0 -46
  2. package/dist/index.js +751 -2021
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,13 +7,6 @@ import { analyze } from "eslint-scope";
7
7
  //#region src/plugin/utils/is-node-of-type.ts
8
8
  const isNodeOfType = (node, type) => node !== null && typeof node === "object" && "type" in node && node.type === type;
9
9
  //#endregion
10
- //#region src/plugin/utils/is-type-only-import.ts
11
- const isEverySpecifierInlineType = (specifiers, specifierType, kindField) => {
12
- if (!specifiers || specifiers.length === 0) return false;
13
- return specifiers.every((specifier) => isNodeOfType(specifier, specifierType) && specifier[kindField] === "type");
14
- };
15
- const isTypeOnlyImport = (node) => node.importKind === "type" || isEverySpecifierInlineType(node.specifiers, "ImportSpecifier", "importKind");
16
- //#endregion
17
10
  //#region src/plugin/utils/non-react-jsx-dialect.ts
18
11
  const NON_REACT_JSX_DIALECT_PACKAGES = new Set([
19
12
  "solid-js",
@@ -28,33 +21,17 @@ const NON_REACT_JSX_DIALECT_PACKAGES = new Set([
28
21
  "vidode"
29
22
  ]);
30
23
  const NON_REACT_JSX_DIALECT_PACKAGE_PREFIXES = ["solid-js", "@builder.io/qwik"];
31
- const REACT_JSX_DIALECT_PACKAGE_PREFIXES = [
32
- "react",
33
- "react-dom",
34
- "preact"
35
- ];
36
24
  const startsWithAny = (source, prefixes) => prefixes.some((prefix) => source === prefix || source.startsWith(`${prefix}/`));
37
- const collectJsxRuntimeImports = (program) => {
38
- let hasNonReactRuntime = false;
39
- let hasReactRuntime = false;
25
+ const fileImportsNonReactJsxDialect = (program) => {
40
26
  for (const statement of program.body) {
41
27
  if (!isNodeOfType(statement, "ImportDeclaration")) continue;
42
- const importDeclaration = statement;
43
- if (isTypeOnlyImport(importDeclaration)) continue;
44
- const source = importDeclaration.source;
28
+ const source = statement.source;
45
29
  const value = source && typeof source.value === "string" ? source.value : null;
46
30
  if (!value) continue;
47
- if (NON_REACT_JSX_DIALECT_PACKAGES.has(value) || startsWithAny(value, NON_REACT_JSX_DIALECT_PACKAGE_PREFIXES)) hasNonReactRuntime = true;
48
- if (startsWithAny(value, REACT_JSX_DIALECT_PACKAGE_PREFIXES)) hasReactRuntime = true;
31
+ if (NON_REACT_JSX_DIALECT_PACKAGES.has(value)) return true;
32
+ if (startsWithAny(value, NON_REACT_JSX_DIALECT_PACKAGE_PREFIXES)) return true;
49
33
  }
50
- return {
51
- hasNonReactRuntime,
52
- hasReactRuntime
53
- };
54
- };
55
- const fileImportsNonReactJsxDialect = (program) => {
56
- const runtimeImports = collectJsxRuntimeImports(program);
57
- return runtimeImports.hasNonReactRuntime && !runtimeImports.hasReactRuntime;
34
+ return false;
58
35
  };
59
36
  const jsxAttributeIsNonReactDialectMarker = (openingNode) => {
60
37
  for (const attribute of openingNode.attributes) {
@@ -267,7 +244,6 @@ const VISITOR_NODE_NAME_PATTERN = /^[A-Z]/;
267
244
  const wrapCreateForReactJsxOnly = (create) => ((context) => {
268
245
  const innerVisitors = create(context);
269
246
  let fileIsNonReactJsx = false;
270
- let fileImportsReactRuntime = false;
271
247
  const wrappedVisitors = {};
272
248
  for (const [key, visitor] of Object.entries(innerVisitors)) {
273
249
  if (typeof visitor !== "function") {
@@ -280,16 +256,14 @@ const wrapCreateForReactJsxOnly = (create) => ((context) => {
280
256
  }
281
257
  if (key === "Program") {
282
258
  wrappedVisitors.Program = (node) => {
283
- const runtimeImports = collectJsxRuntimeImports(node);
284
- fileImportsReactRuntime = runtimeImports.hasReactRuntime;
285
- fileIsNonReactJsx = runtimeImports.hasNonReactRuntime && !runtimeImports.hasReactRuntime;
259
+ fileIsNonReactJsx = fileImportsNonReactJsxDialect(node);
286
260
  visitor(node);
287
261
  };
288
262
  continue;
289
263
  }
290
264
  if (key === "JSXOpeningElement") {
291
265
  wrappedVisitors.JSXOpeningElement = (node) => {
292
- if (!fileImportsReactRuntime && !fileIsNonReactJsx && jsxAttributeIsNonReactDialectMarker(node)) fileIsNonReactJsx = true;
266
+ if (!fileIsNonReactJsx && jsxAttributeIsNonReactDialectMarker(node)) fileIsNonReactJsx = true;
293
267
  if (fileIsNonReactJsx) return;
294
268
  visitor(node);
295
269
  };
@@ -301,9 +275,7 @@ const wrapCreateForReactJsxOnly = (create) => ((context) => {
301
275
  };
302
276
  }
303
277
  if (!("Program" in wrappedVisitors)) wrappedVisitors.Program = (node) => {
304
- const runtimeImports = collectJsxRuntimeImports(node);
305
- fileImportsReactRuntime = runtimeImports.hasReactRuntime;
306
- fileIsNonReactJsx = runtimeImports.hasNonReactRuntime && !runtimeImports.hasReactRuntime;
278
+ fileIsNonReactJsx = fileImportsNonReactJsxDialect(node);
307
279
  };
308
280
  return wrappedVisitors;
309
281
  });
@@ -2340,7 +2312,7 @@ const anchorAmbiguousText = defineRule({
2340
2312
  });
2341
2313
  //#endregion
2342
2314
  //#region src/plugin/rules/a11y/anchor-has-content.ts
2343
- const MESSAGE$62 = "Blind users can't follow this link because screen readers announce nothing, so add visible text, `aria-label`, or `aria-labelledby`.";
2315
+ const MESSAGE$61 = "Blind users can't follow this link because screen readers announce nothing, so add visible text, `aria-label`, or `aria-labelledby`.";
2344
2316
  const isTransComponentsTemplate = (node) => {
2345
2317
  let current = node.parent;
2346
2318
  while (current) {
@@ -2376,7 +2348,7 @@ const anchorHasContent = defineRule({
2376
2348
  if (isTransComponentsTemplate(node)) return;
2377
2349
  context.report({
2378
2350
  node: opening.name,
2379
- message: MESSAGE$62
2351
+ message: MESSAGE$61
2380
2352
  });
2381
2353
  } };
2382
2354
  }
@@ -2808,7 +2780,7 @@ const parseJsxValue = (value) => {
2808
2780
  };
2809
2781
  //#endregion
2810
2782
  //#region src/plugin/rules/a11y/aria-activedescendant-has-tabindex.ts
2811
- const MESSAGE$61 = "Keyboard users can't focus this element with `aria-activedescendant` because it isn't tabbable, so add `tabIndex={0}`.";
2783
+ const MESSAGE$60 = "Keyboard users can't focus this element with `aria-activedescendant` because it isn't tabbable, so add `tabIndex={0}`.";
2812
2784
  const mayBeContentEditable = (node) => {
2813
2785
  const attribute = hasJsxPropIgnoreCase(node.attributes, "contenteditable");
2814
2786
  if (!attribute) return false;
@@ -2839,7 +2811,7 @@ const ariaActivedescendantHasTabindex = defineRule({
2839
2811
  if (tabIndexValue === null || tabIndexValue >= -1) return;
2840
2812
  context.report({
2841
2813
  node: node.name,
2842
- message: MESSAGE$61
2814
+ message: MESSAGE$60
2843
2815
  });
2844
2816
  return;
2845
2817
  }
@@ -2847,7 +2819,7 @@ const ariaActivedescendantHasTabindex = defineRule({
2847
2819
  if (mayBeContentEditable(node)) return;
2848
2820
  context.report({
2849
2821
  node: node.name,
2850
- message: MESSAGE$61
2822
+ message: MESSAGE$60
2851
2823
  });
2852
2824
  } })
2853
2825
  });
@@ -4342,397 +4314,6 @@ const findTransparentExpressionRoot = (node) => {
4342
4314
  return current;
4343
4315
  };
4344
4316
  //#endregion
4345
- //#region src/plugin/utils/get-static-property-key-name.ts
4346
- const getStaticPropertyKeyName = (node, options = {}) => {
4347
- if (!isNodeOfType(node, "Property") && !isNodeOfType(node, "MethodDefinition") && !isNodeOfType(node, "MemberExpression")) return null;
4348
- const key = isNodeOfType(node, "MemberExpression") ? node.property : node.key;
4349
- if (node.computed) {
4350
- if (options.allowComputedString && isNodeOfType(key, "Literal") && typeof key.value === "string") return key.value;
4351
- if (options.allowComputedString && isNodeOfType(key, "TemplateLiteral") && key.expressions.length === 0) return key.quasis[0]?.value.cooked ?? key.quasis[0]?.value.raw ?? null;
4352
- return null;
4353
- }
4354
- if (isNodeOfType(key, "Identifier")) return key.name;
4355
- if (isNodeOfType(key, "Literal")) {
4356
- if (typeof key.value === "string") return key.value;
4357
- if (options.stringifyNonStringLiterals) return String(key.value);
4358
- }
4359
- return null;
4360
- };
4361
- //#endregion
4362
- //#region src/plugin/utils/get-destructured-binding-property-name.ts
4363
- const getDestructuredBindingPropertyName = (bindingIdentifier) => {
4364
- let bindingNode = bindingIdentifier;
4365
- if (isNodeOfType(bindingNode.parent, "AssignmentPattern") && bindingNode.parent.left === bindingNode) bindingNode = bindingNode.parent;
4366
- const property = bindingNode.parent;
4367
- if (!property || !isNodeOfType(property, "Property") || property.value !== bindingNode || !property.parent || !isNodeOfType(property.parent, "ObjectPattern")) return null;
4368
- return getStaticPropertyKeyName(property, { allowComputedString: true });
4369
- };
4370
- //#endregion
4371
- //#region src/plugin/utils/get-static-property-name.ts
4372
- const getStaticPropertyName = (memberExpression) => {
4373
- const property = memberExpression.property;
4374
- if (!memberExpression.computed && isNodeOfType(property, "Identifier")) return property.name;
4375
- if (memberExpression.computed && isNodeOfType(property, "Literal")) return typeof property.value === "string" ? property.value : null;
4376
- if (memberExpression.computed && isNodeOfType(property, "TemplateLiteral") && property.expressions.length === 0) return property.quasis[0]?.value.cooked ?? property.quasis[0]?.value.raw ?? null;
4377
- return null;
4378
- };
4379
- //#endregion
4380
- //#region src/plugin/utils/has-static-property-write-before.ts
4381
- const equivalentSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
4382
- const potentiallyAliasedSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
4383
- const CONDITIONAL_EXECUTION_NODE_TYPES = new Set([
4384
- "CatchClause",
4385
- "ConditionalExpression",
4386
- "DoWhileStatement",
4387
- "ForInStatement",
4388
- "ForOfStatement",
4389
- "ForStatement",
4390
- "IfStatement",
4391
- "LogicalExpression",
4392
- "SwitchCase",
4393
- "SwitchStatement",
4394
- "TryStatement",
4395
- "WhileStatement"
4396
- ]);
4397
- const getResolvedStaticPropertyName = (memberExpression, scopes) => {
4398
- if (!isNodeOfType(memberExpression, "MemberExpression")) return null;
4399
- const directPropertyName = getStaticPropertyName(memberExpression);
4400
- if (directPropertyName || !memberExpression.computed) return directPropertyName;
4401
- const property = stripParenExpression(memberExpression.property);
4402
- if (!isNodeOfType(property, "Identifier")) return null;
4403
- const propertySymbol = resolveConstIdentifierAlias(property, scopes);
4404
- const initializer = propertySymbol?.initializer ? stripParenExpression(propertySymbol.initializer) : null;
4405
- return initializer && isNodeOfType(initializer, "Literal") && typeof initializer.value === "string" ? initializer.value : null;
4406
- };
4407
- const collectScopeSymbols = (scope, symbols) => {
4408
- symbols.push(...scope.symbols);
4409
- for (const childScope of scope.children) collectScopeSymbols(childScope, symbols);
4410
- };
4411
- const getEquivalentSymbols = (identifier, scopes) => {
4412
- const rootSymbol = resolveConstIdentifierAlias(identifier, scopes);
4413
- if (!rootSymbol) return [];
4414
- let symbolsByRootId = equivalentSymbolsByAnalysis.get(scopes);
4415
- if (!symbolsByRootId) {
4416
- symbolsByRootId = /* @__PURE__ */ new Map();
4417
- equivalentSymbolsByAnalysis.set(scopes, symbolsByRootId);
4418
- }
4419
- const cachedSymbols = symbolsByRootId.get(rootSymbol.id);
4420
- if (cachedSymbols) return cachedSymbols;
4421
- const allSymbols = [];
4422
- collectScopeSymbols(scopes.rootScope, allSymbols);
4423
- const equivalentSymbols = allSymbols.filter((symbol) => resolveConstIdentifierAlias(symbol.bindingIdentifier, scopes)?.id === rootSymbol.id);
4424
- symbolsByRootId.set(rootSymbol.id, equivalentSymbols);
4425
- return equivalentSymbols;
4426
- };
4427
- const getDirectAliasSourceSymbol = (expression, scopes) => {
4428
- const unwrappedExpression = stripParenExpression(expression);
4429
- return isNodeOfType(unwrappedExpression, "Identifier") ? scopes.symbolFor(unwrappedExpression) : null;
4430
- };
4431
- const getDirectAssignmentSourceSymbol = (identifier, scopes) => {
4432
- const assignmentTarget = findTransparentExpressionRoot(identifier);
4433
- const parent = assignmentTarget.parent;
4434
- if (!parent || !isNodeOfType(parent, "AssignmentExpression") || parent.operator !== "=" || parent.left !== assignmentTarget) return null;
4435
- return getDirectAliasSourceSymbol(parent.right, scopes);
4436
- };
4437
- const isDirectAliasSourceReference = (identifier) => {
4438
- const aliasSource = findTransparentExpressionRoot(identifier);
4439
- const parent = aliasSource.parent;
4440
- if (parent && isNodeOfType(parent, "VariableDeclarator") && parent.init === aliasSource && (isNodeOfType(parent.id, "Identifier") || isNodeOfType(parent.id, "ObjectPattern"))) return true;
4441
- return Boolean(parent && isNodeOfType(parent, "AssignmentExpression") && parent.operator === "=" && parent.right === aliasSource && isNodeOfType(stripParenExpression(parent.left), "Identifier"));
4442
- };
4443
- const isDirectAliasOfKnownSymbol = (symbol, knownSymbolIds, scopes) => {
4444
- if (symbol.initializer && isNodeOfType(symbol.declarationNode, "VariableDeclarator") && symbol.declarationNode.id === symbol.bindingIdentifier) {
4445
- const initializerSymbol = getDirectAliasSourceSymbol(symbol.initializer, scopes);
4446
- if (initializerSymbol && knownSymbolIds.has(initializerSymbol.id)) return true;
4447
- }
4448
- return symbol.references.some((reference) => {
4449
- const assignmentSourceSymbol = getDirectAssignmentSourceSymbol(reference.identifier, scopes);
4450
- return Boolean(assignmentSourceSymbol && knownSymbolIds.has(assignmentSourceSymbol.id));
4451
- });
4452
- };
4453
- const getPotentiallyAliasedSymbols = (identifier, scopes) => {
4454
- const rootSymbol = resolveConstIdentifierAlias(identifier, scopes);
4455
- if (!rootSymbol) return [];
4456
- let symbolsByRootId = potentiallyAliasedSymbolsByAnalysis.get(scopes);
4457
- if (!symbolsByRootId) {
4458
- symbolsByRootId = /* @__PURE__ */ new Map();
4459
- potentiallyAliasedSymbolsByAnalysis.set(scopes, symbolsByRootId);
4460
- }
4461
- const cachedSymbols = symbolsByRootId.get(rootSymbol.id);
4462
- if (cachedSymbols) return cachedSymbols;
4463
- const allSymbols = [];
4464
- collectScopeSymbols(scopes.rootScope, allSymbols);
4465
- const aliasedSymbolIds = new Set([rootSymbol.id]);
4466
- let didAddAlias = true;
4467
- while (didAddAlias) {
4468
- didAddAlias = false;
4469
- for (const symbol of allSymbols) {
4470
- if (aliasedSymbolIds.has(symbol.id)) continue;
4471
- if (!isDirectAliasOfKnownSymbol(symbol, aliasedSymbolIds, scopes)) continue;
4472
- aliasedSymbolIds.add(symbol.id);
4473
- didAddAlias = true;
4474
- }
4475
- }
4476
- const aliasedSymbols = allSymbols.filter((symbol) => aliasedSymbolIds.has(symbol.id));
4477
- symbolsByRootId.set(rootSymbol.id, aliasedSymbols);
4478
- return aliasedSymbols;
4479
- };
4480
- const findExecutionBoundary = (node) => {
4481
- let current = node;
4482
- while (current) {
4483
- if (isFunctionLike$2(current) || isNodeOfType(current, "Program")) return current;
4484
- current = current.parent ?? null;
4485
- }
4486
- return null;
4487
- };
4488
- const isOnUnconditionalPath = (node, boundary) => {
4489
- let current = node.parent ?? null;
4490
- while (current && current !== boundary) {
4491
- if (CONDITIONAL_EXECUTION_NODE_TYPES.has(current.type)) return false;
4492
- current = current.parent ?? null;
4493
- }
4494
- return current === boundary;
4495
- };
4496
- const findFunctionBindingIdentifier = (functionNode) => {
4497
- if (isNodeOfType(functionNode, "FunctionDeclaration")) return functionNode.id ?? null;
4498
- const parent = functionNode.parent;
4499
- if (parent && isNodeOfType(parent, "VariableDeclarator") && parent.init === functionNode && isNodeOfType(parent.id, "Identifier")) return parent.id;
4500
- return null;
4501
- };
4502
- const findDirectCall = (identifier) => {
4503
- let callee = identifier;
4504
- let parent = callee.parent;
4505
- while (parent && stripParenExpression(parent) === identifier) {
4506
- callee = parent;
4507
- parent = callee.parent;
4508
- }
4509
- return parent && isNodeOfType(parent, "CallExpression") && parent.callee === callee ? parent : null;
4510
- };
4511
- const isFunctionSynchronouslyInvokedBefore = (functionNode, referenceNode, scopes, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
4512
- if (visitedFunctionNodes.has(functionNode) || !isFunctionLike$2(functionNode) || functionNode.generator) return false;
4513
- visitedFunctionNodes.add(functionNode);
4514
- const referenceBoundary = findExecutionBoundary(referenceNode);
4515
- if (!referenceBoundary) return false;
4516
- const invocationCalls = [];
4517
- const bindingIdentifier = findFunctionBindingIdentifier(functionNode);
4518
- if (bindingIdentifier) for (const symbol of getEquivalentSymbols(bindingIdentifier, scopes)) for (const reference of symbol.references) {
4519
- const call = findDirectCall(reference.identifier);
4520
- if (call) invocationCalls.push(call);
4521
- }
4522
- else {
4523
- const call = findDirectCall(functionNode);
4524
- if (call) invocationCalls.push(call);
4525
- }
4526
- return invocationCalls.some((call) => {
4527
- if (call.range[0] >= referenceNode.range[0]) return false;
4528
- const callBoundary = findExecutionBoundary(call);
4529
- if (!callBoundary) return false;
4530
- if (callBoundary === referenceBoundary) return true;
4531
- if (!isFunctionLike$2(callBoundary)) return false;
4532
- return isFunctionSynchronouslyInvokedBefore(callBoundary, referenceNode, scopes, new Set(visitedFunctionNodes));
4533
- });
4534
- };
4535
- const isMemberWriteTarget = (memberExpression) => {
4536
- const parent = memberExpression.parent;
4537
- if (!parent) return false;
4538
- if (isNodeOfType(parent, "AssignmentExpression")) return parent.left === memberExpression;
4539
- if (isNodeOfType(parent, "UpdateExpression")) return parent.argument === memberExpression;
4540
- return isNodeOfType(parent, "UnaryExpression") && parent.operator === "delete" && parent.argument === memberExpression;
4541
- };
4542
- const getMemberWriteTarget = (identifier) => {
4543
- let parent = identifier.parent;
4544
- while (parent && stripParenExpression(parent) === identifier) parent = parent.parent;
4545
- if (!parent || !isNodeOfType(parent, "MemberExpression") || stripParenExpression(parent.object) !== identifier || !isMemberWriteTarget(parent)) return null;
4546
- return parent;
4547
- };
4548
- const getStaticPropertyWriteTarget = (identifier, propertyName, scopes) => {
4549
- const writeTarget = getMemberWriteTarget(identifier);
4550
- return writeTarget && getResolvedStaticPropertyName(writeTarget, scopes) === propertyName ? writeTarget : null;
4551
- };
4552
- const symbolHasStaticPropertyWriteBefore = (symbol, propertyName, referenceNode, scopes) => symbol.references.some((reference) => {
4553
- const writeTarget = getStaticPropertyWriteTarget(reference.identifier, propertyName, scopes);
4554
- if (!writeTarget) return false;
4555
- const writeBoundary = findExecutionBoundary(writeTarget);
4556
- const referenceBoundary = findExecutionBoundary(referenceNode);
4557
- if (!writeBoundary || !referenceBoundary || !isOnUnconditionalPath(writeTarget, writeBoundary)) return false;
4558
- if (writeBoundary === referenceBoundary) return writeTarget.range[0] < referenceNode.range[0];
4559
- return isFunctionLike$2(writeBoundary) && isFunctionSynchronouslyInvokedBefore(writeBoundary, referenceNode, scopes);
4560
- });
4561
- const isStableStaticPropertyReference = (identifier) => {
4562
- if (isDirectAliasSourceReference(identifier)) return true;
4563
- const identifierRoot = findTransparentExpressionRoot(identifier);
4564
- const memberExpression = identifierRoot.parent;
4565
- return Boolean(memberExpression && isNodeOfType(memberExpression, "MemberExpression") && stripParenExpression(memberExpression.object) === identifierRoot);
4566
- };
4567
- const hasPossibleStaticPropertyWrite = (identifier, propertyName, scopes) => {
4568
- if (!isNodeOfType(identifier, "Identifier")) return false;
4569
- return getPotentiallyAliasedSymbols(identifier, scopes).some((symbol) => symbol.references.some((reference) => {
4570
- const writeTarget = getMemberWriteTarget(reference.identifier);
4571
- if (!writeTarget) return false;
4572
- const writtenPropertyName = getResolvedStaticPropertyName(writeTarget, scopes);
4573
- return writtenPropertyName === null || writtenPropertyName === propertyName;
4574
- }));
4575
- };
4576
- const hasPossibleStaticPropertyMutationOrEscape = (identifier, propertyName, scopes) => {
4577
- if (!isNodeOfType(identifier, "Identifier")) return false;
4578
- if (hasPossibleStaticPropertyWrite(identifier, propertyName, scopes)) return true;
4579
- return getPotentiallyAliasedSymbols(identifier, scopes).some((symbol) => symbol.references.some((reference) => !isStableStaticPropertyReference(reference.identifier)));
4580
- };
4581
- const hasPossibleStaticMemberCallWrite = (callExpression, scopes) => {
4582
- const unwrappedCallExpression = stripParenExpression(callExpression);
4583
- if (!isNodeOfType(unwrappedCallExpression, "CallExpression")) return false;
4584
- const callee = stripParenExpression(unwrappedCallExpression.callee);
4585
- if (!isNodeOfType(callee, "MemberExpression")) return false;
4586
- const propertyName = getStaticPropertyName(callee);
4587
- if (propertyName === null) return false;
4588
- const receiver = stripParenExpression(callee.object);
4589
- return isNodeOfType(receiver, "Identifier") && hasPossibleStaticPropertyWrite(receiver, propertyName, scopes);
4590
- };
4591
- const hasStaticPropertyWriteBefore = (identifier, propertyName, referenceNode, scopes) => {
4592
- if (!isNodeOfType(identifier, "Identifier")) return false;
4593
- return getEquivalentSymbols(identifier, scopes).some((symbol) => symbolHasStaticPropertyWriteBefore(symbol, propertyName, referenceNode, scopes));
4594
- };
4595
- //#endregion
4596
- //#region src/plugin/utils/find-enclosing-function.ts
4597
- const findEnclosingFunction$1 = (node) => {
4598
- let cursor = node.parent;
4599
- while (cursor) {
4600
- if (isFunctionLike$2(cursor)) return cursor;
4601
- cursor = cursor.parent ?? null;
4602
- }
4603
- return null;
4604
- };
4605
- //#endregion
4606
- //#region src/plugin/utils/has-symbol-write-before.ts
4607
- const hasSymbolWriteBefore = (symbol, referenceNode, scopes) => symbol.references.some((reference) => {
4608
- if (reference.flag === "read") return false;
4609
- const writeFunction = findEnclosingFunction$1(reference.identifier);
4610
- if (writeFunction === findEnclosingFunction$1(referenceNode)) return reference.identifier.range[0] < referenceNode.range[0];
4611
- if (!writeFunction) return true;
4612
- return isFunctionSynchronouslyInvokedBefore(writeFunction, referenceNode, scopes);
4613
- });
4614
- //#endregion
4615
- //#region src/plugin/utils/get-order-independent-local-function.ts
4616
- const COMMUTATIVE_COMPOUND_ASSIGNMENT_OPERATORS = new Set([
4617
- "+=",
4618
- "-=",
4619
- "*=",
4620
- "/=",
4621
- "%=",
4622
- "&=",
4623
- "^=",
4624
- "|="
4625
- ]);
4626
- const isPureParameterExpression = (expression, parameterNames) => {
4627
- const unwrappedExpression = stripParenExpression(expression);
4628
- if (isNodeOfType(unwrappedExpression, "Literal")) return true;
4629
- if (isNodeOfType(unwrappedExpression, "Identifier")) return parameterNames.has(unwrappedExpression.name);
4630
- if (isNodeOfType(unwrappedExpression, "BinaryExpression") || isNodeOfType(unwrappedExpression, "LogicalExpression")) return isPureParameterExpression(unwrappedExpression.left, parameterNames) && isPureParameterExpression(unwrappedExpression.right, parameterNames);
4631
- if (isNodeOfType(unwrappedExpression, "UnaryExpression")) return unwrappedExpression.operator !== "delete" && isPureParameterExpression(unwrappedExpression.argument, parameterNames);
4632
- if (isNodeOfType(unwrappedExpression, "ConditionalExpression")) return isPureParameterExpression(unwrappedExpression.test, parameterNames) && isPureParameterExpression(unwrappedExpression.consequent, parameterNames) && isPureParameterExpression(unwrappedExpression.alternate, parameterNames);
4633
- if (isNodeOfType(unwrappedExpression, "TemplateLiteral")) return unwrappedExpression.expressions.every((nestedExpression) => isPureParameterExpression(nestedExpression, parameterNames));
4634
- return false;
4635
- };
4636
- const isOrderIndependentPromiseResolveCall = (expression, parameterNames, scopes) => {
4637
- const unwrappedExpression = stripParenExpression(expression);
4638
- if (!isNodeOfType(unwrappedExpression, "CallExpression")) return false;
4639
- if (!unwrappedExpression.arguments.every((argument) => !isNodeOfType(argument, "SpreadElement") && isPureParameterExpression(argument, parameterNames))) return false;
4640
- const callee = stripParenExpression(unwrappedExpression.callee);
4641
- if (!isNodeOfType(callee, "MemberExpression")) return false;
4642
- if (getStaticPropertyName(callee) !== "resolve") return false;
4643
- const receiver = stripParenExpression(callee.object);
4644
- return isNodeOfType(receiver, "Identifier") && receiver.name === "Promise" && scopes.isGlobalReference(receiver);
4645
- };
4646
- const isHarmlessPromiseResolveAwait = (statement, parameterNames, scopes) => {
4647
- if (!isNodeOfType(statement, "ExpressionStatement") || !isNodeOfType(statement.expression, "AwaitExpression")) return false;
4648
- return isOrderIndependentPromiseResolveCall(statement.expression.argument, parameterNames, scopes);
4649
- };
4650
- const isCommutativeParameterMutation = (statement, parameterNames) => {
4651
- if (!isNodeOfType(statement, "ExpressionStatement") || !isNodeOfType(statement.expression, "AssignmentExpression") || !COMMUTATIVE_COMPOUND_ASSIGNMENT_OPERATORS.has(statement.expression.operator)) return false;
4652
- const mutationTarget = stripParenExpression(statement.expression.left);
4653
- if (!isNodeOfType(mutationTarget, "MemberExpression")) return false;
4654
- if (getStaticPropertyName(mutationTarget) === null) return false;
4655
- const receiver = stripParenExpression(mutationTarget.object);
4656
- return isNodeOfType(receiver, "Identifier") && parameterNames.has(receiver.name) && isNodeOfType(stripParenExpression(statement.expression.right), "Literal");
4657
- };
4658
- const isOrderIndependentFunction = (functionNode, scopes) => {
4659
- if (!isFunctionLike$2(functionNode)) return false;
4660
- const parameterNames = /* @__PURE__ */ new Set();
4661
- for (const parameter of functionNode.params) {
4662
- if (!isNodeOfType(parameter, "Identifier")) return false;
4663
- parameterNames.add(parameter.name);
4664
- }
4665
- if (!functionNode.async) {
4666
- if (!isNodeOfType(functionNode.body, "BlockStatement")) return isOrderIndependentPromiseResolveCall(functionNode.body, parameterNames, scopes);
4667
- if (functionNode.body.body.length !== 1) return false;
4668
- const [returnStatement] = functionNode.body.body;
4669
- return Boolean(isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument && isOrderIndependentPromiseResolveCall(returnStatement.argument, parameterNames, scopes));
4670
- }
4671
- if (!isNodeOfType(functionNode.body, "BlockStatement")) return isPureParameterExpression(functionNode.body, parameterNames);
4672
- const statements = functionNode.body.body;
4673
- for (let statementIndex = 0; statementIndex < statements.length; statementIndex++) {
4674
- const statement = statements[statementIndex];
4675
- const isTerminalStatement = statementIndex === statements.length - 1;
4676
- if (isHarmlessPromiseResolveAwait(statement, parameterNames, scopes)) continue;
4677
- if (isNodeOfType(statement, "ExpressionStatement") && isPureParameterExpression(statement.expression, parameterNames)) continue;
4678
- if (isCommutativeParameterMutation(statement, parameterNames)) return isTerminalStatement;
4679
- if (!isNodeOfType(statement, "ReturnStatement") || !isTerminalStatement) return false;
4680
- return !statement.argument || isPureParameterExpression(statement.argument, parameterNames) || isOrderIndependentPromiseResolveCall(statement.argument, parameterNames, scopes);
4681
- }
4682
- return true;
4683
- };
4684
- const getObjectPropertyName = (property) => {
4685
- if (!isNodeOfType(property, "Property")) return null;
4686
- return getStaticPropertyKeyName(property, { allowComputedString: true });
4687
- };
4688
- const resolveOrderIndependentObjectPropertyFunction = (objectExpression, propertyName, callExpression, scopes, visitedSymbolIds) => {
4689
- const unwrappedObject = stripParenExpression(objectExpression);
4690
- if (isNodeOfType(unwrappedObject, "Identifier")) {
4691
- const symbol = scopes.symbolFor(unwrappedObject);
4692
- if (!symbol || symbol.kind !== "const" || !symbol.initializer || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, callExpression, scopes) || hasPossibleStaticPropertyMutationOrEscape(unwrappedObject, propertyName, scopes)) return null;
4693
- visitedSymbolIds.add(symbol.id);
4694
- return resolveOrderIndependentObjectPropertyFunction(symbol.initializer, propertyName, callExpression, scopes, visitedSymbolIds);
4695
- }
4696
- if (!isNodeOfType(unwrappedObject, "ObjectExpression")) return null;
4697
- let matchingProperty = null;
4698
- for (const property of unwrappedObject.properties) {
4699
- if (!isNodeOfType(property, "Property")) return null;
4700
- if (property.kind !== "init") return null;
4701
- const candidatePropertyName = getObjectPropertyName(property);
4702
- if (candidatePropertyName === null) return null;
4703
- if (candidatePropertyName === propertyName) matchingProperty = property;
4704
- }
4705
- if (!matchingProperty || !isNodeOfType(matchingProperty, "Property")) return null;
4706
- const propertyValue = stripParenExpression(matchingProperty.value);
4707
- if (isFunctionLike$2(propertyValue)) return isOrderIndependentFunction(propertyValue, scopes) ? propertyValue : null;
4708
- return resolveOrderIndependentLocalFunction(propertyValue, callExpression, scopes, visitedSymbolIds);
4709
- };
4710
- const resolveOrderIndependentLocalFunction = (callee, callExpression, scopes, visitedSymbolIds) => {
4711
- const unwrappedCallee = stripParenExpression(callee);
4712
- if (isNodeOfType(unwrappedCallee, "MemberExpression")) {
4713
- const propertyName = getStaticPropertyName(unwrappedCallee);
4714
- if (propertyName === null) return null;
4715
- return resolveOrderIndependentObjectPropertyFunction(stripParenExpression(unwrappedCallee.object), propertyName, callExpression, scopes, visitedSymbolIds);
4716
- }
4717
- if (!isNodeOfType(unwrappedCallee, "Identifier")) return null;
4718
- const symbol = scopes.symbolFor(unwrappedCallee);
4719
- if (!symbol || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, callExpression, scopes)) return null;
4720
- visitedSymbolIds.add(symbol.id);
4721
- if (!symbol.initializer) return null;
4722
- const initializer = stripParenExpression(symbol.initializer);
4723
- const destructuredPropertyName = getDestructuredBindingPropertyName(symbol.bindingIdentifier);
4724
- if (destructuredPropertyName !== null) return resolveOrderIndependentObjectPropertyFunction(initializer, destructuredPropertyName, callExpression, scopes, visitedSymbolIds);
4725
- if (isFunctionLike$2(initializer)) return isOrderIndependentFunction(initializer, scopes) ? initializer : null;
4726
- if (symbol.kind !== "const") return null;
4727
- return resolveOrderIndependentLocalFunction(initializer, callExpression, scopes, visitedSymbolIds);
4728
- };
4729
- const getOrderIndependentLocalFunction = (callExpression, scopes) => {
4730
- const unwrappedCall = stripParenExpression(callExpression);
4731
- if (!isNodeOfType(unwrappedCall, "CallExpression")) return null;
4732
- if (hasPossibleStaticMemberCallWrite(unwrappedCall, scopes)) return null;
4733
- return resolveOrderIndependentLocalFunction(unwrappedCall.callee, unwrappedCall, scopes, /* @__PURE__ */ new Set());
4734
- };
4735
- //#endregion
4736
4317
  //#region src/plugin/utils/is-inline-function-expression.ts
4737
4318
  /**
4738
4319
  * Type-guard for the two "inline function expression" ESTree forms:
@@ -4766,15 +4347,13 @@ const isIntentionalSequencingCallee = (callee) => {
4766
4347
  if (isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier")) return INTENTIONAL_SEQUENCING_CALLEE_NAMES.has(callee.property.name);
4767
4348
  return false;
4768
4349
  };
4769
- const isAwaitingSleepLikeCall = (awaitNode, context) => {
4350
+ const isAwaitingSleepLikeCall = (awaitNode) => {
4770
4351
  if (!isNodeOfType(awaitNode, "AwaitExpression")) return false;
4771
4352
  const argument = awaitNode.argument;
4772
4353
  if (!argument) return false;
4773
4354
  if (!isNodeOfType(argument, "CallExpression")) return false;
4774
- if (getOrderIndependentLocalFunction(argument, context.scopes) !== null) return false;
4775
4355
  return isIntentionalSequencingCallee(argument.callee);
4776
4356
  };
4777
- const isAwaitingPossiblyMutatedMemberCall = (awaitNode, context) => isNodeOfType(awaitNode, "AwaitExpression") && Boolean(awaitNode.argument) && hasPossibleStaticMemberCallWrite(awaitNode.argument, context.scopes);
4778
4357
  const PROMISE_CONCURRENCY_METHODS = new Set([
4779
4358
  "all",
4780
4359
  "allSettled",
@@ -4817,7 +4396,7 @@ const isAwaitingManualPromiseWait = (awaitNode) => {
4817
4396
  });
4818
4397
  return isWaitLike;
4819
4398
  };
4820
- const isIntentionallySequentialAwait = (awaitNode, context) => isAwaitingPossiblyMutatedMemberCall(awaitNode, context) || isAwaitingSleepLikeCall(awaitNode, context) || isAwaitingPromiseConcurrencyCall(awaitNode) || isAwaitingManualPromiseWait(awaitNode);
4399
+ const isIntentionallySequentialAwait = (awaitNode) => isAwaitingSleepLikeCall(awaitNode) || isAwaitingPromiseConcurrencyCall(awaitNode) || isAwaitingManualPromiseWait(awaitNode);
4821
4400
  const collectPatternIdentifiers = (pattern, target) => {
4822
4401
  if (isNodeOfType(pattern, "Identifier")) target.add(pattern.name);
4823
4402
  else if (isNodeOfType(pattern, "ObjectPattern")) {
@@ -5008,12 +4587,12 @@ const getLoopLabelName = (loopNode) => {
5008
4587
  if (isNodeOfType(parent, "LabeledStatement") && isNodeOfType(parent.label, "Identifier")) return parent.label.name;
5009
4588
  return null;
5010
4589
  };
5011
- const loopBodyHasIntentionallySequentialAwait = (block, context) => {
4590
+ const loopBodyHasIntentionallySequentialAwait = (block) => {
5012
4591
  let foundIntentional = false;
5013
4592
  walkAst(block, (child) => {
5014
4593
  if (foundIntentional) return false;
5015
4594
  if (isInlineFunctionExpression(child) || isNodeOfType(child, "FunctionDeclaration")) return false;
5016
- if (isNodeOfType(child, "AwaitExpression") && isIntentionallySequentialAwait(child, context)) {
4595
+ if (isNodeOfType(child, "AwaitExpression") && isIntentionallySequentialAwait(child)) {
5017
4596
  foundIntentional = true;
5018
4597
  return false;
5019
4598
  }
@@ -5118,7 +4697,7 @@ const asyncAwaitInLoop = defineRule({
5118
4697
  const inspectLoop = (loopNode, label) => {
5119
4698
  const loopBody = loopNode.body;
5120
4699
  if (!loopBody) return;
5121
- if (loopBodyHasIntentionallySequentialAwait(loopBody, context)) return;
4700
+ if (loopBodyHasIntentionallySequentialAwait(loopBody)) return;
5122
4701
  if ((isNodeOfType(loopNode, "WhileStatement") || isNodeOfType(loopNode, "DoWhileStatement")) && isLoopTestDependentOnBodyState(loopNode.test, loopBody)) return;
5123
4702
  if (hasLoopCarriedDependency(loopBody)) return;
5124
4703
  if (loopBodyHasAwaitDependentEarlyExit(loopBody, getLoopLabelName(loopNode))) return;
@@ -5378,7 +4957,7 @@ const guardConsequentPerformsSideEffects = (consequent) => {
5378
4957
  });
5379
4958
  return performsSideEffects;
5380
4959
  };
5381
- const findEnclosingFunction = (node) => {
4960
+ const findEnclosingFunction$1 = (node) => {
5382
4961
  let ancestor = node.parent;
5383
4962
  while (ancestor) {
5384
4963
  if (isFunctionLike$2(ancestor)) return ancestor;
@@ -5391,7 +4970,7 @@ const guardTestReadsReassignedLocal = (test, guardStatement) => {
5391
4970
  const testIdentifierNames = /* @__PURE__ */ new Set();
5392
4971
  collectReferenceIdentifierNames(test, testIdentifierNames);
5393
4972
  if (testIdentifierNames.size === 0) return false;
5394
- const enclosingFunction = findEnclosingFunction(guardStatement);
4973
+ const enclosingFunction = findEnclosingFunction$1(guardStatement);
5395
4974
  if (!enclosingFunction || !isFunctionLike$2(enclosingFunction) || !enclosingFunction.body) return false;
5396
4975
  let readsReassignedLocal = false;
5397
4976
  walkAst(enclosingFunction.body, (child) => {
@@ -5562,36 +5141,19 @@ const isIntentionalSequencingAwait = (awaitedCall) => {
5562
5141
  return getCalleeIdentifierTrail(awaitedCall).some((name) => INTENTIONAL_SEQUENCING_CALLEE_NAMES.has(name));
5563
5142
  };
5564
5143
  const isBareExpressionAwait = (statement) => isNodeOfType(statement, "ExpressionStatement") && isNodeOfType(statement.expression, "AwaitExpression");
5565
- const hasOrderIndependentBareAwaitArguments = (callExpression) => {
5566
- const unwrappedCallExpression = stripParenExpression(callExpression);
5567
- if (!isNodeOfType(unwrappedCallExpression, "CallExpression")) return false;
5568
- return unwrappedCallExpression.arguments.every((argument) => {
5569
- if (isNodeOfType(argument, "SpreadElement")) return false;
5570
- const unwrappedArgument = stripParenExpression(argument);
5571
- return isNodeOfType(unwrappedArgument, "Identifier") || isNodeOfType(unwrappedArgument, "Literal");
5572
- });
5573
- };
5574
5144
  const isNonCallAwait = (statement) => {
5575
5145
  const awaitedExpression = getAwaitedCall(statement);
5576
5146
  if (!awaitedExpression) return false;
5577
5147
  const stripped = stripParenExpression(awaitedExpression);
5578
5148
  return !isNodeOfType(stripped, "CallExpression") && !isNodeOfType(stripped, "NewExpression") && !isNodeOfType(stripped, "ImportExpression");
5579
5149
  };
5580
- const sequenceContainsSerializationSignal = (statements, context) => {
5581
- let bareAwaitFunction = null;
5150
+ const sequenceContainsSerializationSignal = (statements) => {
5582
5151
  for (const statement of statements) {
5152
+ if (isBareExpressionAwait(statement)) return true;
5583
5153
  if (isNonCallAwait(statement)) return true;
5584
5154
  const awaitedCall = getAwaitedCall(statement);
5585
- if (awaitedCall && hasPossibleStaticMemberCallWrite(awaitedCall, context.scopes)) return true;
5586
- const orderIndependentFunction = awaitedCall ? getOrderIndependentLocalFunction(awaitedCall, context.scopes) : null;
5587
- if (isBareExpressionAwait(statement)) {
5588
- if (orderIndependentFunction === null) return true;
5589
- if (!awaitedCall || !hasOrderIndependentBareAwaitArguments(awaitedCall)) return true;
5590
- if (bareAwaitFunction !== null && bareAwaitFunction !== orderIndependentFunction) return true;
5591
- bareAwaitFunction = orderIndependentFunction;
5592
- }
5593
5155
  if (isOrderedUiFlowAwait(awaitedCall)) return true;
5594
- if (isIntentionalSequencingAwait(awaitedCall) && orderIndependentFunction === null) return true;
5156
+ if (isIntentionalSequencingAwait(awaitedCall)) return true;
5595
5157
  }
5596
5158
  return false;
5597
5159
  };
@@ -5649,7 +5211,7 @@ const asyncParallel = defineRule({
5649
5211
  const consecutiveAwaitStatements = [];
5650
5212
  const flushConsecutiveAwaits = () => {
5651
5213
  if (consecutiveAwaitStatements.length >= 3) {
5652
- if (!sequenceContainsSerializationSignal(consecutiveAwaitStatements, context)) reportIfIndependent(consecutiveAwaitStatements, context);
5214
+ if (!sequenceContainsSerializationSignal(consecutiveAwaitStatements)) reportIfIndependent(consecutiveAwaitStatements, context);
5653
5215
  }
5654
5216
  consecutiveAwaitStatements.length = 0;
5655
5217
  };
@@ -5662,7 +5224,7 @@ const asyncParallel = defineRule({
5662
5224
  });
5663
5225
  //#endregion
5664
5226
  //#region src/plugin/rules/security/auth-token-in-web-storage.ts
5665
- const MESSAGE$60 = "Storing an auth token in `localStorage`/`sessionStorage` exposes it to any XSS on the page: JavaScript can read web storage and exfiltrate the token. Keep tokens in an `HttpOnly`, `Secure`, `SameSite` cookie instead.";
5227
+ const MESSAGE$59 = "Storing an auth token in `localStorage`/`sessionStorage` exposes it to any XSS on the page: JavaScript can read web storage and exfiltrate the token. Keep tokens in an `HttpOnly`, `Secure`, `SameSite` cookie instead.";
5666
5228
  const STORAGE_NAMES = new Set(["localStorage", "sessionStorage"]);
5667
5229
  const STORAGE_GLOBALS = new Set([
5668
5230
  "window",
@@ -5727,7 +5289,7 @@ const authTokenInWebStorage = defineRule({
5727
5289
  if (keyString === null || !isAuthCredentialKey(keyString)) return;
5728
5290
  context.report({
5729
5291
  node,
5730
- message: MESSAGE$60
5292
+ message: MESSAGE$59
5731
5293
  });
5732
5294
  },
5733
5295
  AssignmentExpression(node) {
@@ -5738,7 +5300,7 @@ const authTokenInWebStorage = defineRule({
5738
5300
  if (!propertyName || !isAuthCredentialKey(propertyName)) return;
5739
5301
  context.report({
5740
5302
  node: target,
5741
- message: MESSAGE$60
5303
+ message: MESSAGE$59
5742
5304
  });
5743
5305
  }
5744
5306
  }))
@@ -5877,7 +5439,7 @@ const CI_INSTALL_NEAR_SECRET_PATTERN = /(?:npm|pnpm|yarn|bun)\s+(?:install|ci)\b
5877
5439
  const INSTALL_COMMAND_PATTERN = /(?:npm|pnpm|yarn|bun)\s+(?:install|ci)\b/i;
5878
5440
  const SECRET_REFERENCE_PATTERN = /\bsecrets\.[A-Z0-9_]+/;
5879
5441
  const IGNORE_SCRIPTS_FLAG_PATTERN = /--ignore-scripts\b/;
5880
- const MESSAGE$59 = "The build or install pipeline can execute package lifecycle code while CI secrets may be present.";
5442
+ const MESSAGE$58 = "The build or install pipeline can execute package lifecycle code while CI secrets may be present.";
5881
5443
  const isWorkflowPath = (relativePath) => /(?:^|\/)\.github\/workflows\/[^/]+\.ya?ml$/i.test(relativePath);
5882
5444
  const scanWorkflowContent = (content) => {
5883
5445
  const lines = content.split("\n");
@@ -5922,7 +5484,7 @@ const scanWorkflowContent = (content) => {
5922
5484
  const installLineOffset = Math.max(step.lines.findIndex((stepLine) => INSTALL_COMMAND_PATTERN.test(stepLine)), 0);
5923
5485
  const installColumnIndex = step.lines[installLineOffset].search(INSTALL_COMMAND_PATTERN);
5924
5486
  return [{
5925
- message: MESSAGE$59,
5487
+ message: MESSAGE$58,
5926
5488
  line: step.startLineIndex + installLineOffset + 1,
5927
5489
  column: (installColumnIndex === -1 ? 0 : installColumnIndex) + 1
5928
5490
  }];
@@ -5932,7 +5494,7 @@ const scanWorkflowContent = (content) => {
5932
5494
  const scanNonWorkflowConfig = scanByPattern({
5933
5495
  shouldScan: (file) => isConfigOrCiPath(file.relativePath) && !file.relativePath.endsWith("package.json") && !isWorkflowPath(file.relativePath),
5934
5496
  pattern: CI_INSTALL_NEAR_SECRET_PATTERN,
5935
- message: MESSAGE$59
5497
+ message: MESSAGE$58
5936
5498
  });
5937
5499
  const scan = (file) => {
5938
5500
  if (isWorkflowPath(file.relativePath)) return scanWorkflowContent(file.content);
@@ -6427,6 +5989,21 @@ const checkedRequiresOnchangeOrReadonly = defineRule({
6427
5989
  }
6428
5990
  });
6429
5991
  //#endregion
5992
+ //#region src/plugin/utils/get-static-property-key-name.ts
5993
+ const getStaticPropertyKeyName = (node, options = {}) => {
5994
+ if (!isNodeOfType(node, "Property") && !isNodeOfType(node, "MethodDefinition")) return null;
5995
+ if (node.computed) {
5996
+ if (options.allowComputedString && isNodeOfType(node.key, "Literal") && typeof node.key.value === "string") return node.key.value;
5997
+ return null;
5998
+ }
5999
+ if (isNodeOfType(node.key, "Identifier")) return node.key.name;
6000
+ if (isNodeOfType(node.key, "Literal")) {
6001
+ if (typeof node.key.value === "string") return node.key.value;
6002
+ if (options.stringifyNonStringLiterals) return String(node.key.value);
6003
+ }
6004
+ return null;
6005
+ };
6006
+ //#endregion
6430
6007
  //#region src/plugin/utils/are-expressions-structurally-equal.ts
6431
6008
  const areExpressionsStructurallyEqual = (a, b) => {
6432
6009
  if (!a || !b) return a === b;
@@ -6684,7 +6261,7 @@ const isPureEventBlockerHandler = (attribute) => {
6684
6261
  };
6685
6262
  //#endregion
6686
6263
  //#region src/plugin/rules/a11y/click-events-have-key-events.ts
6687
- const MESSAGE$58 = "Keyboard users can't trigger this click handler because there's no keyboard one, so add `onKeyUp`, `onKeyDown`, or `onKeyPress`.";
6264
+ const MESSAGE$57 = "Keyboard users can't trigger this click handler because there's no keyboard one, so add `onKeyUp`, `onKeyDown`, or `onKeyPress`.";
6688
6265
  const KEY_HANDLERS = [
6689
6266
  "onKeyUp",
6690
6267
  "onKeyDown",
@@ -6895,7 +6472,7 @@ const clickEventsHaveKeyEvents = defineRule({
6895
6472
  if (KEY_HANDLERS.some((handler) => hasJsxPropIgnoreCase(node.attributes, handler) || spreadEventValues.has(handler.toLowerCase()))) return;
6896
6473
  context.report({
6897
6474
  node: node.name,
6898
- message: MESSAGE$58
6475
+ message: MESSAGE$57
6899
6476
  });
6900
6477
  } };
6901
6478
  }
@@ -7110,6 +6687,15 @@ const getDirectConstInitializer = (symbol) => {
7110
6687
  return symbol.initializer;
7111
6688
  };
7112
6689
  //#endregion
6690
+ //#region src/plugin/utils/get-static-property-name.ts
6691
+ const getStaticPropertyName = (memberExpression) => {
6692
+ const property = memberExpression.property;
6693
+ if (!memberExpression.computed && isNodeOfType(property, "Identifier")) return property.name;
6694
+ if (memberExpression.computed && isNodeOfType(property, "Literal")) return typeof property.value === "string" ? property.value : null;
6695
+ if (memberExpression.computed && isNodeOfType(property, "TemplateLiteral") && property.expressions.length === 0) return property.quasis[0]?.value.cooked ?? property.quasis[0]?.value.raw ?? null;
6696
+ return null;
6697
+ };
6698
+ //#endregion
7113
6699
  //#region src/plugin/utils/get-range-start.ts
7114
6700
  const getRangeStart = (node) => {
7115
6701
  const rangeStart = node.range?.[0];
@@ -7505,6 +7091,16 @@ const collectFunctionReturnStatements = (functionNode) => {
7505
7091
  return returnStatements;
7506
7092
  };
7507
7093
  //#endregion
7094
+ //#region src/plugin/utils/find-enclosing-function.ts
7095
+ const findEnclosingFunction = (node) => {
7096
+ let cursor = node.parent;
7097
+ while (cursor) {
7098
+ if (isFunctionLike$2(cursor)) return cursor;
7099
+ cursor = cursor.parent ?? null;
7100
+ }
7101
+ return null;
7102
+ };
7103
+ //#endregion
7508
7104
  //#region src/plugin/utils/statement-always-exits.ts
7509
7105
  const statementAlwaysExits = (statement) => {
7510
7106
  if (isNodeOfType(statement, "ReturnStatement") || isNodeOfType(statement, "ThrowStatement")) return true;
@@ -7550,8 +7146,8 @@ const applyDefinitions = (incomingDefinitions, definitions) => {
7550
7146
  const collectPossibleAssignedExpressions = (symbol, referenceNode, controlFlow) => {
7551
7147
  if (!REASSIGNABLE_BINDING_KINDS.has(symbol.kind)) return symbol.initializer ? [symbol.initializer] : [];
7552
7148
  if (!controlFlow) return [];
7553
- const referenceFunction = findEnclosingFunction$1(referenceNode);
7554
- if (findEnclosingFunction$1(symbol.bindingIdentifier) !== referenceFunction) return [];
7149
+ const referenceFunction = findEnclosingFunction(referenceNode);
7150
+ if (findEnclosingFunction(symbol.bindingIdentifier) !== referenceFunction) return [];
7555
7151
  if (!referenceFunction) return [];
7556
7152
  const functionControlFlow = controlFlow.cfgFor(referenceFunction);
7557
7153
  if (!functionControlFlow) return [];
@@ -7575,7 +7171,7 @@ const collectPossibleAssignedExpressions = (symbol, referenceNode, controlFlow)
7575
7171
  if (symbol.initializer) addDefinition(symbol.initializer, symbol.bindingIdentifier, bindingPosition);
7576
7172
  for (const reference of symbol.references) {
7577
7173
  const writePosition = getRangeStart(reference.identifier);
7578
- if (reference.flag === "read" || findEnclosingFunction$1(reference.identifier) !== referenceFunction || writePosition === null || writePosition >= referencePosition) continue;
7174
+ if (reference.flag === "read" || findEnclosingFunction(reference.identifier) !== referenceFunction || writePosition === null || writePosition >= referencePosition) continue;
7579
7175
  const assignedExpression = getAssignedExpressionForWrite(reference.identifier);
7580
7176
  if (!assignedExpression) continue;
7581
7177
  addDefinition(assignedExpression, reference.identifier, writePosition);
@@ -9129,7 +8725,7 @@ const getClassNameLiteral = (classAttribute) => {
9129
8725
  };
9130
8726
  //#endregion
9131
8727
  //#region src/plugin/rules/a11y/control-has-associated-label.ts
9132
- const MESSAGE$57 = "Blind users can't tell what this control does because screen readers find no label, so add visible text, `aria-label`, or `aria-labelledby`.";
8728
+ const MESSAGE$56 = "Blind users can't tell what this control does because screen readers find no label, so add visible text, `aria-label`, or `aria-labelledby`.";
9133
8729
  const NON_OPERABLE_ELEMENTS = new Set([
9134
8730
  "td",
9135
8731
  "th",
@@ -9247,7 +8843,6 @@ const HTML_FOR_ATTRIBUTE = "htmlFor";
9247
8843
  const LABEL_ELEMENT = "label";
9248
8844
  const LABEL_COMPONENT_NAME = "Label";
9249
8845
  const POLYMORPHIC_COMPONENT_PROP = "component";
9250
- const TITLE_ATTRIBUTE = "title";
9251
8846
  const WRAPPER_LABEL_PROP = "label";
9252
8847
  const SELECT_ELEMENT = "select";
9253
8848
  const DEFAULT_DEPTH = 5;
@@ -9293,96 +8888,6 @@ const hasNonEmptyPropValue = (attribute) => {
9293
8888
  }
9294
8889
  return true;
9295
8890
  };
9296
- const getLastJsxPropIgnoreCase = (attributes, targetProp) => {
9297
- const targetPropLower = targetProp.toLowerCase();
9298
- for (let attributeIndex = attributes.length - 1; attributeIndex >= 0; attributeIndex -= 1) {
9299
- const attribute = attributes[attributeIndex];
9300
- if (!attribute || !isNodeOfType(attribute, "JSXAttribute")) continue;
9301
- if (getJsxAttributeName(attribute.name)?.toLowerCase() === targetPropLower) return attribute;
9302
- }
9303
- };
9304
- const getStaticNativeTitleArrayValue = (expression, scopes) => {
9305
- const elementValues = [];
9306
- for (const rawElement of expression.elements) {
9307
- if (rawElement === null) {
9308
- elementValues.push("");
9309
- continue;
9310
- }
9311
- if (isNodeOfType(rawElement, "SpreadElement")) return null;
9312
- const element = stripParenExpression(rawElement);
9313
- if (isNodeOfType(element, "Literal")) {
9314
- elementValues.push(element.value === null ? "" : String(element.value));
9315
- continue;
9316
- }
9317
- if (isNodeOfType(element, "TemplateLiteral")) {
9318
- const staticValue = getStaticTemplateLiteralValue(element);
9319
- if (staticValue === null) return null;
9320
- elementValues.push(staticValue);
9321
- continue;
9322
- }
9323
- if (isNodeOfType(element, "Identifier") && element.name === "undefined" && scopes.isGlobalReference(element) || isNodeOfType(element, "UnaryExpression") && element.operator === "void") {
9324
- elementValues.push("");
9325
- continue;
9326
- }
9327
- if (isNodeOfType(element, "ArrayExpression")) {
9328
- const nestedValue = getStaticNativeTitleArrayValue(element, scopes);
9329
- if (nestedValue === null) return null;
9330
- elementValues.push(nestedValue);
9331
- continue;
9332
- }
9333
- return null;
9334
- }
9335
- return elementValues.join(",");
9336
- };
9337
- const isGlobalSymbolExpression = (expression, scopes) => {
9338
- if (isNodeOfType(expression, "Identifier")) return expression.name === "Symbol" && scopes.isGlobalReference(expression);
9339
- if (!isNodeOfType(expression, "MemberExpression")) return false;
9340
- const object = stripParenExpression(expression.object);
9341
- return isNodeOfType(object, "Identifier") && object.name === "Symbol" && scopes.isGlobalReference(object);
9342
- };
9343
- const hasNonEmptyNativeTitleExpression = (rawExpression, scopes) => {
9344
- const expression = stripParenExpression(rawExpression);
9345
- if (isNodeOfType(expression, "Literal")) {
9346
- if (typeof expression.value === "string") return expression.value.trim().length > 0;
9347
- return expression.value !== null && typeof expression.value !== "boolean";
9348
- }
9349
- if (isNodeOfType(expression, "TemplateLiteral")) {
9350
- const staticValue = getStaticTemplateLiteralValue(expression);
9351
- return staticValue === null || staticValue.trim().length > 0;
9352
- }
9353
- if (isNodeOfType(expression, "Identifier")) return expression.name !== "undefined" || !scopes.isGlobalReference(expression);
9354
- if (isNodeOfType(expression, "UnaryExpression") && expression.operator === "void") return false;
9355
- if (isNodeOfType(expression, "UnaryExpression") && expression.operator === "!") return false;
9356
- if (isNodeOfType(expression, "ArrowFunctionExpression")) return false;
9357
- if (isNodeOfType(expression, "FunctionExpression")) return false;
9358
- if (isNodeOfType(expression, "ClassExpression")) return false;
9359
- if (isNodeOfType(expression, "ArrayExpression")) {
9360
- const staticValue = getStaticNativeTitleArrayValue(expression, scopes);
9361
- return staticValue === null || staticValue.trim().length > 0;
9362
- }
9363
- if (isGlobalSymbolExpression(expression, scopes)) return false;
9364
- if (isNodeOfType(expression, "CallExpression") && isGlobalSymbolExpression(expression.callee, scopes)) return false;
9365
- if (isNodeOfType(expression, "ConditionalExpression")) return hasNonEmptyNativeTitleExpression(expression.consequent, scopes) && hasNonEmptyNativeTitleExpression(expression.alternate, scopes);
9366
- if (isNodeOfType(expression, "SequenceExpression")) {
9367
- const finalExpression = expression.expressions.at(-1);
9368
- return finalExpression ? hasNonEmptyNativeTitleExpression(finalExpression, scopes) : false;
9369
- }
9370
- if (isNodeOfType(expression, "LogicalExpression")) {
9371
- const leftExpression = stripParenExpression(expression.left);
9372
- if (!isNodeOfType(leftExpression, "Literal")) return expression.operator !== "&&";
9373
- if (expression.operator === "??") return hasNonEmptyNativeTitleExpression(leftExpression.value === null ? expression.right : leftExpression, scopes);
9374
- const leftValueIsTruthy = Boolean(leftExpression.value);
9375
- if (expression.operator === "&&") return hasNonEmptyNativeTitleExpression(leftValueIsTruthy ? expression.right : leftExpression, scopes);
9376
- return hasNonEmptyNativeTitleExpression(leftValueIsTruthy ? leftExpression : expression.right, scopes);
9377
- }
9378
- return true;
9379
- };
9380
- const hasNonEmptyNativeTitle = (attribute, scopes) => {
9381
- if (!attribute?.value) return false;
9382
- if (isNodeOfType(attribute.value, "Literal")) return typeof attribute.value.value === "string" && attribute.value.value.trim().length > 0;
9383
- if (isNodeOfType(attribute.value, "JSXExpressionContainer")) return hasNonEmptyNativeTitleExpression(attribute.value.expression, scopes);
9384
- return true;
9385
- };
9386
8891
  const toAttributeMatchKey = (kind, value) => {
9387
8892
  const trimmedValue = value.trim();
9388
8893
  return trimmedValue.length > 0 ? `${kind}:${trimmedValue}` : null;
@@ -9639,7 +9144,6 @@ const controlHasAssociatedLabel = defineRule({
9639
9144
  if (typeValue === "submit" || typeValue === "reset") return;
9640
9145
  if (typeValue === "button" && hasNonEmptyPropValue(hasJsxPropIgnoreCase(opening.attributes, "value"))) return;
9641
9146
  }
9642
- if (isDomElement && hasNonEmptyNativeTitle(getLastJsxPropIgnoreCase(opening.attributes, TITLE_ATTRIBUTE), context.scopes)) return;
9643
9147
  if (supportsPlaceholderNameFallback(tagName, opening) && hasNonEmptyPropValue(hasJsxPropIgnoreCase(opening.attributes, "placeholder"))) return;
9644
9148
  if (hasLabellingProp(opening.attributes, settings.labelAttributes)) return;
9645
9149
  if (isInsideJsxAttribute(node)) return;
@@ -9659,7 +9163,7 @@ const controlHasAssociatedLabel = defineRule({
9659
9163
  if (candidate.enclosingBindingName !== null && labelEmbeddedNames.has(candidate.enclosingBindingName)) continue;
9660
9164
  context.report({
9661
9165
  node: candidate.opening,
9662
- message: MESSAGE$57
9166
+ message: MESSAGE$56
9663
9167
  });
9664
9168
  }
9665
9169
  }
@@ -10420,7 +9924,7 @@ const noVagueButtonLabel = defineRule({
10420
9924
  });
10421
9925
  //#endregion
10422
9926
  //#region src/plugin/rules/a11y/dialog-has-accessible-name.ts
10423
- const MESSAGE$56 = "This dialog has no accessible name, so screen readers announce it as just “dialog.” Add `aria-label` or point `aria-labelledby` at its heading.";
9927
+ const MESSAGE$55 = "This dialog has no accessible name, so screen readers announce it as just “dialog.” Add `aria-label` or point `aria-labelledby` at its heading.";
10424
9928
  const DIALOG_ROLES = new Set(["dialog", "alertdialog"]);
10425
9929
  const NAME_PROVIDING_ATTRIBUTES = [
10426
9930
  "aria-label",
@@ -10445,7 +9949,7 @@ const dialogHasAccessibleName = defineRule({
10445
9949
  if (NAME_PROVIDING_ATTRIBUTES.some((attribute) => hasJsxPropIgnoreCase(node.attributes, attribute))) return;
10446
9950
  context.report({
10447
9951
  node: node.name,
10448
- message: MESSAGE$56
9952
+ message: MESSAGE$55
10449
9953
  });
10450
9954
  } };
10451
9955
  }
@@ -10485,7 +9989,7 @@ const isEs6Component = (node) => {
10485
9989
  };
10486
9990
  //#endregion
10487
9991
  //#region src/plugin/rules/react-builtins/display-name.ts
10488
- const MESSAGE$55 = "This component shows up as Anonymous in React DevTools because it has no `displayName`.";
9992
+ const MESSAGE$54 = "This component shows up as Anonymous in React DevTools because it has no `displayName`.";
10489
9993
  const DEFAULT_ADDITIONAL_HOCS = [
10490
9994
  "observer",
10491
9995
  "lazy",
@@ -10678,7 +10182,7 @@ const displayName = defineRule({
10678
10182
  const reportAt = (node) => {
10679
10183
  context.report({
10680
10184
  node,
10681
- message: MESSAGE$55
10185
+ message: MESSAGE$54
10682
10186
  });
10683
10187
  };
10684
10188
  return {
@@ -11499,14 +11003,6 @@ const PROMISE_CHAIN_METHOD_NAMES$1 = new Set([
11499
11003
  "catch",
11500
11004
  "finally"
11501
11005
  ]);
11502
- const isPromiseChainCall = (callee) => isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier") && PROMISE_CHAIN_METHOD_NAMES$1.has(callee.property.name) && isNodeOfType(stripParenExpression(callee.object), "CallExpression");
11503
- const getPromiseChainCallForCallback = (candidate) => {
11504
- let callbackContainer = candidate.parent;
11505
- while (callbackContainer && TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(callbackContainer.type)) callbackContainer = callbackContainer.parent;
11506
- if (!isNodeOfType(callbackContainer, "CallExpression")) return null;
11507
- if (!callbackContainer.arguments?.some((argument) => stripParenExpression(argument) === candidate)) return null;
11508
- return isPromiseChainCall(stripParenExpression(callbackContainer.callee)) ? callbackContainer : null;
11509
- };
11510
11006
  const collectEffectInvokedFunctions = (effectCallback) => {
11511
11007
  const invokedFunctions = new Set([effectCallback]);
11512
11008
  const localFunctionBindings = /* @__PURE__ */ new Map();
@@ -11518,6 +11014,7 @@ const collectEffectInvokedFunctions = (effectCallback) => {
11518
11014
  invokedFunctions.add(strippedCandidate);
11519
11015
  pendingFunctions.push(strippedCandidate);
11520
11016
  };
11017
+ const isPromiseChainCall = (callee) => isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier") && PROMISE_CHAIN_METHOD_NAMES$1.has(callee.property.name) && isNodeOfType(stripParenExpression(callee.object), "CallExpression");
11521
11018
  while (pendingFunctions.length > 0) {
11522
11019
  const currentFunction = pendingFunctions.pop();
11523
11020
  if (!currentFunction) break;
@@ -11589,7 +11086,7 @@ const componentOrHookDisplayNameForFunction = (functionNode) => {
11589
11086
  //#endregion
11590
11087
  //#region src/plugin/utils/enclosing-component-or-hook-name.ts
11591
11088
  const enclosingComponentOrHookName = (node) => {
11592
- const functionNode = findEnclosingFunction$1(node);
11089
+ const functionNode = findEnclosingFunction(node);
11593
11090
  return functionNode ? componentOrHookDisplayNameForFunction(functionNode) : null;
11594
11091
  };
11595
11092
  //#endregion
@@ -11646,11 +11143,11 @@ const executesDuringRender = (functionNode, scopes) => {
11646
11143
  //#endregion
11647
11144
  //#region src/plugin/utils/find-render-phase-component-or-hook.ts
11648
11145
  const findRenderPhaseComponentOrHook = (node, scopes) => {
11649
- let functionNode = findEnclosingFunction$1(node);
11146
+ let functionNode = findEnclosingFunction(node);
11650
11147
  while (functionNode) {
11651
11148
  if (componentOrHookDisplayNameForFunction(functionNode)) return functionNode;
11652
11149
  if (!executesDuringRender(functionNode, scopes)) return null;
11653
- functionNode = findEnclosingFunction$1(functionNode);
11150
+ functionNode = findEnclosingFunction(functionNode);
11654
11151
  }
11655
11152
  return null;
11656
11153
  };
@@ -11725,50 +11222,6 @@ const isCleanupReturningSubscribeLikeCallExpression = (node) => {
11725
11222
  return true;
11726
11223
  };
11727
11224
  //#endregion
11728
- //#region src/plugin/utils/is-node-reachable-within-function.ts
11729
- const isInsideStaticallyUnreachableBranch = (node) => {
11730
- let child = node;
11731
- let parent = node.parent;
11732
- while (parent) {
11733
- if (isNodeOfType(parent, "IfStatement") && isNodeOfType(parent.test, "Literal")) {
11734
- if (parent.test.value === false && parent.consequent === child) return true;
11735
- if (parent.test.value === true && parent.alternate === child) return true;
11736
- }
11737
- if (isNodeOfType(parent, "ConditionalExpression") && isNodeOfType(parent.test, "Literal")) {
11738
- if (parent.test.value === false && parent.consequent === child) return true;
11739
- if (parent.test.value === true && parent.alternate === child) return true;
11740
- }
11741
- if (isNodeOfType(parent, "LogicalExpression") && parent.right === child) {
11742
- if (isNodeOfType(parent.left, "Literal") && (parent.operator === "&&" && !parent.left.value || parent.operator === "||" && Boolean(parent.left.value))) return true;
11743
- }
11744
- child = parent;
11745
- parent = parent.parent;
11746
- }
11747
- return false;
11748
- };
11749
- const isNodeReachableWithinFunction = (node, context) => {
11750
- if (isInsideStaticallyUnreachableBranch(node)) return false;
11751
- const owner = context.cfg.enclosingFunction(node);
11752
- if (!owner) return true;
11753
- const functionCfg = context.cfg.cfgFor(owner);
11754
- if (!functionCfg) return true;
11755
- const targetBlock = functionCfg.blockOf(node);
11756
- if (!targetBlock) return true;
11757
- const visitedBlocks = new Set([functionCfg.entry]);
11758
- const pendingBlocks = [functionCfg.entry];
11759
- while (pendingBlocks.length > 0) {
11760
- const currentBlock = pendingBlocks.pop();
11761
- if (!currentBlock) break;
11762
- if (currentBlock === targetBlock) return true;
11763
- for (const edge of currentBlock.successors) {
11764
- if (visitedBlocks.has(edge.to)) continue;
11765
- visitedBlocks.add(edge.to);
11766
- pendingBlocks.push(edge.to);
11767
- }
11768
- }
11769
- return false;
11770
- };
11771
- //#endregion
11772
11225
  //#region src/plugin/rules/state-and-effects/effect-needs-cleanup.ts
11773
11226
  const OBSERVER_REGISTRATION_METHOD_NAME = "observe";
11774
11227
  const CLEANUP_EFFECT_HOOK_NAMES = new Set([...EFFECT_HOOK_NAMES$1, "useInsertionEffect"]);
@@ -11897,15 +11350,36 @@ const findSubscribeLikeUsages = (callback, context) => {
11897
11350
  });
11898
11351
  return usages.filter((usage) => isNodeReachableWithinFunction(usage.node, context));
11899
11352
  };
11353
+ const isNodeReachableWithinFunction = (node, context) => {
11354
+ const owner = context.cfg.enclosingFunction(node);
11355
+ if (!owner) return true;
11356
+ const functionCfg = context.cfg.cfgFor(owner);
11357
+ if (!functionCfg) return true;
11358
+ const targetBlock = functionCfg.blockOf(node);
11359
+ if (!targetBlock) return true;
11360
+ const visitedBlocks = new Set([functionCfg.entry]);
11361
+ const pendingBlocks = [functionCfg.entry];
11362
+ while (pendingBlocks.length > 0) {
11363
+ const currentBlock = pendingBlocks.pop();
11364
+ if (!currentBlock) break;
11365
+ if (currentBlock === targetBlock) return true;
11366
+ for (const edge of currentBlock.successors) {
11367
+ if (visitedBlocks.has(edge.to)) continue;
11368
+ visitedBlocks.add(edge.to);
11369
+ pendingBlocks.push(edge.to);
11370
+ }
11371
+ }
11372
+ return false;
11373
+ };
11900
11374
  const doMatchingNodesCoverEveryPathAfterUsage = (usageNode, matchingNodes, context) => {
11901
11375
  let pathAnchor = usageNode;
11902
- let pathOwner = findEnclosingFunction$1(pathAnchor);
11376
+ let pathOwner = findEnclosingFunction(pathAnchor);
11903
11377
  while (pathOwner && isSynchronousIteratorCallback(pathOwner)) {
11904
11378
  if (matchingNodes.length > 0 && matchingNodes.every((matchingNode) => context.cfg.enclosingFunction(matchingNode) === pathOwner)) break;
11905
11379
  const iteratorCall = pathOwner.parent;
11906
11380
  if (!isNodeOfType(iteratorCall, "CallExpression")) break;
11907
11381
  pathAnchor = iteratorCall;
11908
- pathOwner = findEnclosingFunction$1(pathAnchor);
11382
+ pathOwner = findEnclosingFunction(pathAnchor);
11909
11383
  }
11910
11384
  const owner = context.cfg.enclosingFunction(pathAnchor);
11911
11385
  if (!owner) return false;
@@ -12134,7 +11608,7 @@ const findCollectionMappingCall = (callbackNode) => {
12134
11608
  return callee.property.name === "map" && callNode.arguments?.[0] === callbackNode ? callNode : null;
12135
11609
  };
12136
11610
  const findMappedResourceCollectionKey = (resourceNode, context) => {
12137
- const callbackNode = findEnclosingFunction$1(resourceNode);
11611
+ const callbackNode = findEnclosingFunction(resourceNode);
12138
11612
  if (!callbackNode || !isNodeOfType(callbackNode, "ArrowFunctionExpression") && !isNodeOfType(callbackNode, "FunctionExpression")) return null;
12139
11613
  const mappingCall = findCollectionMappingCall(callbackNode);
12140
11614
  if (!mappingCall) return null;
@@ -12245,10 +11719,10 @@ const findSingleDirectInvocation = (functionNode, caller, context) => {
12245
11719
  });
12246
11720
  if (invocationCalls.length !== 1) return null;
12247
11721
  const invocationCall = invocationCalls[0];
12248
- return findEnclosingFunction$1(invocationCall) === caller && isNodeReachableWithinFunction(invocationCall, context) ? invocationCall : null;
11722
+ return findEnclosingFunction(invocationCall) === caller && isNodeReachableWithinFunction(invocationCall, context) ? invocationCall : null;
12249
11723
  };
12250
11724
  const resolveCleanupPathAnchor = (usageNode, effectCallback, context) => {
12251
- const usageFunction = findEnclosingFunction$1(usageNode);
11725
+ const usageFunction = findEnclosingFunction(usageNode);
12252
11726
  if (!usageFunction || usageFunction === effectCallback) return usageNode;
12253
11727
  return findSingleDirectInvocation(usageFunction, effectCallback, context) ?? usageNode;
12254
11728
  };
@@ -12263,7 +11737,7 @@ const resolveSingleAssignedCleanupFunction = (expression, usage, context) => {
12263
11737
  const assignmentReference = assignmentReferences[0];
12264
11738
  const assignmentTarget = findTransparentExpressionRoot(assignmentReference.identifier);
12265
11739
  const assignmentNode = assignmentTarget.parent;
12266
- if (!isNodeOfType(assignmentNode, "AssignmentExpression") || assignmentNode.operator !== "=" || assignmentNode.left !== assignmentTarget || findEnclosingFunction$1(assignmentNode) !== findEnclosingFunction$1(usage.node) || !doMatchingNodesCoverEveryPathAfterUsage(usage.node, [assignmentNode], context)) return null;
11740
+ if (!isNodeOfType(assignmentNode, "AssignmentExpression") || assignmentNode.operator !== "=" || assignmentNode.left !== assignmentTarget || findEnclosingFunction(assignmentNode) !== findEnclosingFunction(usage.node) || !doMatchingNodesCoverEveryPathAfterUsage(usage.node, [assignmentNode], context)) return null;
12267
11741
  const assignedValue = stripParenExpression(assignmentNode.right);
12268
11742
  return isFunctionLike$2(assignedValue) ? assignedValue : null;
12269
11743
  };
@@ -12352,12 +11826,12 @@ const hasRerunReleaseBeforeUsage = (callback, usage, context) => {
12352
11826
  return doMatchingNodesCoverEveryPathFromFunctionEntry(callback, matchingReleaseAnchors, context);
12353
11827
  };
12354
11828
  const hasStableUnmountCleanupForUsage = (callback, usage, context) => {
12355
- const componentFunction = findEnclosingFunction$1(callback);
11829
+ const componentFunction = findEnclosingFunction(callback);
12356
11830
  if (!componentFunction || !isNodeOfType(componentFunction, "ArrowFunctionExpression") && !isNodeOfType(componentFunction, "FunctionExpression") && !isNodeOfType(componentFunction, "FunctionDeclaration")) return false;
12357
11831
  let didFindUnmountCleanup = false;
12358
11832
  walkAst(componentFunction.body, (child) => {
12359
11833
  if (didFindUnmountCleanup) return false;
12360
- if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction$1(child) !== componentFunction) return;
11834
+ if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction(child) !== componentFunction) return;
12361
11835
  if (!isHookCall$2(child, CLEANUP_EFFECT_HOOK_NAMES)) return;
12362
11836
  const dependencyList = child.arguments?.[1];
12363
11837
  if (!isNodeOfType(dependencyList, "ArrayExpression") || dependencyList.elements.length > 0) return;
@@ -12370,98 +11844,10 @@ const hasStableUnmountCleanupForUsage = (callback, usage, context) => {
12370
11844
  return didFindUnmountCleanup;
12371
11845
  };
12372
11846
  const hasSplitLifecycleCleanup = (callback, usage, context) => usage.handleKey !== null && hasRerunReleaseBeforeUsage(callback, usage, context) && hasStableUnmountCleanupForUsage(callback, usage, context);
12373
- const collectBlockingBooleanStates = (expression, blockedExpressionValue, context) => {
12374
- const unwrappedExpression = stripParenExpression(expression);
12375
- if (isNodeOfType(unwrappedExpression, "UnaryExpression") && unwrappedExpression.operator === "!") return collectBlockingBooleanStates(unwrappedExpression.argument, !blockedExpressionValue, context);
12376
- if (isNodeOfType(unwrappedExpression, "LogicalExpression")) {
12377
- if (!(unwrappedExpression.operator === "||" && blockedExpressionValue || unwrappedExpression.operator === "&&" && !blockedExpressionValue)) return [];
12378
- return [...collectBlockingBooleanStates(unwrappedExpression.left, blockedExpressionValue, context), ...collectBlockingBooleanStates(unwrappedExpression.right, blockedExpressionValue, context)];
12379
- }
12380
- if (isNodeOfType(unwrappedExpression, "BinaryExpression") && [
12381
- "===",
12382
- "==",
12383
- "!==",
12384
- "!="
12385
- ].includes(unwrappedExpression.operator)) {
12386
- const leftValue = readStaticBoolean(unwrappedExpression.left);
12387
- const rightValue = readStaticBoolean(unwrappedExpression.right);
12388
- const booleanValue = leftValue ?? rightValue;
12389
- const comparedKey = resolveExpressionKey(leftValue === null ? unwrappedExpression.left : unwrappedExpression.right, context);
12390
- if (booleanValue === null || comparedKey === null) return [];
12391
- return [{
12392
- key: comparedKey,
12393
- value: (unwrappedExpression.operator === "===" || unwrappedExpression.operator === "==") === blockedExpressionValue ? booleanValue : !booleanValue
12394
- }];
12395
- }
12396
- const expressionKey = resolveExpressionKey(unwrappedExpression, context);
12397
- return expressionKey === null ? [] : [{
12398
- key: expressionKey,
12399
- value: blockedExpressionValue
12400
- }];
12401
- };
12402
- const isDirectEarlyReturnConsequent = (ifStatement) => {
12403
- if (!isNodeOfType(ifStatement, "IfStatement") || ifStatement.alternate) return false;
12404
- if (isNodeOfType(ifStatement.consequent, "ReturnStatement")) return true;
12405
- return isNodeOfType(ifStatement.consequent, "BlockStatement") && ifStatement.consequent.body.length === 1 && isNodeOfType(ifStatement.consequent.body[0], "ReturnStatement");
12406
- };
12407
- const collectDeferredUsageGuardStates = (callback, usageNode, context) => {
12408
- if (!isFunctionLike$2(callback) || callback.async) return [];
12409
- const guardStates = [];
12410
- walkAst(callback.body, (child) => {
12411
- if (child !== callback.body && isFunctionLike$2(child)) return false;
12412
- if (isNodeOfType(child, "IfStatement") && isDirectEarlyReturnConsequent(child) && doMatchingNodesCoverEveryPathBeforeUsage(usageNode, [child], callback, context)) guardStates.push(...collectBlockingBooleanStates(child.test, true, context));
12413
- });
12414
- let descendant = usageNode;
12415
- let ancestor = descendant.parent;
12416
- while (ancestor && ancestor !== callback) {
12417
- if (isNodeOfType(ancestor, "IfStatement") && ancestor.consequent === descendant) guardStates.push(...collectBlockingBooleanStates(ancestor.test, false, context));
12418
- descendant = ancestor;
12419
- ancestor = ancestor.parent;
12420
- }
12421
- return guardStates;
12422
- };
12423
- const cleanupReturnInvalidatesGuard = (cleanupReturn, guardState, context) => {
12424
- if (!isNodeOfType(cleanupReturn, "ReturnStatement") || !cleanupReturn.argument) return false;
12425
- const cleanupFunction = resolveStableValue(cleanupReturn.argument, context);
12426
- if (!cleanupFunction || !isFunctionLike$2(cleanupFunction) || cleanupFunction.async) return false;
12427
- let didInvalidateGuard = false;
12428
- walkAst(cleanupFunction.body, (child) => {
12429
- if (didInvalidateGuard) return false;
12430
- if (child !== cleanupFunction.body && isFunctionLike$2(child)) return false;
12431
- if (isNodeOfType(child, "AssignmentExpression") && child.operator === "=" && resolveExpressionKey(child.left, context) === guardState.key && readStaticBoolean(child.right) === guardState.value && context.cfg.isUnconditionalFromEntry(child)) {
12432
- didInvalidateGuard = true;
12433
- return false;
12434
- }
12435
- });
12436
- return didInvalidateGuard;
12437
- };
12438
- const deferredUsageWritesGuardBeforeUsage = (callback, usageNode, guardState, context) => {
12439
- const usageStart = getRangeStart(usageNode);
12440
- if (!isFunctionLike$2(callback) || usageStart === null) return true;
12441
- let didWriteGuard = false;
12442
- walkAst(callback.body, (child) => {
12443
- if (didWriteGuard) return false;
12444
- if (child !== callback.body && isFunctionLike$2(child)) return false;
12445
- const childStart = getRangeStart(child);
12446
- if (childStart === null || childStart >= usageStart) return;
12447
- const writtenExpression = isNodeOfType(child, "AssignmentExpression") ? child.left : isNodeOfType(child, "UpdateExpression") ? child.argument : null;
12448
- if (writtenExpression && resolveExpressionKey(writtenExpression, context) === guardState.key) {
12449
- didWriteGuard = true;
12450
- return false;
12451
- }
12452
- });
12453
- return didWriteGuard;
12454
- };
12455
- const hasGuardedDeferredCleanup = (callback, usage, cleanupReturns, context) => {
12456
- const usageFunction = findEnclosingFunction$1(usage.node);
12457
- const promiseChainCall = usageFunction ? getPromiseChainCallForCallback(usageFunction) : null;
12458
- if (usage.handleKey === null || !usageFunction || usageFunction === callback || !promiseChainCall || !collectEffectInvokedFunctions(callback).has(usageFunction) || !doMatchingNodesCoverEveryPathAfterUsage(promiseChainCall, cleanupReturns, context)) return false;
12459
- return collectDeferredUsageGuardStates(usageFunction, usage.node, context).some((guardState) => !deferredUsageWritesGuardBeforeUsage(usageFunction, usage.node, guardState, context) && cleanupReturns.every((cleanupReturn) => cleanupReturnInvalidatesGuard(cleanupReturn, guardState, context)));
12460
- };
12461
11847
  const effectHasCleanupForUsage = (callback, usage, context) => {
12462
11848
  if (!isNodeOfType(callback, "ArrowFunctionExpression") && !isNodeOfType(callback, "FunctionExpression")) return false;
12463
11849
  if (callback.async) return false;
12464
- if (usage.kind === "subscribe" && findEnclosingFunction$1(usage.node) === callback && doesResourceResultEscape(usage.node, true) && isCleanupReturningSubscribeLikeCallExpression(usage.node)) return true;
11850
+ if (usage.kind === "subscribe" && findEnclosingFunction(usage.node) === callback && doesResourceResultEscape(usage.node, true) && isCleanupReturningSubscribeLikeCallExpression(usage.node)) return true;
12465
11851
  if (!isNodeOfType(callback.body, "BlockStatement")) return callback.body === usage.node && isCleanupReturningSubscribeLikeCallExpression(callback.body);
12466
11852
  const matchingCleanupReturns = [];
12467
11853
  walkInsideStatementBlocks(callback.body, (child) => {
@@ -12497,7 +11883,6 @@ const effectHasCleanupForUsage = (callback, usage, context) => {
12497
11883
  if (!cleanupFunction || !isFunctionLike$2(cleanupFunction)) return;
12498
11884
  if (doesCleanupFunctionReleaseUsage(cleanupFunction, usage, context)) matchingCleanupReturns.push(child);
12499
11885
  });
12500
- if (hasGuardedDeferredCleanup(callback, usage, matchingCleanupReturns, context)) return true;
12501
11886
  return doMatchingNodesCoverEveryPathAfterUsage(resolveCleanupPathAnchor(usage.node, callback, context), matchingCleanupReturns, context);
12502
11887
  };
12503
11888
  const findFirstUsageWithoutCleanup = (callback, usages, context) => {
@@ -12630,7 +12015,7 @@ const isReturnedEffectCleanupFunction = (functionNode) => {
12630
12015
  parentNode = currentNode.parent;
12631
12016
  }
12632
12017
  if (!isNodeOfType(parentNode, "ReturnStatement") || parentNode.argument !== currentNode) return false;
12633
- const effectCallback = findEnclosingFunction$1(parentNode);
12018
+ const effectCallback = findEnclosingFunction(parentNode);
12634
12019
  const effectCall = effectCallback?.parent;
12635
12020
  return Boolean(effectCallback && isNodeOfType(effectCall, "CallExpression") && isHookCall$2(effectCall, CLEANUP_EFFECT_HOOK_NAMES));
12636
12021
  };
@@ -12640,13 +12025,13 @@ const isPotentiallyReachableFunction = (functionNode, context) => {
12640
12025
  if (!bindingIdentifier) return false;
12641
12026
  const symbol = context.scopes.symbolFor(bindingIdentifier);
12642
12027
  if (!symbol) return false;
12643
- return symbol.references.some((reference) => findEnclosingFunction$1(reference.identifier) !== functionNode);
12028
+ return symbol.references.some((reference) => findEnclosingFunction(reference.identifier) !== functionNode);
12644
12029
  };
12645
12030
  const isReleaseReachableForUsage = (releaseNode, usage, context) => {
12646
12031
  if (!isNodeReachableWithinFunction(releaseNode, context)) return false;
12647
- const releaseFunction = findEnclosingFunction$1(releaseNode);
12032
+ const releaseFunction = findEnclosingFunction(releaseNode);
12648
12033
  if (!releaseFunction) return true;
12649
- if (releaseFunction === findEnclosingFunction$1(usage.node)) return true;
12034
+ if (releaseFunction === findEnclosingFunction(usage.node)) return true;
12650
12035
  return isPotentiallyReachableFunction(releaseFunction, context);
12651
12036
  };
12652
12037
  const fileContainsReleaseForUsage = (usage, context) => {
@@ -12829,10 +12214,10 @@ const cleanupFunctionReleasesRefOwnedUsage = (cleanupFunction, componentFunction
12829
12214
  }
12830
12215
  if (assignedKey !== storage.refCurrentKey) return;
12831
12216
  const assignedValue = stripParenExpression(child.right);
12832
- if (isNodeOfType(assignedValue, "Literal") && assignedValue.value === null && findEnclosingFunction$1(child) === cleanupFunction) return;
12217
+ if (isNodeOfType(assignedValue, "Literal") && assignedValue.value === null && findEnclosingFunction(child) === cleanupFunction) return;
12833
12218
  const assignedSessionProperties = (isNodeOfType(assignedValue, "ObjectExpression") ? assignedValue : null)?.properties ?? [];
12834
12219
  const storesMatchingHandler = assignedSessionProperties.every((property) => isNodeOfType(property, "Property")) && assignedSessionProperties.some((property) => isNodeOfType(property, "Property") && `${storage.refCurrentKey}.${getStaticPropertyKeyName(property) ?? ""}` === storage.handlerKey && resolveExpressionKey(property.value, context) === usage.handlerKey);
12835
- if (findEnclosingFunction$1(child) !== retainedFunction || !storesMatchingHandler) {
12220
+ if (findEnclosingFunction(child) !== retainedFunction || !storesMatchingHandler) {
12836
12221
  hasUnsafeRefWrite = true;
12837
12222
  return false;
12838
12223
  }
@@ -12853,12 +12238,12 @@ const effectReturnsRefOwnedCleanup = (effectCallback, componentFunction, retaine
12853
12238
  return doMatchingNodesCoverEveryPathFromFunctionEntry(effectCallback, matchingReturns, context);
12854
12239
  };
12855
12240
  const hasGuaranteedRefOwnedUnmountCleanup = (retainedFunction, usage, context) => {
12856
- const componentFunction = findEnclosingFunction$1(retainedFunction);
12241
+ const componentFunction = findEnclosingFunction(retainedFunction);
12857
12242
  if (!componentFunction || !isFunctionLike$2(componentFunction)) return false;
12858
12243
  let didFindCleanupEffect = false;
12859
12244
  walkAst(componentFunction.body, (child) => {
12860
12245
  if (didFindCleanupEffect) return false;
12861
- if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction$1(child) !== componentFunction || !isReactApiCall(child, "useEffect", context.scopes)) return;
12246
+ if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction(child) !== componentFunction || !isReactApiCall(child, "useEffect", context.scopes)) return;
12862
12247
  const effectStatement = findTransparentExpressionRoot(child).parent;
12863
12248
  if (!isNodeOfType(effectStatement, "ExpressionStatement") || effectStatement.parent !== componentFunction.body) return;
12864
12249
  const effectCallback = getEffectCallback(child);
@@ -13712,202 +13097,6 @@ const resolveExhaustiveDepsSettings = (settings) => {
13712
13097
  };
13713
13098
  };
13714
13099
  //#endregion
13715
- //#region src/plugin/utils/is-ast-descendant.ts
13716
- /**
13717
- * True when `inner` is `outer` itself or any descendant in the AST
13718
- * `parent` chain. Walks `inner.parent` upward and stops at either a
13719
- * match (`true`) or the chain's root (`false`).
13720
- *
13721
- * Was duplicated byte-identical in:
13722
- * - exhaustive-deps-symbol-stability.ts
13723
- * - semantic/closure-captures.ts
13724
- */
13725
- const isAstDescendant = (inner, outer) => {
13726
- let current = inner;
13727
- while (current) {
13728
- if (current === outer) return true;
13729
- current = current.parent ?? null;
13730
- }
13731
- return false;
13732
- };
13733
- //#endregion
13734
- //#region src/plugin/rules/react-builtins/exhaustive-deps-sole-writer-guard.ts
13735
- const EQUALITY_BINARY_OPERATORS = new Set(["===", "!=="]);
13736
- const getUseStateSetterSymbol = (stateSymbol, scopes) => {
13737
- const declaration = stateSymbol.declarationNode;
13738
- if (!isNodeOfType(declaration, "VariableDeclarator")) return null;
13739
- if (!isNodeOfType(declaration.id, "ArrayPattern")) return null;
13740
- const stateBinding = declaration.id.elements[0];
13741
- const setterBinding = declaration.id.elements[1];
13742
- if (stateBinding !== stateSymbol.bindingIdentifier || !isNodeOfType(setterBinding, "Identifier")) return null;
13743
- const initializer = declaration.init ? stripParenExpression(declaration.init) : null;
13744
- if (!initializer || !isReactApiCall(initializer, "useState", scopes, {
13745
- allowGlobalReactNamespace: true,
13746
- allowUnboundBareCalls: true,
13747
- resolveNamedAliases: true
13748
- })) return null;
13749
- return scopes.symbolFor(setterBinding);
13750
- };
13751
- const getDirectSetterCall = (setterSymbol, callback) => {
13752
- if (setterSymbol.references.length !== 1) return null;
13753
- const setterReference = setterSymbol.references[0];
13754
- if (setterReference.flag !== "read") return null;
13755
- const referenceRoot = findTransparentExpressionRoot(setterReference.identifier);
13756
- const callExpression = referenceRoot.parent;
13757
- if (!isNodeOfType(callExpression, "CallExpression") || callExpression.callee !== referenceRoot || callExpression.arguments.length !== 1 || findEnclosingFunction$1(callExpression) !== callback) return null;
13758
- const writtenValue = stripParenExpression(callExpression.arguments[0]);
13759
- if (isNodeOfType(writtenValue, "ArrowFunctionExpression") || isNodeOfType(writtenValue, "FunctionExpression") || isNodeOfType(writtenValue, "SpreadElement")) return null;
13760
- return {
13761
- callExpression,
13762
- writtenValue
13763
- };
13764
- };
13765
- const isGlobalObjectIsCall = (callExpression, scopes) => {
13766
- if (!isNodeOfType(callExpression, "CallExpression")) return false;
13767
- const callee = stripParenExpression(callExpression.callee);
13768
- if (!isNodeOfType(callee, "MemberExpression")) return false;
13769
- const propertyName = getStaticPropertyName(callee);
13770
- const receiver = stripParenExpression(callee.object);
13771
- return Boolean(propertyName === "is" && isNodeOfType(receiver, "Identifier") && receiver.name === "Object" && scopes.isGlobalReference(receiver));
13772
- };
13773
- const isGlobalNaNReference = (expression, scopes) => {
13774
- const unwrappedExpression = stripParenExpression(expression);
13775
- return isNodeOfType(unwrappedExpression, "Identifier") && unwrappedExpression.name === "NaN" && scopes.isGlobalReference(unwrappedExpression);
13776
- };
13777
- const getEqualityComparison = (stateReference, candidate, scopes) => {
13778
- const unwrappedStateReference = stripParenExpression(stateReference);
13779
- if (isNodeOfType(candidate, "BinaryExpression") && EQUALITY_BINARY_OPERATORS.has(candidate.operator)) {
13780
- if (stripParenExpression(candidate.left) === unwrappedStateReference) return isGlobalNaNReference(candidate.right, scopes) ? null : {
13781
- comparison: candidate,
13782
- counterpart: candidate.right,
13783
- areValuesEqualWhenTruthy: candidate.operator === "==="
13784
- };
13785
- if (stripParenExpression(candidate.right) === unwrappedStateReference) return isGlobalNaNReference(candidate.left, scopes) ? null : {
13786
- comparison: candidate,
13787
- counterpart: candidate.left,
13788
- areValuesEqualWhenTruthy: candidate.operator === "==="
13789
- };
13790
- return null;
13791
- }
13792
- if (!isNodeOfType(candidate, "CallExpression") || !isGlobalObjectIsCall(candidate, scopes) || candidate.arguments.length !== 2) return null;
13793
- const firstArgument = candidate.arguments[0];
13794
- const secondArgument = candidate.arguments[1];
13795
- if (isNodeOfType(firstArgument, "SpreadElement") || isNodeOfType(secondArgument, "SpreadElement")) return null;
13796
- if (stripParenExpression(firstArgument) === unwrappedStateReference) return {
13797
- comparison: candidate,
13798
- counterpart: secondArgument,
13799
- areValuesEqualWhenTruthy: true
13800
- };
13801
- if (stripParenExpression(secondArgument) === unwrappedStateReference) return {
13802
- comparison: candidate,
13803
- counterpart: firstArgument,
13804
- areValuesEqualWhenTruthy: true
13805
- };
13806
- return null;
13807
- };
13808
- const findEqualityComparison = (stateReference, test, scopes) => {
13809
- let current = stateReference.parent;
13810
- while (current && isAstDescendant(current, test)) {
13811
- const comparison = getEqualityComparison(stateReference, current, scopes);
13812
- if (comparison) return comparison;
13813
- if (current === test) break;
13814
- current = current.parent;
13815
- }
13816
- return null;
13817
- };
13818
- const doesTestOutcomeRequireComparisonOutcome = (comparison, test, testOutcome, comparisonOutcome) => {
13819
- let requiredChildOutcome = testOutcome;
13820
- let current = comparison;
13821
- while (current !== test) {
13822
- const parent = current.parent;
13823
- if (!parent || !isAstDescendant(parent, test)) return false;
13824
- if (isNodeOfType(parent, "UnaryExpression") && parent.operator === "!") requiredChildOutcome = !requiredChildOutcome;
13825
- else if (isNodeOfType(parent, "LogicalExpression")) {
13826
- if (parent.operator === "&&" && !requiredChildOutcome) return false;
13827
- if (parent.operator === "||" && requiredChildOutcome) return false;
13828
- if (parent.operator !== "&&" && parent.operator !== "||") return false;
13829
- } else if (!TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(parent.type)) return false;
13830
- current = parent;
13831
- }
13832
- return requiredChildOutcome === comparisonOutcome;
13833
- };
13834
- const resolveImmutableAliasExpression = (expression, scopes) => {
13835
- const visitedSymbolIds = /* @__PURE__ */ new Set();
13836
- let current = stripParenExpression(expression);
13837
- while (isNodeOfType(current, "Identifier")) {
13838
- const symbol = scopes.symbolFor(current);
13839
- if (!symbol || visitedSymbolIds.has(symbol.id)) break;
13840
- const initializer = getDirectConstInitializer(symbol);
13841
- if (!initializer || !isNodeOfType(stripParenExpression(initializer), "Identifier")) break;
13842
- visitedSymbolIds.add(symbol.id);
13843
- current = stripParenExpression(initializer);
13844
- }
13845
- return current;
13846
- };
13847
- const referencesSameValue = (leftExpression, rightExpression, scopes) => {
13848
- const left = resolveImmutableAliasExpression(leftExpression, scopes);
13849
- const right = resolveImmutableAliasExpression(rightExpression, scopes);
13850
- if (left === right) return true;
13851
- if (isNodeOfType(left, "Identifier") && isNodeOfType(right, "Identifier")) {
13852
- const leftSymbol = scopes.symbolFor(left);
13853
- const rightSymbol = scopes.symbolFor(right);
13854
- if (leftSymbol || rightSymbol) return leftSymbol?.id === rightSymbol?.id;
13855
- return left.name === right.name;
13856
- }
13857
- if (isNodeOfType(left, "Literal") && isNodeOfType(right, "Literal")) return Object.is(left.value, right.value);
13858
- return false;
13859
- };
13860
- const hasDeclaredTriggerDependency = (callback) => {
13861
- const hookCall = findTransparentExpressionRoot(callback).parent;
13862
- if (!isNodeOfType(hookCall, "CallExpression")) return false;
13863
- const dependencyArray = hookCall.arguments[1];
13864
- return Boolean(isNodeOfType(dependencyArray, "ArrayExpression") && dependencyArray.elements.length);
13865
- };
13866
- const doesBranchExitEffect = (branch) => {
13867
- if (isNodeOfType(branch, "ReturnStatement") || isNodeOfType(branch, "ThrowStatement")) return true;
13868
- if (!isNodeOfType(branch, "BlockStatement")) return false;
13869
- const terminalStatement = branch.body.at(-1);
13870
- return Boolean(terminalStatement && doesBranchExitEffect(terminalStatement));
13871
- };
13872
- const doesGuardDominateLaterSetter = (guard, setterCall) => {
13873
- if (!isNodeOfType(guard, "IfStatement") || guard.alternate) return false;
13874
- if (!doesBranchExitEffect(guard.consequent)) return false;
13875
- const block = guard.parent;
13876
- if (!isNodeOfType(block, "BlockStatement")) return false;
13877
- const guardIndex = block.body.findIndex((statement) => statement === guard);
13878
- return block.body.some((statement, statementIndex) => statementIndex > guardIndex && isAstDescendant(setterCall, statement));
13879
- };
13880
- const findDominatingGuardCounterpart = (stateReference, setterCall, callback, scopes) => {
13881
- let current = stateReference.parent;
13882
- while (current && current !== callback) {
13883
- if (isNodeOfType(current, "IfStatement") && isAstDescendant(stateReference, current.test) && (isAstDescendant(setterCall, current.consequent) || Boolean(current.alternate && isAstDescendant(setterCall, current.alternate)) || doesGuardDominateLaterSetter(current, setterCall))) {
13884
- const setterRunsWhenTestTruthy = isAstDescendant(setterCall, current.consequent);
13885
- if (setterRunsWhenTestTruthy === (Boolean(current.alternate && isAstDescendant(setterCall, current.alternate)) || doesGuardDominateLaterSetter(current, setterCall))) return null;
13886
- const equalityComparison = findEqualityComparison(stateReference, current.test, scopes);
13887
- if (!equalityComparison) return null;
13888
- const comparisonOutcomeForDifferentValues = !equalityComparison.areValuesEqualWhenTruthy;
13889
- if (!doesTestOutcomeRequireComparisonOutcome(equalityComparison.comparison, current.test, setterRunsWhenTestTruthy, comparisonOutcomeForDifferentValues)) return null;
13890
- return equalityComparison.counterpart;
13891
- }
13892
- current = current.parent;
13893
- }
13894
- return null;
13895
- };
13896
- const isSoleWriterEffectGuardCapture = (stateSymbol, callback, scopes) => {
13897
- if (!hasDeclaredTriggerDependency(callback)) return false;
13898
- if (stateSymbol.references.some((reference) => reference.flag !== "read")) return false;
13899
- const setterSymbol = getUseStateSetterSymbol(stateSymbol, scopes);
13900
- if (!setterSymbol) return false;
13901
- const setterWrite = getDirectSetterCall(setterSymbol, callback);
13902
- if (!setterWrite) return false;
13903
- const callbackStateReferences = stateSymbol.references.filter((reference) => isAstDescendant(reference.identifier, callback));
13904
- if (callbackStateReferences.length !== 1) return false;
13905
- const stateReferenceRoot = findTransparentExpressionRoot(callbackStateReferences[0].identifier);
13906
- if (isNodeOfType(stateReferenceRoot.parent, "MemberExpression") && stateReferenceRoot.parent.object === stateReferenceRoot) return false;
13907
- const counterpart = findDominatingGuardCounterpart(callbackStateReferences[0].identifier, setterWrite.callExpression, callback, scopes);
13908
- return Boolean(counterpart && referencesSameValue(counterpart, setterWrite.writtenValue, scopes));
13909
- };
13910
- //#endregion
13911
13100
  //#region src/plugin/rules/react-builtins/exhaustive-deps-suppression.ts
13912
13101
  const DISABLE_COMMENT_RULE_NAME_PATTERN$1 = /(?:^|[\s,/])exhaustive-deps(?:$|[\s,:])/;
13913
13102
  const DISABLE_NEXT_LINE_PATTERN$1 = /\b(?:eslint|oxlint)-disable-next-line\b([^\n]*)/;
@@ -13979,6 +13168,25 @@ const isExhaustiveDepsSuppressedAt = (filename, nodeStartOffset) => {
13979
13168
  return index.suppressedLines.has(lineForOffset$1(nodeStartOffset, index.utf16NewlineOffsets)) || index.suppressedLines.has(lineForOffset$1(nodeStartOffset, index.utf8NewlineOffsets));
13980
13169
  };
13981
13170
  //#endregion
13171
+ //#region src/plugin/utils/is-ast-descendant.ts
13172
+ /**
13173
+ * True when `inner` is `outer` itself or any descendant in the AST
13174
+ * `parent` chain. Walks `inner.parent` upward and stops at either a
13175
+ * match (`true`) or the chain's root (`false`).
13176
+ *
13177
+ * Was duplicated byte-identical in:
13178
+ * - exhaustive-deps-symbol-stability.ts
13179
+ * - semantic/closure-captures.ts
13180
+ */
13181
+ const isAstDescendant = (inner, outer) => {
13182
+ let current = inner;
13183
+ while (current) {
13184
+ if (current === outer) return true;
13185
+ current = current.parent ?? null;
13186
+ }
13187
+ return false;
13188
+ };
13189
+ //#endregion
13982
13190
  //#region src/plugin/rules/react-builtins/exhaustive-deps-symbol-stability.ts
13983
13191
  /**
13984
13192
  * Symbol-stability helpers consumed by the `exhaustive-deps` rule.
@@ -14159,7 +13367,6 @@ const EFFECT_HOOKS_ALLOWING_EXTRA_REACTIVE_DEPS = new Set([
14159
13367
  "useLayoutEffect",
14160
13368
  "useInsertionEffect"
14161
13369
  ]);
14162
- const SOLE_WRITER_GUARD_HOOKS = new Set(["useEffect", "useLayoutEffect"]);
14163
13370
  const buildAdditionalHooksRegex = (additional) => {
14164
13371
  if (!additional) return null;
14165
13372
  try {
@@ -14296,7 +13503,7 @@ const stringifyMemberChain = (node) => {
14296
13503
  }
14297
13504
  return null;
14298
13505
  };
14299
- const collectCaptureDepKeys = (callback, scopes, declaredExactBindingKeys, allowSoleWriterEffectGuards = false) => {
13506
+ const collectCaptureDepKeys = (callback, scopes, declaredExactBindingKeys) => {
14300
13507
  const keys = /* @__PURE__ */ new Set();
14301
13508
  const stableCapturedNames = /* @__PURE__ */ new Set();
14302
13509
  const moduleScopeCapturedNames = /* @__PURE__ */ new Set();
@@ -14307,10 +13514,6 @@ const collectCaptureDepKeys = (callback, scopes, declaredExactBindingKeys, allow
14307
13514
  const symbol = reference.resolvedSymbol;
14308
13515
  if (!symbol) continue;
14309
13516
  if (isRecursiveInitializerCapture(symbol, callback)) continue;
14310
- if (allowSoleWriterEffectGuards && isSoleWriterEffectGuardCapture(symbol, callback, scopes)) {
14311
- stableCapturedNames.add(symbol.name);
14312
- continue;
14313
- }
14314
13517
  if (symbolHasStableValue(symbol, scopes)) {
14315
13518
  stableCapturedNames.add(symbol.name);
14316
13519
  continue;
@@ -14983,7 +14186,7 @@ If the missing value is recreated every render, move it inside the hook or stabi
14983
14186
  if (isNodeOfType(stripped, "Identifier")) declaredExactBindingKeys.add(key);
14984
14187
  declaredKeyToReportNode.set(key, elementNode);
14985
14188
  }
14986
- const { keys: captureKeys, stableCapturedNames, moduleScopeCapturedNames, outerFunctionCapturedNames } = collectCaptureDepKeys(callbackToAnalyze ?? callbackArgument, context.scopes, declaredExactBindingKeys, SOLE_WRITER_GUARD_HOOKS.has(hookName));
14189
+ const { keys: captureKeys, stableCapturedNames, moduleScopeCapturedNames, outerFunctionCapturedNames } = collectCaptureDepKeys(callbackToAnalyze ?? callbackArgument, context.scopes, declaredExactBindingKeys);
14987
14190
  for (const forcedCaptureKey of forcedCaptureKeys) captureKeys.add(forcedCaptureKey);
14988
14191
  addAggregatePropsDependency(captureKeys, declaredKeys, callbackToAnalyze ?? callbackArgument, context.scopes);
14989
14192
  const missingCaptureKeys = [];
@@ -15423,7 +14626,7 @@ const forbidElements = defineRule({
15423
14626
  });
15424
14627
  //#endregion
15425
14628
  //#region src/plugin/rules/react-builtins/forward-ref-uses-ref.ts
15426
- const MESSAGE$54 = "The parent can't reach this component's node because the `forwardRef` wrapper ignores `ref`.";
14629
+ const MESSAGE$53 = "The parent can't reach this component's node because the `forwardRef` wrapper ignores `ref`.";
15427
14630
  const forwardRefUsesRef = defineRule({
15428
14631
  id: "forward-ref-uses-ref",
15429
14632
  title: "forwardRef without ref parameter",
@@ -15446,7 +14649,7 @@ const forwardRefUsesRef = defineRule({
15446
14649
  if (isNodeOfType(onlyParam, "RestElement")) return;
15447
14650
  context.report({
15448
14651
  node: inner,
15449
- message: MESSAGE$54
14652
+ message: MESSAGE$53
15450
14653
  });
15451
14654
  } })
15452
14655
  });
@@ -15487,7 +14690,7 @@ const gitProviderUrlInjectionRisk = defineRule({
15487
14690
  });
15488
14691
  //#endregion
15489
14692
  //#region src/plugin/rules/a11y/heading-has-content.ts
15490
- const MESSAGE$53 = "Blind users can't use this heading to navigate because screen readers skip it empty, so add text, `aria-label`, or `aria-labelledby`.";
14693
+ const MESSAGE$52 = "Blind users can't use this heading to navigate because screen readers skip it empty, so add text, `aria-label`, or `aria-labelledby`.";
15491
14694
  const DEFAULT_HEADING_TAGS = [
15492
14695
  "h1",
15493
14696
  "h2",
@@ -15521,7 +14724,7 @@ const headingHasContent = defineRule({
15521
14724
  for (const attribute of ["aria-label", "aria-labelledby"]) if (hasJsxPropIgnoreCase(node.attributes, attribute)) return;
15522
14725
  context.report({
15523
14726
  node,
15524
- message: MESSAGE$53
14727
+ message: MESSAGE$52
15525
14728
  });
15526
14729
  } };
15527
14730
  }
@@ -15685,7 +14888,7 @@ const hooksNoNanInDeps = defineRule({
15685
14888
  });
15686
14889
  //#endregion
15687
14890
  //#region src/plugin/rules/a11y/html-has-lang.ts
15688
- const MESSAGE$52 = "Screen readers may mispronounce this page because it doesn't declare a language, so add a `lang` attribute like `en`.";
14891
+ const MESSAGE$51 = "Screen readers may mispronounce this page because it doesn't declare a language, so add a `lang` attribute like `en`.";
15689
14892
  const resolveSettings$39 = (settings) => {
15690
14893
  const reactDoctor = settings?.["react-doctor"];
15691
14894
  return { htmlTags: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.htmlHasLang ?? {} : {}).htmlTags ?? ["html"] };
@@ -15732,13 +14935,13 @@ const htmlHasLang = defineRule({
15732
14935
  if (!lang) {
15733
14936
  context.report({
15734
14937
  node: node.name,
15735
- message: MESSAGE$52
14938
+ message: MESSAGE$51
15736
14939
  });
15737
14940
  return;
15738
14941
  }
15739
14942
  if (evaluateLang(lang.value) === "empty") context.report({
15740
14943
  node: lang,
15741
- message: MESSAGE$52
14944
+ message: MESSAGE$51
15742
14945
  });
15743
14946
  } };
15744
14947
  }
@@ -15978,7 +15181,7 @@ const htmlNoNestedInteractive = defineRule({
15978
15181
  });
15979
15182
  //#endregion
15980
15183
  //#region src/plugin/rules/a11y/iframe-has-title.ts
15981
- const MESSAGE$51 = "Screen reader users cannot identify this `<iframe>` because it has no title. Add a `title` that describes its content.";
15184
+ const MESSAGE$50 = "Screen reader users cannot identify this `<iframe>` because it has no title. Add a `title` that describes its content.";
15982
15185
  const evaluateTitleValue = (value) => {
15983
15186
  if (!value) return "missing";
15984
15187
  if (isNodeOfType(value, "Literal")) {
@@ -16018,14 +15221,14 @@ const iframeHasTitle = defineRule({
16018
15221
  if (!titleAttr) {
16019
15222
  if (hasSpread || tag === "iframe") context.report({
16020
15223
  node: node.name,
16021
- message: MESSAGE$51
15224
+ message: MESSAGE$50
16022
15225
  });
16023
15226
  return;
16024
15227
  }
16025
15228
  const verdict = evaluateTitleValue(titleAttr.value);
16026
15229
  if (verdict === "missing" || verdict === "empty") context.report({
16027
15230
  node: titleAttr,
16028
- message: MESSAGE$51
15231
+ message: MESSAGE$50
16029
15232
  });
16030
15233
  } })
16031
15234
  });
@@ -16150,7 +15353,7 @@ const iframeMissingSandbox = defineRule({
16150
15353
  });
16151
15354
  //#endregion
16152
15355
  //#region src/plugin/rules/a11y/img-redundant-alt.ts
16153
- const MESSAGE$50 = "Screen reader users hear \"image\" or \"photo\" twice because they already announce it, so describe what the image shows instead.";
15356
+ const MESSAGE$49 = "Screen reader users hear \"image\" or \"photo\" twice because they already announce it, so describe what the image shows instead.";
16154
15357
  const DEFAULT_COMPONENTS = ["img"];
16155
15358
  const DEFAULT_REDUNDANT_WORDS = [
16156
15359
  "image",
@@ -16215,7 +15418,7 @@ const imgRedundantAlt = defineRule({
16215
15418
  if (!altAttribute) return;
16216
15419
  if (altValueRedundant(altAttribute, settings.words)) context.report({
16217
15420
  node: altAttribute,
16218
- message: MESSAGE$50
15421
+ message: MESSAGE$49
16219
15422
  });
16220
15423
  } };
16221
15424
  }
@@ -16797,14 +16000,14 @@ const isBindingInvokedOnRenderPath = (root, bindingName) => {
16797
16000
  if (didFindRenderPathInvocation) return false;
16798
16001
  if (!isNodeOfType(node, "CallExpression")) return;
16799
16002
  if (!isNodeOfType(node.callee, "Identifier") || node.callee.name !== bindingName) return;
16800
- let enclosingFunction = findEnclosingFunction$1(node);
16003
+ let enclosingFunction = findEnclosingFunction(node);
16801
16004
  while (enclosingFunction) {
16802
16005
  if (isDeferredCallbackPosition$1(enclosingFunction) || getHandlerNamedBindingName(enclosingFunction)) return;
16803
16006
  if (containingFunctionIsComponentOrHook(enclosingFunction)) {
16804
16007
  didFindRenderPathInvocation = true;
16805
16008
  return;
16806
16009
  }
16807
- enclosingFunction = findEnclosingFunction$1(enclosingFunction);
16010
+ enclosingFunction = findEnclosingFunction(enclosingFunction);
16808
16011
  }
16809
16012
  });
16810
16013
  return didFindRenderPathInvocation;
@@ -16839,7 +16042,7 @@ const jotaiSelectAtomInRenderBody = defineRule({
16839
16042
  };
16840
16043
  return { CallExpression(node) {
16841
16044
  if (!isImportedSelectAtom(node)) return;
16842
- const nearestFunctionLike = findEnclosingFunction$1(node);
16045
+ const nearestFunctionLike = findEnclosingFunction(node);
16843
16046
  if (!nearestFunctionLike) return;
16844
16047
  if (isDeferredCallback(nearestFunctionLike)) return;
16845
16048
  if (isBindingUsedAsHandler(nearestFunctionLike)) return;
@@ -17836,7 +17039,7 @@ const isPersistentCacheSetWrite = (callExpression, newExpression, enclosingFunct
17836
17039
  return !isAstDescendant(receiverBinding.scopeOwner, enclosingFunction);
17837
17040
  };
17838
17041
  const isInsideCacheMemo = (node) => {
17839
- const enclosingFunction = findEnclosingFunction$1(node);
17042
+ const enclosingFunction = findEnclosingFunction(node);
17840
17043
  let child = node;
17841
17044
  let cursor = node.parent ?? null;
17842
17045
  while (cursor) {
@@ -17874,7 +17077,7 @@ const getFunctionName = (functionNode) => {
17874
17077
  return null;
17875
17078
  };
17876
17079
  const isUncacheableOptionsMergeUtility = (node) => {
17877
- const enclosingFunction = findEnclosingFunction$1(node);
17080
+ const enclosingFunction = findEnclosingFunction(node);
17878
17081
  if (!enclosingFunction || !isFunctionLike$2(enclosingFunction)) return false;
17879
17082
  const functionName = getFunctionName(enclosingFunction);
17880
17083
  if (!functionName || isComponentOrHookName(functionName)) return false;
@@ -17998,7 +17201,7 @@ const GLOBAL_BUILTIN_NAMES = new Set([
17998
17201
  ]);
17999
17202
  const STRING_PROTOTYPE_PATH = "String.prototype";
18000
17203
  const REGEXP_PROTOTYPE_PATH = "RegExp.prototype";
18001
- const getStaticStringValue$1 = (argument) => {
17204
+ const getStaticStringValue = (argument) => {
18002
17205
  if (!argument) return null;
18003
17206
  const unwrappedArgument = stripParenExpression(argument);
18004
17207
  if (isNodeOfType(unwrappedArgument, "Literal") && typeof unwrappedArgument.value === "string") return unwrappedArgument.value;
@@ -18006,7 +17209,7 @@ const getStaticStringValue$1 = (argument) => {
18006
17209
  return null;
18007
17210
  };
18008
17211
  const getEffectiveRegExpFlags = (patternArgument, flagsArgument) => {
18009
- if (flagsArgument) return getStaticStringValue$1(flagsArgument);
17212
+ if (flagsArgument) return getStaticStringValue(flagsArgument);
18010
17213
  if (!patternArgument) return "";
18011
17214
  const unwrappedPattern = stripParenExpression(patternArgument);
18012
17215
  if (isNodeOfType(unwrappedPattern, "Literal") && unwrappedPattern.value instanceof RegExp) return unwrappedPattern.value.flags;
@@ -18065,6 +17268,13 @@ const isSafeStatefulReplaceAllSearch = (node, flags, context) => {
18065
17268
  const callee = stripParenExpression(replaceAllCall.callee);
18066
17269
  return isNodeOfType(callee, "MemberExpression") && !callee.computed && !callee.optional && !replaceAllCall.optional && isNodeOfType(callee.property, "Identifier") && callee.property.name === "replaceAll" && isProvenNativeStringReceiver(callee.object, context);
18067
17270
  };
17271
+ const getDestructuredBindingPropertyName = (bindingIdentifier) => {
17272
+ let bindingNode = bindingIdentifier;
17273
+ if (isNodeOfType(bindingNode.parent, "AssignmentPattern") && bindingNode.parent.left === bindingNode) bindingNode = bindingNode.parent;
17274
+ const property = bindingNode.parent;
17275
+ if (!isNodeOfType(property, "Property") || property.value !== bindingNode || !isNodeOfType(property.parent, "ObjectPattern")) return null;
17276
+ return getStaticPropertyKeyName(property, { allowComputedString: true });
17277
+ };
18068
17278
  const extendGlobalPath = (basePath, propertyName) => {
18069
17279
  if (basePath === "global") {
18070
17280
  if (propertyName === null || GLOBAL_OBJECT_NAMES.has(propertyName)) return "global";
@@ -18149,7 +17359,7 @@ const getCallRegExpHazard = (node, context, symbolCache) => {
18149
17359
  const mutationHazard = targetPath === "global" ? "globalRegExpReplaced" : "replaceAllIntegrityLost";
18150
17360
  const guardedPropertyName = targetPath === "global" ? "RegExp" : "replaceAll";
18151
17361
  if (isSinglePropertyMutation) {
18152
- const propertyName = getStaticStringValue$1(node.arguments?.[1]);
17362
+ const propertyName = getStaticStringValue(node.arguments?.[1]);
18153
17363
  return propertyName === null || propertyName === guardedPropertyName ? mutationHazard : "none";
18154
17364
  }
18155
17365
  if (!isPropertyCollectionMutation) return "none";
@@ -18178,7 +17388,7 @@ const getHoistableRegExpConstructionKind = (node, context) => {
18178
17388
  if (!STATEFUL_REGEXP_FLAGS_PATTERN.test(effectiveFlags)) return "stateless";
18179
17389
  return isSafeStatefulReplaceAllSearch(node, effectiveFlags, context) ? "statefulReplaceAll" : null;
18180
17390
  };
18181
- const MESSAGE$49 = "`new RegExp()` rebuilds the pattern on every loop pass. Move it to a constant outside the loop.";
17391
+ const MESSAGE$48 = "`new RegExp()` rebuilds the pattern on every loop pass. Move it to a constant outside the loop.";
18182
17392
  const jsHoistRegexp = defineRule({
18183
17393
  id: "js-hoist-regexp",
18184
17394
  title: "RegExp built inside a loop",
@@ -18195,7 +17405,7 @@ const jsHoistRegexp = defineRule({
18195
17405
  if (constructionKind === "statefulReplaceAll" && cachedEnvironmentHazard === "replaceAllIntegrityLost") return;
18196
17406
  context.report({
18197
17407
  node,
18198
- message: MESSAGE$49
17408
+ message: MESSAGE$48
18199
17409
  });
18200
17410
  };
18201
17411
  return createLoopAwareVisitors({
@@ -18354,89 +17564,7 @@ const collectEarlierAndGuardOperands = (node) => {
18354
17564
  return earlierOperands;
18355
17565
  };
18356
17566
  //#endregion
18357
- //#region src/plugin/utils/unwrap-object-integrity-expression.ts
18358
- const OBJECT_INTEGRITY_METHOD_NAMES = new Set([
18359
- "freeze",
18360
- "seal",
18361
- "preventExtensions"
18362
- ]);
18363
- const OBJECT_FREEZE_OR_SEAL_METHOD_NAMES = new Set(["freeze", "seal"]);
18364
- const getObjectIntegrityMethodName = (node, scopes, methodNames = OBJECT_INTEGRITY_METHOD_NAMES) => {
18365
- const expression = stripParenExpression(node);
18366
- if (!isNodeOfType(expression, "CallExpression")) return null;
18367
- const callee = stripParenExpression(expression.callee);
18368
- const receiver = isNodeOfType(callee, "MemberExpression") ? stripParenExpression(callee.object) : callee;
18369
- if (!isNodeOfType(callee, "MemberExpression") || callee.computed || !isNodeOfType(receiver, "Identifier") || receiver.name !== "Object" || !scopes.isGlobalReference(receiver) || !isNodeOfType(callee.property, "Identifier") || !methodNames.has(callee.property.name)) return null;
18370
- return callee.property.name;
18371
- };
18372
- const unwrapObjectIntegrityExpression = (node, scopes, methodNames = OBJECT_INTEGRITY_METHOD_NAMES) => {
18373
- let expression = stripParenExpression(node);
18374
- while (isNodeOfType(expression, "CallExpression")) {
18375
- if (!getObjectIntegrityMethodName(expression, scopes, methodNames)) break;
18376
- const wrappedExpression = expression.arguments[0];
18377
- if (!wrappedExpression || isNodeOfType(wrappedExpression, "SpreadElement")) break;
18378
- expression = stripParenExpression(wrappedExpression);
18379
- }
18380
- return expression;
18381
- };
18382
- //#endregion
18383
17567
  //#region src/plugin/rules/js-performance/js-length-check-first.ts
18384
- const OBJECT_CARDINALITY_PROJECTION_METHOD_NAMES = new Set(["keys", "values"]);
18385
- const getGlobalObjectProjection = (expression, context) => {
18386
- const callExpression = stripParenExpression(expression);
18387
- if (!isNodeOfType(callExpression, "CallExpression")) return null;
18388
- const callee = stripParenExpression(callExpression.callee);
18389
- if (!isNodeOfType(callee, "MemberExpression")) return null;
18390
- const receiver = stripParenExpression(callee.object);
18391
- if (!isNodeOfType(receiver, "Identifier") || receiver.name !== "Object" || !context.scopes.isGlobalReference(receiver)) return null;
18392
- const methodName = getStaticPropertyName(callee);
18393
- if (!methodName || !OBJECT_CARDINALITY_PROJECTION_METHOD_NAMES.has(methodName)) return null;
18394
- const callArguments = callExpression.arguments ?? [];
18395
- if (callArguments.length !== 1 || isNodeOfType(callArguments[0], "SpreadElement")) return null;
18396
- return {
18397
- methodName,
18398
- source: callArguments[0]
18399
- };
18400
- };
18401
- const isPlainDataObjectLiteral = (expression) => {
18402
- const objectExpression = stripParenExpression(expression);
18403
- if (!isNodeOfType(objectExpression, "ObjectExpression")) return false;
18404
- return (objectExpression.properties ?? []).every((property) => {
18405
- if (!isNodeOfType(property, "Property") || property.kind !== "init" || property.method === true) return false;
18406
- const propertyValue = stripParenExpression(property.value);
18407
- return isNodeOfType(propertyValue, "Literal") || isNodeOfType(propertyValue, "TemplateLiteral") && propertyValue.expressions.length === 0;
18408
- });
18409
- };
18410
- const getGlobalObjectFreezeArgument = (expression, context) => {
18411
- const callExpression = stripParenExpression(expression);
18412
- if (!isNodeOfType(callExpression, "CallExpression")) return null;
18413
- if (getObjectIntegrityMethodName(callExpression, context.scopes) !== "freeze") return null;
18414
- const callArguments = callExpression.arguments ?? [];
18415
- if (callArguments.length !== 1 || isNodeOfType(callArguments[0], "SpreadElement")) return null;
18416
- return callArguments[0];
18417
- };
18418
- const resolveStablePlainObjectRootId = (expression, context, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
18419
- const source = stripParenExpression(expression);
18420
- if (!isNodeOfType(source, "Identifier")) return null;
18421
- const symbol = context.scopes.symbolFor(source);
18422
- if (!symbol || visitedSymbolIds.has(symbol.id)) return null;
18423
- const directConstInitializer = getDirectConstInitializer(symbol);
18424
- if (!directConstInitializer) return null;
18425
- visitedSymbolIds.add(symbol.id);
18426
- const initializer = stripParenExpression(directConstInitializer);
18427
- const frozenValue = getGlobalObjectFreezeArgument(initializer, context);
18428
- if (frozenValue) return isPlainDataObjectLiteral(frozenValue) ? symbol.id : null;
18429
- return resolveStablePlainObjectRootId(initializer, context, visitedSymbolIds);
18430
- };
18431
- const areEqualCardinalityObjectProjections = (receiverArray, indexedArray, context) => {
18432
- const receiverProjection = getGlobalObjectProjection(receiverArray, context);
18433
- const indexedProjection = getGlobalObjectProjection(indexedArray, context);
18434
- if (!receiverProjection || !indexedProjection) return false;
18435
- if (receiverProjection.methodName === indexedProjection.methodName) return false;
18436
- const receiverRootId = resolveStablePlainObjectRootId(receiverProjection.source, context);
18437
- const indexedRootId = resolveStablePlainObjectRootId(indexedProjection.source, context);
18438
- return receiverRootId !== null && receiverRootId === indexedRootId;
18439
- };
18440
17568
  const findIndexedArrayObject = (callbackBody, indexParameterName) => {
18441
17569
  let indexedArrayObject = null;
18442
17570
  walkAst(callbackBody, (child) => {
@@ -18651,7 +17779,6 @@ const jsLengthCheckFirst = defineRule({
18651
17779
  const resolvedReceiverSource = resolveComparedArraySource(receiverArrayObject, node);
18652
17780
  const resolvedIndexedSource = resolveComparedArraySource(indexedArrayObject, node);
18653
17781
  if (areExpressionsStructurallyEqual(resolvedReceiverSource, resolvedIndexedSource)) return;
18654
- if (areEqualCardinalityObjectProjections(receiverArrayObject, indexedArrayObject, context) || areEqualCardinalityObjectProjections(resolvedReceiverSource, resolvedIndexedSource, context)) return;
18655
17782
  const comparedArrayPairs = [[receiverArrayObject, indexedArrayObject], [resolvedReceiverSource, resolvedIndexedSource]];
18656
17783
  if (collectEarlierAndGuardOperands(node).some((guardOperand) => comparedArrayPairs.some(([receiverSide, indexedSide]) => isLengthComparison(guardOperand, receiverSide, indexedSide, LENGTH_ANY_COMPARISON_OPERATORS)))) return;
18657
17784
  if (collectEarlierOrOperands(node).some((guardOperand) => comparedArrayPairs.some(([receiverSide, indexedSide]) => isLengthComparison(guardOperand, receiverSide, indexedSide, LENGTH_MISMATCH_OPERATORS)))) return;
@@ -20898,7 +20025,7 @@ const jsxMaxDepth = defineRule({
20898
20025
  });
20899
20026
  //#endregion
20900
20027
  //#region src/plugin/rules/react-builtins/jsx-no-comment-textnodes.ts
20901
- const MESSAGE$48 = "Your users see this comment as text on the page because `//` & `/*` aren't hidden in JSX.";
20028
+ const MESSAGE$47 = "Your users see this comment as text on the page because `//` & `/*` aren't hidden in JSX.";
20902
20029
  const LITERAL_TEXT_TAGS = new Set([
20903
20030
  "code",
20904
20031
  "pre",
@@ -20968,7 +20095,7 @@ const jsxNoCommentTextnodes = defineRule({
20968
20095
  if (isDeliberateStyledCommentToken(node)) return;
20969
20096
  context.report({
20970
20097
  node,
20971
- message: MESSAGE$48
20098
+ message: MESSAGE$47
20972
20099
  });
20973
20100
  } })
20974
20101
  });
@@ -20999,7 +20126,7 @@ const isInsideFunctionScope = (node) => {
20999
20126
  };
21000
20127
  //#endregion
21001
20128
  //#region src/plugin/rules/react-builtins/jsx-no-constructed-context-values.ts
21002
- const MESSAGE$47 = "Every reader of this context redraws on each render because you build its `value` inline.";
20129
+ const MESSAGE$46 = "Every reader of this context redraws on each render because you build its `value` inline.";
21003
20130
  const CONTEXT_MODULES$1 = [
21004
20131
  "react",
21005
20132
  "use-context-selector",
@@ -21097,7 +20224,7 @@ const jsxNoConstructedContextValues = defineRule({
21097
20224
  if (!isConstructedValue(innerExpression)) continue;
21098
20225
  context.report({
21099
20226
  node: attribute,
21100
- message: MESSAGE$47
20227
+ message: MESSAGE$46
21101
20228
  });
21102
20229
  }
21103
20230
  }
@@ -21952,7 +21079,7 @@ const DATA_ARRAY_PROP_SUFFIXES = [
21952
21079
  ];
21953
21080
  //#endregion
21954
21081
  //#region src/plugin/rules/react-builtins/jsx-no-new-array-as-prop.ts
21955
- const MESSAGE$46 = "This child redraws every render because the prop gets a brand new array each time.";
21082
+ const MESSAGE$45 = "This child redraws every render because the prop gets a brand new array each time.";
21956
21083
  const isDataArrayPropName = (propName) => {
21957
21084
  if (DATA_ARRAY_PROP_NAMES.has(propName)) return true;
21958
21085
  for (const suffix of DATA_ARRAY_PROP_SUFFIXES) if (propName.length > suffix.length && propName.endsWith(suffix)) return true;
@@ -22039,7 +21166,7 @@ const jsxNoNewArrayAsProp = defineRule({
22039
21166
  if (!isArrayProducingExpression(expressionNode) && !followsRenderLocalArrayBinding(expressionNode, node)) return;
22040
21167
  context.report({
22041
21168
  node,
22042
- message: MESSAGE$46
21169
+ message: MESSAGE$45
22043
21170
  });
22044
21171
  }
22045
21172
  };
@@ -22297,7 +21424,7 @@ const SAFE_RECEIVER_NAMES = new Set([
22297
21424
  ]);
22298
21425
  //#endregion
22299
21426
  //#region src/plugin/rules/react-builtins/jsx-no-new-function-as-prop.ts
22300
- const MESSAGE$45 = "This child redraws every render because the prop gets a brand new function each time.";
21427
+ const MESSAGE$44 = "This child redraws every render because the prop gets a brand new function each time.";
22301
21428
  const isAccessorPredicateName = (propName) => {
22302
21429
  for (const prefix of ACCESSOR_PREDICATE_PREFIXES) {
22303
21430
  if (propName.length <= prefix.length) continue;
@@ -22503,7 +21630,7 @@ const jsxNoNewFunctionAsProp = defineRule({
22503
21630
  if (!isFunctionProducingExpression(expressionNode) && !followsRenderLocalFunctionBinding(expressionNode, node)) return;
22504
21631
  context.report({
22505
21632
  node,
22506
- message: MESSAGE$45
21633
+ message: MESSAGE$44
22507
21634
  });
22508
21635
  }
22509
21636
  };
@@ -22723,7 +21850,7 @@ const CONFIG_OBJECT_PROP_SUFFIXES = [
22723
21850
  ];
22724
21851
  //#endregion
22725
21852
  //#region src/plugin/rules/react-builtins/jsx-no-new-object-as-prop.ts
22726
- const MESSAGE$44 = "This child redraws every render because the prop gets a brand new object each time.";
21853
+ const MESSAGE$43 = "This child redraws every render because the prop gets a brand new object each time.";
22727
21854
  const isConfigObjectPropName = (propName) => {
22728
21855
  if (CONFIG_OBJECT_PROP_NAMES.has(propName)) return true;
22729
21856
  for (const suffix of CONFIG_OBJECT_PROP_SUFFIXES) if (propName.length > suffix.length && propName.endsWith(suffix)) return true;
@@ -22812,7 +21939,7 @@ const jsxNoNewObjectAsProp = defineRule({
22812
21939
  if (!isObjectProducingExpression(expressionNode) && !followsRenderLocalObjectBinding(expressionNode, node)) return;
22813
21940
  context.report({
22814
21941
  node,
22815
- message: MESSAGE$44
21942
+ message: MESSAGE$43
22816
21943
  });
22817
21944
  }
22818
21945
  };
@@ -22820,7 +21947,7 @@ const jsxNoNewObjectAsProp = defineRule({
22820
21947
  });
22821
21948
  //#endregion
22822
21949
  //#region src/plugin/rules/react-builtins/jsx-no-script-url.ts
22823
- const MESSAGE$43 = "A `javascript:` URL is an XSS hole that runs injected input as code.";
21950
+ const MESSAGE$42 = "A `javascript:` URL is an XSS hole that runs injected input as code.";
22824
21951
  const JAVASCRIPT_URL_PATTERN = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*:/i;
22825
21952
  const resolveSettings$29 = (settings) => {
22826
21953
  const reactDoctor = settings?.["react-doctor"];
@@ -22858,7 +21985,7 @@ const jsxNoScriptUrl = defineRule({
22858
21985
  if (!value || !isNodeOfType(value, "Literal") || typeof value.value !== "string") continue;
22859
21986
  if (JAVASCRIPT_URL_PATTERN.test(value.value)) context.report({
22860
21987
  node: attribute,
22861
- message: MESSAGE$43
21988
+ message: MESSAGE$42
22862
21989
  });
22863
21990
  }
22864
21991
  } };
@@ -23478,7 +22605,7 @@ const jsxPropsNoSpreadMulti = defineRule({
23478
22605
  });
23479
22606
  //#endregion
23480
22607
  //#region src/plugin/rules/react-builtins/jsx-props-no-spreading.ts
23481
- const MESSAGE$42 = "You can't tell what props reach this element when you spread them.";
22608
+ const MESSAGE$41 = "You can't tell what props reach this element when you spread them.";
23482
22609
  const resolveSettings$25 = (settings) => {
23483
22610
  const reactDoctor = settings?.["react-doctor"];
23484
22611
  const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.jsxPropsNoSpreading ?? {} : {};
@@ -23521,7 +22648,7 @@ const jsxPropsNoSpreading = defineRule({
23521
22648
  }
23522
22649
  context.report({
23523
22650
  node: attribute,
23524
- message: MESSAGE$42
22651
+ message: MESSAGE$41
23525
22652
  });
23526
22653
  didReportInFile = true;
23527
22654
  return;
@@ -23797,7 +22924,7 @@ const labelHasAssociatedControl = defineRule({
23797
22924
  });
23798
22925
  //#endregion
23799
22926
  //#region src/plugin/rules/a11y/lang.ts
23800
- const MESSAGE$41 = "Screen readers can't pick the right voice because this `lang` isn't a real language code, so use a valid one like `en` or `en-US`.";
22927
+ const MESSAGE$40 = "Screen readers can't pick the right voice because this `lang` isn't a real language code, so use a valid one like `en` or `en-US`.";
23801
22928
  const COMMON_LANGUAGE_PRIMARY_TAGS = new Set([
23802
22929
  "aa",
23803
22930
  "ab",
@@ -24277,7 +23404,7 @@ const lang = defineRule({
24277
23404
  if (expression.type === "Identifier" && expression.name === "undefined" || expression.type === "Literal" && expression.value === null) {
24278
23405
  context.report({
24279
23406
  node: langAttr,
24280
- message: MESSAGE$41
23407
+ message: MESSAGE$40
24281
23408
  });
24282
23409
  return;
24283
23410
  }
@@ -24286,7 +23413,7 @@ const lang = defineRule({
24286
23413
  if (value === null) return;
24287
23414
  if (!isValidLangTag(value)) context.report({
24288
23415
  node: langAttr,
24289
- message: MESSAGE$41
23416
+ message: MESSAGE$40
24290
23417
  });
24291
23418
  } })
24292
23419
  });
@@ -24337,7 +23464,7 @@ const mdxSsrExecutionRisk = defineRule({
24337
23464
  });
24338
23465
  //#endregion
24339
23466
  //#region src/plugin/rules/a11y/media-has-caption.ts
24340
- const MESSAGE$40 = "Deaf and hard-of-hearing users need captions for this media. Add a `<track kind=\"captions\">` inside the `<audio>` or `<video>`.";
23467
+ const MESSAGE$39 = "Deaf and hard-of-hearing users need captions for this media. Add a `<track kind=\"captions\">` inside the `<audio>` or `<video>`.";
24341
23468
  const DEFAULT_AUDIO = ["audio"];
24342
23469
  const DEFAULT_VIDEO = ["video"];
24343
23470
  const DEFAULT_TRACK = ["track"];
@@ -24426,7 +23553,7 @@ const mediaHasCaption = defineRule({
24426
23553
  if (!parent || !isNodeOfType(parent, "JSXElement")) {
24427
23554
  context.report({
24428
23555
  node: node.name,
24429
- message: MESSAGE$40
23556
+ message: MESSAGE$39
24430
23557
  });
24431
23558
  return;
24432
23559
  }
@@ -24445,7 +23572,7 @@ const mediaHasCaption = defineRule({
24445
23572
  return kindValue.value.toLowerCase() === "captions";
24446
23573
  })) context.report({
24447
23574
  node: node.name,
24448
- message: MESSAGE$40
23575
+ message: MESSAGE$39
24449
23576
  });
24450
23577
  } };
24451
23578
  }
@@ -24529,6 +23656,32 @@ const hasDirective = (programNode, directive) => {
24529
23656
  return Boolean(programNode.body?.some((statement) => isNodeOfType(statement, "ExpressionStatement") && isNodeOfType(statement.expression, "Literal") && statement.expression.value === directive));
24530
23657
  };
24531
23658
  //#endregion
23659
+ //#region src/plugin/utils/unwrap-object-integrity-expression.ts
23660
+ const OBJECT_INTEGRITY_METHOD_NAMES = new Set([
23661
+ "freeze",
23662
+ "seal",
23663
+ "preventExtensions"
23664
+ ]);
23665
+ const OBJECT_FREEZE_OR_SEAL_METHOD_NAMES = new Set(["freeze", "seal"]);
23666
+ const getObjectIntegrityMethodName = (node, scopes, methodNames = OBJECT_INTEGRITY_METHOD_NAMES) => {
23667
+ const expression = stripParenExpression(node);
23668
+ if (!isNodeOfType(expression, "CallExpression")) return null;
23669
+ const callee = stripParenExpression(expression.callee);
23670
+ const receiver = isNodeOfType(callee, "MemberExpression") ? stripParenExpression(callee.object) : callee;
23671
+ if (!isNodeOfType(callee, "MemberExpression") || callee.computed || !isNodeOfType(receiver, "Identifier") || receiver.name !== "Object" || !scopes.isGlobalReference(receiver) || !isNodeOfType(callee.property, "Identifier") || !methodNames.has(callee.property.name)) return null;
23672
+ return callee.property.name;
23673
+ };
23674
+ const unwrapObjectIntegrityExpression = (node, scopes, methodNames = OBJECT_INTEGRITY_METHOD_NAMES) => {
23675
+ let expression = stripParenExpression(node);
23676
+ while (isNodeOfType(expression, "CallExpression")) {
23677
+ if (!getObjectIntegrityMethodName(expression, scopes, methodNames)) break;
23678
+ const wrappedExpression = expression.arguments[0];
23679
+ if (!wrappedExpression || isNodeOfType(wrappedExpression, "SpreadElement")) break;
23680
+ expression = stripParenExpression(wrappedExpression);
23681
+ }
23682
+ return expression;
23683
+ };
23684
+ //#endregion
24532
23685
  //#region src/plugin/rules/nextjs/nextjs-async-client-component.ts
24533
23686
  const nextjsAsyncClientComponent = defineRule({
24534
23687
  id: "nextjs-async-client-component",
@@ -25962,7 +25115,7 @@ const nextjsNoVercelOgImport = defineRule({
25962
25115
  });
25963
25116
  //#endregion
25964
25117
  //#region src/plugin/rules/a11y/no-access-key.ts
25965
- const MESSAGE$39 = "Screen reader users can lose their shortcuts because `accessKey` clashes with them, so remove it.";
25118
+ const MESSAGE$38 = "Screen reader users can lose their shortcuts because `accessKey` clashes with them, so remove it.";
25966
25119
  const isUndefinedIdentifier = (expression) => isNodeOfType(expression, "Identifier") && expression.name === "undefined";
25967
25120
  const noAccessKey = defineRule({
25968
25121
  id: "no-access-key",
@@ -25981,7 +25134,7 @@ const noAccessKey = defineRule({
25981
25134
  if (isNodeOfType(attributeValue, "Literal") && typeof attributeValue.value === "string") {
25982
25135
  context.report({
25983
25136
  node: accessKey,
25984
- message: MESSAGE$39
25137
+ message: MESSAGE$38
25985
25138
  });
25986
25139
  return;
25987
25140
  }
@@ -25991,7 +25144,7 @@ const noAccessKey = defineRule({
25991
25144
  if (isUndefinedIdentifier(expression)) return;
25992
25145
  context.report({
25993
25146
  node: accessKey,
25994
- message: MESSAGE$39
25147
+ message: MESSAGE$38
25995
25148
  });
25996
25149
  }
25997
25150
  } };
@@ -26296,10 +25449,9 @@ const unwrapUseCallback = (node) => {
26296
25449
  const callee = node.callee;
26297
25450
  return isNodeOfType(callee, "Identifier") && callee.name === "useCallback" || isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier") && callee.property.name === "useCallback" ? node.arguments?.[0] : node;
26298
25451
  };
26299
- const hasParameterDefinition = (ref) => Boolean(ref.resolved?.defs.some((definition) => definition.type === "Parameter"));
26300
25452
  const resolveToFunction = (ref) => {
26301
25453
  const definition = ref.resolved?.defs[0];
26302
- if (!definition || hasParameterDefinition(ref)) return null;
25454
+ if (!definition || definition.type === "Parameter") return null;
26303
25455
  const definitionNode = definition.node;
26304
25456
  if (!definitionNode) return null;
26305
25457
  if (isFunctionLike$2(definitionNode)) return definitionNode;
@@ -26710,7 +25862,7 @@ const isCleanupReturnArgument = (analysis, node) => {
26710
25862
  if (isNodeOfType(node, "MemberExpression")) return true;
26711
25863
  if (isNodeOfType(node, "Identifier")) {
26712
25864
  const ref = getRef(analysis, node);
26713
- if (ref && (hasParameterDefinition(ref) || resolveToFunction(ref))) return true;
25865
+ if (ref && resolveToFunction(ref)) return true;
26714
25866
  }
26715
25867
  if (isNodeOfType(node, "ConditionalExpression")) return isCleanupReturnArgument(analysis, node.consequent) || isCleanupReturnArgument(analysis, node.alternate);
26716
25868
  return false;
@@ -26868,7 +26020,7 @@ const isIndependentWriterIdentifier = (componentFunction, identifier, includeDef
26868
26020
  };
26869
26021
  const hasUserInputSetterWriter = (setterRef, effectNode, includeDeferredWriters = false) => {
26870
26022
  if (!setterRef.resolved) return false;
26871
- const componentFunction = findEnclosingFunction$1(effectNode);
26023
+ const componentFunction = findEnclosingFunction(effectNode);
26872
26024
  if (!componentFunction) return false;
26873
26025
  for (const reference of setterRef.resolved.references) {
26874
26026
  if (reference.init) continue;
@@ -27182,7 +26334,7 @@ const resolveWrappedCallable = (analysis, node) => {
27182
26334
  if (isNodeOfType(candidate, "Identifier")) {
27183
26335
  const reference = getRef(analysis, candidate);
27184
26336
  if (!reference) return null;
27185
- if (reference.resolved?.defs.some((definition) => definition.type === "ImportBinding")) return null;
26337
+ if (reference.resolved?.defs.some((definition) => definition.type === "Parameter" || definition.type === "ImportBinding")) return null;
27186
26338
  const resolved = resolveToFunction(reference);
27187
26339
  if (resolved) return resolved;
27188
26340
  const definitionNode = reference.resolved?.defs[0]?.node;
@@ -27846,7 +26998,7 @@ const noAdjustStateOnPropChange = defineRule({
27846
26998
  });
27847
26999
  //#endregion
27848
27000
  //#region src/plugin/rules/a11y/no-aria-hidden-on-focusable.ts
27849
- const MESSAGE$38 = "Screen reader users tab to this focusable element but hear nothing because `aria-hidden` skips it, so remove `aria-hidden` or stop it being focusable.";
27001
+ const MESSAGE$37 = "Screen reader users tab to this focusable element but hear nothing because `aria-hidden` skips it, so remove `aria-hidden` or stop it being focusable.";
27850
27002
  const ALWAYS_FOCUSABLE_TAGS = new Set([
27851
27003
  "button",
27852
27004
  "embed",
@@ -27958,7 +27110,7 @@ const noAriaHiddenOnFocusable = defineRule({
27958
27110
  const isImplicitlyFocusable = isNativelyFocusable(tag, node);
27959
27111
  if (isExplicitlyFocusable || isImplicitlyFocusable) context.report({
27960
27112
  node: ariaHidden,
27961
- message: MESSAGE$38
27113
+ message: MESSAGE$37
27962
27114
  });
27963
27115
  } })
27964
27116
  });
@@ -28880,7 +28032,7 @@ const isAllLiteralArrayExpression = (node) => {
28880
28032
  };
28881
28033
  //#endregion
28882
28034
  //#region src/plugin/rules/react-builtins/no-array-index-key.ts
28883
- const MESSAGE$37 = "Your users can see & submit the wrong data when this list reorders.";
28035
+ const MESSAGE$36 = "Your users can see & submit the wrong data when this list reorders.";
28884
28036
  const SECOND_INDEX_METHODS = new Set([
28885
28037
  "every",
28886
28038
  "filter",
@@ -28999,14 +28151,14 @@ const noArrayIndexKey = defineRule({
28999
28151
  if (propName !== "key") continue;
29000
28152
  if (expressionUsesIndex(property.value, indexBinding.name)) context.report({
29001
28153
  node: property,
29002
- message: MESSAGE$37
28154
+ message: MESSAGE$36
29003
28155
  });
29004
28156
  }
29005
28157
  } })
29006
28158
  });
29007
28159
  //#endregion
29008
28160
  //#region src/plugin/rules/state-and-effects/no-async-effect-callback.ts
29009
- const MESSAGE$36 = "The `useEffect` callback is `async`, so it returns a Promise instead of a cleanup function. React calls that Promise as cleanup (a no-op) and the effect can race on unmount. Put the async work in an inner function and call it.";
28161
+ const MESSAGE$35 = "The `useEffect` callback is `async`, so it returns a Promise instead of a cleanup function. React calls that Promise as cleanup (a no-op) and the effect can race on unmount. Put the async work in an inner function and call it.";
29010
28162
  const noAsyncEffectCallback = defineRule({
29011
28163
  id: "no-async-effect-callback",
29012
28164
  title: "Async effect callback",
@@ -29024,13 +28176,13 @@ const noAsyncEffectCallback = defineRule({
29024
28176
  if (!callback.async) return;
29025
28177
  context.report({
29026
28178
  node: callback,
29027
- message: MESSAGE$36
28179
+ message: MESSAGE$35
29028
28180
  });
29029
28181
  } })
29030
28182
  });
29031
28183
  //#endregion
29032
28184
  //#region src/plugin/rules/a11y/no-autofocus.ts
29033
- const MESSAGE$35 = "`autoFocus` moves focus on load, which can disrupt screen reader and keyboard users. Remove it and let users choose where to focus.";
28185
+ const MESSAGE$34 = "`autoFocus` moves focus on load, which can disrupt screen reader and keyboard users. Remove it and let users choose where to focus.";
29034
28186
  const resolveSettings$21 = (settings) => {
29035
28187
  const reactDoctor = settings?.["react-doctor"];
29036
28188
  return { ignoreNonDOM: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noAutofocus ?? {} : {}).ignoreNonDOM ?? true };
@@ -29127,7 +28279,7 @@ const noAutofocus = defineRule({
29127
28279
  if (isConditionallyRendered(node)) return;
29128
28280
  context.report({
29129
28281
  node: autoFocusAttribute,
29130
- message: MESSAGE$35
28282
+ message: MESSAGE$34
29131
28283
  });
29132
28284
  } };
29133
28285
  }
@@ -29641,6 +28793,138 @@ const noBarrelImport = defineRule({
29641
28793
  }
29642
28794
  });
29643
28795
  //#endregion
28796
+ //#region src/plugin/utils/has-static-property-write-before.ts
28797
+ const equivalentSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
28798
+ const CONDITIONAL_EXECUTION_NODE_TYPES = new Set([
28799
+ "CatchClause",
28800
+ "ConditionalExpression",
28801
+ "DoWhileStatement",
28802
+ "ForInStatement",
28803
+ "ForOfStatement",
28804
+ "ForStatement",
28805
+ "IfStatement",
28806
+ "LogicalExpression",
28807
+ "SwitchCase",
28808
+ "SwitchStatement",
28809
+ "TryStatement",
28810
+ "WhileStatement"
28811
+ ]);
28812
+ const getResolvedStaticPropertyName = (memberExpression, scopes) => {
28813
+ if (!isNodeOfType(memberExpression, "MemberExpression")) return null;
28814
+ const directPropertyName = getStaticPropertyName(memberExpression);
28815
+ if (directPropertyName || !memberExpression.computed) return directPropertyName;
28816
+ const property = stripParenExpression(memberExpression.property);
28817
+ if (!isNodeOfType(property, "Identifier")) return null;
28818
+ const propertySymbol = resolveConstIdentifierAlias(property, scopes);
28819
+ const initializer = propertySymbol?.initializer ? stripParenExpression(propertySymbol.initializer) : null;
28820
+ return initializer && isNodeOfType(initializer, "Literal") && typeof initializer.value === "string" ? initializer.value : null;
28821
+ };
28822
+ const collectScopeSymbols = (scope, symbols) => {
28823
+ symbols.push(...scope.symbols);
28824
+ for (const childScope of scope.children) collectScopeSymbols(childScope, symbols);
28825
+ };
28826
+ const getEquivalentSymbols = (identifier, scopes) => {
28827
+ const rootSymbol = resolveConstIdentifierAlias(identifier, scopes);
28828
+ if (!rootSymbol) return [];
28829
+ let symbolsByRootId = equivalentSymbolsByAnalysis.get(scopes);
28830
+ if (!symbolsByRootId) {
28831
+ symbolsByRootId = /* @__PURE__ */ new Map();
28832
+ equivalentSymbolsByAnalysis.set(scopes, symbolsByRootId);
28833
+ }
28834
+ const cachedSymbols = symbolsByRootId.get(rootSymbol.id);
28835
+ if (cachedSymbols) return cachedSymbols;
28836
+ const allSymbols = [];
28837
+ collectScopeSymbols(scopes.rootScope, allSymbols);
28838
+ const equivalentSymbols = allSymbols.filter((symbol) => resolveConstIdentifierAlias(symbol.bindingIdentifier, scopes)?.id === rootSymbol.id);
28839
+ symbolsByRootId.set(rootSymbol.id, equivalentSymbols);
28840
+ return equivalentSymbols;
28841
+ };
28842
+ const findExecutionBoundary = (node) => {
28843
+ let current = node;
28844
+ while (current) {
28845
+ if (isFunctionLike$2(current) || isNodeOfType(current, "Program")) return current;
28846
+ current = current.parent ?? null;
28847
+ }
28848
+ return null;
28849
+ };
28850
+ const isOnUnconditionalPath = (node, boundary) => {
28851
+ let current = node.parent ?? null;
28852
+ while (current && current !== boundary) {
28853
+ if (CONDITIONAL_EXECUTION_NODE_TYPES.has(current.type)) return false;
28854
+ current = current.parent ?? null;
28855
+ }
28856
+ return current === boundary;
28857
+ };
28858
+ const findFunctionBindingIdentifier = (functionNode) => {
28859
+ if (isNodeOfType(functionNode, "FunctionDeclaration")) return functionNode.id ?? null;
28860
+ const parent = functionNode.parent;
28861
+ if (parent && isNodeOfType(parent, "VariableDeclarator") && parent.init === functionNode && isNodeOfType(parent.id, "Identifier")) return parent.id;
28862
+ return null;
28863
+ };
28864
+ const findDirectCall = (identifier) => {
28865
+ let callee = identifier;
28866
+ let parent = callee.parent;
28867
+ while (parent && stripParenExpression(parent) === identifier) {
28868
+ callee = parent;
28869
+ parent = callee.parent;
28870
+ }
28871
+ return parent && isNodeOfType(parent, "CallExpression") && parent.callee === callee ? parent : null;
28872
+ };
28873
+ const isFunctionSynchronouslyInvokedBefore = (functionNode, referenceNode, scopes, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
28874
+ if (visitedFunctionNodes.has(functionNode) || !isFunctionLike$2(functionNode) || functionNode.generator) return false;
28875
+ visitedFunctionNodes.add(functionNode);
28876
+ const referenceBoundary = findExecutionBoundary(referenceNode);
28877
+ if (!referenceBoundary) return false;
28878
+ const invocationCalls = [];
28879
+ const bindingIdentifier = findFunctionBindingIdentifier(functionNode);
28880
+ if (bindingIdentifier) for (const symbol of getEquivalentSymbols(bindingIdentifier, scopes)) for (const reference of symbol.references) {
28881
+ const call = findDirectCall(reference.identifier);
28882
+ if (call) invocationCalls.push(call);
28883
+ }
28884
+ else {
28885
+ const call = findDirectCall(functionNode);
28886
+ if (call) invocationCalls.push(call);
28887
+ }
28888
+ return invocationCalls.some((call) => {
28889
+ if (call.range[0] >= referenceNode.range[0]) return false;
28890
+ const callBoundary = findExecutionBoundary(call);
28891
+ if (!callBoundary) return false;
28892
+ if (callBoundary === referenceBoundary) return true;
28893
+ if (!isFunctionLike$2(callBoundary)) return false;
28894
+ return isFunctionSynchronouslyInvokedBefore(callBoundary, referenceNode, scopes, new Set(visitedFunctionNodes));
28895
+ });
28896
+ };
28897
+ const isMemberWriteTarget = (memberExpression) => {
28898
+ const parent = memberExpression.parent;
28899
+ if (!parent) return false;
28900
+ if (isNodeOfType(parent, "AssignmentExpression")) return parent.left === memberExpression;
28901
+ if (isNodeOfType(parent, "UpdateExpression")) return parent.argument === memberExpression;
28902
+ return isNodeOfType(parent, "UnaryExpression") && parent.operator === "delete" && parent.argument === memberExpression;
28903
+ };
28904
+ const symbolHasStaticPropertyWriteBefore = (symbol, propertyName, referenceNode, scopes) => symbol.references.some((reference) => {
28905
+ let parent = reference.identifier.parent;
28906
+ while (parent && stripParenExpression(parent) === reference.identifier) parent = parent.parent;
28907
+ if (!parent || !isNodeOfType(parent, "MemberExpression") || stripParenExpression(parent.object) !== reference.identifier || getResolvedStaticPropertyName(parent, scopes) !== propertyName || !isMemberWriteTarget(parent)) return false;
28908
+ const writeBoundary = findExecutionBoundary(parent);
28909
+ const referenceBoundary = findExecutionBoundary(referenceNode);
28910
+ if (!writeBoundary || !referenceBoundary || !isOnUnconditionalPath(parent, writeBoundary)) return false;
28911
+ if (writeBoundary === referenceBoundary) return parent.range[0] < referenceNode.range[0];
28912
+ return isFunctionLike$2(writeBoundary) && isFunctionSynchronouslyInvokedBefore(writeBoundary, referenceNode, scopes);
28913
+ });
28914
+ const hasStaticPropertyWriteBefore = (identifier, propertyName, referenceNode, scopes) => {
28915
+ if (!isNodeOfType(identifier, "Identifier")) return false;
28916
+ return getEquivalentSymbols(identifier, scopes).some((symbol) => symbolHasStaticPropertyWriteBefore(symbol, propertyName, referenceNode, scopes));
28917
+ };
28918
+ //#endregion
28919
+ //#region src/plugin/utils/has-symbol-write-before.ts
28920
+ const hasSymbolWriteBefore = (symbol, referenceNode, scopes) => symbol.references.some((reference) => {
28921
+ if (reference.flag === "read") return false;
28922
+ const writeFunction = findEnclosingFunction(reference.identifier);
28923
+ if (writeFunction === findEnclosingFunction(referenceNode)) return reference.identifier.range[0] < referenceNode.range[0];
28924
+ if (!writeFunction) return true;
28925
+ return isFunctionSynchronouslyInvokedBefore(writeFunction, referenceNode, scopes);
28926
+ });
28927
+ //#endregion
29644
28928
  //#region src/plugin/utils/has-stable-call-target.ts
29645
28929
  const hasStableCallTarget = (callExpression, scopes) => {
29646
28930
  if (!isNodeOfType(callExpression, "CallExpression")) return false;
@@ -29968,7 +29252,7 @@ const noChainStateUpdates = defineRule({
29968
29252
  });
29969
29253
  //#endregion
29970
29254
  //#region src/plugin/rules/react-builtins/no-children-prop.ts
29971
- const MESSAGE$34 = "A `children` prop can override or hide nested children, so the component may render different content than the JSX shows.";
29255
+ const MESSAGE$33 = "A `children` prop can override or hide nested children, so the component may render different content than the JSX shows.";
29972
29256
  const noChildrenProp = defineRule({
29973
29257
  id: "no-children-prop",
29974
29258
  title: "Children passed as a prop",
@@ -29980,7 +29264,7 @@ const noChildrenProp = defineRule({
29980
29264
  if (node.name.name !== "children") return;
29981
29265
  context.report({
29982
29266
  node: node.name,
29983
- message: MESSAGE$34
29267
+ message: MESSAGE$33
29984
29268
  });
29985
29269
  },
29986
29270
  CallExpression(node) {
@@ -29993,7 +29277,7 @@ const noChildrenProp = defineRule({
29993
29277
  const propertyKey = property.key;
29994
29278
  if (isNodeOfType(propertyKey, "Identifier") && propertyKey.name === "children" || isNodeOfType(propertyKey, "Literal") && propertyKey.value === "children") context.report({
29995
29279
  node: propertyKey,
29996
- message: MESSAGE$34
29280
+ message: MESSAGE$33
29997
29281
  });
29998
29282
  }
29999
29283
  }
@@ -30001,7 +29285,7 @@ const noChildrenProp = defineRule({
30001
29285
  });
30002
29286
  //#endregion
30003
29287
  //#region src/plugin/rules/react-builtins/no-clone-element.ts
30004
- const MESSAGE$33 = "`React.cloneElement` couples the parent to the child's prop shape, so child prop changes can silently break injected behavior.";
29288
+ const MESSAGE$32 = "`React.cloneElement` couples the parent to the child's prop shape, so child prop changes can silently break injected behavior.";
30005
29289
  const noCloneElement = defineRule({
30006
29290
  id: "no-clone-element",
30007
29291
  title: "cloneElement makes child props fragile",
@@ -30014,7 +29298,7 @@ const noCloneElement = defineRule({
30014
29298
  if (isNodeOfType(callee, "Identifier") && callee.name === "cloneElement") {
30015
29299
  if (isImportedFromModule(node, "cloneElement", "react")) context.report({
30016
29300
  node: callee,
30017
- message: MESSAGE$33
29301
+ message: MESSAGE$32
30018
29302
  });
30019
29303
  return;
30020
29304
  }
@@ -30027,7 +29311,7 @@ const noCloneElement = defineRule({
30027
29311
  if (!isImportedFromModule(node, callee.object.name, "react")) return;
30028
29312
  context.report({
30029
29313
  node: callee,
30030
- message: MESSAGE$33
29314
+ message: MESSAGE$32
30031
29315
  });
30032
29316
  }
30033
29317
  } })
@@ -30047,7 +29331,7 @@ const getCallMethodName = (callee) => {
30047
29331
  };
30048
29332
  //#endregion
30049
29333
  //#region src/plugin/rules/state-and-effects/no-create-context-in-render.ts
30050
- const MESSAGE$32 = "createContext() builds a new context every render, so every consumer gets cut off & resets.";
29334
+ const MESSAGE$31 = "createContext() builds a new context every render, so every consumer gets cut off & resets.";
30051
29335
  const CONTEXT_MODULES = [
30052
29336
  "react",
30053
29337
  "use-context-selector",
@@ -30095,13 +29379,13 @@ const noCreateContextInRender = defineRule({
30095
29379
  if (!componentOrHookName) return;
30096
29380
  context.report({
30097
29381
  node,
30098
- message: `${MESSAGE$32} (called inside "${componentOrHookName}")`
29382
+ message: `${MESSAGE$31} (called inside "${componentOrHookName}")`
30099
29383
  });
30100
29384
  } })
30101
29385
  });
30102
29386
  //#endregion
30103
29387
  //#region src/plugin/rules/react-builtins/no-create-ref-in-function-component.ts
30104
- const MESSAGE$31 = "`createRef()` in a function component allocates a brand-new ref on every render, so it never holds a value between renders. Use the `useRef()` hook instead.";
29388
+ const MESSAGE$30 = "`createRef()` in a function component allocates a brand-new ref on every render, so it never holds a value between renders. Use the `useRef()` hook instead.";
30105
29389
  const isUseMemoCallbackArgument = (functionNode) => {
30106
29390
  const parent = functionNode.parent;
30107
29391
  if (!parent || !isNodeOfType(parent, "CallExpression")) return false;
@@ -30109,8 +29393,8 @@ const isUseMemoCallbackArgument = (functionNode) => {
30109
29393
  return isReactFunctionCall(parent, "useMemo");
30110
29394
  };
30111
29395
  const findEnclosingRenderFunction = (node) => {
30112
- let enclosingFunction = findEnclosingFunction$1(node);
30113
- while (enclosingFunction && isUseMemoCallbackArgument(enclosingFunction)) enclosingFunction = findEnclosingFunction$1(enclosingFunction);
29396
+ let enclosingFunction = findEnclosingFunction(node);
29397
+ while (enclosingFunction && isUseMemoCallbackArgument(enclosingFunction)) enclosingFunction = findEnclosingFunction(enclosingFunction);
30114
29398
  return enclosingFunction;
30115
29399
  };
30116
29400
  const noCreateRefInFunctionComponent = defineRule({
@@ -30131,7 +29415,7 @@ const noCreateRefInFunctionComponent = defineRule({
30131
29415
  if (!(isReactHookName(displayName) || functionContainsReactRenderOutput(enclosingFunction, context.scopes, context.cfg))) return;
30132
29416
  context.report({
30133
29417
  node,
30134
- message: MESSAGE$31
29418
+ message: MESSAGE$30
30135
29419
  });
30136
29420
  } })
30137
29421
  });
@@ -30271,7 +29555,7 @@ const noCreateStoreInRender = defineRule({
30271
29555
  });
30272
29556
  //#endregion
30273
29557
  //#region src/plugin/rules/react-builtins/no-danger.ts
30274
- const MESSAGE$30 = "`dangerouslySetInnerHTML` is an XSS hole that runs attacker-controlled HTML in your users' browsers.";
29558
+ const MESSAGE$29 = "`dangerouslySetInnerHTML` is an XSS hole that runs attacker-controlled HTML in your users' browsers.";
30275
29559
  const noDanger = defineRule({
30276
29560
  id: "no-danger",
30277
29561
  title: "Raw HTML injection can run unsafe markup",
@@ -30285,7 +29569,7 @@ const noDanger = defineRule({
30285
29569
  if (!propAttribute) return;
30286
29570
  context.report({
30287
29571
  node: propAttribute.name,
30288
- message: MESSAGE$30
29572
+ message: MESSAGE$29
30289
29573
  });
30290
29574
  },
30291
29575
  CallExpression(node) {
@@ -30297,7 +29581,7 @@ const noDanger = defineRule({
30297
29581
  const propertyKey = property.key;
30298
29582
  if (isNodeOfType(propertyKey, "Identifier") && propertyKey.name === "dangerouslySetInnerHTML" || isNodeOfType(propertyKey, "Literal") && propertyKey.value === "dangerouslySetInnerHTML") context.report({
30299
29583
  node: propertyKey,
30300
- message: MESSAGE$30
29584
+ message: MESSAGE$29
30301
29585
  });
30302
29586
  }
30303
29587
  }
@@ -30320,7 +29604,7 @@ const isMeaningfulJsxChild = (child) => {
30320
29604
  };
30321
29605
  //#endregion
30322
29606
  //#region src/plugin/rules/react-builtins/no-danger-with-children.ts
30323
- const MESSAGE$29 = "React throws an error when you set both children & `dangerouslySetInnerHTML`.";
29607
+ const MESSAGE$28 = "React throws an error when you set both children & `dangerouslySetInnerHTML`.";
30324
29608
  const mergePropsShape = (target, source) => {
30325
29609
  target.hasDangerously ||= source.hasDangerously;
30326
29610
  target.hasChildren ||= source.hasChildren;
@@ -30395,7 +29679,7 @@ const noDangerWithChildren = defineRule({
30395
29679
  if (!hasChildrenProp && !hasNestedChildren) return;
30396
29680
  if (hasJsxPropIgnoreCase(opening.attributes, "dangerouslySetInnerHTML") || spreadPropsShape.hasDangerously) context.report({
30397
29681
  node: opening,
30398
- message: MESSAGE$29
29682
+ message: MESSAGE$28
30399
29683
  });
30400
29684
  },
30401
29685
  CallExpression(node) {
@@ -30408,7 +29692,7 @@ const noDangerWithChildren = defineRule({
30408
29692
  const positionalChildren = node.arguments.slice(2);
30409
29693
  if (positionalChildren.length > 1 || positionalChildren.some((argument) => !isNullishExpression(argument)) || propsShape.hasChildren) context.report({
30410
29694
  node,
30411
- message: MESSAGE$29
29695
+ message: MESSAGE$28
30412
29696
  });
30413
29697
  }
30414
29698
  })
@@ -31161,7 +30445,7 @@ const getEnclosingEffectHookCallback = (node, componentFunction) => {
31161
30445
  const isEffectDrivenResync = (useStateCall) => {
31162
30446
  const setterName = getStateSetterName(useStateCall);
31163
30447
  if (!setterName) return false;
31164
- const componentFunction = findEnclosingFunction$1(useStateCall);
30448
+ const componentFunction = findEnclosingFunction(useStateCall);
31165
30449
  if (!componentFunction) return false;
31166
30450
  let isExempt = false;
31167
30451
  walkAst(componentFunction, (child) => {
@@ -31265,7 +30549,7 @@ const isDraftReseedOrRenderAdjusted = (useStateCall, isPropName) => {
31265
30549
  const setterName = getStateSetterName(useStateCall);
31266
30550
  if (!setterName) return false;
31267
30551
  const stateValueName = getStateValueName(useStateCall);
31268
- const componentFunction = findEnclosingFunction$1(useStateCall);
30552
+ const componentFunction = findEnclosingFunction(useStateCall);
31269
30553
  if (!componentFunction) return false;
31270
30554
  let isExempt = false;
31271
30555
  walkAst(componentFunction, (child) => {
@@ -31311,7 +30595,7 @@ const noDerivedUseState = defineRule({
31311
30595
  if (isDraftReseedOrRenderAdjusted(node, propStackTracker.isPropName)) return;
31312
30596
  if (isEffectDrivenResync(node)) return;
31313
30597
  if (isNextjsDataFetchingPage(node)) return;
31314
- const componentFunction = findEnclosingFunction$1(node);
30598
+ const componentFunction = findEnclosingFunction(node);
31315
30599
  if (componentFunction) {
31316
30600
  if (isDefaultedDestructuredProp(componentFunction, propName)) return;
31317
30601
  if (isDraftCommittedToParent(componentFunction, getStateValueName(node), propStackTracker.isPropName)) return;
@@ -31373,7 +30657,7 @@ const isSetStateCallInLifecycle = (setStateCall, lifecycleNames, options = {}) =
31373
30657
  //#endregion
31374
30658
  //#region src/plugin/rules/react-builtins/no-did-mount-set-state.ts
31375
30659
  const LIFECYCLE_NAMES$2 = new Set(["componentDidMount"]);
31376
- const MESSAGE$28 = "Your users see an extra render right after mount when you call `setState` in `componentDidMount`.";
30660
+ const MESSAGE$27 = "Your users see an extra render right after mount when you call `setState` in `componentDidMount`.";
31377
30661
  const getNodeStart = (node) => "start" in node && typeof node.start === "number" ? node.start : -1;
31378
30662
  const getEnclosingLifecycleFunction = (setStateCall) => {
31379
30663
  let ancestor = setStateCall.parent;
@@ -31501,7 +30785,7 @@ const noDidMountSetState = defineRule({
31501
30785
  }
31502
30786
  context.report({
31503
30787
  node: node.callee,
31504
- message: MESSAGE$28
30788
+ message: MESSAGE$27
31505
30789
  });
31506
30790
  } };
31507
30791
  }
@@ -31509,7 +30793,7 @@ const noDidMountSetState = defineRule({
31509
30793
  //#endregion
31510
30794
  //#region src/plugin/rules/react-builtins/no-did-update-set-state.ts
31511
30795
  const LIFECYCLE_NAMES$1 = new Set(["componentDidUpdate"]);
31512
- const MESSAGE$27 = "Calling setState in componentDidUpdate can trigger another update immediately, loop forever, and freeze the component.";
30796
+ const MESSAGE$26 = "Calling setState in componentDidUpdate can trigger another update immediately, loop forever, and freeze the component.";
31513
30797
  const EQUALITY_OPERATORS = new Set([
31514
30798
  "==",
31515
30799
  "===",
@@ -31683,7 +30967,7 @@ const noDidUpdateSetState = defineRule({
31683
30967
  if (isInsideDiffGuard(node)) return;
31684
30968
  context.report({
31685
30969
  node: node.callee,
31686
- message: MESSAGE$27
30970
+ message: MESSAGE$26
31687
30971
  });
31688
30972
  } };
31689
30973
  }
@@ -31706,7 +30990,7 @@ const isStateMemberExpression = (node) => {
31706
30990
  };
31707
30991
  //#endregion
31708
30992
  //#region src/plugin/rules/react-builtins/no-direct-mutation-state.ts
31709
- const MESSAGE$26 = "Mutating `this.state` by hand never triggers a redraw on its own & a later setState can overwrite it, so use `this.setState` instead.";
30993
+ const MESSAGE$25 = "Mutating `this.state` by hand never triggers a redraw on its own & a later setState can overwrite it, so use `this.setState` instead.";
31710
30994
  const shouldIgnoreMutation = (node) => {
31711
30995
  let isConstructor = false;
31712
30996
  let isInsideCallExpression = false;
@@ -31728,7 +31012,7 @@ const reportIfStateMutation = (context, reportNode, target) => {
31728
31012
  if (shouldIgnoreMutation(reportNode)) return;
31729
31013
  context.report({
31730
31014
  node: reportNode,
31731
- message: MESSAGE$26
31015
+ message: MESSAGE$25
31732
31016
  });
31733
31017
  };
31734
31018
  const noDirectMutationState = defineRule({
@@ -32079,7 +31363,7 @@ const noDocumentStartViewTransition = defineRule({
32079
31363
  });
32080
31364
  //#endregion
32081
31365
  //#region src/plugin/rules/js-performance/no-document-write.ts
32082
- const MESSAGE$25 = "`document.write()` blocks parsing, is ignored (or wipes the page) after load, and is flagged by browsers as a performance anti-pattern. Build DOM nodes or set `innerHTML`/`textContent` on a target element instead.";
31366
+ const MESSAGE$24 = "`document.write()` blocks parsing, is ignored (or wipes the page) after load, and is flagged by browsers as a performance anti-pattern. Build DOM nodes or set `innerHTML`/`textContent` on a target element instead.";
32083
31367
  const WRITE_METHODS = new Set(["write", "writeln"]);
32084
31368
  const isGlobalDocumentReference = (node, context) => node.name === "document" && context.scopes.isGlobalReference(node);
32085
31369
  const noDocumentWrite = defineRule({
@@ -32096,7 +31380,7 @@ const noDocumentWrite = defineRule({
32096
31380
  if (methodName === null || !WRITE_METHODS.has(methodName)) return;
32097
31381
  context.report({
32098
31382
  node,
32099
- message: MESSAGE$25
31383
+ message: MESSAGE$24
32100
31384
  });
32101
31385
  } })
32102
31386
  });
@@ -32786,29 +32070,6 @@ const isReturnOnlyStatement = (node) => {
32786
32070
  return isNodeOfType(node, "BlockStatement") && (node.body?.length ?? 0) === 1 && isNodeOfType(node.body?.[0], "ReturnStatement");
32787
32071
  };
32788
32072
  const hasEventLikeRemainingStatements = (statements) => statements.some((statement) => !isNodeOfType(statement, "ReturnStatement") && hasEventLikeNode(statement));
32789
- const collectLeadingEarlyReturnGuards = (statements) => {
32790
- const guardExpressions = [];
32791
- for (const statement of statements) {
32792
- if (isNodeOfType(statement, "VariableDeclaration")) continue;
32793
- if (!isNodeOfType(statement, "IfStatement") || statement.alternate || !isReturnOnlyStatement(statement.consequent)) break;
32794
- collectGuardExpressions(statement.test, guardExpressions);
32795
- }
32796
- return guardExpressions;
32797
- };
32798
- const collectImmutableExpressionOrigins = (expression, scopes) => {
32799
- const origins = [];
32800
- const visitedSymbolIds = /* @__PURE__ */ new Set();
32801
- let currentExpression = stripParenExpression(expression);
32802
- while (currentExpression) {
32803
- origins.push(currentExpression);
32804
- if (!isNodeOfType(currentExpression, "Identifier")) break;
32805
- const bindingSymbol = scopes.symbolFor(currentExpression);
32806
- if (!bindingSymbol || bindingSymbol.kind !== "const" || visitedSymbolIds.has(bindingSymbol.id) || !bindingSymbol.initializer) break;
32807
- visitedSymbolIds.add(bindingSymbol.id);
32808
- currentExpression = stripParenExpression(bindingSymbol.initializer);
32809
- }
32810
- return origins;
32811
- };
32812
32073
  const doesGuardMatchDependency = (guardExpression, dependencyExpression) => {
32813
32074
  const unwrappedDependencyExpression = unwrapChainExpression$1(dependencyExpression);
32814
32075
  if (!unwrappedDependencyExpression) return false;
@@ -32816,69 +32077,6 @@ const doesGuardMatchDependency = (guardExpression, dependencyExpression) => {
32816
32077
  return isNodeOfType(unwrappedDependencyExpression, "Identifier") && unwrappedDependencyExpression.name === guardExpression.rootIdentifierName;
32817
32078
  };
32818
32079
  const hasDependencyMatch = (guardExpression, dependencyExpressions) => dependencyExpressions.some((dependencyExpression) => doesGuardMatchDependency(guardExpression, dependencyExpression));
32819
- const hasAliasedDependencyMatch = (guardExpression, dependencyExpressions, scopes) => {
32820
- const guardOrigins = collectImmutableExpressionOrigins(guardExpression.expression, scopes);
32821
- return dependencyExpressions.some((dependencyExpression) => {
32822
- if (!dependencyExpression) return false;
32823
- const dependencyOrigins = collectImmutableExpressionOrigins(dependencyExpression, scopes);
32824
- return guardOrigins.some((guardOrigin) => dependencyOrigins.some((dependencyOrigin) => areExpressionsStructurallyEqual(guardOrigin, dependencyOrigin)));
32825
- });
32826
- };
32827
- const isStaticallyTrue = (expression, scopes) => collectImmutableExpressionOrigins(expression, scopes).some((origin) => isNodeOfType(origin, "Literal") && origin.value === true);
32828
- const isReactRouterReplacementNavigation = (node, rootIdentifierNames, scopes) => {
32829
- let didFindNavigation = false;
32830
- let didFindOtherTriggeredSideEffect = false;
32831
- walkAst(node, (child) => {
32832
- if (!isNodeOfType(child, "CallExpression")) return;
32833
- if (!(findTriggeredSideEffectCalleeName(child) !== null || hasDocumentClassListMutation(child))) return;
32834
- const destinationExpression = child.arguments?.[0];
32835
- const doesDestinationReferenceReconciliationValue = Boolean(destinationExpression && collectImmutableExpressionOrigins(destinationExpression, scopes).some((origin) => doesNodeReferenceAnyRoot(origin, rootIdentifierNames)));
32836
- if (!isNodeOfType(child.callee, "Identifier") || !doesDestinationReferenceReconciliationValue) {
32837
- didFindOtherTriggeredSideEffect = true;
32838
- return;
32839
- }
32840
- const navigationSymbol = scopes.symbolFor(child.callee);
32841
- const navigationInitializer = navigationSymbol?.initializer ? stripParenExpression(navigationSymbol.initializer) : null;
32842
- if (navigationSymbol?.kind !== "const" || !isNodeOfType(navigationInitializer, "CallExpression") || !isNodeOfType(navigationInitializer.callee, "Identifier")) {
32843
- didFindOtherTriggeredSideEffect = true;
32844
- return;
32845
- }
32846
- if (scopes.symbolFor(navigationInitializer.callee)?.kind !== "import") {
32847
- didFindOtherTriggeredSideEffect = true;
32848
- return;
32849
- }
32850
- if ((getImportedNameFromModule(navigationInitializer.callee, navigationInitializer.callee.name, "react-router-dom") ?? getImportedNameFromModule(navigationInitializer.callee, navigationInitializer.callee.name, "react-router")) !== "useNavigate") {
32851
- didFindOtherTriggeredSideEffect = true;
32852
- return;
32853
- }
32854
- const navigationOptionsArgument = child.arguments?.[1];
32855
- const navigationOptions = navigationOptionsArgument ? stripParenExpression(navigationOptionsArgument) : null;
32856
- if (!isNodeOfType(navigationOptions, "ObjectExpression")) {
32857
- didFindOtherTriggeredSideEffect = true;
32858
- return;
32859
- }
32860
- let isReplacementGuaranteed = false;
32861
- for (const property of navigationOptions.properties) {
32862
- if (isNodeOfType(property, "SpreadElement")) {
32863
- isReplacementGuaranteed = false;
32864
- continue;
32865
- }
32866
- const propertyName = getStaticPropertyKeyName(property, { allowComputedString: true });
32867
- if (propertyName === null) {
32868
- isReplacementGuaranteed = false;
32869
- continue;
32870
- }
32871
- if (propertyName !== "replace") continue;
32872
- isReplacementGuaranteed = isStaticallyTrue(property.value, scopes);
32873
- }
32874
- if (isReplacementGuaranteed) {
32875
- didFindNavigation = true;
32876
- return;
32877
- }
32878
- didFindOtherTriggeredSideEffect = true;
32879
- });
32880
- return didFindNavigation && !didFindOtherTriggeredSideEffect;
32881
- };
32882
32080
  const isEqualityToLiteralGuard = (guardExpression) => {
32883
32081
  const parent = guardExpression.expression.parent;
32884
32082
  if (!isNodeOfType(parent, "BinaryExpression")) return false;
@@ -32943,35 +32141,18 @@ const noEffectEventHandler = defineRule({
32943
32141
  if (statements.length === 0) return;
32944
32142
  const soleStatement = statements[0];
32945
32143
  if (!isNodeOfType(soleStatement, "IfStatement")) return;
32946
- const initialGuardExpressions = [];
32947
- collectGuardExpressions(soleStatement.test, initialGuardExpressions);
32948
- const guardExpressions = collectLeadingEarlyReturnGuards(statements);
32949
- if (guardExpressions.length === 0) guardExpressions.push(...initialGuardExpressions);
32950
- const matchingPropGuardExpressions = initialGuardExpressions.filter((guardExpression) => hasDependencyMatch(guardExpression, dependencyExpressions) && propStackTracker.isPropName(guardExpression.rootIdentifierName, node));
32144
+ const guardExpressions = [];
32145
+ collectGuardExpressions(soleStatement.test, guardExpressions);
32146
+ const matchingPropGuardExpressions = guardExpressions.filter((guardExpression) => hasDependencyMatch(guardExpression, dependencyExpressions) && propStackTracker.isPropName(guardExpression.rootIdentifierName, node));
32951
32147
  if (matchingPropGuardExpressions.length === 0) return;
32952
32148
  const isSingleGuardedEventLikeStatement = statements.length === 1 && hasEventLikeNode(soleStatement.consequent);
32953
32149
  const isEarlyReturnGuardedEventLikeBody = statements.length > 1 && !soleStatement.alternate && isReturnOnlyStatement(soleStatement.consequent) && hasEventLikeRemainingStatements(statements.slice(1));
32954
32150
  if (!isSingleGuardedEventLikeStatement && !isEarlyReturnGuardedEventLikeBody) return;
32955
32151
  if (isEarlyReturnGuardedEventLikeBody && !isSingleGuardedEventLikeStatement && matchingPropGuardExpressions.every(isEqualityToLiteralGuard)) return;
32956
- if (initialGuardExpressions.some((guardExpression) => !matchingPropGuardExpressions.some((matchingGuardExpression) => matchingGuardExpression.expression === guardExpression.expression))) {
32152
+ if (guardExpressions.some((guardExpression) => !matchingPropGuardExpressions.some((matchingGuardExpression) => matchingGuardExpression.expression === guardExpression.expression))) {
32957
32153
  const matchingPropRootNames = new Set(matchingPropGuardExpressions.map((guardExpression) => guardExpression.rootIdentifierName));
32958
32154
  if (!(isSingleGuardedEventLikeStatement ? doesEventLikeCallReferenceAnyRoot(soleStatement.consequent, matchingPropRootNames) : doesAnyEventLikeCallReferenceAnyRoot(statements.slice(1), matchingPropRootNames))) return;
32959
32155
  }
32960
- if (isEarlyReturnGuardedEventLikeBody) {
32961
- const reconciliationGuardRootNames = new Set(guardExpressions.filter((guardExpression) => !propStackTracker.isPropName(guardExpression.rootIdentifierName, node) && hasAliasedDependencyMatch(guardExpression, dependencyExpressions, context.scopes) && guardExpressions.some((comparisonGuardExpression) => {
32962
- if (comparisonGuardExpression.rootIdentifierName !== guardExpression.rootIdentifierName) return false;
32963
- const comparisonExpression = comparisonGuardExpression.expression.parent;
32964
- if (!isNodeOfType(comparisonExpression, "BinaryExpression") || comparisonExpression.operator !== "===" && comparisonExpression.operator !== "==") return false;
32965
- const comparedRootIdentifierName = getRootIdentifierName(comparisonExpression.left === comparisonGuardExpression.expression ? comparisonExpression.right : comparisonExpression.left);
32966
- return Boolean(comparedRootIdentifierName && propStackTracker.isPropName(comparedRootIdentifierName, node));
32967
- })).map((guardExpression) => guardExpression.rootIdentifierName));
32968
- if (reconciliationGuardRootNames.size > 0) {
32969
- const matchingPropRootNames = new Set(matchingPropGuardExpressions.map((guardExpression) => guardExpression.rootIdentifierName));
32970
- const eventLikeStatements = statements.slice(1);
32971
- const triggeredStatements = eventLikeStatements.filter(hasEventLikeNode);
32972
- if (triggeredStatements.length > 0 && triggeredStatements.every((statement) => isReactRouterReplacementNavigation(statement, reconciliationGuardRootNames, context.scopes)) && !doesAnyEventLikeCallReferenceAnyRoot(eventLikeStatements, matchingPropRootNames)) return;
32973
- }
32974
- }
32975
32156
  context.report({
32976
32157
  node,
32977
32158
  message: "This useEffect is simulating an event handler, which costs an extra render & runs late."
@@ -33252,7 +32433,7 @@ const isFunctionUsedOutsideHandlers = (analysis, functionNode, componentFunction
33252
32433
  if (isInsideInlineEventHandler(identifier, componentFunction)) return false;
33253
32434
  const parent = identifier.parent;
33254
32435
  if (parent && isNodeOfType(parent, "CallExpression") && parent.callee === identifier) {
33255
- if (findEnclosingFunction$1(parent) === functionNode) return false;
32436
+ if (findEnclosingFunction(parent) === functionNode) return false;
33256
32437
  if (isInsideProvenEventHandler(analysis, parent, componentFunction, false)) return false;
33257
32438
  }
33258
32439
  return true;
@@ -33298,7 +32479,7 @@ const isStateWrittenOnlyFromEventHandlers = (analysis, stateReference) => {
33298
32479
  if (!setterVariable) return false;
33299
32480
  const stateDeclarator = getUseStateDecl(analysis, stateReference);
33300
32481
  if (!stateDeclarator) return false;
33301
- const componentFunction = findEnclosingFunction$1(stateDeclarator);
32482
+ const componentFunction = findEnclosingFunction(stateDeclarator);
33302
32483
  if (!componentFunction) return false;
33303
32484
  let hasWriter = false;
33304
32485
  for (const reference of setterVariable.references) {
@@ -34360,8 +33541,8 @@ const isAwaitedInFunction = (request, functionNode) => {
34360
33541
  return false;
34361
33542
  };
34362
33543
  const isCompletionSinkForRequest = (completionSink, request) => {
34363
- const requestFunction = findEnclosingFunction$1(request);
34364
- const completionSinkFunction = findEnclosingFunction$1(completionSink);
33544
+ const requestFunction = findEnclosingFunction(request);
33545
+ const completionSinkFunction = findEnclosingFunction(completionSink);
34365
33546
  if (!requestFunction || !completionSinkFunction) return false;
34366
33547
  if (requestFunction === completionSinkFunction) {
34367
33548
  if (!isAwaitedInFunction(request, requestFunction)) return false;
@@ -34417,7 +33598,7 @@ const ALLOWED_NAMESPACES = new Set([
34417
33598
  "ReactDOM",
34418
33599
  "ReactDom"
34419
33600
  ]);
34420
- const MESSAGE$24 = "`findDOMNode` crashes your app in React 19 because it was removed.";
33601
+ const MESSAGE$23 = "`findDOMNode` crashes your app in React 19 because it was removed.";
34421
33602
  const noFindDomNode = defineRule({
34422
33603
  id: "no-find-dom-node",
34423
33604
  title: "findDOMNode breaks component encapsulation",
@@ -34428,7 +33609,7 @@ const noFindDomNode = defineRule({
34428
33609
  if (isNodeOfType(callee, "Identifier") && callee.name === "findDOMNode") {
34429
33610
  if (isImportedFromModule(node, callee.name, "react-dom")) context.report({
34430
33611
  node: callee,
34431
- message: MESSAGE$24
33612
+ message: MESSAGE$23
34432
33613
  });
34433
33614
  return;
34434
33615
  }
@@ -34439,7 +33620,7 @@ const noFindDomNode = defineRule({
34439
33620
  if (callee.property.name !== "findDOMNode") return;
34440
33621
  context.report({
34441
33622
  node: callee.property,
34442
- message: MESSAGE$24
33623
+ message: MESSAGE$23
34443
33624
  });
34444
33625
  }
34445
33626
  } })
@@ -34648,6 +33829,13 @@ const isPublishedLibraryPackage = (filename) => {
34648
33829
  return manifest.private !== true && typeof manifest.peerDependencies === "object" && manifest.peerDependencies !== null && "react" in manifest.peerDependencies;
34649
33830
  };
34650
33831
  //#endregion
33832
+ //#region src/plugin/utils/is-type-only-import.ts
33833
+ const isEverySpecifierInlineType = (specifiers, specifierType, kindField) => {
33834
+ if (!specifiers || specifiers.length === 0) return false;
33835
+ return specifiers.every((specifier) => isNodeOfType(specifier, specifierType) && specifier[kindField] === "type");
33836
+ };
33837
+ const isTypeOnlyImport = (node) => node.importKind === "type" || isEverySpecifierInlineType(node.specifiers, "ImportSpecifier", "importKind");
33838
+ //#endregion
34651
33839
  //#region src/plugin/rules/bundle-size/no-full-lodash-import.ts
34652
33840
  const isLibraryDevPage = (filename) => {
34653
33841
  if (!filename) return false;
@@ -35211,7 +34399,7 @@ const isInRenderedOutput = (node, componentOrHookNode, scopes) => {
35211
34399
  return attribute ? !isEventHandlerAttribute(attribute) : true;
35212
34400
  }
35213
34401
  if (isNodeOfType(parentNode, "ReturnStatement")) {
35214
- if (findEnclosingFunction$1(parentNode) === componentOrHookNode) return true;
34402
+ if (findEnclosingFunction(parentNode) === componentOrHookNode) return true;
35215
34403
  }
35216
34404
  if (parentNode === componentOrHookNode) return isFunctionLike$2(componentOrHookNode) && !isNodeOfType(componentOrHookNode.body, "BlockStatement") && componentOrHookNode.body === currentNode;
35217
34405
  if (isFunctionLike$2(parentNode) && !executesDuringRender(parentNode, scopes)) return false;
@@ -35334,7 +34522,7 @@ const noHydrationBranchOnBrowserGlobal = defineRule({
35334
34522
  if (consequentValues.length === 0 || alternateValues.length === 0) return;
35335
34523
  const componentOrHookNode = findRenderPhaseComponentOrHook(node.test, context.scopes);
35336
34524
  if (!componentOrHookNode) return;
35337
- const enclosingFunction = findEnclosingFunction$1(node);
34525
+ const enclosingFunction = findEnclosingFunction(node);
35338
34526
  if (enclosingFunction !== componentOrHookNode && (!enclosingFunction || !isInRenderedOutput(enclosingFunction, componentOrHookNode, context.scopes))) return;
35339
34527
  for (const consequentValue of consequentValues) for (const alternateValue of alternateValues) {
35340
34528
  if (!isRenderedValue(consequentValue) && !isRenderedValue(alternateValue)) continue;
@@ -35346,7 +34534,7 @@ const noHydrationBranchOnBrowserGlobal = defineRule({
35346
34534
  });
35347
34535
  //#endregion
35348
34536
  //#region src/plugin/rules/performance/no-img-lazy-with-high-fetchpriority.ts
35349
- const MESSAGE$23 = "`<img loading=\"lazy\">` defers the request while `fetchPriority=\"high\"` asks the browser to rush it, so the two directives contradict each other. Drop one: keep `fetchPriority=\"high\"` (and eager loading) for an LCP image, or `loading=\"lazy\"` for a below-the-fold one.";
34537
+ const MESSAGE$22 = "`<img loading=\"lazy\">` defers the request while `fetchPriority=\"high\"` asks the browser to rush it, so the two directives contradict each other. Drop one: keep `fetchPriority=\"high\"` (and eager loading) for an LCP image, or `loading=\"lazy\"` for a below-the-fold one.";
35350
34538
  const noImgLazyWithHighFetchpriority = defineRule({
35351
34539
  id: "no-img-lazy-with-high-fetchpriority",
35352
34540
  title: "Lazy image with high fetchPriority",
@@ -35360,7 +34548,7 @@ const noImgLazyWithHighFetchpriority = defineRule({
35360
34548
  if (!fetchPriorityAttribute || getJsxPropStringValue(fetchPriorityAttribute)?.toLowerCase() !== "high") return;
35361
34549
  context.report({
35362
34550
  node: node.name,
35363
- message: MESSAGE$23
34551
+ message: MESSAGE$22
35364
34552
  });
35365
34553
  } })
35366
34554
  });
@@ -35549,7 +34737,7 @@ const noImpureStateUpdater = defineRule({
35549
34737
  });
35550
34738
  //#endregion
35551
34739
  //#region src/plugin/rules/correctness/no-indeterminate-attribute.ts
35552
- const MESSAGE$22 = "The `indeterminate` HTML attribute does not set a checkbox's visual state. Assign the `HTMLInputElement.indeterminate` DOM property instead.";
34740
+ const MESSAGE$21 = "The `indeterminate` HTML attribute does not set a checkbox's visual state. Assign the `HTMLInputElement.indeterminate` DOM property instead.";
35553
34741
  const REACT_USE_REF_OPTIONS = {
35554
34742
  allowGlobalReactNamespace: false,
35555
34743
  allowUnboundBareCalls: false
@@ -35650,7 +34838,7 @@ const noIndeterminateAttribute = defineRule({
35650
34838
  if (!inputTypeValues || !inputTypeValues.every((inputTypeValue) => inputTypeValue.toLowerCase() === "checkbox")) return;
35651
34839
  context.report({
35652
34840
  node: indeterminateAttribute,
35653
- message: MESSAGE$22
34841
+ message: MESSAGE$21
35654
34842
  });
35655
34843
  },
35656
34844
  CallExpression(node) {
@@ -35659,7 +34847,7 @@ const noIndeterminateAttribute = defineRule({
35659
34847
  if (!isProvenHtmlInputElement(receiver, context.scopes)) return;
35660
34848
  context.report({
35661
34849
  node,
35662
- message: MESSAGE$22
34850
+ message: MESSAGE$21
35663
34851
  });
35664
34852
  }
35665
34853
  };
@@ -35782,10 +34970,10 @@ const isInsideInstanceField = (node) => {
35782
34970
  return false;
35783
34971
  };
35784
34972
  const isOneShotModuleInitialization = (node, context) => {
35785
- let functionNode = findEnclosingFunction$1(node);
34973
+ let functionNode = findEnclosingFunction(node);
35786
34974
  while (functionNode) {
35787
34975
  if (!executesDuringRender(functionNode, context.scopes)) return false;
35788
- functionNode = findEnclosingFunction$1(functionNode);
34976
+ functionNode = findEnclosingFunction(functionNode);
35789
34977
  }
35790
34978
  return !isInsideInstanceField(node);
35791
34979
  };
@@ -35947,7 +35135,7 @@ const noIsMounted = defineRule({
35947
35135
  });
35948
35136
  //#endregion
35949
35137
  //#region src/plugin/rules/js-performance/no-json-parse-stringify-clone.ts
35950
- const MESSAGE$21 = "`JSON.parse(JSON.stringify(x))` deep-clones by re-serializing: it is slow on large objects and silently drops `undefined`, functions, `Date`/`Map`/`Set`, and cyclic references. Use `structuredClone(x)`.";
35138
+ const MESSAGE$20 = "`JSON.parse(JSON.stringify(x))` deep-clones by re-serializing: it is slow on large objects and silently drops `undefined`, functions, `Date`/`Map`/`Set`, and cyclic references. Use `structuredClone(x)`.";
35951
35139
  const isJsonMethodCall = (node, method) => {
35952
35140
  if (!isNodeOfType(node, "CallExpression")) return false;
35953
35141
  const callee = node.callee;
@@ -36011,13 +35199,13 @@ const noJsonParseStringifyClone = defineRule({
36011
35199
  if (isCatchParameterRoundTrip(firstArgument)) return;
36012
35200
  context.report({
36013
35201
  node,
36014
- message: MESSAGE$21
35202
+ message: MESSAGE$20
36015
35203
  });
36016
35204
  } })
36017
35205
  });
36018
35206
  //#endregion
36019
35207
  //#region src/plugin/rules/correctness/no-jsx-element-type.ts
36020
- const MESSAGE$20 = "`JSX.Element` is too narrow: it excludes `null`, strings, numbers, and fragments that components commonly return. Use `React.ReactNode` instead.";
35208
+ const MESSAGE$19 = "`JSX.Element` is too narrow: it excludes `null`, strings, numbers, and fragments that components commonly return. Use `React.ReactNode` instead.";
36021
35209
  const isJsxElementTypeReference = (node) => {
36022
35210
  if (!isNodeOfType(node, "TSTypeReference")) return false;
36023
35211
  const typeName = node.typeName;
@@ -36071,7 +35259,7 @@ const noJsxElementType = defineRule({
36071
35259
  if (isJsxImported) return;
36072
35260
  for (const typeAnnotation of flaggedAnnotations) context.report({
36073
35261
  node: typeAnnotation,
36074
- message: MESSAGE$20
35262
+ message: MESSAGE$19
36075
35263
  });
36076
35264
  }
36077
35265
  };
@@ -36303,221 +35491,6 @@ const noLegacyClassLifecycles = defineRule({
36303
35491
  }
36304
35492
  });
36305
35493
  //#endregion
36306
- //#region src/plugin/utils/is-proven-react-class-component.ts
36307
- const REACT_COMPONENT_CLASS_NAMES = new Set(["Component", "PureComponent"]);
36308
- const isReactComponentClassValue = (node, scopes, visitedClassNodes, visitedSymbolIds) => {
36309
- const expression = stripParenExpression(node);
36310
- if (isNodeOfType(expression, "MemberExpression")) {
36311
- const propertyName = getStaticPropertyName(expression);
36312
- const receiver = stripParenExpression(expression.object);
36313
- return Boolean(propertyName && REACT_COMPONENT_CLASS_NAMES.has(propertyName) && isNodeOfType(receiver, "Identifier") && !hasStaticPropertyWriteBefore(receiver, propertyName, expression, scopes) && isReactNamespaceImport(receiver, scopes));
36314
- }
36315
- if (isNodeOfType(expression, "ClassExpression")) return isProvenReactClassComponent(expression, scopes, visitedClassNodes, visitedSymbolIds);
36316
- if (!isNodeOfType(expression, "Identifier")) return false;
36317
- const symbol = scopes.symbolFor(expression);
36318
- if (!symbol || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, expression, scopes)) return false;
36319
- visitedSymbolIds.add(symbol.id);
36320
- if (isImportedFromReact(symbol)) {
36321
- const importedName = getImportedName(symbol.declarationNode);
36322
- return Boolean(importedName && REACT_COMPONENT_CLASS_NAMES.has(importedName));
36323
- }
36324
- if (isNodeOfType(symbol.declarationNode, "ClassDeclaration") || isNodeOfType(symbol.declarationNode, "ClassExpression")) return isProvenReactClassComponent(symbol.declarationNode, scopes, visitedClassNodes, visitedSymbolIds);
36325
- return Boolean(symbol.kind === "const" && symbol.initializer && isReactComponentClassValue(symbol.initializer, scopes, visitedClassNodes, visitedSymbolIds));
36326
- };
36327
- const isProvenReactClassComponent = (classNode, scopes, visitedClassNodes = /* @__PURE__ */ new Set(), visitedSymbolIds = /* @__PURE__ */ new Set()) => {
36328
- if (!isNodeOfType(classNode, "ClassDeclaration") && !isNodeOfType(classNode, "ClassExpression") || visitedClassNodes.has(classNode) || !classNode.superClass) return false;
36329
- visitedClassNodes.add(classNode);
36330
- return isReactComponentClassValue(classNode.superClass, scopes, visitedClassNodes, visitedSymbolIds);
36331
- };
36332
- //#endregion
36333
- //#region src/plugin/utils/function-contains-proven-react-hook-call.ts
36334
- const functionContainsProvenReactHookCall = (functionNode, scopes) => {
36335
- if (!isFunctionLike$2(functionNode)) return false;
36336
- let containsReactHookCall = false;
36337
- walkAst(functionNode.body, (node) => {
36338
- if (containsReactHookCall) return false;
36339
- if (node !== functionNode.body && (isFunctionLike$2(node) || isNodeOfType(node, "ClassDeclaration") || isNodeOfType(node, "ClassExpression"))) return false;
36340
- if (isNodeOfType(node, "CallExpression") && isReactApiCall(node, BUILTIN_HOOK_NAMES, scopes, { resolveNamedAliases: true })) {
36341
- containsReactHookCall = true;
36342
- return false;
36343
- }
36344
- });
36345
- return containsReactHookCall;
36346
- };
36347
- //#endregion
36348
- //#region src/plugin/utils/function-returns-props-children.ts
36349
- const functionReturnsPropsChildren = (functionNode, scopes, controlFlow) => {
36350
- if (!isFunctionLike$2(functionNode) || functionNode.params.length === 0) return false;
36351
- const firstParameter = stripParenExpression(functionNode.params[0]);
36352
- const firstParameterPattern = isNodeOfType(firstParameter, "AssignmentPattern") ? stripParenExpression(firstParameter.left) : firstParameter;
36353
- const propsParameterSymbol = isNodeOfType(firstParameterPattern, "Identifier") ? scopes.symbolFor(firstParameterPattern) : null;
36354
- const childrenBindingSymbolIds = /* @__PURE__ */ new Set();
36355
- if (isNodeOfType(firstParameterPattern, "ObjectPattern")) {
36356
- for (const property of firstParameterPattern.properties) if (isNodeOfType(property, "Property") && getStaticPropertyKeyName(property, { allowComputedString: true }) === "children") {
36357
- const propertyValue = stripParenExpression(property.value);
36358
- const childrenBinding = isNodeOfType(propertyValue, "AssignmentPattern") ? stripParenExpression(propertyValue.left) : propertyValue;
36359
- if (!isNodeOfType(childrenBinding, "Identifier")) continue;
36360
- const childrenBindingSymbol = scopes.symbolFor(childrenBinding);
36361
- if (childrenBindingSymbol) childrenBindingSymbolIds.add(childrenBindingSymbol.id);
36362
- }
36363
- }
36364
- return functionReturnsMatchingExpression(functionNode, scopes, (expression) => {
36365
- const candidate = stripParenExpression(expression);
36366
- if (isNodeOfType(candidate, "Identifier")) {
36367
- const symbol = scopes.symbolFor(candidate);
36368
- return Boolean(symbol && childrenBindingSymbolIds.has(symbol.id) && !hasSymbolWriteBefore(symbol, candidate, scopes));
36369
- }
36370
- if (!isNodeOfType(candidate, "MemberExpression")) return false;
36371
- if (getStaticPropertyName(candidate) !== "children") return false;
36372
- const receiver = stripParenExpression(candidate.object);
36373
- if (!isNodeOfType(receiver, "Identifier")) return false;
36374
- const receiverSymbol = scopes.symbolFor(receiver);
36375
- if (!receiverSymbol || !propsParameterSymbol) return false;
36376
- return receiverSymbol.id === propsParameterSymbol.id && !hasSymbolWriteBefore(receiverSymbol, candidate, scopes) && !hasStaticPropertyWriteBefore(receiver, "children", candidate, scopes);
36377
- }, controlFlow);
36378
- };
36379
- //#endregion
36380
- //#region src/plugin/utils/function-returns-only-null.ts
36381
- const isNullExpression = (expression) => {
36382
- const candidate = stripParenExpression(expression);
36383
- return isNodeOfType(candidate, "Literal") && candidate.value === null;
36384
- };
36385
- const functionReturnsOnlyNull = (functionNode) => {
36386
- if (!isFunctionLike$2(functionNode)) return false;
36387
- if (!isNodeOfType(functionNode.body, "BlockStatement")) return isNullExpression(functionNode.body);
36388
- const returnStatements = collectFunctionReturnStatements(functionNode);
36389
- return returnStatements.length > 0 && returnStatements.every((returnStatement) => Boolean(returnStatement.argument && isNullExpression(returnStatement.argument)));
36390
- };
36391
- //#endregion
36392
- //#region src/plugin/utils/is-proven-styled-component-expression.ts
36393
- const findFactoryRoot = (node) => {
36394
- const candidate = stripParenExpression(node);
36395
- if (isNodeOfType(candidate, "Identifier")) return candidate;
36396
- if (isNodeOfType(candidate, "MemberExpression")) return findFactoryRoot(candidate.object);
36397
- if (isNodeOfType(candidate, "CallExpression")) return findFactoryRoot(candidate.callee);
36398
- return null;
36399
- };
36400
- const findFactoryPropertyName = (node) => {
36401
- const candidate = stripParenExpression(node);
36402
- if (isNodeOfType(candidate, "MemberExpression")) return findFactoryPropertyName(candidate.object) ?? getStaticPropertyName(candidate);
36403
- if (isNodeOfType(candidate, "CallExpression")) return findFactoryPropertyName(candidate.callee);
36404
- return null;
36405
- };
36406
- const isProvenStyledComponentExpression = (expression, scopes) => {
36407
- const candidate = stripParenExpression(expression);
36408
- if (!isNodeOfType(candidate, "TaggedTemplateExpression")) return false;
36409
- const factoryRoot = findFactoryRoot(candidate.tag);
36410
- if (!factoryRoot) return false;
36411
- const factoryPropertyName = findFactoryPropertyName(candidate.tag);
36412
- if (factoryPropertyName && hasStaticPropertyWriteBefore(factoryRoot, factoryPropertyName, candidate, scopes)) return false;
36413
- const symbol = resolveConstIdentifierAlias(factoryRoot, scopes);
36414
- if (!symbol || symbol.kind !== "import") return false;
36415
- if (!(isNodeOfType(symbol.declarationNode, "ImportDefaultSpecifier") || getImportedName(symbol.declarationNode) === "styled")) return false;
36416
- const importDeclaration = symbol.declarationNode.parent;
36417
- return Boolean(importDeclaration && isNodeOfType(importDeclaration, "ImportDeclaration") && importDeclaration.source.value === "styled-components");
36418
- };
36419
- //#endregion
36420
- //#region src/plugin/utils/is-proven-react-component-symbol.ts
36421
- const REACT_COMPONENT_HOC_NAMES = new Set(["memo", "forwardRef"]);
36422
- const LEGACY_REACT_COMPONENT_FACTORY_NAMES = new Set(["createClass", "createReactClass"]);
36423
- const functionHasComponentEvidence = (functionNode, scopes, controlFlow) => functionContainsReactRenderOutput(functionNode, scopes, controlFlow) || functionReturnsPropsChildren(functionNode, scopes, controlFlow) || functionContainsProvenReactHookCall(functionNode, scopes) && functionReturnsOnlyNull(functionNode);
36424
- const isProvenReactComponentExpression = (expression, scopes, controlFlow, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
36425
- const candidate = stripParenExpression(expression);
36426
- if (isInlineFunctionExpression(candidate)) return functionHasComponentEvidence(candidate, scopes, controlFlow);
36427
- if (isNodeOfType(candidate, "ClassExpression")) return isProvenReactClassComponent(candidate, scopes);
36428
- if (isProvenStyledComponentExpression(candidate, scopes)) return true;
36429
- if (isNodeOfType(candidate, "Identifier")) {
36430
- const symbol = scopes.symbolFor(candidate);
36431
- if (!symbol || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, candidate, scopes)) return false;
36432
- visitedSymbolIds.add(symbol.id);
36433
- if (isNodeOfType(symbol.declarationNode, "FunctionDeclaration")) return functionHasComponentEvidence(symbol.declarationNode, scopes, controlFlow);
36434
- if (isNodeOfType(symbol.declarationNode, "ClassDeclaration") || isNodeOfType(symbol.declarationNode, "ClassExpression")) return isProvenReactClassComponent(symbol.declarationNode, scopes);
36435
- return Boolean(symbol.initializer && isProvenReactComponentExpression(symbol.initializer, scopes, controlFlow, visitedSymbolIds));
36436
- }
36437
- if (!isNodeOfType(candidate, "CallExpression")) return false;
36438
- if (!hasStableCallTarget(candidate, scopes)) return false;
36439
- const factoryCallee = stripParenExpression(candidate.callee);
36440
- if (isNodeOfType(factoryCallee, "Identifier") && isDefaultImportFromModule(factoryCallee, factoryCallee.name, "create-react-class") || isReactApiCall(candidate, LEGACY_REACT_COMPONENT_FACTORY_NAMES, scopes)) return true;
36441
- if (isReactApiCall(candidate, REACT_COMPONENT_HOC_NAMES, scopes, { resolveNamedAliases: true })) {
36442
- const wrappedComponent = candidate.arguments[0];
36443
- return Boolean(wrappedComponent && !isNodeOfType(wrappedComponent, "SpreadElement") && isProvenReactComponentExpression(wrappedComponent, scopes, controlFlow, visitedSymbolIds));
36444
- }
36445
- if (!isReactApiCall(candidate, "useMemo", scopes, { resolveNamedAliases: true })) return false;
36446
- const factory = candidate.arguments[0];
36447
- if (!factory || isNodeOfType(factory, "SpreadElement")) return false;
36448
- const unwrappedFactory = stripParenExpression(factory);
36449
- if (!isInlineFunctionExpression(unwrappedFactory)) return false;
36450
- if (!isNodeOfType(unwrappedFactory.body, "BlockStatement")) return isProvenReactComponentExpression(unwrappedFactory.body, scopes, controlFlow, visitedSymbolIds);
36451
- const returnStatements = collectFunctionReturnStatements(unwrappedFactory);
36452
- const returnedExpression = returnStatements[0]?.argument;
36453
- return Boolean(returnStatements.length === 1 && returnedExpression && isProvenReactComponentExpression(returnedExpression, scopes, controlFlow, visitedSymbolIds));
36454
- };
36455
- const isProvenReactComponentSymbol = (symbol, scopes, controlFlow, componentReference) => {
36456
- const candidateSymbols = symbol.kind === "ts-module" ? symbol.scope.symbols.filter((candidateSymbol) => candidateSymbol.name === symbol.name && candidateSymbol.kind !== "ts-module") : [symbol];
36457
- for (const candidateSymbol of candidateSymbols) {
36458
- if (hasSymbolWriteBefore(candidateSymbol, componentReference, scopes)) continue;
36459
- if (isComponentDeclaration(candidateSymbol.declarationNode)) {
36460
- if (functionHasComponentEvidence(candidateSymbol.declarationNode, scopes, controlFlow)) return true;
36461
- continue;
36462
- }
36463
- const initializer = candidateSymbol.initializer ? stripParenExpression(candidateSymbol.initializer) : null;
36464
- if (isNodeOfType(candidateSymbol.declarationNode, "VariableDeclarator") && isNodeOfType(candidateSymbol.declarationNode.id, "Identifier") && isUppercaseName(candidateSymbol.declarationNode.id.name) && initializer) {
36465
- if (isProvenReactComponentExpression(initializer, scopes, controlFlow)) return true;
36466
- continue;
36467
- }
36468
- if (isNodeOfType(candidateSymbol.declarationNode, "ClassDeclaration") || isNodeOfType(candidateSymbol.declarationNode, "ClassExpression")) {
36469
- if (isProvenReactClassComponent(candidateSymbol.declarationNode, scopes)) return true;
36470
- continue;
36471
- }
36472
- if (initializer && isNodeOfType(initializer, "ClassExpression") && isProvenReactClassComponent(initializer, scopes)) return true;
36473
- }
36474
- return false;
36475
- };
36476
- //#endregion
36477
- //#region src/plugin/utils/symbol-has-react-component-type-annotation.ts
36478
- const REACT_COMPONENT_TYPE_NAMES = new Set([
36479
- "ComponentClass",
36480
- "ComponentType",
36481
- "FC",
36482
- "FunctionComponent"
36483
- ]);
36484
- const findVisibleSymbol = (identifier, scopes) => {
36485
- if (!isNodeOfType(identifier, "Identifier")) return null;
36486
- let scope = scopes.scopeFor(identifier);
36487
- while (true) {
36488
- const symbol = scope.symbolsByName.get(identifier.name);
36489
- if (symbol) return symbol;
36490
- if (!scope.parent) return null;
36491
- scope = scope.parent;
36492
- }
36493
- };
36494
- const isReactNamespaceType = (identifier, scopes) => {
36495
- const symbol = findVisibleSymbol(identifier, scopes);
36496
- return Boolean(symbol && isImportedFromReact(symbol) && (isNodeOfType(symbol.declarationNode, "ImportDefaultSpecifier") || isNodeOfType(symbol.declarationNode, "ImportNamespaceSpecifier")));
36497
- };
36498
- const isReactComponentType = (typeNode, scopes, visitedSymbolIds) => {
36499
- if (!typeNode) return false;
36500
- if (isNodeOfType(typeNode, "TSTypeAnnotation")) return isReactComponentType(typeNode.typeAnnotation, scopes, visitedSymbolIds);
36501
- if (isNodeOfType(typeNode, "TSIntersectionType")) return (typeNode.types ?? []).some((member) => isReactComponentType(member, scopes, visitedSymbolIds));
36502
- if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
36503
- const typeName = typeNode.typeName;
36504
- if (isNodeOfType(typeName, "TSQualifiedName")) return isNodeOfType(typeName.left, "Identifier") && isNodeOfType(typeName.right, "Identifier") && REACT_COMPONENT_TYPE_NAMES.has(typeName.right.name) && isReactNamespaceType(typeName.left, scopes);
36505
- if (!isNodeOfType(typeName, "Identifier")) return false;
36506
- const typeSymbol = findVisibleSymbol(typeName, scopes);
36507
- if (!typeSymbol || visitedSymbolIds.has(typeSymbol.id)) return false;
36508
- if (isImportedFromReact(typeSymbol)) {
36509
- const importedName = getImportedName(typeSymbol.declarationNode);
36510
- return Boolean(importedName && REACT_COMPONENT_TYPE_NAMES.has(importedName));
36511
- }
36512
- if (!isNodeOfType(typeSymbol.declarationNode, "TSTypeAliasDeclaration")) return false;
36513
- visitedSymbolIds.add(typeSymbol.id);
36514
- return isReactComponentType(typeSymbol.declarationNode.typeAnnotation, scopes, visitedSymbolIds);
36515
- };
36516
- const symbolHasReactComponentTypeAnnotation = (symbol, scopes) => {
36517
- const bindingIdentifier = symbol.bindingIdentifier;
36518
- return isNodeOfType(bindingIdentifier, "Identifier") && isReactComponentType(bindingIdentifier.typeAnnotation, scopes, /* @__PURE__ */ new Set());
36519
- };
36520
- //#endregion
36521
35494
  //#region src/plugin/rules/architecture/no-legacy-context-api.ts
36522
35495
  const LEGACY_CONTEXT_NAMES = new Set([
36523
35496
  "childContextTypes",
@@ -36528,6 +35501,15 @@ const buildLegacyContextMessage = (memberName) => {
36528
35501
  if (memberName === "childContextTypes" || memberName === "getChildContext") return `${memberName} uses the old context API that React 19 removes, so your provider stops passing data. Switch to \`createContext\` with \`<MyContext.Provider value={...}>\` & read it with \`useContext()\`, moving every consumer together.`;
36529
35502
  return "contextTypes uses the old context API that React 19 removes, so your component stops receiving context. Use `static contextType = MyContext` or `useContext()` in a function component, & update the provider too.";
36530
35503
  };
35504
+ const isInsideClassBody = (node) => {
35505
+ let current = node.parent;
35506
+ while (current) {
35507
+ if (isNodeOfType(current, "ClassBody")) return true;
35508
+ if (isFunctionLike$2(current)) return false;
35509
+ current = current.parent;
35510
+ }
35511
+ return false;
35512
+ };
36531
35513
  const noLegacyContextApi = defineRule({
36532
35514
  id: "no-legacy-context-api",
36533
35515
  title: "Legacy context API",
@@ -36542,7 +35524,6 @@ const noLegacyContextApi = defineRule({
36542
35524
  if (!isNodeOfType(memberNode, "MethodDefinition") && !isNodeOfType(memberNode, "PropertyDefinition")) return;
36543
35525
  if (!isNodeOfType(memberNode.key, "Identifier")) return;
36544
35526
  if (!LEGACY_CONTEXT_NAMES.has(memberNode.key.name)) return;
36545
- if (memberNode.key.name === "getChildContext" ? memberNode.static : !memberNode.static) return;
36546
35527
  context.report({
36547
35528
  node: memberNode.key,
36548
35529
  message: buildLegacyContextMessage(memberNode.key.name)
@@ -36550,8 +35531,6 @@ const noLegacyContextApi = defineRule({
36550
35531
  };
36551
35532
  return {
36552
35533
  ClassBody(node) {
36553
- const classNode = node.parent;
36554
- if (!classNode || !isProvenReactClassComponent(classNode, context.scopes)) return;
36555
35534
  for (const member of node.body ?? []) checkMember(member);
36556
35535
  },
36557
35536
  AssignmentExpression(node) {
@@ -36561,11 +35540,9 @@ const noLegacyContextApi = defineRule({
36561
35540
  if (left.computed) return;
36562
35541
  if (!isNodeOfType(left.property, "Identifier")) return;
36563
35542
  if (!LEGACY_CONTEXT_NAMES.has(left.property.name)) return;
36564
- if (left.property.name === "getChildContext") return;
36565
- const component = stripParenExpression(left.object);
36566
- if (!isNodeOfType(component, "Identifier")) return;
36567
- const symbol = context.scopes.symbolFor(component);
36568
- if (!symbol || !isProvenReactComponentSymbol(symbol, context.scopes, context.cfg, component) && (hasSymbolWriteBefore(symbol, component, context.scopes) || !symbolHasReactComponentTypeAnnotation(symbol, context.scopes))) return;
35543
+ if (!isNodeOfType(left.object, "Identifier")) return;
35544
+ if (!isUppercaseName(left.object.name)) return;
35545
+ if (isInsideClassBody(node)) return;
36569
35546
  context.report({
36570
35547
  node: left,
36571
35548
  message: buildLegacyContextMessage(left.property.name)
@@ -36769,10 +35746,10 @@ const getMethodCalls = (functionNode, scopes) => {
36769
35746
  const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, scopes, visitedSymbolIds, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
36770
35747
  if (visitedFunctionNodes.has(functionNode)) return false;
36771
35748
  visitedFunctionNodes.add(functionNode);
36772
- const usageFunction = findEnclosingFunction$1(usageNode);
35749
+ const usageFunction = findEnclosingFunction(usageNode);
36773
35750
  const immediateCall = getDirectCallForExpression(functionNode);
36774
35751
  if (immediateCall) {
36775
- const immediateCallFunction = findEnclosingFunction$1(immediateCall);
35752
+ const immediateCallFunction = findEnclosingFunction(immediateCall);
36776
35753
  if (immediateCallFunction === usageFunction) {
36777
35754
  const immediateCallStart = getRangeStart(immediateCall);
36778
35755
  return immediateCallStart === null || immediateCallStart < usageBoundary;
@@ -36781,7 +35758,7 @@ const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, sc
36781
35758
  return isFunctionInvokedBeforeUsage(immediateCallFunction, usageNode, usageBoundary, scopes, visitedSymbolIds, new Set(visitedFunctionNodes));
36782
35759
  }
36783
35760
  for (const methodCall of getMethodCalls(functionNode, scopes)) {
36784
- const methodCallFunction = findEnclosingFunction$1(methodCall);
35761
+ const methodCallFunction = findEnclosingFunction(methodCall);
36785
35762
  if (methodCallFunction === usageFunction) {
36786
35763
  const methodCallStart = getRangeStart(methodCall);
36787
35764
  if (methodCallStart === null || methodCallStart < usageBoundary) return true;
@@ -36804,7 +35781,7 @@ const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, sc
36804
35781
  if (scopes.symbolFor(child)?.declarationNode !== symbol.declarationNode) return;
36805
35782
  const call = getDirectCallForExpression(child);
36806
35783
  if (!call) return false;
36807
- const callFunction = findEnclosingFunction$1(call);
35784
+ const callFunction = findEnclosingFunction(call);
36808
35785
  if (callFunction === usageFunction) {
36809
35786
  const callStart = getRangeStart(call);
36810
35787
  wasInvokedBeforeUsage = callStart === null || callStart < usageBoundary;
@@ -36835,14 +35812,14 @@ const wasMutatedBeforeUsage = (symbol, usageNode, readNode, scopes, visitedMutat
36835
35812
  visitedMutationSymbolIds.add(symbol.id);
36836
35813
  const usageBoundary = inheritedUsageBoundary === void 0 ? getMutationUsageBoundary(usageNode, readNode) : inheritedUsageBoundary;
36837
35814
  if (typeof usageBoundary !== "number") return true;
36838
- const usageFunction = findEnclosingFunction$1(usageNode);
35815
+ const usageFunction = findEnclosingFunction(usageNode);
36839
35816
  return symbol.references.some((reference) => {
36840
35817
  const referenceStart = getRangeStart(reference.identifier);
36841
35818
  const simpleAlias = getSimpleAlias(reference.identifier, scopes);
36842
35819
  if (simpleAlias) return wasMutatedBeforeUsage(simpleAlias.symbol, usageNode, readNodesBySymbolId.get(simpleAlias.symbol.id) ?? simpleAlias.readNode, scopes, new Set(visitedMutationSymbolIds), usageBoundary, readNodesBySymbolId);
36843
35820
  if (!isPotentialMutationReference(reference.identifier, readNode)) return false;
36844
35821
  if (referenceStart === null) return true;
36845
- const mutationFunction = findEnclosingFunction$1(reference.identifier);
35822
+ const mutationFunction = findEnclosingFunction(reference.identifier);
36846
35823
  if (mutationFunction === usageFunction) return referenceStart < usageBoundary;
36847
35824
  if (!mutationFunction) return usageFunction !== null;
36848
35825
  if (usageFunction && isAstDescendant(usageFunction, mutationFunction)) return true;
@@ -37387,7 +36364,7 @@ const noMoment = defineRule({
37387
36364
  });
37388
36365
  //#endregion
37389
36366
  //#region src/plugin/rules/react-builtins/no-multi-comp.ts
37390
- const MESSAGE$19 = "This file declares several components, so each component is harder to find, test, and change.";
36367
+ const MESSAGE$18 = "This file declares several components, so each component is harder to find, test, and change.";
37391
36368
  const resolveSettings$16 = (settings) => {
37392
36369
  const reactDoctor = settings?.["react-doctor"];
37393
36370
  return { ignoreStateless: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noMultiComp ?? {} : {}).ignoreStateless ?? false };
@@ -37424,6 +36401,13 @@ const isReactNamespaceExpression = (node, scopes) => {
37424
36401
  return isReactNamespaceImport(node, scopes);
37425
36402
  };
37426
36403
  const isReactHocMemberReference = (node, scopes) => Boolean(isNodeOfType(node, "MemberExpression") && !node.computed && isNodeOfType(node.property, "Identifier") && REACT_HOC_NAMES.has(node.property.name) && isReactNamespaceExpression(node.object, scopes));
36404
+ const getDestructuredPropertyName$1 = (symbol) => {
36405
+ const property = symbol.bindingIdentifier.parent;
36406
+ if (!property || !isNodeOfType(property, "Property") || !property.parent || !isNodeOfType(property.parent, "ObjectPattern")) return null;
36407
+ if (isNodeOfType(property.key, "Identifier") && !property.computed) return property.key.name;
36408
+ if (isNodeOfType(property.key, "Literal") && typeof property.key.value === "string") return property.key.value;
36409
+ return null;
36410
+ };
37427
36411
  const symbolMapsToHoc = (symbol, scopes, visitedSymbolIds) => {
37428
36412
  if (visitedSymbolIds.has(symbol.id)) return false;
37429
36413
  visitedSymbolIds.add(symbol.id);
@@ -37433,7 +36417,7 @@ const symbolMapsToHoc = (symbol, scopes, visitedSymbolIds) => {
37433
36417
  }
37434
36418
  const init = symbol.initializer;
37435
36419
  if (!init) return false;
37436
- const destructuredPropertyName = getDestructuredBindingPropertyName(symbol.bindingIdentifier);
36420
+ const destructuredPropertyName = getDestructuredPropertyName$1(symbol);
37437
36421
  if (destructuredPropertyName && REACT_HOC_NAMES.has(destructuredPropertyName) && isReactNamespaceExpression(init, scopes)) return true;
37438
36422
  if (isReactHocMemberReference(init, scopes)) return true;
37439
36423
  if (isNodeOfType(init, "Identifier")) {
@@ -37739,7 +36723,7 @@ const noMultiComp = defineRule({
37739
36723
  if (isSmallFeatureModule || isLargeFeatureModule || isVeryLargeFeatureModule) return;
37740
36724
  for (const component of flagged.slice(1)) context.report({
37741
36725
  node: component.reportNode,
37742
- message: MESSAGE$19
36726
+ message: MESSAGE$18
37743
36727
  });
37744
36728
  } };
37745
36729
  }
@@ -37952,7 +36936,7 @@ const resolveReducerFunction = (node, currentFilename) => {
37952
36936
  };
37953
36937
  //#endregion
37954
36938
  //#region src/plugin/rules/state-and-effects/no-mutating-reducer-state.ts
37955
- const MESSAGE$18 = "This reducer changes state in place, so your update is silently skipped.";
36939
+ const MESSAGE$17 = "This reducer changes state in place, so your update is silently skipped.";
37956
36940
  const SAME_REFERENCE_ARRAY_RETURN_METHODS = new Set([
37957
36941
  "copyWithin",
37958
36942
  "fill",
@@ -38161,7 +37145,7 @@ const analyzeReactUseReducerFunctionForStateMutation = (context, functionNode, r
38161
37145
  reportedNodes.add(options.crossFileConsumerCallSite);
38162
37146
  context.report({
38163
37147
  node: options.crossFileConsumerCallSite,
38164
- message: `${MESSAGE$18} (mutation in imported reducer at \`${options.crossFileSourceDisplay}\`)`
37148
+ message: `${MESSAGE$17} (mutation in imported reducer at \`${options.crossFileSourceDisplay}\`)`
38165
37149
  });
38166
37150
  return;
38167
37151
  }
@@ -38170,7 +37154,7 @@ const analyzeReactUseReducerFunctionForStateMutation = (context, functionNode, r
38170
37154
  reportedNodes.add(mutation.node);
38171
37155
  context.report({
38172
37156
  node: mutation.node,
38173
- message: MESSAGE$18
37157
+ message: MESSAGE$17
38174
37158
  });
38175
37159
  }
38176
37160
  };
@@ -38577,7 +37561,7 @@ const noNoninteractiveElementToInteractiveRole = defineRule({
38577
37561
  });
38578
37562
  //#endregion
38579
37563
  //#region src/plugin/rules/a11y/no-noninteractive-tabindex.ts
38580
- const MESSAGE$17 = "Keyboard users get stuck focusing this element they can't act on because `tabIndex` makes it tabbable, so remove it.";
37564
+ const MESSAGE$16 = "Keyboard users get stuck focusing this element they can't act on because `tabIndex` makes it tabbable, so remove it.";
38581
37565
  const KEYBOARD_HANDLER_PROP_NAMES = [
38582
37566
  "onKeyDown",
38583
37567
  "onKeyUp",
@@ -38696,7 +37680,7 @@ const noNoninteractiveTabindex = defineRule({
38696
37680
  if (numeric === null) {
38697
37681
  if (isNodeOfType(tabIndexValue, "JSXExpressionContainer") && !settings.allowExpressionValues && !isKeyboardOperable(node) && !isFocusOperable(node) && !hasJsxSpreadAttribute$1(node.attributes)) context.report({
38698
37682
  node: tabIndex,
38699
- message: MESSAGE$17
37683
+ message: MESSAGE$16
38700
37684
  });
38701
37685
  return;
38702
37686
  }
@@ -38718,7 +37702,7 @@ const noNoninteractiveTabindex = defineRule({
38718
37702
  if (!roleAttribute) {
38719
37703
  context.report({
38720
37704
  node: tabIndex,
38721
- message: MESSAGE$17
37705
+ message: MESSAGE$16
38722
37706
  });
38723
37707
  return;
38724
37708
  }
@@ -38732,7 +37716,7 @@ const noNoninteractiveTabindex = defineRule({
38732
37716
  }
38733
37717
  context.report({
38734
37718
  node: tabIndex,
38735
- message: MESSAGE$17
37719
+ message: MESSAGE$16
38736
37720
  });
38737
37721
  } };
38738
37722
  }
@@ -39187,6 +38171,12 @@ const getDeclarationKind = (declarator) => {
39187
38171
  return declaration && isNodeOfType(declaration, "VariableDeclaration") ? declaration.kind : null;
39188
38172
  };
39189
38173
  const hasMutableBindingWrite = (reference) => Boolean(reference.resolved?.references.some((candidateReference) => candidateReference.isWrite() && !candidateReference.init));
38174
+ const getDestructuredPropertyName = (bindingIdentifier) => {
38175
+ const property = bindingIdentifier.parent;
38176
+ if (!property || !isNodeOfType(property, "Property")) return null;
38177
+ if (property.computed) return isNodeOfType(property.key, "Literal") && typeof property.key.value === "string" ? String(property.key.value) : null;
38178
+ return isNodeOfType(property.key, "Identifier") ? property.key.name : null;
38179
+ };
39190
38180
  const getParentCallbackPropName = (analysis, expression, visitedVariables = /* @__PURE__ */ new Set()) => {
39191
38181
  const unwrappedExpression = stripParenExpression(expression);
39192
38182
  if (isNodeOfType(unwrappedExpression, "Identifier")) {
@@ -39196,7 +38186,7 @@ const getParentCallbackPropName = (analysis, expression, visitedVariables = /* @
39196
38186
  if (isProp(analysis, callbackReference)) {
39197
38187
  if (isWholePropsObjectReference(analysis, callbackReference)) return null;
39198
38188
  const bindingIdentifier = callbackVariable.defs.find((definition) => definition.type === "Parameter")?.name;
39199
- return (bindingIdentifier && getDestructuredBindingPropertyName(bindingIdentifier)) ?? unwrappedExpression.name;
38189
+ return (bindingIdentifier && getDestructuredPropertyName(bindingIdentifier)) ?? unwrappedExpression.name;
39200
38190
  }
39201
38191
  if (hasMutableBindingWrite(callbackReference)) return null;
39202
38192
  const definitions = callbackVariable.defs.map((definition) => definition.node).filter((definitionNode) => isNodeOfType(definitionNode, "VariableDeclarator"));
@@ -39206,7 +38196,7 @@ const getParentCallbackPropName = (analysis, expression, visitedVariables = /* @
39206
38196
  visitedVariables.add(callbackVariable);
39207
38197
  if (isNodeOfType(declarator.id, "ObjectPattern")) {
39208
38198
  const bindingIdentifier = callbackVariable.defs[0]?.name;
39209
- const propertyName = bindingIdentifier ? getDestructuredBindingPropertyName(bindingIdentifier) : null;
38199
+ const propertyName = bindingIdentifier ? getDestructuredPropertyName(bindingIdentifier) : null;
39210
38200
  const propsReference = getDownstreamRefs(analysis, declarator.init).find((candidateReference) => isWholePropsObjectReference(analysis, candidateReference));
39211
38201
  return propertyName && propsReference ? propertyName : null;
39212
38202
  }
@@ -39309,7 +38299,7 @@ const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactU
39309
38299
  const bindingProvenance = getRefBindingProvenance(analysis, stripParenExpression(callee.object), isReactUseRefCall);
39310
38300
  if (!bindingProvenance) return null;
39311
38301
  const { refCall, variables } = bindingProvenance;
39312
- const componentFunction = findEnclosingFunction$1(effectCall);
38302
+ const componentFunction = findEnclosingFunction(effectCall);
39313
38303
  if (!componentFunction || !isFunctionLike$2(componentFunction) || !isComponentFunction$1(componentFunction) || !isNodeOfType(componentFunction.body, "BlockStatement")) return null;
39314
38304
  if (!getDirectComponentBodyStatement(effectCall, componentFunction.body)) return null;
39315
38305
  const callbackPropNames = /* @__PURE__ */ new Set();
@@ -40145,6 +39135,174 @@ const noPropCallbackInRender = defineRule({
40145
39135
  } })
40146
39136
  });
40147
39137
  //#endregion
39138
+ //#region src/plugin/utils/is-proven-react-class-component.ts
39139
+ const REACT_COMPONENT_CLASS_NAMES = new Set(["Component", "PureComponent"]);
39140
+ const isReactComponentClassValue = (node, scopes, visitedClassNodes, visitedSymbolIds) => {
39141
+ const expression = stripParenExpression(node);
39142
+ if (isNodeOfType(expression, "MemberExpression")) {
39143
+ const propertyName = getStaticPropertyName(expression);
39144
+ const receiver = stripParenExpression(expression.object);
39145
+ return Boolean(propertyName && REACT_COMPONENT_CLASS_NAMES.has(propertyName) && isNodeOfType(receiver, "Identifier") && !hasStaticPropertyWriteBefore(receiver, propertyName, expression, scopes) && isReactNamespaceImport(receiver, scopes));
39146
+ }
39147
+ if (isNodeOfType(expression, "ClassExpression")) return isProvenReactClassComponent(expression, scopes, visitedClassNodes, visitedSymbolIds);
39148
+ if (!isNodeOfType(expression, "Identifier")) return false;
39149
+ const symbol = scopes.symbolFor(expression);
39150
+ if (!symbol || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, expression, scopes)) return false;
39151
+ visitedSymbolIds.add(symbol.id);
39152
+ if (isImportedFromReact(symbol)) {
39153
+ const importedName = getImportedName(symbol.declarationNode);
39154
+ return Boolean(importedName && REACT_COMPONENT_CLASS_NAMES.has(importedName));
39155
+ }
39156
+ if (isNodeOfType(symbol.declarationNode, "ClassDeclaration") || isNodeOfType(symbol.declarationNode, "ClassExpression")) return isProvenReactClassComponent(symbol.declarationNode, scopes, visitedClassNodes, visitedSymbolIds);
39157
+ return Boolean(symbol.kind === "const" && symbol.initializer && isReactComponentClassValue(symbol.initializer, scopes, visitedClassNodes, visitedSymbolIds));
39158
+ };
39159
+ const isProvenReactClassComponent = (classNode, scopes, visitedClassNodes = /* @__PURE__ */ new Set(), visitedSymbolIds = /* @__PURE__ */ new Set()) => {
39160
+ if (!isNodeOfType(classNode, "ClassDeclaration") && !isNodeOfType(classNode, "ClassExpression") || visitedClassNodes.has(classNode) || !classNode.superClass) return false;
39161
+ visitedClassNodes.add(classNode);
39162
+ return isReactComponentClassValue(classNode.superClass, scopes, visitedClassNodes, visitedSymbolIds);
39163
+ };
39164
+ //#endregion
39165
+ //#region src/plugin/utils/function-contains-proven-react-hook-call.ts
39166
+ const functionContainsProvenReactHookCall = (functionNode, scopes) => {
39167
+ if (!isFunctionLike$2(functionNode)) return false;
39168
+ let containsReactHookCall = false;
39169
+ walkAst(functionNode.body, (node) => {
39170
+ if (containsReactHookCall) return false;
39171
+ if (node !== functionNode.body && (isFunctionLike$2(node) || isNodeOfType(node, "ClassDeclaration") || isNodeOfType(node, "ClassExpression"))) return false;
39172
+ if (isNodeOfType(node, "CallExpression") && isReactApiCall(node, BUILTIN_HOOK_NAMES, scopes, { resolveNamedAliases: true })) {
39173
+ containsReactHookCall = true;
39174
+ return false;
39175
+ }
39176
+ });
39177
+ return containsReactHookCall;
39178
+ };
39179
+ //#endregion
39180
+ //#region src/plugin/utils/function-returns-props-children.ts
39181
+ const functionReturnsPropsChildren = (functionNode, scopes, controlFlow) => {
39182
+ if (!isFunctionLike$2(functionNode) || functionNode.params.length === 0) return false;
39183
+ const firstParameter = stripParenExpression(functionNode.params[0]);
39184
+ const firstParameterPattern = isNodeOfType(firstParameter, "AssignmentPattern") ? stripParenExpression(firstParameter.left) : firstParameter;
39185
+ const propsParameterSymbol = isNodeOfType(firstParameterPattern, "Identifier") ? scopes.symbolFor(firstParameterPattern) : null;
39186
+ const childrenBindingSymbolIds = /* @__PURE__ */ new Set();
39187
+ if (isNodeOfType(firstParameterPattern, "ObjectPattern")) {
39188
+ for (const property of firstParameterPattern.properties) if (isNodeOfType(property, "Property") && getStaticPropertyKeyName(property, { allowComputedString: true }) === "children") {
39189
+ const propertyValue = stripParenExpression(property.value);
39190
+ const childrenBinding = isNodeOfType(propertyValue, "AssignmentPattern") ? stripParenExpression(propertyValue.left) : propertyValue;
39191
+ if (!isNodeOfType(childrenBinding, "Identifier")) continue;
39192
+ const childrenBindingSymbol = scopes.symbolFor(childrenBinding);
39193
+ if (childrenBindingSymbol) childrenBindingSymbolIds.add(childrenBindingSymbol.id);
39194
+ }
39195
+ }
39196
+ return functionReturnsMatchingExpression(functionNode, scopes, (expression) => {
39197
+ const candidate = stripParenExpression(expression);
39198
+ if (isNodeOfType(candidate, "Identifier")) {
39199
+ const symbol = scopes.symbolFor(candidate);
39200
+ return Boolean(symbol && childrenBindingSymbolIds.has(symbol.id) && !hasSymbolWriteBefore(symbol, candidate, scopes));
39201
+ }
39202
+ if (!isNodeOfType(candidate, "MemberExpression")) return false;
39203
+ if (getStaticPropertyName(candidate) !== "children") return false;
39204
+ const receiver = stripParenExpression(candidate.object);
39205
+ if (!isNodeOfType(receiver, "Identifier")) return false;
39206
+ const receiverSymbol = scopes.symbolFor(receiver);
39207
+ if (!receiverSymbol || !propsParameterSymbol) return false;
39208
+ return receiverSymbol.id === propsParameterSymbol.id && !hasSymbolWriteBefore(receiverSymbol, candidate, scopes) && !hasStaticPropertyWriteBefore(receiver, "children", candidate, scopes);
39209
+ }, controlFlow);
39210
+ };
39211
+ //#endregion
39212
+ //#region src/plugin/utils/function-returns-only-null.ts
39213
+ const isNullExpression = (expression) => {
39214
+ const candidate = stripParenExpression(expression);
39215
+ return isNodeOfType(candidate, "Literal") && candidate.value === null;
39216
+ };
39217
+ const functionReturnsOnlyNull = (functionNode) => {
39218
+ if (!isFunctionLike$2(functionNode)) return false;
39219
+ if (!isNodeOfType(functionNode.body, "BlockStatement")) return isNullExpression(functionNode.body);
39220
+ const returnStatements = collectFunctionReturnStatements(functionNode);
39221
+ return returnStatements.length > 0 && returnStatements.every((returnStatement) => Boolean(returnStatement.argument && isNullExpression(returnStatement.argument)));
39222
+ };
39223
+ //#endregion
39224
+ //#region src/plugin/utils/is-proven-styled-component-expression.ts
39225
+ const findFactoryRoot = (node) => {
39226
+ const candidate = stripParenExpression(node);
39227
+ if (isNodeOfType(candidate, "Identifier")) return candidate;
39228
+ if (isNodeOfType(candidate, "MemberExpression")) return findFactoryRoot(candidate.object);
39229
+ if (isNodeOfType(candidate, "CallExpression")) return findFactoryRoot(candidate.callee);
39230
+ return null;
39231
+ };
39232
+ const findFactoryPropertyName = (node) => {
39233
+ const candidate = stripParenExpression(node);
39234
+ if (isNodeOfType(candidate, "MemberExpression")) return findFactoryPropertyName(candidate.object) ?? getStaticPropertyName(candidate);
39235
+ if (isNodeOfType(candidate, "CallExpression")) return findFactoryPropertyName(candidate.callee);
39236
+ return null;
39237
+ };
39238
+ const isProvenStyledComponentExpression = (expression, scopes) => {
39239
+ const candidate = stripParenExpression(expression);
39240
+ if (!isNodeOfType(candidate, "TaggedTemplateExpression")) return false;
39241
+ const factoryRoot = findFactoryRoot(candidate.tag);
39242
+ if (!factoryRoot) return false;
39243
+ const factoryPropertyName = findFactoryPropertyName(candidate.tag);
39244
+ if (factoryPropertyName && hasStaticPropertyWriteBefore(factoryRoot, factoryPropertyName, candidate, scopes)) return false;
39245
+ const symbol = resolveConstIdentifierAlias(factoryRoot, scopes);
39246
+ if (!symbol || symbol.kind !== "import") return false;
39247
+ if (!(isNodeOfType(symbol.declarationNode, "ImportDefaultSpecifier") || getImportedName(symbol.declarationNode) === "styled")) return false;
39248
+ const importDeclaration = symbol.declarationNode.parent;
39249
+ return Boolean(importDeclaration && isNodeOfType(importDeclaration, "ImportDeclaration") && importDeclaration.source.value === "styled-components");
39250
+ };
39251
+ //#endregion
39252
+ //#region src/plugin/utils/is-proven-react-component-symbol.ts
39253
+ const REACT_COMPONENT_HOC_NAMES = new Set(["memo", "forwardRef"]);
39254
+ const functionHasComponentEvidence = (functionNode, scopes, controlFlow) => functionContainsReactRenderOutput(functionNode, scopes, controlFlow) || functionReturnsPropsChildren(functionNode, scopes, controlFlow) || functionContainsProvenReactHookCall(functionNode, scopes) && functionReturnsOnlyNull(functionNode);
39255
+ const isProvenReactComponentExpression = (expression, scopes, controlFlow, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
39256
+ const candidate = stripParenExpression(expression);
39257
+ if (isInlineFunctionExpression(candidate)) return functionHasComponentEvidence(candidate, scopes, controlFlow);
39258
+ if (isNodeOfType(candidate, "ClassExpression")) return isProvenReactClassComponent(candidate, scopes);
39259
+ if (isProvenStyledComponentExpression(candidate, scopes)) return true;
39260
+ if (isNodeOfType(candidate, "Identifier")) {
39261
+ const symbol = scopes.symbolFor(candidate);
39262
+ if (!symbol || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, candidate, scopes)) return false;
39263
+ visitedSymbolIds.add(symbol.id);
39264
+ if (isNodeOfType(symbol.declarationNode, "FunctionDeclaration")) return functionHasComponentEvidence(symbol.declarationNode, scopes, controlFlow);
39265
+ if (isNodeOfType(symbol.declarationNode, "ClassDeclaration") || isNodeOfType(symbol.declarationNode, "ClassExpression")) return isProvenReactClassComponent(symbol.declarationNode, scopes);
39266
+ return Boolean(symbol.initializer && isProvenReactComponentExpression(symbol.initializer, scopes, controlFlow, visitedSymbolIds));
39267
+ }
39268
+ if (!isNodeOfType(candidate, "CallExpression")) return false;
39269
+ if (!hasStableCallTarget(candidate, scopes)) return false;
39270
+ if (isReactApiCall(candidate, REACT_COMPONENT_HOC_NAMES, scopes, { resolveNamedAliases: true })) {
39271
+ const wrappedComponent = candidate.arguments[0];
39272
+ return Boolean(wrappedComponent && !isNodeOfType(wrappedComponent, "SpreadElement") && isProvenReactComponentExpression(wrappedComponent, scopes, controlFlow, visitedSymbolIds));
39273
+ }
39274
+ if (!isReactApiCall(candidate, "useMemo", scopes, { resolveNamedAliases: true })) return false;
39275
+ const factory = candidate.arguments[0];
39276
+ if (!factory || isNodeOfType(factory, "SpreadElement")) return false;
39277
+ const unwrappedFactory = stripParenExpression(factory);
39278
+ if (!isInlineFunctionExpression(unwrappedFactory)) return false;
39279
+ if (!isNodeOfType(unwrappedFactory.body, "BlockStatement")) return isProvenReactComponentExpression(unwrappedFactory.body, scopes, controlFlow, visitedSymbolIds);
39280
+ const returnStatements = collectFunctionReturnStatements(unwrappedFactory);
39281
+ const returnedExpression = returnStatements[0]?.argument;
39282
+ return Boolean(returnStatements.length === 1 && returnedExpression && isProvenReactComponentExpression(returnedExpression, scopes, controlFlow, visitedSymbolIds));
39283
+ };
39284
+ const isProvenReactComponentSymbol = (symbol, scopes, controlFlow, componentReference) => {
39285
+ const candidateSymbols = symbol.kind === "ts-module" ? symbol.scope.symbols.filter((candidateSymbol) => candidateSymbol.name === symbol.name && candidateSymbol.kind !== "ts-module") : [symbol];
39286
+ for (const candidateSymbol of candidateSymbols) {
39287
+ if (hasSymbolWriteBefore(candidateSymbol, componentReference, scopes)) continue;
39288
+ if (isComponentDeclaration(candidateSymbol.declarationNode)) {
39289
+ if (functionHasComponentEvidence(candidateSymbol.declarationNode, scopes, controlFlow)) return true;
39290
+ continue;
39291
+ }
39292
+ const initializer = candidateSymbol.initializer ? stripParenExpression(candidateSymbol.initializer) : null;
39293
+ if (isNodeOfType(candidateSymbol.declarationNode, "VariableDeclarator") && isNodeOfType(candidateSymbol.declarationNode.id, "Identifier") && isUppercaseName(candidateSymbol.declarationNode.id.name) && initializer) {
39294
+ if (isProvenReactComponentExpression(initializer, scopes, controlFlow)) return true;
39295
+ continue;
39296
+ }
39297
+ if (isNodeOfType(candidateSymbol.declarationNode, "ClassDeclaration") || isNodeOfType(candidateSymbol.declarationNode, "ClassExpression")) {
39298
+ if (isProvenReactClassComponent(candidateSymbol.declarationNode, scopes)) return true;
39299
+ continue;
39300
+ }
39301
+ if (initializer && isNodeOfType(initializer, "ClassExpression") && isProvenReactClassComponent(initializer, scopes)) return true;
39302
+ }
39303
+ return false;
39304
+ };
39305
+ //#endregion
40148
39306
  //#region src/plugin/rules/architecture/no-prop-types.ts
40149
39307
  const PROP_TYPES_PROPERTY = "propTypes";
40150
39308
  const isPropTypesKey = (key, computed) => {
@@ -40297,7 +39455,7 @@ const isModuleScopedBinding = (identifier) => {
40297
39455
  const binding = findVariableInitializer(identifier, identifier.name);
40298
39456
  if (!binding) return false;
40299
39457
  if (isNodeOfType(binding.scopeOwner, "Program")) return true;
40300
- if (isNodeOfType(binding.scopeOwner, "BlockStatement")) return findEnclosingFunction$1(binding.scopeOwner) === null;
39458
+ if (isNodeOfType(binding.scopeOwner, "BlockStatement")) return findEnclosingFunction(binding.scopeOwner) === null;
40301
39459
  return false;
40302
39460
  };
40303
39461
  const looksLikeFreshUpdateExpression = (expression) => {
@@ -40352,7 +39510,7 @@ const noRandomKey = defineRule({
40352
39510
  });
40353
39511
  //#endregion
40354
39512
  //#region src/plugin/rules/react-builtins/no-react-children.ts
40355
- const MESSAGE$16 = "`React.Children` traversal depends on the runtime child shape, so wrapping or unwrapping a child can silently change what gets visited.";
39513
+ const MESSAGE$15 = "`React.Children` traversal depends on the runtime child shape, so wrapping or unwrapping a child can silently change what gets visited.";
40356
39514
  const isChildrenIdentifier = (node, contextNode) => {
40357
39515
  if (!isNodeOfType(node, "Identifier") || node.name !== "Children") return false;
40358
39516
  return isImportedFromModule(contextNode, "Children", "react");
@@ -40378,13 +39536,13 @@ const noReactChildren = defineRule({
40378
39536
  if (isChildrenIdentifier(memberObject, node)) {
40379
39537
  context.report({
40380
39538
  node: calleeOuter,
40381
- message: MESSAGE$16
39539
+ message: MESSAGE$15
40382
39540
  });
40383
39541
  return;
40384
39542
  }
40385
39543
  if (isReactNamespaceMember(memberObject, node)) context.report({
40386
39544
  node: calleeOuter,
40387
- message: MESSAGE$16
39545
+ message: MESSAGE$15
40388
39546
  });
40389
39547
  } })
40390
39548
  });
@@ -41065,7 +40223,7 @@ const noRenderPropChildren = defineRule({
41065
40223
  });
41066
40224
  //#endregion
41067
40225
  //#region src/plugin/rules/react-builtins/no-render-return-value.ts
41068
- const MESSAGE$15 = "Your app breaks in React 19 because `ReactDOM.render` returns nothing there.";
40226
+ const MESSAGE$14 = "Your app breaks in React 19 because `ReactDOM.render` returns nothing there.";
41069
40227
  const isReactDomRenderCall = (node) => isGlobalMethodCall(node, "ReactDOM", "render");
41070
40228
  const isUsedAsReturnValue = (parent) => {
41071
40229
  if (!parent) return false;
@@ -41083,7 +40241,7 @@ const noRenderReturnValue = defineRule({
41083
40241
  if (!isUsedAsReturnValue(node.parent)) return;
41084
40242
  context.report({
41085
40243
  node: node.callee,
41086
- message: MESSAGE$15
40244
+ message: MESSAGE$14
41087
40245
  });
41088
40246
  } })
41089
40247
  });
@@ -41892,7 +41050,7 @@ const noSelfUpdatingEffect = defineRule({
41892
41050
  });
41893
41051
  //#endregion
41894
41052
  //#region src/plugin/rules/react-builtins/no-set-state.ts
41895
- const MESSAGE$14 = "`this.setState` keeps local class state in a project that forbids it, so state ownership becomes harder to reason about.";
41053
+ const MESSAGE$13 = "`this.setState` keeps local class state in a project that forbids it, so state ownership becomes harder to reason about.";
41896
41054
  const noSetState = defineRule({
41897
41055
  id: "no-set-state",
41898
41056
  title: "Local class state forbidden",
@@ -41907,7 +41065,7 @@ const noSetState = defineRule({
41907
41065
  if (!getParentComponent(node)) return;
41908
41066
  context.report({
41909
41067
  node: node.callee,
41910
- message: MESSAGE$14
41068
+ message: MESSAGE$13
41911
41069
  });
41912
41070
  } })
41913
41071
  });
@@ -42214,9 +41372,9 @@ const isReturnedFromAnyEffectInScope = (functionNode, ownerScope) => {
42214
41372
  return isReturnedFromEffect;
42215
41373
  };
42216
41374
  const isInsideEffectCleanupReturn = (node, ownerScope) => {
42217
- let functionNode = findEnclosingFunction$1(node);
41375
+ let functionNode = findEnclosingFunction(node);
42218
41376
  while (functionNode) {
42219
- const outerFunction = findEnclosingFunction$1(functionNode);
41377
+ const outerFunction = findEnclosingFunction(functionNode);
42220
41378
  if (outerFunction && isEffectCallbackFunction(outerFunction) && isFunctionReturnedFromEffectCallback(functionNode, outerFunction)) return true;
42221
41379
  if (isReturnedFromAnyEffectInScope(functionNode, ownerScope)) return true;
42222
41380
  functionNode = outerFunction;
@@ -42224,7 +41382,7 @@ const isInsideEffectCleanupReturn = (node, ownerScope) => {
42224
41382
  return false;
42225
41383
  };
42226
41384
  const hasRefCurrentReassignmentAfterClear = (clearCall, refName) => {
42227
- const enclosingFunction = findEnclosingFunction$1(clearCall);
41385
+ const enclosingFunction = findEnclosingFunction(clearCall);
42228
41386
  if (!isFunctionLike$2(enclosingFunction)) return false;
42229
41387
  if (!isNodeOfType(enclosingFunction.body, "BlockStatement")) return false;
42230
41388
  const clearStart = getRangeStart(clearCall);
@@ -42277,7 +41435,7 @@ const isAbstractRole = (openingElement, settings) => {
42277
41435
  };
42278
41436
  //#endregion
42279
41437
  //#region src/plugin/rules/a11y/no-static-element-interactions.ts
42280
- const MESSAGE$13 = "Screen reader users can't tell this click handler is interactive because it has no `role`, so add a `role` or use a button or link.";
41438
+ const MESSAGE$12 = "Screen reader users can't tell this click handler is interactive because it has no `role`, so add a `role` or use a button or link.";
42281
41439
  const DEFAULT_HANDLERS = [
42282
41440
  "onClick",
42283
41441
  "onMouseDown",
@@ -42392,7 +41550,7 @@ const noStaticElementInteractions = defineRule({
42392
41550
  if (!roleAttribute || !roleAttribute.value) {
42393
41551
  context.report({
42394
41552
  node: node.name,
42395
- message: MESSAGE$13
41553
+ message: MESSAGE$12
42396
41554
  });
42397
41555
  return;
42398
41556
  }
@@ -42402,7 +41560,7 @@ const noStaticElementInteractions = defineRule({
42402
41560
  if (isRecognizedRoleString(attributeValue.value)) return;
42403
41561
  context.report({
42404
41562
  node: node.name,
42405
- message: MESSAGE$13
41563
+ message: MESSAGE$12
42406
41564
  });
42407
41565
  return;
42408
41566
  }
@@ -42410,7 +41568,7 @@ const noStaticElementInteractions = defineRule({
42410
41568
  if (!settings.allowExpressionValues) {
42411
41569
  context.report({
42412
41570
  node: node.name,
42413
- message: MESSAGE$13
41571
+ message: MESSAGE$12
42414
41572
  });
42415
41573
  return;
42416
41574
  }
@@ -42418,7 +41576,7 @@ const noStaticElementInteractions = defineRule({
42418
41576
  if (isStaticNullishExpression(expression)) {
42419
41577
  context.report({
42420
41578
  node: node.name,
42421
- message: MESSAGE$13
41579
+ message: MESSAGE$12
42422
41580
  });
42423
41581
  return;
42424
41582
  }
@@ -42428,7 +41586,7 @@ const noStaticElementInteractions = defineRule({
42428
41586
  if (branches.some((branch) => branch.role !== null && isRecognizedRoleString(branch.role))) return;
42429
41587
  context.report({
42430
41588
  node: node.name,
42431
- message: MESSAGE$13
41589
+ message: MESSAGE$12
42432
41590
  });
42433
41591
  return;
42434
41592
  }
@@ -42436,7 +41594,7 @@ const noStaticElementInteractions = defineRule({
42436
41594
  }
42437
41595
  context.report({
42438
41596
  node: node.name,
42439
- message: MESSAGE$13
41597
+ message: MESSAGE$12
42440
41598
  });
42441
41599
  } };
42442
41600
  }
@@ -42542,7 +41700,7 @@ const noStringRefs = defineRule({
42542
41700
  });
42543
41701
  //#endregion
42544
41702
  //#region src/plugin/rules/js-performance/no-sync-xhr.ts
42545
- const MESSAGE$12 = "A synchronous `XMLHttpRequest` (`.open(method, url, false)`) freezes the main thread until the request finishes, blocking all rendering and input. Use `fetch()` or an async XHR (`open(method, url, true)`).";
41703
+ const MESSAGE$11 = "A synchronous `XMLHttpRequest` (`.open(method, url, false)`) freezes the main thread until the request finishes, blocking all rendering and input. Use `fetch()` or an async XHR (`open(method, url, true)`).";
42546
41704
  const isFalseLiteral = (node) => isNodeOfType(node, "Literal") && node.value === false;
42547
41705
  const PUBLIC_ASSET_PATH_PATTERN = /(?:^|\/)public\//i;
42548
41706
  const noSyncXhr = defineRule({
@@ -42563,7 +41721,7 @@ const noSyncXhr = defineRule({
42563
41721
  if (!asyncArgument || !isFalseLiteral(stripParenExpression(asyncArgument))) return;
42564
41722
  context.report({
42565
41723
  node,
42566
- message: MESSAGE$12
41724
+ message: MESSAGE$11
42567
41725
  });
42568
41726
  };
42569
41727
  return {
@@ -42588,7 +41746,7 @@ const noSyncXhr = defineRule({
42588
41746
  });
42589
41747
  //#endregion
42590
41748
  //#region src/plugin/rules/react-builtins/no-this-in-sfc.ts
42591
- const MESSAGE$11 = "This value is `undefined` because function components have no `this`.";
41749
+ const MESSAGE$10 = "This value is `undefined` because function components have no `this`.";
42592
41750
  const isInsideClassMethod = (node, customClassFactoryNames) => {
42593
41751
  let ancestor = node.parent;
42594
41752
  while (ancestor) {
@@ -42676,7 +41834,7 @@ const noThisInSfc = defineRule({
42676
41834
  if (functionHasOwnThisMemberWrite(enclosingFunction)) return;
42677
41835
  context.report({
42678
41836
  node,
42679
- message: MESSAGE$11
41837
+ message: MESSAGE$10
42680
41838
  });
42681
41839
  } };
42682
41840
  }
@@ -43054,7 +42212,7 @@ const isInsideAvailabilityGuard = (node, browserGlobalName, context) => {
43054
42212
  return false;
43055
42213
  };
43056
42214
  const isAfterAvailabilityEarlyExit = (node, componentOrHookNode, browserGlobalName, context) => {
43057
- const enclosingFunction = findEnclosingFunction$1(node);
42215
+ const enclosingFunction = findEnclosingFunction(node);
43058
42216
  if (!enclosingFunction || enclosingFunction !== componentOrHookNode && !executesDuringRender(enclosingFunction, context.scopes) || !isFunctionLike$2(enclosingFunction) || !isNodeOfType(enclosingFunction.body, "BlockStatement")) return false;
43059
42217
  let currentNode = node;
43060
42218
  while (currentNode !== enclosingFunction) {
@@ -44321,11 +43479,7 @@ const resolveSettings$8 = (settings) => {
44321
43479
  propNamePattern: ruleSettings.propNamePattern ?? "render*"
44322
43480
  };
44323
43481
  };
44324
- const isReactCreateElementCall = (node, scopes) => isReactApiCall(node, "createElement", scopes, {
44325
- allowGlobalReactNamespace: true,
44326
- resolveNamedAliases: true
44327
- });
44328
- const expressionContainsJsxOrCreateElement = (root, scopes) => {
43482
+ const expressionContainsJsxOrCreateElement = (root) => {
44329
43483
  let found = false;
44330
43484
  walkAst(root, (node) => {
44331
43485
  if (found) return false;
@@ -44334,17 +43488,17 @@ const expressionContainsJsxOrCreateElement = (root, scopes) => {
44334
43488
  found = true;
44335
43489
  return false;
44336
43490
  }
44337
- if (isNodeOfType(node, "CallExpression") && isReactCreateElementCall(node, scopes)) {
43491
+ if (isNodeOfType(node, "CallExpression") && isCreateElementCall(node)) {
44338
43492
  found = true;
44339
43493
  return false;
44340
43494
  }
44341
43495
  });
44342
43496
  return found;
44343
43497
  };
44344
- const functionContainsJsxOrCreateElement = (functionNode, scopes, controlFlow) => expressionContainsJsxOrCreateElement(functionNode, scopes) || functionReturnsMatchingExpression(functionNode, scopes, (expression) => expressionContainsJsxOrCreateElement(expression, scopes), controlFlow);
44345
- const isReactClassComponent = (classNode, scopes) => {
43498
+ const functionContainsJsxOrCreateElement = (functionNode, scopes, controlFlow) => expressionContainsJsxOrCreateElement(functionNode) || functionReturnsMatchingExpression(functionNode, scopes, expressionContainsJsxOrCreateElement, controlFlow);
43499
+ const isReactClassComponent = (classNode) => {
44346
43500
  if (isEs6Component(classNode)) return true;
44347
- return expressionContainsJsxOrCreateElement(classNode, scopes);
43501
+ return expressionContainsJsxOrCreateElement(classNode);
44348
43502
  };
44349
43503
  const findEnclosingComponent = (node, scopes, controlFlow) => {
44350
43504
  let walker = node.parent;
@@ -44361,7 +43515,7 @@ const findEnclosingComponent = (node, scopes, controlFlow) => {
44361
43515
  };
44362
43516
  }
44363
43517
  if (isNodeOfType(walker, "ClassDeclaration") || isNodeOfType(walker, "ClassExpression")) {
44364
- if (walker.id && isReactComponentName(walker.id.name) && isReactClassComponent(walker, scopes)) return {
43518
+ if (walker.id && isReactComponentName(walker.id.name) && isReactClassComponent(walker)) return {
44365
43519
  component: walker,
44366
43520
  name: walker.id.name
44367
43521
  };
@@ -44450,12 +43604,12 @@ const isObjectCallbackCandidate = (node) => {
44450
43604
  }
44451
43605
  return false;
44452
43606
  };
44453
- const hocCallContainsComponent = (call, scopes) => {
43607
+ const hocCallContainsComponent = (call) => {
44454
43608
  const firstArgument = call.arguments[0];
44455
43609
  if (!firstArgument) return false;
44456
- if (isNodeOfType(firstArgument, "FunctionExpression") || isNodeOfType(firstArgument, "ArrowFunctionExpression") || isNodeOfType(firstArgument, "ClassExpression")) return expressionContainsJsxOrCreateElement(firstArgument, scopes);
44457
- if (isNodeOfType(firstArgument, "CallExpression") && isHocCallee$1(firstArgument)) return hocCallContainsComponent(firstArgument, scopes);
44458
- return expressionContainsJsxOrCreateElement(firstArgument, scopes);
43610
+ if (isNodeOfType(firstArgument, "FunctionExpression") || isNodeOfType(firstArgument, "ArrowFunctionExpression") || isNodeOfType(firstArgument, "ClassExpression")) return expressionContainsJsxOrCreateElement(firstArgument);
43611
+ if (isNodeOfType(firstArgument, "CallExpression") && isHocCallee$1(firstArgument)) return hocCallContainsComponent(firstArgument);
43612
+ return expressionContainsJsxOrCreateElement(firstArgument);
44459
43613
  };
44460
43614
  const isFirstArgumentOfHocCall = (node) => {
44461
43615
  const parent = node.parent;
@@ -44488,35 +43642,19 @@ const isReturnOfMapCallback = (node) => {
44488
43642
  }
44489
43643
  return false;
44490
43644
  };
43645
+ const isCloneElementCall = (node) => {
43646
+ if (!isNodeOfType(node, "CallExpression")) return false;
43647
+ const callee = node.callee;
43648
+ if (isNodeOfType(callee, "Identifier")) return callee.name === "cloneElement";
43649
+ return isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier") && callee.property.name === "cloneElement";
43650
+ };
44491
43651
  const TS_VALUE_PASSTHROUGH_TYPES = new Set([
44492
43652
  "TSAsExpression",
44493
43653
  "TSNonNullExpression",
44494
43654
  "TSSatisfiesExpression",
44495
43655
  "TSTypeAssertion"
44496
43656
  ]);
44497
- const ELEMENT_TYPE_PROP_NAMES = new Set([
44498
- "as",
44499
- "body",
44500
- "calendarcontainer",
44501
- "component",
44502
- "fallback",
44503
- "tooltip"
44504
- ]);
44505
- const isElementTypeJsxAttribute = (node) => {
44506
- if (!isNodeOfType(node, "JSXAttribute")) return false;
44507
- if (!isNodeOfType(node.name, "JSXIdentifier")) return false;
44508
- const attributeName = node.name.name;
44509
- return ELEMENT_TYPE_PROP_NAMES.has(attributeName.toLowerCase()) || attributeName.endsWith("Component");
44510
- };
44511
- const isReactUseMemoCallback = (call, valueNode, scopes) => call.arguments[0] === valueNode && isReactApiCall(call, "useMemo", scopes, {
44512
- allowGlobalReactNamespace: true,
44513
- resolveNamedAliases: true
44514
- });
44515
- const isReactLazyCall = (call, scopes) => isReactApiCall(call, "lazy", scopes, {
44516
- allowGlobalReactNamespace: true,
44517
- resolveNamedAliases: true
44518
- });
44519
- const isRenderFlowingReadReference = (identifier, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
43657
+ const isRenderFlowingReadReference = (identifier) => {
44520
43658
  let valueNode = identifier;
44521
43659
  let parent = valueNode.parent;
44522
43660
  while (parent) {
@@ -44526,26 +43664,20 @@ const isRenderFlowingReadReference = (identifier, scopes, visitedSymbols = /* @_
44526
43664
  continue;
44527
43665
  }
44528
43666
  switch (parent.type) {
44529
- case "JSXOpeningElement": return parent.name === valueNode;
44530
- case "JSXExpressionContainer": return Boolean(parent.parent && isElementTypeJsxAttribute(parent.parent));
44531
- case "ReturnStatement": return false;
44532
- case "ArrowFunctionExpression": return false;
43667
+ case "JSXExpressionContainer":
43668
+ case "ReturnStatement": return true;
43669
+ case "ArrowFunctionExpression": return parent.body === valueNode;
44533
43670
  case "CallExpression":
44534
43671
  if (parent.callee === valueNode) return false;
44535
- if (isReactUseMemoCallback(parent, valueNode, scopes)) return false;
44536
- if (isReactCreateElementCall(parent, scopes)) return true;
43672
+ if (isCreateElementCall(parent) || isCloneElementCall(parent)) return true;
44537
43673
  valueNode = parent;
44538
43674
  parent = parent.parent;
44539
43675
  continue;
44540
- case "VariableDeclarator": {
44541
- if (parent.init !== valueNode || !isNodeOfType(parent.id, "Identifier")) return false;
44542
- const aliasSymbol = scopes.symbolFor(parent.id);
44543
- if (!aliasSymbol || aliasSymbol.kind !== "const" || visitedSymbols.has(aliasSymbol.id)) return false;
44544
- const nextVisitedSymbols = new Set(visitedSymbols);
44545
- nextVisitedSymbols.add(aliasSymbol.id);
44546
- return aliasSymbol.references.some((reference) => reference.flag === "read" && isRenderFlowingReadReference(reference.identifier, scopes, nextVisitedSymbols));
43676
+ case "VariableDeclarator": return parent.init === valueNode && isNodeOfType(parent.id, "Identifier") && isReactComponentName(parent.id.name);
43677
+ case "AssignmentExpression": {
43678
+ const assignmentTarget = parent.left;
43679
+ return parent.right === valueNode && isNodeOfType(assignmentTarget, "Identifier") && isReactComponentName(assignmentTarget.name);
44547
43680
  }
44548
- case "AssignmentExpression": return false;
44549
43681
  case "Property":
44550
43682
  if (parent.value !== valueNode) return false;
44551
43683
  valueNode = parent;
@@ -44583,7 +43715,6 @@ const noUnstableNestedComponents = defineRule({
44583
43715
  severity: "warn",
44584
43716
  recommendation: "Move nested components to module scope so React does not remount them and lose state on every render.",
44585
43717
  category: "Performance",
44586
- tags: ["react-jsx-only"],
44587
43718
  create: (context) => {
44588
43719
  const settings = resolveSettings$8(context.settings);
44589
43720
  const renderPropRegex = compileGlob(settings.propNamePattern);
@@ -44646,7 +43777,7 @@ const noUnstableNestedComponents = defineRule({
44646
43777
  },
44647
43778
  Identifier(node) {
44648
43779
  if (!isReactComponentName(node.name)) return;
44649
- if (!isRenderFlowingReadReference(node, context.scopes)) return;
43780
+ if (!isRenderFlowingReadReference(node)) return;
44650
43781
  recordInstantiation(node, node.name);
44651
43782
  },
44652
43783
  FunctionDeclaration: checkFunctionLike,
@@ -44655,33 +43786,28 @@ const noUnstableNestedComponents = defineRule({
44655
43786
  ClassDeclaration(node) {
44656
43787
  if (!node.id) return;
44657
43788
  if (!isReactComponentName(node.id.name)) return;
44658
- if (!isReactClassComponent(node, context.scopes)) return;
43789
+ if (!isReactClassComponent(node)) return;
44659
43790
  enqueueCandidate(node, null);
44660
43791
  },
44661
43792
  ClassExpression(node) {
44662
43793
  const inferredName = node.id?.name ?? inferFunctionLikeName(node);
44663
43794
  if (!inferredName || !isReactComponentName(inferredName)) return;
44664
- if (!isReactClassComponent(node, context.scopes)) return;
43795
+ if (!isReactClassComponent(node)) return;
44665
43796
  enqueueCandidate(node, null);
44666
43797
  },
44667
43798
  CallExpression(node) {
44668
- if (isReactCreateElementCall(node, context.scopes)) {
43799
+ if (isCreateElementCall(node)) {
44669
43800
  const firstArgument = node.arguments[0];
44670
43801
  if (firstArgument && isNodeOfType(firstArgument, "Identifier")) recordInstantiation(firstArgument, firstArgument.name);
44671
43802
  else if (firstArgument && isNodeOfType(firstArgument, "MemberExpression")) recordMemberChainInstantiation(firstArgument);
44672
43803
  }
44673
- const isReactLazy = isReactLazyCall(node, context.scopes);
44674
- if (!isReactLazy && !isHocCallee$1(node)) return;
44675
- if (!isReactLazy && !hocCallContainsComponent(node, context.scopes)) return;
44676
- const inferredName = inferFunctionLikeName(node);
44677
- const propInfo = isComponentDeclaredInProp(node);
44678
- if (propInfo === null && (!inferredName || !isReactComponentName(inferredName))) return;
44679
- enqueueCandidate(node, propInfo === null ? inferredName : null);
43804
+ if (!isHocCallee$1(node)) return;
43805
+ if (!hocCallContainsComponent(node)) return;
43806
+ enqueueCandidate(node, null);
44680
43807
  },
44681
43808
  "Program:exit"() {
44682
43809
  for (const report of queuedReports) {
44683
43810
  if (report.requiredInstantiationName !== null) {
44684
- if ((report.requiredInstantiationBinding ? context.scopes.symbolFor(report.requiredInstantiationBinding) : null)?.references.some((reference) => reference.flag === "write" || reference.flag === "read-write")) continue;
44685
43811
  if (!(report.requiredInstantiationBinding !== null ? instantiatedBindingIdentifiers.has(report.requiredInstantiationBinding) : instantiatedComponentNames.has(report.requiredInstantiationName))) continue;
44686
43812
  }
44687
43813
  context.report({
@@ -44855,7 +43981,7 @@ const noWideLetterSpacing = defineRule({
44855
43981
  //#endregion
44856
43982
  //#region src/plugin/rules/react-builtins/no-will-update-set-state.ts
44857
43983
  const LIFECYCLE_NAMES = new Set(["componentWillUpdate", "UNSAFE_componentWillUpdate"]);
44858
- const MESSAGE$10 = "Calling setState in componentWillUpdate can trigger another update immediately, loop forever, and freeze the component.";
43984
+ const MESSAGE$9 = "Calling setState in componentWillUpdate can trigger another update immediately, loop forever, and freeze the component.";
44859
43985
  const resolveSettings$7 = (settings) => {
44860
43986
  const reactDoctor = settings?.["react-doctor"];
44861
43987
  return { mode: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noWillUpdateSetState ?? {} : {}).mode ?? "allowed" };
@@ -44889,7 +44015,7 @@ const noWillUpdateSetState = defineRule({
44889
44015
  if (!isSetStateCallInLifecycle(node, activeLifecycleNames, { disallowInNestedFunctions: mode === "disallow-in-func" })) return;
44890
44016
  context.report({
44891
44017
  node: node.callee,
44892
- message: MESSAGE$10
44018
+ message: MESSAGE$9
44893
44019
  });
44894
44020
  } };
44895
44021
  }
@@ -45714,7 +44840,7 @@ const findChildrenDestructuringFunction = (identifier, scopes) => {
45714
44840
  const symbol = scopes.symbolFor(identifier);
45715
44841
  if (symbol) {
45716
44842
  if (symbol.kind !== "parameter") return null;
45717
- const declaringFunction = findEnclosingFunction$1(symbol.bindingIdentifier);
44843
+ const declaringFunction = findEnclosingFunction(symbol.bindingIdentifier);
45718
44844
  if (declaringFunction && destructuresChildrenAsFirstParam(declaringFunction)) return declaringFunction;
45719
44845
  return null;
45720
44846
  }
@@ -45760,7 +44886,7 @@ const isChildrenMemberExpression = (node, scopes) => {
45760
44886
  const symbol = scopes.symbolFor(propsObject);
45761
44887
  if (symbol) {
45762
44888
  if (symbol.kind !== "parameter") return false;
45763
- const declaringFunction = findEnclosingFunction$1(symbol.bindingIdentifier);
44889
+ const declaringFunction = findEnclosingFunction(symbol.bindingIdentifier);
45764
44890
  return declaringFunction ? isDeclaringFunctionComponentLike(declaringFunction) : false;
45765
44891
  }
45766
44892
  return hasComponentLikeAncestorFunction(node);
@@ -45885,7 +45011,7 @@ const preactNoRenderArguments = defineRule({
45885
45011
  });
45886
45012
  //#endregion
45887
45013
  //#region src/plugin/rules/preact/preact-prefer-ondblclick.ts
45888
- const MESSAGE$9 = "Your users get no response from `onDoubleClick` in Preact core, where it never fires, so use `onDblClick` instead, which matches the DOM event name.";
45014
+ const MESSAGE$8 = "Your users get no response from `onDoubleClick` in Preact core, where it never fires, so use `onDblClick` instead, which matches the DOM event name.";
45889
45015
  const preactPreferOndblclick = defineRule({
45890
45016
  id: "preact-prefer-ondblclick",
45891
45017
  title: "onDoubleClick instead of onDblClick",
@@ -45900,7 +45026,7 @@ const preactPreferOndblclick = defineRule({
45900
45026
  if (!onDoubleClickAttribute) return;
45901
45027
  context.report({
45902
45028
  node: onDoubleClickAttribute,
45903
- message: MESSAGE$9
45029
+ message: MESSAGE$8
45904
45030
  });
45905
45031
  } })
45906
45032
  });
@@ -46151,7 +45277,7 @@ const preferExplicitVariants = defineRule({
46151
45277
  });
46152
45278
  //#endregion
46153
45279
  //#region src/plugin/rules/react-builtins/prefer-function-component.ts
46154
- const MESSAGE$8 = "This class component keeps behavior in lifecycle methods, so state and effects are harder to follow than in a hook-based function component.";
45280
+ const MESSAGE$7 = "This class component keeps behavior in lifecycle methods, so state and effects are harder to follow than in a hook-based function component.";
46155
45281
  const resolveSettings$4 = (settings) => {
46156
45282
  const reactDoctor = settings?.["react-doctor"];
46157
45283
  const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.preferFunctionComponent ?? {} : {};
@@ -46190,7 +45316,7 @@ const preferFunctionComponent = defineRule({
46190
45316
  const reportNode = node.id ?? node;
46191
45317
  context.report({
46192
45318
  node: reportNode,
46193
- message: MESSAGE$8
45319
+ message: MESSAGE$7
46194
45320
  });
46195
45321
  };
46196
45322
  return {
@@ -46412,7 +45538,7 @@ const doesFunctionReturnsObjectLiteral = (functionNode) => {
46412
45538
  //#endregion
46413
45539
  //#region src/plugin/utils/enclosing-component-or-hook-scope.ts
46414
45540
  const enclosingComponentOrHookScope = (startNode, ownScopeFor) => {
46415
- const functionNode = findEnclosingFunction$1(startNode);
45541
+ const functionNode = findEnclosingFunction(startNode);
46416
45542
  if (!functionNode) return null;
46417
45543
  const displayName = componentOrHookDisplayNameForFunction(functionNode);
46418
45544
  if (!displayName) return null;
@@ -47474,7 +46600,7 @@ const isTanstackQuerySource = (source) => TANSTACK_QUERY_PACKAGE_PATTERN.test(so
47474
46600
  //#region src/plugin/rules/tanstack-query/query-destructure-result.ts
47475
46601
  const isHookReturnForwardingSpread = (objectExpression) => {
47476
46602
  const objectParent = objectExpression.parent;
47477
- const enclosingFunction = findEnclosingFunction$1(objectExpression);
46603
+ const enclosingFunction = findEnclosingFunction(objectExpression);
47478
46604
  if (!enclosingFunction) return false;
47479
46605
  if (!(isNodeOfType(objectParent, "ReturnStatement") || isNodeOfType(enclosingFunction, "ArrowFunctionExpression") && enclosingFunction.body === objectExpression)) return false;
47480
46606
  const enclosingName = componentOrHookDisplayNameForFunction(enclosingFunction);
@@ -47768,258 +46894,7 @@ const queryMutationMissingInvalidation = defineRule({
47768
46894
  }
47769
46895
  });
47770
46896
  //#endregion
47771
- //#region src/plugin/utils/is-node-conditionally-executed.ts
47772
- const isNodeConditionallyExecuted = (node, boundary) => {
47773
- let child = node;
47774
- let parent = child.parent ?? null;
47775
- while (parent && parent !== boundary) {
47776
- if (isNodeOfType(parent, "ConditionalExpression") && (parent.consequent === child || parent.alternate === child)) return true;
47777
- if (isNodeOfType(parent, "LogicalExpression") && parent.right === child) return true;
47778
- if (isNodeOfType(parent, "AssignmentPattern") && parent.right === child) return true;
47779
- child = parent;
47780
- parent = child.parent ?? null;
47781
- }
47782
- return false;
47783
- };
47784
- //#endregion
47785
- //#region src/plugin/rules/tanstack-query/utils/resolve-tanstack-query-hook-name.ts
47786
- const resolveTanstackNamespaceHookName = (memberExpression, contextNode, scopes) => {
47787
- const hookName = getStaticPropertyKeyName(memberExpression, { allowComputedString: true });
47788
- const namespaceObject = stripParenExpression(memberExpression.object);
47789
- if (!hookName || !TANSTACK_QUERY_HOOKS.has(hookName)) return null;
47790
- if (!isNodeOfType(namespaceObject, "Identifier")) return null;
47791
- const resolvedNamespaceSymbol = resolveConstIdentifierAlias(namespaceObject, scopes);
47792
- if (resolvedNamespaceSymbol?.kind !== "import") return null;
47793
- const namespaceBinding = getImportBindingForName(contextNode, resolvedNamespaceSymbol.name);
47794
- return namespaceBinding?.isNamespace && isTanstackQuerySource(namespaceBinding.source) ? hookName : null;
47795
- };
47796
- const resolveTanstackQueryHookName = (callExpression, scopes) => {
47797
- const callee = stripParenExpression(callExpression.callee);
47798
- if (isNodeOfType(callee, "Identifier")) {
47799
- const resolvedSymbol = resolveConstIdentifierAlias(callee, scopes);
47800
- if (!resolvedSymbol) return null;
47801
- if (resolvedSymbol.kind === "const" && resolvedSymbol.initializer) {
47802
- const initializer = stripParenExpression(resolvedSymbol.initializer);
47803
- return isNodeOfType(initializer, "MemberExpression") ? resolveTanstackNamespaceHookName(initializer, callExpression, scopes) : null;
47804
- }
47805
- if (resolvedSymbol.kind !== "import") return null;
47806
- const importBinding = getImportBindingForName(callExpression, resolvedSymbol.name);
47807
- if (importBinding === null) return null;
47808
- if (importBinding.isNamespace || !isTanstackQuerySource(importBinding.source)) return null;
47809
- return importBinding.exportedName !== null && TANSTACK_QUERY_HOOKS.has(importBinding.exportedName) ? importBinding.exportedName : null;
47810
- }
47811
- if (isNodeOfType(callee, "MemberExpression")) return resolveTanstackNamespaceHookName(callee, callExpression, scopes);
47812
- return null;
47813
- };
47814
- const resolveTanstackQueryHookNameFromInitializer = (initializer, scopes) => {
47815
- const unwrappedInitializer = stripParenExpression(initializer);
47816
- if (isNodeOfType(unwrappedInitializer, "CallExpression")) return resolveTanstackQueryHookName(unwrappedInitializer, scopes);
47817
- if (!isNodeOfType(unwrappedInitializer, "Identifier")) return null;
47818
- const resolvedSymbol = resolveConstIdentifierAlias(unwrappedInitializer, scopes);
47819
- if (resolvedSymbol?.kind !== "const" || !resolvedSymbol.initializer) return null;
47820
- const resolvedInitializer = stripParenExpression(resolvedSymbol.initializer);
47821
- if (!isNodeOfType(resolvedInitializer, "CallExpression")) return null;
47822
- return resolveTanstackQueryHookName(resolvedInitializer, scopes);
47823
- };
47824
- //#endregion
47825
46897
  //#region src/plugin/rules/tanstack-query/query-no-query-in-effect.ts
47826
- const isTanstackQueryResult = (expression, context) => Boolean(resolveTanstackQueryHookNameFromInitializer(expression, context.scopes));
47827
- const isStaticRefetchMember = (memberExpression) => getStaticPropertyKeyName(memberExpression, { allowComputedString: true }) === "refetch";
47828
- const resolveCalledFunction = (callee, context) => {
47829
- const unwrappedCallee = stripParenExpression(callee);
47830
- if (isFunctionLike$2(unwrappedCallee)) return unwrappedCallee;
47831
- if (!isNodeOfType(unwrappedCallee, "Identifier")) return null;
47832
- const symbol = resolveConstIdentifierAlias(unwrappedCallee, context.scopes);
47833
- if (!symbol) return null;
47834
- const candidate = symbol.kind === "function" ? symbol.declarationNode : symbol.initializer;
47835
- return candidate && isFunctionLike$2(candidate) ? candidate : null;
47836
- };
47837
- const hasSuspensionBefore = (functionNode, boundary, context) => {
47838
- if (!isFunctionLike$2(functionNode)) return true;
47839
- if (functionNode.generator) return true;
47840
- const boundaryStart = getRangeStart(boundary);
47841
- if (boundaryStart === null) return true;
47842
- let hasSuspension = false;
47843
- walkAst(functionNode, (node) => {
47844
- if (node !== functionNode && isFunctionLike$2(node)) return false;
47845
- if (!isNodeOfType(node, "AwaitExpression") || !isNodeReachableWithinFunction(node, context)) return;
47846
- const suspensionStart = getRangeStart(node);
47847
- if (suspensionStart !== null && suspensionStart < boundaryStart) {
47848
- hasSuspension = true;
47849
- return false;
47850
- }
47851
- });
47852
- return hasSuspension;
47853
- };
47854
- const isFunctionAncestor = (ancestor, functionNode) => {
47855
- let enclosingFunction = findEnclosingFunction$1(functionNode);
47856
- while (enclosingFunction) {
47857
- if (enclosingFunction === ancestor) return true;
47858
- enclosingFunction = findEnclosingFunction$1(enclosingFunction);
47859
- }
47860
- return false;
47861
- };
47862
- const isUnconditionallyExecuted = (node, functionNode, context) => context.cfg.isUnconditionalFromEntry(node) && !isNodeConditionallyExecuted(node, functionNode) && !(isNodeOfType(node, "MemberExpression") && isNodeOfType(node.parent, "AssignmentExpression") && node.parent.left === node && (node.parent.operator === "&&=" || node.parent.operator === "||=" || node.parent.operator === "??="));
47863
- const functionInvokesTarget = (callerFunction, targetFunction, context, visitedFunctions, canCrossSuspension = false) => {
47864
- if (visitedFunctions.has(callerFunction)) return false;
47865
- visitedFunctions.add(callerFunction);
47866
- let invokesTarget = false;
47867
- walkAst(callerFunction, (node) => {
47868
- if (node !== callerFunction && isFunctionLike$2(node)) return false;
47869
- if (!isNodeOfType(node, "CallExpression")) return;
47870
- if (!isNodeReachableWithinFunction(node, context) || !isUnconditionallyExecuted(node, callerFunction, context) || !canCrossSuspension && hasSuspensionBefore(callerFunction, node, context)) return;
47871
- const calledFunction = resolveCalledFunction(node.callee, context);
47872
- if (calledFunction === targetFunction || calledFunction && functionInvokesTarget(calledFunction, targetFunction, context, visitedFunctions, canCrossSuspension)) {
47873
- invokesTarget = true;
47874
- return false;
47875
- }
47876
- });
47877
- return invokesTarget;
47878
- };
47879
- const isFunctionInvokedBefore = (invokedFunction, boundary, context) => {
47880
- const boundaryFunction = findEnclosingFunction$1(boundary);
47881
- const boundaryStart = getRangeStart(boundary);
47882
- if (!boundaryFunction || boundaryStart === null) return false;
47883
- let isInvokedBefore = false;
47884
- walkAst(boundaryFunction, (node) => {
47885
- if (node !== boundaryFunction && isFunctionLike$2(node)) return false;
47886
- if (!isNodeOfType(node, "CallExpression")) return;
47887
- const callStart = getRangeStart(node);
47888
- if (callStart === null || callStart >= boundaryStart || !isNodeReachableWithinFunction(node, context) || !isUnconditionallyExecuted(node, boundaryFunction, context) || hasSuspensionBefore(boundaryFunction, node, context)) return;
47889
- const calledFunction = resolveCalledFunction(node.callee, context);
47890
- if (calledFunction === invokedFunction || calledFunction && functionInvokesTarget(calledFunction, invokedFunction, context, /* @__PURE__ */ new Set())) {
47891
- isInvokedBefore = true;
47892
- return false;
47893
- }
47894
- });
47895
- return isInvokedBefore;
47896
- };
47897
- const isFunctionInvokedAfter = (invokedFunction, boundary, callerFunction, context) => {
47898
- const boundaryStart = getRangeStart(boundary);
47899
- if (boundaryStart === null) return false;
47900
- let isInvokedAfter = false;
47901
- walkAst(callerFunction, (node) => {
47902
- if (node !== callerFunction && isFunctionLike$2(node)) return false;
47903
- if (!isNodeOfType(node, "CallExpression")) return;
47904
- const callStart = getRangeStart(node);
47905
- if (callStart === null || callStart <= boundaryStart || !isNodeReachableWithinFunction(node, context) || !isUnconditionallyExecuted(node, callerFunction, context)) return;
47906
- const calledFunction = resolveCalledFunction(node.callee, context);
47907
- if (calledFunction === invokedFunction || calledFunction && functionInvokesTarget(calledFunction, invokedFunction, context, /* @__PURE__ */ new Set(), true)) {
47908
- isInvokedAfter = true;
47909
- return false;
47910
- }
47911
- });
47912
- return isInvokedAfter;
47913
- };
47914
- const isWriteExecutedBefore = (writeNode, boundary, context, deferredExecutionFunction) => {
47915
- const writeStart = getRangeStart(writeNode);
47916
- const boundaryStart = getRangeStart(boundary);
47917
- const writeFunction = findEnclosingFunction$1(writeNode);
47918
- const writeExecutionBoundary = writeFunction ?? findProgramRoot(writeNode);
47919
- if (writeStart === null || boundaryStart === null || !writeExecutionBoundary || !isNodeReachableWithinFunction(writeNode, context) || !isUnconditionallyExecuted(writeNode, writeExecutionBoundary, context)) return false;
47920
- const boundaryFunction = findEnclosingFunction$1(boundary);
47921
- const renderFunction = deferredExecutionFunction ? findEnclosingFunction$1(deferredExecutionFunction) : null;
47922
- if (writeFunction === boundaryFunction) return writeStart < boundaryStart;
47923
- if (!writeFunction) return writeStart < boundaryStart;
47924
- if (boundaryFunction && isFunctionAncestor(writeFunction, boundaryFunction)) {
47925
- if (Boolean(renderFunction && (writeFunction === renderFunction || isFunctionAncestor(writeFunction, renderFunction)))) return true;
47926
- if (deferredExecutionFunction && boundaryFunction !== deferredExecutionFunction) {
47927
- if (hasSuspensionBefore(boundaryFunction, boundary, context) && isFunctionInvokedBefore(boundaryFunction, writeNode, context)) return true;
47928
- return isFunctionInvokedAfter(boundaryFunction, writeNode, writeFunction, context);
47929
- }
47930
- return writeStart < boundaryStart;
47931
- }
47932
- if (renderFunction && isFunctionAncestor(renderFunction, writeFunction) && !hasSuspensionBefore(writeFunction, writeNode, context) && functionInvokesTarget(renderFunction, writeFunction, context, /* @__PURE__ */ new Set())) return true;
47933
- return !hasSuspensionBefore(writeFunction, writeNode, context) && isFunctionInvokedBefore(writeFunction, boundary, context);
47934
- };
47935
- const getStaticStringValue = (node) => {
47936
- const unwrappedNode = stripParenExpression(node);
47937
- if (isNodeOfType(unwrappedNode, "Literal") && typeof unwrappedNode.value === "string") return unwrappedNode.value;
47938
- if (isNodeOfType(unwrappedNode, "TemplateLiteral") && unwrappedNode.expressions.length === 0) return getStaticTemplateLiteralValue(unwrappedNode);
47939
- return null;
47940
- };
47941
- const isSameRefetchMember = (target, candidate, context) => {
47942
- const unwrappedTarget = stripParenExpression(target);
47943
- const unwrappedCandidate = stripParenExpression(candidate);
47944
- if (!isNodeOfType(unwrappedTarget, "Identifier") || !isNodeOfType(unwrappedCandidate, "MemberExpression") || !isStaticRefetchMember(unwrappedCandidate)) return false;
47945
- const candidateTarget = stripParenExpression(unwrappedCandidate.object);
47946
- if (!isNodeOfType(candidateTarget, "Identifier")) return false;
47947
- const targetSymbol = resolveConstIdentifierAlias(unwrappedTarget, context.scopes);
47948
- const candidateSymbol = resolveConstIdentifierAlias(candidateTarget, context.scopes);
47949
- return Boolean(targetSymbol && candidateSymbol?.id === targetSymbol.id);
47950
- };
47951
- const getRefetchMutationTarget = (node, context) => {
47952
- if (isNodeOfType(node, "MemberExpression") && isStaticRefetchMember(node)) {
47953
- const parent = node.parent;
47954
- if (isNodeOfType(parent, "AssignmentExpression") && parent.left === node && isSameRefetchMember(node.object, parent.right, context)) return null;
47955
- return isNodeOfType(parent, "AssignmentExpression") && parent.left === node || isNodeOfType(parent, "UpdateExpression") && parent.argument === node || isNodeOfType(parent, "UnaryExpression") && parent.operator === "delete" ? node.object : null;
47956
- }
47957
- if (!isNodeOfType(node, "CallExpression")) return null;
47958
- const callee = stripParenExpression(node.callee);
47959
- if (!isNodeOfType(callee, "MemberExpression")) return null;
47960
- const receiver = stripParenExpression(callee.object);
47961
- if (!isNodeOfType(receiver, "Identifier") || receiver.name !== "Object" || context.scopes.symbolFor(receiver)) return null;
47962
- const methodName = getStaticPropertyKeyName(callee, { allowComputedString: true });
47963
- const target = node.arguments[0];
47964
- if (!target || isNodeOfType(target, "SpreadElement")) return null;
47965
- if (methodName === "defineProperty") {
47966
- const propertyKey = node.arguments[1];
47967
- if (!propertyKey || getStaticStringValue(propertyKey) !== "refetch") return null;
47968
- const descriptor = node.arguments[2];
47969
- if (isNodeOfType(descriptor, "ObjectExpression")) {
47970
- const valueProperty = descriptor.properties.find((property) => isNodeOfType(property, "Property") && getStaticPropertyKeyName(property, { allowComputedString: true }) === "value");
47971
- if (isNodeOfType(valueProperty, "Property") && isSameRefetchMember(target, valueProperty.value, context)) return null;
47972
- }
47973
- return target;
47974
- }
47975
- if (methodName !== "assign") return null;
47976
- let finalRefetchValue = null;
47977
- for (const source of node.arguments.slice(1)) {
47978
- if (!isNodeOfType(source, "ObjectExpression")) continue;
47979
- for (const property of source.properties) if (isNodeOfType(property, "Property") && getStaticPropertyKeyName(property, { allowComputedString: true }) === "refetch") finalRefetchValue = property.value;
47980
- }
47981
- if (!finalRefetchValue || isSameRefetchMember(target, finalRefetchValue, context)) return null;
47982
- return target;
47983
- };
47984
- const hasRefetchMemberWriteBefore = (expression, boundary, context, deferredExecutionFunction) => {
47985
- const unwrappedExpression = stripParenExpression(expression);
47986
- if (!isNodeOfType(unwrappedExpression, "Identifier")) return false;
47987
- const resultSymbol = resolveConstIdentifierAlias(unwrappedExpression, context.scopes);
47988
- if (!resultSymbol) return false;
47989
- const program = findProgramRoot(expression);
47990
- if (!program) return true;
47991
- if (getRangeStart(boundary) === null) return true;
47992
- let hasWrite = false;
47993
- walkAst(program, (node) => {
47994
- const mutationTarget = getRefetchMutationTarget(node, context);
47995
- if (!mutationTarget) return;
47996
- if (!isWriteExecutedBefore(node, boundary, context, deferredExecutionFunction)) return;
47997
- const object = stripParenExpression(mutationTarget);
47998
- if (!isNodeOfType(object, "Identifier")) return;
47999
- if (resolveConstIdentifierAlias(object, context.scopes)?.id === resultSymbol.id) {
48000
- hasWrite = true;
48001
- return false;
48002
- }
48003
- });
48004
- return hasWrite;
48005
- };
48006
- const isTanstackRefetchExpression = (expression, context, deferredExecutionFunction, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
48007
- const unwrappedExpression = stripParenExpression(expression);
48008
- if (isNodeOfType(unwrappedExpression, "MemberExpression")) return isStaticRefetchMember(unwrappedExpression) && isTanstackQueryResult(unwrappedExpression.object, context) && !hasRefetchMemberWriteBefore(unwrappedExpression.object, unwrappedExpression, context, deferredExecutionFunction);
48009
- if (!isNodeOfType(unwrappedExpression, "Identifier")) return false;
48010
- const symbol = context.scopes.symbolFor(unwrappedExpression);
48011
- if (!symbol || symbol.kind !== "const" || visitedSymbolIds.has(symbol.id) || symbol.references.some((reference) => reference.flag !== "read") || !isNodeOfType(symbol.declarationNode, "VariableDeclarator")) return false;
48012
- visitedSymbolIds.add(symbol.id);
48013
- const bindingProperty = symbol.bindingIdentifier.parent;
48014
- if (isNodeOfType(bindingProperty, "Property") && getStaticPropertyKeyName(bindingProperty, { allowComputedString: true }) === "refetch") {
48015
- const initializer = symbol.declarationNode.init;
48016
- return Boolean(initializer && isTanstackQueryResult(initializer, context) && !hasRefetchMemberWriteBefore(initializer, symbol.declarationNode, context, null));
48017
- }
48018
- return Boolean(symbol.declarationNode.id === symbol.bindingIdentifier && symbol.initializer && isTanstackRefetchExpression(symbol.initializer, context, null, visitedSymbolIds));
48019
- };
48020
- const isTanstackRefetchCall = (callExpression, context, effectCallback) => {
48021
- return isTanstackRefetchExpression(callExpression.callee, context, effectCallback);
48022
- };
48023
46898
  const queryNoQueryInEffect = defineRule({
48024
46899
  id: "query-no-query-in-effect",
48025
46900
  title: "Query refetch inside useEffect",
@@ -48035,7 +46910,8 @@ const queryNoQueryInEffect = defineRule({
48035
46910
  walkAst(callback, (child) => {
48036
46911
  if (child !== callback && isFunctionLike$2(child) && !effectInvokedFunctions.has(child)) return false;
48037
46912
  if (!isNodeOfType(child, "CallExpression")) return;
48038
- if (isTanstackRefetchCall(child, context, callback)) context.report({
46913
+ const callee = child.callee;
46914
+ if (isNodeOfType(callee, "Identifier") && callee.name === "refetch" || isNodeOfType(callee, "MemberExpression") && !callee.computed && isNodeOfType(callee.property, "Identifier") && callee.property.name === "refetch") context.report({
48039
46915
  node: child,
48040
46916
  message: "refetch() inside useEffect duplicates work React Query already does, causing extra fetches."
48041
46917
  });
@@ -48044,6 +46920,28 @@ const queryNoQueryInEffect = defineRule({
48044
46920
  });
48045
46921
  //#endregion
48046
46922
  //#region src/plugin/rules/tanstack-query/query-no-rest-destructuring.ts
46923
+ const resolveTanstackQueryHookName = (callExpression) => {
46924
+ const callee = callExpression.callee;
46925
+ if (isNodeOfType(callee, "Identifier")) {
46926
+ const importBinding = getImportBindingForName(callExpression, callee.name);
46927
+ if (importBinding === null) return TANSTACK_QUERY_HOOKS.has(callee.name) ? callee.name : null;
46928
+ if (importBinding.isNamespace || !isTanstackQuerySource(importBinding.source)) return null;
46929
+ return importBinding.exportedName !== null && TANSTACK_QUERY_HOOKS.has(importBinding.exportedName) ? importBinding.exportedName : null;
46930
+ }
46931
+ if (isNodeOfType(callee, "MemberExpression") && !callee.computed && isNodeOfType(callee.property, "Identifier") && TANSTACK_QUERY_HOOKS.has(callee.property.name) && isNodeOfType(callee.object, "Identifier")) {
46932
+ const namespaceBinding = getImportBindingForName(callExpression, callee.object.name);
46933
+ if (namespaceBinding?.isNamespace && isTanstackQuerySource(namespaceBinding.source)) return callee.property.name;
46934
+ }
46935
+ return null;
46936
+ };
46937
+ const resolveHookNameFromInitializer = (initializer, scopes) => {
46938
+ if (isNodeOfType(initializer, "CallExpression")) return resolveTanstackQueryHookName(initializer);
46939
+ if (!isNodeOfType(initializer, "Identifier")) return null;
46940
+ const resolvedSymbol = resolveConstIdentifierAlias(initializer, scopes);
46941
+ if (resolvedSymbol?.kind !== "const" || !resolvedSymbol.initializer) return null;
46942
+ if (!isNodeOfType(resolvedSymbol.initializer, "CallExpression")) return null;
46943
+ return resolveTanstackQueryHookName(resolvedSymbol.initializer);
46944
+ };
48047
46945
  const queryNoRestDestructuring = defineRule({
48048
46946
  id: "query-no-rest-destructuring",
48049
46947
  title: "Rest destructuring on query result",
@@ -48055,7 +46953,7 @@ const queryNoRestDestructuring = defineRule({
48055
46953
  if (!isNodeOfType(node.id, "ObjectPattern")) return;
48056
46954
  if (!node.init) return;
48057
46955
  if (!node.id.properties?.some((property) => isNodeOfType(property, "RestElement"))) return;
48058
- const hookName = resolveTanstackQueryHookNameFromInitializer(node.init, context.scopes);
46956
+ const hookName = resolveHookNameFromInitializer(node.init, context.scopes);
48059
46957
  if (!hookName) return;
48060
46958
  context.report({
48061
46959
  node: node.id,
@@ -48190,8 +47088,8 @@ const queryStableQueryClient = defineRule({
48190
47088
  create: (context) => ({ NewExpression(node) {
48191
47089
  if (!isNodeOfType(node.callee, "Identifier") || node.callee.name !== "QueryClient") return;
48192
47090
  if (isStableHookWrapperArgument(node)) return;
48193
- let enclosingFunction = findEnclosingFunction$1(node);
48194
- while (enclosingFunction && isImmediatelyInvokedFunction(enclosingFunction)) enclosingFunction = findEnclosingFunction$1(enclosingFunction);
47091
+ let enclosingFunction = findEnclosingFunction(node);
47092
+ while (enclosingFunction && isImmediatelyInvokedFunction(enclosingFunction)) enclosingFunction = findEnclosingFunction(enclosingFunction);
48195
47093
  if (!enclosingFunction) return;
48196
47094
  if (!isComponentFunction(enclosingFunction)) return;
48197
47095
  context.report({
@@ -48286,7 +47184,7 @@ const reactCompilerNoManualMemoization = defineRule({
48286
47184
  const comparatorArgument = node.arguments?.[1];
48287
47185
  if (comparatorArgument && !isNullishComparatorArgument(comparatorArgument)) return;
48288
47186
  } else {
48289
- const enclosingFunction = findEnclosingFunction$1(node);
47187
+ const enclosingFunction = findEnclosingFunction(node);
48290
47188
  if (!enclosingFunction || !isCompilerInferableFunction(enclosingFunction)) return;
48291
47189
  }
48292
47190
  const removalMessage = REMOVAL_MESSAGE_BY_REACT_API_NAME.get(apiName);
@@ -48299,7 +47197,7 @@ const reactCompilerNoManualMemoization = defineRule({
48299
47197
  });
48300
47198
  //#endregion
48301
47199
  //#region src/plugin/rules/react-builtins/react-in-jsx-scope.ts
48302
- const MESSAGE$7 = "This JSX crashes because `React` isn't in scope.";
47200
+ const MESSAGE$6 = "This JSX crashes because `React` isn't in scope.";
48303
47201
  const reactInJsxScope = defineRule({
48304
47202
  id: "react-in-jsx-scope",
48305
47203
  title: "React not in scope for JSX",
@@ -48311,190 +47209,19 @@ const reactInJsxScope = defineRule({
48311
47209
  if (findVariableInitializer(node, "React")) return;
48312
47210
  context.report({
48313
47211
  node: node.name,
48314
- message: MESSAGE$7
47212
+ message: MESSAGE$6
48315
47213
  });
48316
47214
  },
48317
47215
  JSXFragment(node) {
48318
47216
  if (findVariableInitializer(node, "React")) return;
48319
47217
  context.report({
48320
47218
  node: node.openingFragment,
48321
- message: MESSAGE$7
47219
+ message: MESSAGE$6
48322
47220
  });
48323
47221
  }
48324
47222
  })
48325
47223
  });
48326
47224
  //#endregion
48327
- //#region src/plugin/rules/security/react-markdown-unsanitized-raw-html.ts
48328
- const MESSAGE$6 = "React Markdown parses dynamic raw HTML when `rehype-raw` is enabled. Add `rehype-sanitize` to `rehypePlugins` or sanitize the markdown before rendering it.";
48329
- const REACT_MARKDOWN_MODULE = "react-markdown";
48330
- const REHYPE_RAW_MODULE = "rehype-raw";
48331
- const REHYPE_SANITIZE_MODULE = "rehype-sanitize";
48332
- const DOMPURIFY_MODULES = new Set(["dompurify", "isomorphic-dompurify"]);
48333
- const REACT_MARKDOWN_NAMED_EXPORTS = new Set(["MarkdownAsync", "MarkdownHooks"]);
48334
- const REACT_MARKDOWN_NAMESPACE_EXPORTS = new Set(["default", ...REACT_MARKDOWN_NAMED_EXPORTS]);
48335
- const DEFAULT_EXPORT_NAMES = new Set(["default"]);
48336
- const getImportDeclaration = (symbol) => {
48337
- if (symbol.kind !== "import") return null;
48338
- const importDeclaration = symbol.declarationNode.parent;
48339
- return isNodeOfType(importDeclaration, "ImportDeclaration") ? importDeclaration : null;
48340
- };
48341
- const isImportFromModule = (symbol, moduleName) => getImportDeclaration(symbol)?.source.value === moduleName;
48342
- const isDefaultImportSymbol = (symbol, moduleName) => {
48343
- if (!isImportFromModule(symbol, moduleName)) return false;
48344
- return isNodeOfType(symbol.declarationNode, "ImportDefaultSpecifier") || getImportedName(symbol.declarationNode) === "default";
48345
- };
48346
- const resolveImportedIdentifier = (node, scopes) => {
48347
- if (!isNodeOfType(node, "Identifier") && !isNodeOfType(node, "JSXIdentifier")) return null;
48348
- const symbol = resolveConstIdentifierAlias(node, scopes);
48349
- return symbol?.kind === "import" ? symbol : null;
48350
- };
48351
- const getStaticMemberParts = (node) => {
48352
- if (isNodeOfType(node, "MemberExpression")) {
48353
- if (node.computed || !isNodeOfType(node.property, "Identifier")) return null;
48354
- return {
48355
- object: node.object,
48356
- propertyName: node.property.name
48357
- };
48358
- }
48359
- if (isNodeOfType(node, "JSXMemberExpression")) {
48360
- if (!isNodeOfType(node.property, "JSXIdentifier")) return null;
48361
- return {
48362
- object: node.object,
48363
- propertyName: node.property.name
48364
- };
48365
- }
48366
- return null;
48367
- };
48368
- const isNamespaceMemberFromModule = (node, moduleName, memberNames, scopes) => {
48369
- const memberParts = getStaticMemberParts(node);
48370
- if (!memberParts || !memberNames.has(memberParts.propertyName)) return false;
48371
- const namespaceSymbol = resolveImportedIdentifier(memberParts.object, scopes);
48372
- return Boolean(namespaceSymbol && isImportFromModule(namespaceSymbol, moduleName) && isNodeOfType(namespaceSymbol.declarationNode, "ImportNamespaceSpecifier"));
48373
- };
48374
- const isReactMarkdownComponent = (node, scopes) => {
48375
- if (isNodeOfType(node, "JSXIdentifier")) {
48376
- const symbol = resolveImportedIdentifier(node, scopes);
48377
- if (!symbol || !isImportFromModule(symbol, REACT_MARKDOWN_MODULE)) return false;
48378
- if (isNodeOfType(symbol.declarationNode, "ImportDefaultSpecifier")) return true;
48379
- const importedName = getImportedName(symbol.declarationNode);
48380
- return importedName === "default" || Boolean(importedName && REACT_MARKDOWN_NAMED_EXPORTS.has(importedName));
48381
- }
48382
- return isNamespaceMemberFromModule(node, REACT_MARKDOWN_MODULE, REACT_MARKDOWN_NAMESPACE_EXPORTS, scopes);
48383
- };
48384
- const isPluginFromModule = (rawNode, moduleName, scopes, visitedSymbolIds) => {
48385
- const node = stripParenExpression(rawNode);
48386
- if (isNodeOfType(node, "Identifier")) {
48387
- const symbol = resolveConstIdentifierAlias(node, scopes);
48388
- if (!symbol || visitedSymbolIds.has(symbol.id)) return false;
48389
- if (isDefaultImportSymbol(symbol, moduleName)) return true;
48390
- if (symbol.kind !== "const" || !symbol.initializer) return false;
48391
- visitedSymbolIds.add(symbol.id);
48392
- return isPluginFromModule(symbol.initializer, moduleName, scopes, visitedSymbolIds);
48393
- }
48394
- if (isNamespaceMemberFromModule(node, moduleName, DEFAULT_EXPORT_NAMES, scopes)) return true;
48395
- if (!isNodeOfType(node, "ArrayExpression")) return false;
48396
- for (const element of node.elements) {
48397
- if (!element || isNodeOfType(element, "SpreadElement")) continue;
48398
- return isPluginFromModule(element, moduleName, scopes, visitedSymbolIds);
48399
- }
48400
- return false;
48401
- };
48402
- const collectPluginEntries = (rawNode, scopes, visitedSymbolIds) => {
48403
- const node = stripParenExpression(rawNode);
48404
- if (isNodeOfType(node, "Identifier")) {
48405
- const symbol = scopes.referenceFor(node)?.resolvedSymbol;
48406
- if (!symbol || symbol.kind !== "const" || !symbol.initializer || visitedSymbolIds.has(symbol.id) || !isNodeOfType(symbol.declarationNode, "VariableDeclarator") || symbol.declarationNode.id !== symbol.bindingIdentifier) return null;
48407
- visitedSymbolIds.add(symbol.id);
48408
- return collectPluginEntries(symbol.initializer, scopes, visitedSymbolIds);
48409
- }
48410
- if (!isNodeOfType(node, "ArrayExpression")) return null;
48411
- const entries = [];
48412
- for (const element of node.elements) {
48413
- if (!element) continue;
48414
- if (isNodeOfType(element, "SpreadElement")) {
48415
- const spreadEntries = collectPluginEntries(element.argument, scopes, new Set(visitedSymbolIds));
48416
- if (spreadEntries === null) return null;
48417
- entries.push(...spreadEntries);
48418
- continue;
48419
- }
48420
- entries.push(element);
48421
- }
48422
- return entries;
48423
- };
48424
- const findEffectiveExplicitAttribute = (attributes, attributeName) => {
48425
- for (let attributeIndex = attributes.length - 1; attributeIndex >= 0; attributeIndex -= 1) {
48426
- const attribute = attributes[attributeIndex];
48427
- if (!attribute || isNodeOfType(attribute, "JSXSpreadAttribute")) return null;
48428
- if (isNodeOfType(attribute, "JSXAttribute") && isNodeOfType(attribute.name, "JSXIdentifier") && attribute.name.name === attributeName) return attribute;
48429
- }
48430
- return null;
48431
- };
48432
- const getAttributeExpression = (attribute) => {
48433
- if (!isNodeOfType(attribute.value, "JSXExpressionContainer")) return null;
48434
- return isNodeOfType(attribute.value.expression, "JSXEmptyExpression") ? null : attribute.value.expression;
48435
- };
48436
- const isDomPurifyNamespace = (node, scopes) => {
48437
- const symbol = resolveImportedIdentifier(node, scopes);
48438
- if (!symbol) return false;
48439
- const importDeclaration = getImportDeclaration(symbol);
48440
- if (!importDeclaration || !DOMPURIFY_MODULES.has(String(importDeclaration.source.value))) return false;
48441
- return isNodeOfType(symbol.declarationNode, "ImportDefaultSpecifier") || isNodeOfType(symbol.declarationNode, "ImportNamespaceSpecifier") || getImportedName(symbol.declarationNode) === "default";
48442
- };
48443
- const isDomPurifySanitizeCall = (node, scopes) => {
48444
- if (!isNodeOfType(node, "CallExpression")) return false;
48445
- const memberParts = getStaticMemberParts(stripParenExpression(node.callee));
48446
- return Boolean(memberParts && memberParts.propertyName === "sanitize" && isDomPurifyNamespace(memberParts.object, scopes));
48447
- };
48448
- const isStaticOrSanitizedMarkdownExpression = (rawNode, scopes, visitedSymbolIds) => {
48449
- const node = stripParenExpression(rawNode);
48450
- if (isNodeOfType(node, "Literal")) return true;
48451
- if (isNodeOfType(node, "TemplateLiteral")) return node.expressions.every((expression) => isStaticOrSanitizedMarkdownExpression(expression, scopes, new Set(visitedSymbolIds)));
48452
- if (isDomPurifySanitizeCall(node, scopes)) return true;
48453
- if (isNodeOfType(node, "ConditionalExpression")) return isStaticOrSanitizedMarkdownExpression(node.consequent, scopes, new Set(visitedSymbolIds)) && isStaticOrSanitizedMarkdownExpression(node.alternate, scopes, new Set(visitedSymbolIds));
48454
- if (isNodeOfType(node, "BinaryExpression") && node.operator === "+") return isStaticOrSanitizedMarkdownExpression(node.left, scopes, new Set(visitedSymbolIds)) && isStaticOrSanitizedMarkdownExpression(node.right, scopes, new Set(visitedSymbolIds));
48455
- if (!isNodeOfType(node, "Identifier")) return false;
48456
- const symbol = scopes.referenceFor(node)?.resolvedSymbol;
48457
- if (!symbol || symbol.kind !== "const" || !symbol.initializer || visitedSymbolIds.has(symbol.id) || !isNodeOfType(symbol.declarationNode, "VariableDeclarator") || symbol.declarationNode.id !== symbol.bindingIdentifier) return false;
48458
- visitedSymbolIds.add(symbol.id);
48459
- return isStaticOrSanitizedMarkdownExpression(symbol.initializer, scopes, visitedSymbolIds);
48460
- };
48461
- const hasDynamicUnsanitizedChildren = (openingElement, scopes) => {
48462
- const jsxElement = openingElement.parent;
48463
- if (!isNodeOfType(jsxElement, "JSXElement")) return false;
48464
- const meaningfulChildren = jsxElement.children.filter((child) => !isNodeOfType(child, "JSXText") || child.value.trim().length > 0);
48465
- if (meaningfulChildren.length > 0) return meaningfulChildren.some((child) => {
48466
- if (isNodeOfType(child, "JSXText")) return false;
48467
- if (!isNodeOfType(child, "JSXExpressionContainer")) return true;
48468
- if (isNodeOfType(child.expression, "JSXEmptyExpression")) return false;
48469
- return !isStaticOrSanitizedMarkdownExpression(child.expression, scopes, /* @__PURE__ */ new Set());
48470
- });
48471
- const childrenAttribute = findEffectiveExplicitAttribute(openingElement.attributes, "children");
48472
- if (!childrenAttribute) return false;
48473
- const childrenExpression = getAttributeExpression(childrenAttribute);
48474
- return Boolean(childrenExpression && !isStaticOrSanitizedMarkdownExpression(childrenExpression, scopes, /* @__PURE__ */ new Set()));
48475
- };
48476
- const reactMarkdownUnsanitizedRawHtml = defineRule({
48477
- id: "react-markdown-unsanitized-raw-html",
48478
- title: "Unsanitized raw HTML in React Markdown",
48479
- severity: "warn",
48480
- recommendation: "Add `rehype-sanitize` to `rehypePlugins` or sanitize dynamic markdown before rendering. `skipHtml` does not disable HTML already parsed by `rehype-raw`.",
48481
- create: skipNonProductionFiles((context) => ({ JSXOpeningElement(node) {
48482
- if (!isReactMarkdownComponent(node.name, context.scopes)) return;
48483
- const pluginsAttribute = findEffectiveExplicitAttribute(node.attributes, "rehypePlugins");
48484
- if (!pluginsAttribute) return;
48485
- const pluginsExpression = getAttributeExpression(pluginsAttribute);
48486
- if (!pluginsExpression) return;
48487
- const pluginEntries = collectPluginEntries(pluginsExpression, context.scopes, /* @__PURE__ */ new Set());
48488
- if (pluginEntries === null) return;
48489
- if (!pluginEntries.some((entry) => isPluginFromModule(entry, REHYPE_RAW_MODULE, context.scopes, /* @__PURE__ */ new Set()))) return;
48490
- if (pluginEntries.some((entry) => isPluginFromModule(entry, REHYPE_SANITIZE_MODULE, context.scopes, /* @__PURE__ */ new Set())) || !hasDynamicUnsanitizedChildren(node, context.scopes)) return;
48491
- context.report({
48492
- node,
48493
- message: MESSAGE$6
48494
- });
48495
- } }))
48496
- });
48497
- //#endregion
48498
47225
  //#region src/plugin/utils/collect-react-redux-selector-aliases.ts
48499
47226
  const REACT_REDUX_MODULE = "react-redux";
48500
47227
  const collectReactReduxSelectorAliases = (programRoot) => {
@@ -51391,7 +50118,7 @@ const isReactNativeDimensionsCallee = (node, callee) => {
51391
50118
  };
51392
50119
  const STYLE_FACTORY_CALLEE_PATTERN$1 = /(?:^|\.)(?:make|create)(?:Use)?Styles$/;
51393
50120
  const isInsideStyleFactoryCallback = (node) => {
51394
- const enclosingFunction = findEnclosingFunction$1(node);
50121
+ const enclosingFunction = findEnclosingFunction(node);
51395
50122
  if (!enclosingFunction) return false;
51396
50123
  const callExpression = enclosingFunction.parent;
51397
50124
  if (!callExpression || !isNodeOfType(callExpression, "CallExpression")) return false;
@@ -56922,6 +55649,22 @@ const isInsideClassComponent = (node) => {
56922
55649
  }
56923
55650
  return false;
56924
55651
  };
55652
+ const hasShortCircuitAncestor = (descendant, ancestor) => {
55653
+ let current = descendant.parent;
55654
+ while (current && current !== ancestor) {
55655
+ if (isNodeOfType(current, "ConditionalExpression") && (isWithinRange(descendant, current.consequent) || isWithinRange(descendant, current.alternate))) return true;
55656
+ if (isNodeOfType(current, "LogicalExpression") && (current.operator === "&&" || current.operator === "||" || current.operator === "??") && isWithinRange(descendant, current.right)) return true;
55657
+ if (isNodeOfType(current, "AssignmentPattern") && isWithinRange(descendant, current.right)) return true;
55658
+ current = current.parent ?? null;
55659
+ }
55660
+ return false;
55661
+ };
55662
+ const isWithinRange = (descendant, sibling) => {
55663
+ const descendantSpan = descendant;
55664
+ const siblingSpan = sibling;
55665
+ if (typeof descendantSpan.start !== "number" || typeof siblingSpan.start !== "number" || typeof siblingSpan.end !== "number") return false;
55666
+ return descendantSpan.start >= siblingSpan.start && (descendantSpan.end ?? siblingSpan.end) <= siblingSpan.end;
55667
+ };
56925
55668
  const isInsideTry = (descendant, ancestor) => {
56926
55669
  let current = descendant.parent;
56927
55670
  while (current && current !== ancestor) {
@@ -57113,7 +55856,7 @@ const rulesOfHooks = defineRule({
57113
55856
  });
57114
55857
  return;
57115
55858
  }
57116
- if (isNodeConditionallyExecuted(node, enclosing.node)) {
55859
+ if (hasShortCircuitAncestor(node, enclosing.node)) {
57117
55860
  context.report({
57118
55861
  node: node.callee,
57119
55862
  message: buildConditionalMessage(hookName)
@@ -58247,14 +56990,12 @@ const declarationAwaitsRequestScopedCall = (declaration) => {
58247
56990
  }
58248
56991
  return false;
58249
56992
  };
58250
- const declarationAwaitsGate = (declaration, context) => {
56993
+ const declarationAwaitsGate = (declaration) => {
58251
56994
  if (!isNodeOfType(declaration, "VariableDeclaration")) return false;
58252
56995
  for (const declarator of declaration.declarations ?? []) {
58253
56996
  if (!isNodeOfType(declarator.init, "AwaitExpression")) continue;
58254
56997
  const argument = declarator.init.argument;
58255
56998
  if (!isNodeOfType(argument, "CallExpression")) continue;
58256
- if (hasPossibleStaticMemberCallWrite(argument, context.scopes)) return true;
58257
- if (getOrderIndependentLocalFunction(argument, context.scopes) !== null) continue;
58258
56999
  const calleeName = getCalleeName$2(argument);
58259
57000
  if (!calleeName) continue;
58260
57001
  if (isAuthGuardName(calleeName)) return true;
@@ -58282,7 +57023,7 @@ const serverSequentialIndependentAwait = defineRule({
58282
57023
  if (declarationReadsAnyName(nextStatement, declaredNames)) continue;
58283
57024
  if (declarationAwaitsExistingPromise(nextStatement)) continue;
58284
57025
  if (declarationAwaitsRequestScopedCall(currentStatement) || declarationAwaitsRequestScopedCall(nextStatement)) continue;
58285
- if (declarationAwaitsGate(currentStatement, context)) continue;
57026
+ if (declarationAwaitsGate(currentStatement)) continue;
58286
57027
  context.report({
58287
57028
  node: nextStatement,
58288
57029
  message: "This await doesn't use the previous result, so your users wait twice as long for nothing."
@@ -59268,7 +58009,7 @@ const tanstackStartNoNavigateInRender = defineRule({
59268
58009
  const isReturnedFromCustomHook = (functionNode) => {
59269
58010
  const parent = functionNode.parent;
59270
58011
  if (isNodeOfType(parent, "ReturnStatement")) {
59271
- const outerFunction = findEnclosingFunction$1(parent);
58012
+ const outerFunction = findEnclosingFunction(parent);
59272
58013
  const hookName = outerFunction ? getFunctionBindingName$1(outerFunction) : null;
59273
58014
  return Boolean(hookName && HOOK_NAME_PATTERN$3.test(hookName));
59274
58015
  }
@@ -59285,13 +58026,13 @@ const tanstackStartNoNavigateInRender = defineRule({
59285
58026
  return parent.callee === functionNode || (parent.arguments ?? []).some((callArgument) => callArgument === functionNode);
59286
58027
  };
59287
58028
  const isDeferredNavigateCall = (callNode) => {
59288
- let enclosingFunction = findEnclosingFunction$1(callNode);
58029
+ let enclosingFunction = findEnclosingFunction(callNode);
59289
58030
  while (enclosingFunction) {
59290
58031
  if (isDeferredCallbackPosition(enclosingFunction)) return true;
59291
58032
  if (isWiredAsEventHandler(enclosingFunction)) return true;
59292
58033
  if (isReturnedFromCustomHook(enclosingFunction)) return true;
59293
58034
  if (!isSynchronouslyInvokedAnonymousWrapper(enclosingFunction)) return false;
59294
- enclosingFunction = findEnclosingFunction$1(enclosingFunction);
58035
+ enclosingFunction = findEnclosingFunction(enclosingFunction);
59295
58036
  }
59296
58037
  return false;
59297
58038
  };
@@ -63730,17 +62471,6 @@ const reactDoctorRules = [
63730
62471
  requires: [...new Set(["react", ...reactInJsxScope.requires ?? []])]
63731
62472
  }
63732
62473
  },
63733
- {
63734
- key: "react-doctor/react-markdown-unsanitized-raw-html",
63735
- id: "react-markdown-unsanitized-raw-html",
63736
- source: "react-doctor",
63737
- originallyExternal: false,
63738
- rule: {
63739
- ...reactMarkdownUnsanitizedRawHtml,
63740
- framework: "global",
63741
- category: "Security"
63742
- }
63743
- },
63744
62474
  {
63745
62475
  key: "react-doctor/redux-useselector-inline-derivation",
63746
62476
  id: "redux-useselector-inline-derivation",