oxlint-plugin-react-doctor 0.7.7-dev.a468589 → 0.7.7-dev.afed801

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 +754 -2065
  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$1 = (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$1(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$1(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$1(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,11 +25449,8 @@ 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
- const definition = ref.resolved?.defs[0];
26302
- if (!definition || hasParameterDefinition(ref)) return null;
26303
- const definitionNode = definition.node;
25453
+ const definitionNode = ref.resolved?.defs[0]?.node;
26304
25454
  if (!definitionNode) return null;
26305
25455
  if (isFunctionLike$2(definitionNode)) return definitionNode;
26306
25456
  if (isNodeOfType(definitionNode, "VariableDeclarator")) {
@@ -26710,7 +25860,7 @@ const isCleanupReturnArgument = (analysis, node) => {
26710
25860
  if (isNodeOfType(node, "MemberExpression")) return true;
26711
25861
  if (isNodeOfType(node, "Identifier")) {
26712
25862
  const ref = getRef(analysis, node);
26713
- if (ref && (hasParameterDefinition(ref) || resolveToFunction(ref))) return true;
25863
+ if (ref && resolveToFunction(ref)) return true;
26714
25864
  }
26715
25865
  if (isNodeOfType(node, "ConditionalExpression")) return isCleanupReturnArgument(analysis, node.consequent) || isCleanupReturnArgument(analysis, node.alternate);
26716
25866
  return false;
@@ -26868,7 +26018,7 @@ const isIndependentWriterIdentifier = (componentFunction, identifier, includeDef
26868
26018
  };
26869
26019
  const hasUserInputSetterWriter = (setterRef, effectNode, includeDeferredWriters = false) => {
26870
26020
  if (!setterRef.resolved) return false;
26871
- const componentFunction = findEnclosingFunction$1(effectNode);
26021
+ const componentFunction = findEnclosingFunction(effectNode);
26872
26022
  if (!componentFunction) return false;
26873
26023
  for (const reference of setterRef.resolved.references) {
26874
26024
  if (reference.init) continue;
@@ -27182,7 +26332,7 @@ const resolveWrappedCallable = (analysis, node) => {
27182
26332
  if (isNodeOfType(candidate, "Identifier")) {
27183
26333
  const reference = getRef(analysis, candidate);
27184
26334
  if (!reference) return null;
27185
- if (reference.resolved?.defs.some((definition) => definition.type === "ImportBinding")) return null;
26335
+ if (reference.resolved?.defs.some((definition) => definition.type === "Parameter" || definition.type === "ImportBinding")) return null;
27186
26336
  const resolved = resolveToFunction(reference);
27187
26337
  if (resolved) return resolved;
27188
26338
  const definitionNode = reference.resolved?.defs[0]?.node;
@@ -27846,7 +26996,7 @@ const noAdjustStateOnPropChange = defineRule({
27846
26996
  });
27847
26997
  //#endregion
27848
26998
  //#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.";
26999
+ 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
27000
  const ALWAYS_FOCUSABLE_TAGS = new Set([
27851
27001
  "button",
27852
27002
  "embed",
@@ -27958,7 +27108,7 @@ const noAriaHiddenOnFocusable = defineRule({
27958
27108
  const isImplicitlyFocusable = isNativelyFocusable(tag, node);
27959
27109
  if (isExplicitlyFocusable || isImplicitlyFocusable) context.report({
27960
27110
  node: ariaHidden,
27961
- message: MESSAGE$38
27111
+ message: MESSAGE$37
27962
27112
  });
27963
27113
  } })
27964
27114
  });
@@ -28880,7 +28030,7 @@ const isAllLiteralArrayExpression = (node) => {
28880
28030
  };
28881
28031
  //#endregion
28882
28032
  //#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.";
28033
+ const MESSAGE$36 = "Your users can see & submit the wrong data when this list reorders.";
28884
28034
  const SECOND_INDEX_METHODS = new Set([
28885
28035
  "every",
28886
28036
  "filter",
@@ -28999,14 +28149,14 @@ const noArrayIndexKey = defineRule({
28999
28149
  if (propName !== "key") continue;
29000
28150
  if (expressionUsesIndex(property.value, indexBinding.name)) context.report({
29001
28151
  node: property,
29002
- message: MESSAGE$37
28152
+ message: MESSAGE$36
29003
28153
  });
29004
28154
  }
29005
28155
  } })
29006
28156
  });
29007
28157
  //#endregion
29008
28158
  //#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.";
28159
+ 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
28160
  const noAsyncEffectCallback = defineRule({
29011
28161
  id: "no-async-effect-callback",
29012
28162
  title: "Async effect callback",
@@ -29024,13 +28174,13 @@ const noAsyncEffectCallback = defineRule({
29024
28174
  if (!callback.async) return;
29025
28175
  context.report({
29026
28176
  node: callback,
29027
- message: MESSAGE$36
28177
+ message: MESSAGE$35
29028
28178
  });
29029
28179
  } })
29030
28180
  });
29031
28181
  //#endregion
29032
28182
  //#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.";
28183
+ 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
28184
  const resolveSettings$21 = (settings) => {
29035
28185
  const reactDoctor = settings?.["react-doctor"];
29036
28186
  return { ignoreNonDOM: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noAutofocus ?? {} : {}).ignoreNonDOM ?? true };
@@ -29127,7 +28277,7 @@ const noAutofocus = defineRule({
29127
28277
  if (isConditionallyRendered(node)) return;
29128
28278
  context.report({
29129
28279
  node: autoFocusAttribute,
29130
- message: MESSAGE$35
28280
+ message: MESSAGE$34
29131
28281
  });
29132
28282
  } };
29133
28283
  }
@@ -29641,6 +28791,138 @@ const noBarrelImport = defineRule({
29641
28791
  }
29642
28792
  });
29643
28793
  //#endregion
28794
+ //#region src/plugin/utils/has-static-property-write-before.ts
28795
+ const equivalentSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
28796
+ const CONDITIONAL_EXECUTION_NODE_TYPES = new Set([
28797
+ "CatchClause",
28798
+ "ConditionalExpression",
28799
+ "DoWhileStatement",
28800
+ "ForInStatement",
28801
+ "ForOfStatement",
28802
+ "ForStatement",
28803
+ "IfStatement",
28804
+ "LogicalExpression",
28805
+ "SwitchCase",
28806
+ "SwitchStatement",
28807
+ "TryStatement",
28808
+ "WhileStatement"
28809
+ ]);
28810
+ const getResolvedStaticPropertyName = (memberExpression, scopes) => {
28811
+ if (!isNodeOfType(memberExpression, "MemberExpression")) return null;
28812
+ const directPropertyName = getStaticPropertyName(memberExpression);
28813
+ if (directPropertyName || !memberExpression.computed) return directPropertyName;
28814
+ const property = stripParenExpression(memberExpression.property);
28815
+ if (!isNodeOfType(property, "Identifier")) return null;
28816
+ const propertySymbol = resolveConstIdentifierAlias(property, scopes);
28817
+ const initializer = propertySymbol?.initializer ? stripParenExpression(propertySymbol.initializer) : null;
28818
+ return initializer && isNodeOfType(initializer, "Literal") && typeof initializer.value === "string" ? initializer.value : null;
28819
+ };
28820
+ const collectScopeSymbols = (scope, symbols) => {
28821
+ symbols.push(...scope.symbols);
28822
+ for (const childScope of scope.children) collectScopeSymbols(childScope, symbols);
28823
+ };
28824
+ const getEquivalentSymbols = (identifier, scopes) => {
28825
+ const rootSymbol = resolveConstIdentifierAlias(identifier, scopes);
28826
+ if (!rootSymbol) return [];
28827
+ let symbolsByRootId = equivalentSymbolsByAnalysis.get(scopes);
28828
+ if (!symbolsByRootId) {
28829
+ symbolsByRootId = /* @__PURE__ */ new Map();
28830
+ equivalentSymbolsByAnalysis.set(scopes, symbolsByRootId);
28831
+ }
28832
+ const cachedSymbols = symbolsByRootId.get(rootSymbol.id);
28833
+ if (cachedSymbols) return cachedSymbols;
28834
+ const allSymbols = [];
28835
+ collectScopeSymbols(scopes.rootScope, allSymbols);
28836
+ const equivalentSymbols = allSymbols.filter((symbol) => resolveConstIdentifierAlias(symbol.bindingIdentifier, scopes)?.id === rootSymbol.id);
28837
+ symbolsByRootId.set(rootSymbol.id, equivalentSymbols);
28838
+ return equivalentSymbols;
28839
+ };
28840
+ const findExecutionBoundary = (node) => {
28841
+ let current = node;
28842
+ while (current) {
28843
+ if (isFunctionLike$2(current) || isNodeOfType(current, "Program")) return current;
28844
+ current = current.parent ?? null;
28845
+ }
28846
+ return null;
28847
+ };
28848
+ const isOnUnconditionalPath = (node, boundary) => {
28849
+ let current = node.parent ?? null;
28850
+ while (current && current !== boundary) {
28851
+ if (CONDITIONAL_EXECUTION_NODE_TYPES.has(current.type)) return false;
28852
+ current = current.parent ?? null;
28853
+ }
28854
+ return current === boundary;
28855
+ };
28856
+ const findFunctionBindingIdentifier = (functionNode) => {
28857
+ if (isNodeOfType(functionNode, "FunctionDeclaration")) return functionNode.id ?? null;
28858
+ const parent = functionNode.parent;
28859
+ if (parent && isNodeOfType(parent, "VariableDeclarator") && parent.init === functionNode && isNodeOfType(parent.id, "Identifier")) return parent.id;
28860
+ return null;
28861
+ };
28862
+ const findDirectCall = (identifier) => {
28863
+ let callee = identifier;
28864
+ let parent = callee.parent;
28865
+ while (parent && stripParenExpression(parent) === identifier) {
28866
+ callee = parent;
28867
+ parent = callee.parent;
28868
+ }
28869
+ return parent && isNodeOfType(parent, "CallExpression") && parent.callee === callee ? parent : null;
28870
+ };
28871
+ const isFunctionSynchronouslyInvokedBefore = (functionNode, referenceNode, scopes, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
28872
+ if (visitedFunctionNodes.has(functionNode) || !isFunctionLike$2(functionNode) || functionNode.generator) return false;
28873
+ visitedFunctionNodes.add(functionNode);
28874
+ const referenceBoundary = findExecutionBoundary(referenceNode);
28875
+ if (!referenceBoundary) return false;
28876
+ const invocationCalls = [];
28877
+ const bindingIdentifier = findFunctionBindingIdentifier(functionNode);
28878
+ if (bindingIdentifier) for (const symbol of getEquivalentSymbols(bindingIdentifier, scopes)) for (const reference of symbol.references) {
28879
+ const call = findDirectCall(reference.identifier);
28880
+ if (call) invocationCalls.push(call);
28881
+ }
28882
+ else {
28883
+ const call = findDirectCall(functionNode);
28884
+ if (call) invocationCalls.push(call);
28885
+ }
28886
+ return invocationCalls.some((call) => {
28887
+ if (call.range[0] >= referenceNode.range[0]) return false;
28888
+ const callBoundary = findExecutionBoundary(call);
28889
+ if (!callBoundary) return false;
28890
+ if (callBoundary === referenceBoundary) return true;
28891
+ if (!isFunctionLike$2(callBoundary)) return false;
28892
+ return isFunctionSynchronouslyInvokedBefore(callBoundary, referenceNode, scopes, new Set(visitedFunctionNodes));
28893
+ });
28894
+ };
28895
+ const isMemberWriteTarget = (memberExpression) => {
28896
+ const parent = memberExpression.parent;
28897
+ if (!parent) return false;
28898
+ if (isNodeOfType(parent, "AssignmentExpression")) return parent.left === memberExpression;
28899
+ if (isNodeOfType(parent, "UpdateExpression")) return parent.argument === memberExpression;
28900
+ return isNodeOfType(parent, "UnaryExpression") && parent.operator === "delete" && parent.argument === memberExpression;
28901
+ };
28902
+ const symbolHasStaticPropertyWriteBefore = (symbol, propertyName, referenceNode, scopes) => symbol.references.some((reference) => {
28903
+ let parent = reference.identifier.parent;
28904
+ while (parent && stripParenExpression(parent) === reference.identifier) parent = parent.parent;
28905
+ if (!parent || !isNodeOfType(parent, "MemberExpression") || stripParenExpression(parent.object) !== reference.identifier || getResolvedStaticPropertyName(parent, scopes) !== propertyName || !isMemberWriteTarget(parent)) return false;
28906
+ const writeBoundary = findExecutionBoundary(parent);
28907
+ const referenceBoundary = findExecutionBoundary(referenceNode);
28908
+ if (!writeBoundary || !referenceBoundary || !isOnUnconditionalPath(parent, writeBoundary)) return false;
28909
+ if (writeBoundary === referenceBoundary) return parent.range[0] < referenceNode.range[0];
28910
+ return isFunctionLike$2(writeBoundary) && isFunctionSynchronouslyInvokedBefore(writeBoundary, referenceNode, scopes);
28911
+ });
28912
+ const hasStaticPropertyWriteBefore = (identifier, propertyName, referenceNode, scopes) => {
28913
+ if (!isNodeOfType(identifier, "Identifier")) return false;
28914
+ return getEquivalentSymbols(identifier, scopes).some((symbol) => symbolHasStaticPropertyWriteBefore(symbol, propertyName, referenceNode, scopes));
28915
+ };
28916
+ //#endregion
28917
+ //#region src/plugin/utils/has-symbol-write-before.ts
28918
+ const hasSymbolWriteBefore = (symbol, referenceNode, scopes) => symbol.references.some((reference) => {
28919
+ if (reference.flag === "read") return false;
28920
+ const writeFunction = findEnclosingFunction(reference.identifier);
28921
+ if (writeFunction === findEnclosingFunction(referenceNode)) return reference.identifier.range[0] < referenceNode.range[0];
28922
+ if (!writeFunction) return true;
28923
+ return isFunctionSynchronouslyInvokedBefore(writeFunction, referenceNode, scopes);
28924
+ });
28925
+ //#endregion
29644
28926
  //#region src/plugin/utils/has-stable-call-target.ts
29645
28927
  const hasStableCallTarget = (callExpression, scopes) => {
29646
28928
  if (!isNodeOfType(callExpression, "CallExpression")) return false;
@@ -29968,7 +29250,7 @@ const noChainStateUpdates = defineRule({
29968
29250
  });
29969
29251
  //#endregion
29970
29252
  //#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.";
29253
+ const MESSAGE$33 = "A `children` prop can override or hide nested children, so the component may render different content than the JSX shows.";
29972
29254
  const noChildrenProp = defineRule({
29973
29255
  id: "no-children-prop",
29974
29256
  title: "Children passed as a prop",
@@ -29980,7 +29262,7 @@ const noChildrenProp = defineRule({
29980
29262
  if (node.name.name !== "children") return;
29981
29263
  context.report({
29982
29264
  node: node.name,
29983
- message: MESSAGE$34
29265
+ message: MESSAGE$33
29984
29266
  });
29985
29267
  },
29986
29268
  CallExpression(node) {
@@ -29993,7 +29275,7 @@ const noChildrenProp = defineRule({
29993
29275
  const propertyKey = property.key;
29994
29276
  if (isNodeOfType(propertyKey, "Identifier") && propertyKey.name === "children" || isNodeOfType(propertyKey, "Literal") && propertyKey.value === "children") context.report({
29995
29277
  node: propertyKey,
29996
- message: MESSAGE$34
29278
+ message: MESSAGE$33
29997
29279
  });
29998
29280
  }
29999
29281
  }
@@ -30001,7 +29283,7 @@ const noChildrenProp = defineRule({
30001
29283
  });
30002
29284
  //#endregion
30003
29285
  //#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.";
29286
+ const MESSAGE$32 = "`React.cloneElement` couples the parent to the child's prop shape, so child prop changes can silently break injected behavior.";
30005
29287
  const noCloneElement = defineRule({
30006
29288
  id: "no-clone-element",
30007
29289
  title: "cloneElement makes child props fragile",
@@ -30014,7 +29296,7 @@ const noCloneElement = defineRule({
30014
29296
  if (isNodeOfType(callee, "Identifier") && callee.name === "cloneElement") {
30015
29297
  if (isImportedFromModule(node, "cloneElement", "react")) context.report({
30016
29298
  node: callee,
30017
- message: MESSAGE$33
29299
+ message: MESSAGE$32
30018
29300
  });
30019
29301
  return;
30020
29302
  }
@@ -30027,7 +29309,7 @@ const noCloneElement = defineRule({
30027
29309
  if (!isImportedFromModule(node, callee.object.name, "react")) return;
30028
29310
  context.report({
30029
29311
  node: callee,
30030
- message: MESSAGE$33
29312
+ message: MESSAGE$32
30031
29313
  });
30032
29314
  }
30033
29315
  } })
@@ -30047,7 +29329,7 @@ const getCallMethodName = (callee) => {
30047
29329
  };
30048
29330
  //#endregion
30049
29331
  //#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.";
29332
+ const MESSAGE$31 = "createContext() builds a new context every render, so every consumer gets cut off & resets.";
30051
29333
  const CONTEXT_MODULES = [
30052
29334
  "react",
30053
29335
  "use-context-selector",
@@ -30095,13 +29377,13 @@ const noCreateContextInRender = defineRule({
30095
29377
  if (!componentOrHookName) return;
30096
29378
  context.report({
30097
29379
  node,
30098
- message: `${MESSAGE$32} (called inside "${componentOrHookName}")`
29380
+ message: `${MESSAGE$31} (called inside "${componentOrHookName}")`
30099
29381
  });
30100
29382
  } })
30101
29383
  });
30102
29384
  //#endregion
30103
29385
  //#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.";
29386
+ 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
29387
  const isUseMemoCallbackArgument = (functionNode) => {
30106
29388
  const parent = functionNode.parent;
30107
29389
  if (!parent || !isNodeOfType(parent, "CallExpression")) return false;
@@ -30109,8 +29391,8 @@ const isUseMemoCallbackArgument = (functionNode) => {
30109
29391
  return isReactFunctionCall(parent, "useMemo");
30110
29392
  };
30111
29393
  const findEnclosingRenderFunction = (node) => {
30112
- let enclosingFunction = findEnclosingFunction$1(node);
30113
- while (enclosingFunction && isUseMemoCallbackArgument(enclosingFunction)) enclosingFunction = findEnclosingFunction$1(enclosingFunction);
29394
+ let enclosingFunction = findEnclosingFunction(node);
29395
+ while (enclosingFunction && isUseMemoCallbackArgument(enclosingFunction)) enclosingFunction = findEnclosingFunction(enclosingFunction);
30114
29396
  return enclosingFunction;
30115
29397
  };
30116
29398
  const noCreateRefInFunctionComponent = defineRule({
@@ -30131,7 +29413,7 @@ const noCreateRefInFunctionComponent = defineRule({
30131
29413
  if (!(isReactHookName(displayName) || functionContainsReactRenderOutput(enclosingFunction, context.scopes, context.cfg))) return;
30132
29414
  context.report({
30133
29415
  node,
30134
- message: MESSAGE$31
29416
+ message: MESSAGE$30
30135
29417
  });
30136
29418
  } })
30137
29419
  });
@@ -30271,7 +29553,7 @@ const noCreateStoreInRender = defineRule({
30271
29553
  });
30272
29554
  //#endregion
30273
29555
  //#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.";
29556
+ const MESSAGE$29 = "`dangerouslySetInnerHTML` is an XSS hole that runs attacker-controlled HTML in your users' browsers.";
30275
29557
  const noDanger = defineRule({
30276
29558
  id: "no-danger",
30277
29559
  title: "Raw HTML injection can run unsafe markup",
@@ -30285,7 +29567,7 @@ const noDanger = defineRule({
30285
29567
  if (!propAttribute) return;
30286
29568
  context.report({
30287
29569
  node: propAttribute.name,
30288
- message: MESSAGE$30
29570
+ message: MESSAGE$29
30289
29571
  });
30290
29572
  },
30291
29573
  CallExpression(node) {
@@ -30297,7 +29579,7 @@ const noDanger = defineRule({
30297
29579
  const propertyKey = property.key;
30298
29580
  if (isNodeOfType(propertyKey, "Identifier") && propertyKey.name === "dangerouslySetInnerHTML" || isNodeOfType(propertyKey, "Literal") && propertyKey.value === "dangerouslySetInnerHTML") context.report({
30299
29581
  node: propertyKey,
30300
- message: MESSAGE$30
29582
+ message: MESSAGE$29
30301
29583
  });
30302
29584
  }
30303
29585
  }
@@ -30320,7 +29602,7 @@ const isMeaningfulJsxChild = (child) => {
30320
29602
  };
30321
29603
  //#endregion
30322
29604
  //#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`.";
29605
+ const MESSAGE$28 = "React throws an error when you set both children & `dangerouslySetInnerHTML`.";
30324
29606
  const mergePropsShape = (target, source) => {
30325
29607
  target.hasDangerously ||= source.hasDangerously;
30326
29608
  target.hasChildren ||= source.hasChildren;
@@ -30395,7 +29677,7 @@ const noDangerWithChildren = defineRule({
30395
29677
  if (!hasChildrenProp && !hasNestedChildren) return;
30396
29678
  if (hasJsxPropIgnoreCase(opening.attributes, "dangerouslySetInnerHTML") || spreadPropsShape.hasDangerously) context.report({
30397
29679
  node: opening,
30398
- message: MESSAGE$29
29680
+ message: MESSAGE$28
30399
29681
  });
30400
29682
  },
30401
29683
  CallExpression(node) {
@@ -30408,7 +29690,7 @@ const noDangerWithChildren = defineRule({
30408
29690
  const positionalChildren = node.arguments.slice(2);
30409
29691
  if (positionalChildren.length > 1 || positionalChildren.some((argument) => !isNullishExpression(argument)) || propsShape.hasChildren) context.report({
30410
29692
  node,
30411
- message: MESSAGE$29
29693
+ message: MESSAGE$28
30412
29694
  });
30413
29695
  }
30414
29696
  })
@@ -31161,7 +30443,7 @@ const getEnclosingEffectHookCallback = (node, componentFunction) => {
31161
30443
  const isEffectDrivenResync = (useStateCall) => {
31162
30444
  const setterName = getStateSetterName(useStateCall);
31163
30445
  if (!setterName) return false;
31164
- const componentFunction = findEnclosingFunction$1(useStateCall);
30446
+ const componentFunction = findEnclosingFunction(useStateCall);
31165
30447
  if (!componentFunction) return false;
31166
30448
  let isExempt = false;
31167
30449
  walkAst(componentFunction, (child) => {
@@ -31265,7 +30547,7 @@ const isDraftReseedOrRenderAdjusted = (useStateCall, isPropName) => {
31265
30547
  const setterName = getStateSetterName(useStateCall);
31266
30548
  if (!setterName) return false;
31267
30549
  const stateValueName = getStateValueName(useStateCall);
31268
- const componentFunction = findEnclosingFunction$1(useStateCall);
30550
+ const componentFunction = findEnclosingFunction(useStateCall);
31269
30551
  if (!componentFunction) return false;
31270
30552
  let isExempt = false;
31271
30553
  walkAst(componentFunction, (child) => {
@@ -31311,7 +30593,7 @@ const noDerivedUseState = defineRule({
31311
30593
  if (isDraftReseedOrRenderAdjusted(node, propStackTracker.isPropName)) return;
31312
30594
  if (isEffectDrivenResync(node)) return;
31313
30595
  if (isNextjsDataFetchingPage(node)) return;
31314
- const componentFunction = findEnclosingFunction$1(node);
30596
+ const componentFunction = findEnclosingFunction(node);
31315
30597
  if (componentFunction) {
31316
30598
  if (isDefaultedDestructuredProp(componentFunction, propName)) return;
31317
30599
  if (isDraftCommittedToParent(componentFunction, getStateValueName(node), propStackTracker.isPropName)) return;
@@ -31373,7 +30655,7 @@ const isSetStateCallInLifecycle = (setStateCall, lifecycleNames, options = {}) =
31373
30655
  //#endregion
31374
30656
  //#region src/plugin/rules/react-builtins/no-did-mount-set-state.ts
31375
30657
  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`.";
30658
+ const MESSAGE$27 = "Your users see an extra render right after mount when you call `setState` in `componentDidMount`.";
31377
30659
  const getNodeStart = (node) => "start" in node && typeof node.start === "number" ? node.start : -1;
31378
30660
  const getEnclosingLifecycleFunction = (setStateCall) => {
31379
30661
  let ancestor = setStateCall.parent;
@@ -31501,7 +30783,7 @@ const noDidMountSetState = defineRule({
31501
30783
  }
31502
30784
  context.report({
31503
30785
  node: node.callee,
31504
- message: MESSAGE$28
30786
+ message: MESSAGE$27
31505
30787
  });
31506
30788
  } };
31507
30789
  }
@@ -31509,7 +30791,7 @@ const noDidMountSetState = defineRule({
31509
30791
  //#endregion
31510
30792
  //#region src/plugin/rules/react-builtins/no-did-update-set-state.ts
31511
30793
  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.";
30794
+ const MESSAGE$26 = "Calling setState in componentDidUpdate can trigger another update immediately, loop forever, and freeze the component.";
31513
30795
  const EQUALITY_OPERATORS = new Set([
31514
30796
  "==",
31515
30797
  "===",
@@ -31683,7 +30965,7 @@ const noDidUpdateSetState = defineRule({
31683
30965
  if (isInsideDiffGuard(node)) return;
31684
30966
  context.report({
31685
30967
  node: node.callee,
31686
- message: MESSAGE$27
30968
+ message: MESSAGE$26
31687
30969
  });
31688
30970
  } };
31689
30971
  }
@@ -31706,7 +30988,7 @@ const isStateMemberExpression = (node) => {
31706
30988
  };
31707
30989
  //#endregion
31708
30990
  //#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.";
30991
+ 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
30992
  const shouldIgnoreMutation = (node) => {
31711
30993
  let isConstructor = false;
31712
30994
  let isInsideCallExpression = false;
@@ -31728,7 +31010,7 @@ const reportIfStateMutation = (context, reportNode, target) => {
31728
31010
  if (shouldIgnoreMutation(reportNode)) return;
31729
31011
  context.report({
31730
31012
  node: reportNode,
31731
- message: MESSAGE$26
31013
+ message: MESSAGE$25
31732
31014
  });
31733
31015
  };
31734
31016
  const noDirectMutationState = defineRule({
@@ -32079,7 +31361,7 @@ const noDocumentStartViewTransition = defineRule({
32079
31361
  });
32080
31362
  //#endregion
32081
31363
  //#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.";
31364
+ 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
31365
  const WRITE_METHODS = new Set(["write", "writeln"]);
32084
31366
  const isGlobalDocumentReference = (node, context) => node.name === "document" && context.scopes.isGlobalReference(node);
32085
31367
  const noDocumentWrite = defineRule({
@@ -32096,7 +31378,7 @@ const noDocumentWrite = defineRule({
32096
31378
  if (methodName === null || !WRITE_METHODS.has(methodName)) return;
32097
31379
  context.report({
32098
31380
  node,
32099
- message: MESSAGE$25
31381
+ message: MESSAGE$24
32100
31382
  });
32101
31383
  } })
32102
31384
  });
@@ -32786,29 +32068,6 @@ const isReturnOnlyStatement = (node) => {
32786
32068
  return isNodeOfType(node, "BlockStatement") && (node.body?.length ?? 0) === 1 && isNodeOfType(node.body?.[0], "ReturnStatement");
32787
32069
  };
32788
32070
  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
32071
  const doesGuardMatchDependency = (guardExpression, dependencyExpression) => {
32813
32072
  const unwrappedDependencyExpression = unwrapChainExpression$1(dependencyExpression);
32814
32073
  if (!unwrappedDependencyExpression) return false;
@@ -32816,69 +32075,6 @@ const doesGuardMatchDependency = (guardExpression, dependencyExpression) => {
32816
32075
  return isNodeOfType(unwrappedDependencyExpression, "Identifier") && unwrappedDependencyExpression.name === guardExpression.rootIdentifierName;
32817
32076
  };
32818
32077
  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
32078
  const isEqualityToLiteralGuard = (guardExpression) => {
32883
32079
  const parent = guardExpression.expression.parent;
32884
32080
  if (!isNodeOfType(parent, "BinaryExpression")) return false;
@@ -32943,35 +32139,18 @@ const noEffectEventHandler = defineRule({
32943
32139
  if (statements.length === 0) return;
32944
32140
  const soleStatement = statements[0];
32945
32141
  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));
32142
+ const guardExpressions = [];
32143
+ collectGuardExpressions(soleStatement.test, guardExpressions);
32144
+ const matchingPropGuardExpressions = guardExpressions.filter((guardExpression) => hasDependencyMatch(guardExpression, dependencyExpressions) && propStackTracker.isPropName(guardExpression.rootIdentifierName, node));
32951
32145
  if (matchingPropGuardExpressions.length === 0) return;
32952
32146
  const isSingleGuardedEventLikeStatement = statements.length === 1 && hasEventLikeNode(soleStatement.consequent);
32953
32147
  const isEarlyReturnGuardedEventLikeBody = statements.length > 1 && !soleStatement.alternate && isReturnOnlyStatement(soleStatement.consequent) && hasEventLikeRemainingStatements(statements.slice(1));
32954
32148
  if (!isSingleGuardedEventLikeStatement && !isEarlyReturnGuardedEventLikeBody) return;
32955
32149
  if (isEarlyReturnGuardedEventLikeBody && !isSingleGuardedEventLikeStatement && matchingPropGuardExpressions.every(isEqualityToLiteralGuard)) return;
32956
- if (initialGuardExpressions.some((guardExpression) => !matchingPropGuardExpressions.some((matchingGuardExpression) => matchingGuardExpression.expression === guardExpression.expression))) {
32150
+ if (guardExpressions.some((guardExpression) => !matchingPropGuardExpressions.some((matchingGuardExpression) => matchingGuardExpression.expression === guardExpression.expression))) {
32957
32151
  const matchingPropRootNames = new Set(matchingPropGuardExpressions.map((guardExpression) => guardExpression.rootIdentifierName));
32958
32152
  if (!(isSingleGuardedEventLikeStatement ? doesEventLikeCallReferenceAnyRoot(soleStatement.consequent, matchingPropRootNames) : doesAnyEventLikeCallReferenceAnyRoot(statements.slice(1), matchingPropRootNames))) return;
32959
32153
  }
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
32154
  context.report({
32976
32155
  node,
32977
32156
  message: "This useEffect is simulating an event handler, which costs an extra render & runs late."
@@ -33252,7 +32431,7 @@ const isFunctionUsedOutsideHandlers = (analysis, functionNode, componentFunction
33252
32431
  if (isInsideInlineEventHandler(identifier, componentFunction)) return false;
33253
32432
  const parent = identifier.parent;
33254
32433
  if (parent && isNodeOfType(parent, "CallExpression") && parent.callee === identifier) {
33255
- if (findEnclosingFunction$1(parent) === functionNode) return false;
32434
+ if (findEnclosingFunction(parent) === functionNode) return false;
33256
32435
  if (isInsideProvenEventHandler(analysis, parent, componentFunction, false)) return false;
33257
32436
  }
33258
32437
  return true;
@@ -33298,7 +32477,7 @@ const isStateWrittenOnlyFromEventHandlers = (analysis, stateReference) => {
33298
32477
  if (!setterVariable) return false;
33299
32478
  const stateDeclarator = getUseStateDecl(analysis, stateReference);
33300
32479
  if (!stateDeclarator) return false;
33301
- const componentFunction = findEnclosingFunction$1(stateDeclarator);
32480
+ const componentFunction = findEnclosingFunction(stateDeclarator);
33302
32481
  if (!componentFunction) return false;
33303
32482
  let hasWriter = false;
33304
32483
  for (const reference of setterVariable.references) {
@@ -34360,8 +33539,8 @@ const isAwaitedInFunction = (request, functionNode) => {
34360
33539
  return false;
34361
33540
  };
34362
33541
  const isCompletionSinkForRequest = (completionSink, request) => {
34363
- const requestFunction = findEnclosingFunction$1(request);
34364
- const completionSinkFunction = findEnclosingFunction$1(completionSink);
33542
+ const requestFunction = findEnclosingFunction(request);
33543
+ const completionSinkFunction = findEnclosingFunction(completionSink);
34365
33544
  if (!requestFunction || !completionSinkFunction) return false;
34366
33545
  if (requestFunction === completionSinkFunction) {
34367
33546
  if (!isAwaitedInFunction(request, requestFunction)) return false;
@@ -34417,7 +33596,7 @@ const ALLOWED_NAMESPACES = new Set([
34417
33596
  "ReactDOM",
34418
33597
  "ReactDom"
34419
33598
  ]);
34420
- const MESSAGE$24 = "`findDOMNode` crashes your app in React 19 because it was removed.";
33599
+ const MESSAGE$23 = "`findDOMNode` crashes your app in React 19 because it was removed.";
34421
33600
  const noFindDomNode = defineRule({
34422
33601
  id: "no-find-dom-node",
34423
33602
  title: "findDOMNode breaks component encapsulation",
@@ -34428,7 +33607,7 @@ const noFindDomNode = defineRule({
34428
33607
  if (isNodeOfType(callee, "Identifier") && callee.name === "findDOMNode") {
34429
33608
  if (isImportedFromModule(node, callee.name, "react-dom")) context.report({
34430
33609
  node: callee,
34431
- message: MESSAGE$24
33610
+ message: MESSAGE$23
34432
33611
  });
34433
33612
  return;
34434
33613
  }
@@ -34439,7 +33618,7 @@ const noFindDomNode = defineRule({
34439
33618
  if (callee.property.name !== "findDOMNode") return;
34440
33619
  context.report({
34441
33620
  node: callee.property,
34442
- message: MESSAGE$24
33621
+ message: MESSAGE$23
34443
33622
  });
34444
33623
  }
34445
33624
  } })
@@ -34648,6 +33827,13 @@ const isPublishedLibraryPackage = (filename) => {
34648
33827
  return manifest.private !== true && typeof manifest.peerDependencies === "object" && manifest.peerDependencies !== null && "react" in manifest.peerDependencies;
34649
33828
  };
34650
33829
  //#endregion
33830
+ //#region src/plugin/utils/is-type-only-import.ts
33831
+ const isEverySpecifierInlineType = (specifiers, specifierType, kindField) => {
33832
+ if (!specifiers || specifiers.length === 0) return false;
33833
+ return specifiers.every((specifier) => isNodeOfType(specifier, specifierType) && specifier[kindField] === "type");
33834
+ };
33835
+ const isTypeOnlyImport = (node) => node.importKind === "type" || isEverySpecifierInlineType(node.specifiers, "ImportSpecifier", "importKind");
33836
+ //#endregion
34651
33837
  //#region src/plugin/rules/bundle-size/no-full-lodash-import.ts
34652
33838
  const isLibraryDevPage = (filename) => {
34653
33839
  if (!filename) return false;
@@ -35211,7 +34397,7 @@ const isInRenderedOutput = (node, componentOrHookNode, scopes) => {
35211
34397
  return attribute ? !isEventHandlerAttribute(attribute) : true;
35212
34398
  }
35213
34399
  if (isNodeOfType(parentNode, "ReturnStatement")) {
35214
- if (findEnclosingFunction$1(parentNode) === componentOrHookNode) return true;
34400
+ if (findEnclosingFunction(parentNode) === componentOrHookNode) return true;
35215
34401
  }
35216
34402
  if (parentNode === componentOrHookNode) return isFunctionLike$2(componentOrHookNode) && !isNodeOfType(componentOrHookNode.body, "BlockStatement") && componentOrHookNode.body === currentNode;
35217
34403
  if (isFunctionLike$2(parentNode) && !executesDuringRender(parentNode, scopes)) return false;
@@ -35334,7 +34520,7 @@ const noHydrationBranchOnBrowserGlobal = defineRule({
35334
34520
  if (consequentValues.length === 0 || alternateValues.length === 0) return;
35335
34521
  const componentOrHookNode = findRenderPhaseComponentOrHook(node.test, context.scopes);
35336
34522
  if (!componentOrHookNode) return;
35337
- const enclosingFunction = findEnclosingFunction$1(node);
34523
+ const enclosingFunction = findEnclosingFunction(node);
35338
34524
  if (enclosingFunction !== componentOrHookNode && (!enclosingFunction || !isInRenderedOutput(enclosingFunction, componentOrHookNode, context.scopes))) return;
35339
34525
  for (const consequentValue of consequentValues) for (const alternateValue of alternateValues) {
35340
34526
  if (!isRenderedValue(consequentValue) && !isRenderedValue(alternateValue)) continue;
@@ -35346,7 +34532,7 @@ const noHydrationBranchOnBrowserGlobal = defineRule({
35346
34532
  });
35347
34533
  //#endregion
35348
34534
  //#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.";
34535
+ 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
34536
  const noImgLazyWithHighFetchpriority = defineRule({
35351
34537
  id: "no-img-lazy-with-high-fetchpriority",
35352
34538
  title: "Lazy image with high fetchPriority",
@@ -35360,7 +34546,7 @@ const noImgLazyWithHighFetchpriority = defineRule({
35360
34546
  if (!fetchPriorityAttribute || getJsxPropStringValue(fetchPriorityAttribute)?.toLowerCase() !== "high") return;
35361
34547
  context.report({
35362
34548
  node: node.name,
35363
- message: MESSAGE$23
34549
+ message: MESSAGE$22
35364
34550
  });
35365
34551
  } })
35366
34552
  });
@@ -35549,7 +34735,7 @@ const noImpureStateUpdater = defineRule({
35549
34735
  });
35550
34736
  //#endregion
35551
34737
  //#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.";
34738
+ const MESSAGE$21 = "The `indeterminate` HTML attribute does not set a checkbox's visual state. Assign the `HTMLInputElement.indeterminate` DOM property instead.";
35553
34739
  const REACT_USE_REF_OPTIONS = {
35554
34740
  allowGlobalReactNamespace: false,
35555
34741
  allowUnboundBareCalls: false
@@ -35650,7 +34836,7 @@ const noIndeterminateAttribute = defineRule({
35650
34836
  if (!inputTypeValues || !inputTypeValues.every((inputTypeValue) => inputTypeValue.toLowerCase() === "checkbox")) return;
35651
34837
  context.report({
35652
34838
  node: indeterminateAttribute,
35653
- message: MESSAGE$22
34839
+ message: MESSAGE$21
35654
34840
  });
35655
34841
  },
35656
34842
  CallExpression(node) {
@@ -35659,7 +34845,7 @@ const noIndeterminateAttribute = defineRule({
35659
34845
  if (!isProvenHtmlInputElement(receiver, context.scopes)) return;
35660
34846
  context.report({
35661
34847
  node,
35662
- message: MESSAGE$22
34848
+ message: MESSAGE$21
35663
34849
  });
35664
34850
  }
35665
34851
  };
@@ -35782,10 +34968,10 @@ const isInsideInstanceField = (node) => {
35782
34968
  return false;
35783
34969
  };
35784
34970
  const isOneShotModuleInitialization = (node, context) => {
35785
- let functionNode = findEnclosingFunction$1(node);
34971
+ let functionNode = findEnclosingFunction(node);
35786
34972
  while (functionNode) {
35787
34973
  if (!executesDuringRender(functionNode, context.scopes)) return false;
35788
- functionNode = findEnclosingFunction$1(functionNode);
34974
+ functionNode = findEnclosingFunction(functionNode);
35789
34975
  }
35790
34976
  return !isInsideInstanceField(node);
35791
34977
  };
@@ -35947,7 +35133,7 @@ const noIsMounted = defineRule({
35947
35133
  });
35948
35134
  //#endregion
35949
35135
  //#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)`.";
35136
+ 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
35137
  const isJsonMethodCall = (node, method) => {
35952
35138
  if (!isNodeOfType(node, "CallExpression")) return false;
35953
35139
  const callee = node.callee;
@@ -36011,13 +35197,13 @@ const noJsonParseStringifyClone = defineRule({
36011
35197
  if (isCatchParameterRoundTrip(firstArgument)) return;
36012
35198
  context.report({
36013
35199
  node,
36014
- message: MESSAGE$21
35200
+ message: MESSAGE$20
36015
35201
  });
36016
35202
  } })
36017
35203
  });
36018
35204
  //#endregion
36019
35205
  //#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.";
35206
+ const MESSAGE$19 = "`JSX.Element` is too narrow: it excludes `null`, strings, numbers, and fragments that components commonly return. Use `React.ReactNode` instead.";
36021
35207
  const isJsxElementTypeReference = (node) => {
36022
35208
  if (!isNodeOfType(node, "TSTypeReference")) return false;
36023
35209
  const typeName = node.typeName;
@@ -36071,7 +35257,7 @@ const noJsxElementType = defineRule({
36071
35257
  if (isJsxImported) return;
36072
35258
  for (const typeAnnotation of flaggedAnnotations) context.report({
36073
35259
  node: typeAnnotation,
36074
- message: MESSAGE$20
35260
+ message: MESSAGE$19
36075
35261
  });
36076
35262
  }
36077
35263
  };
@@ -36303,221 +35489,6 @@ const noLegacyClassLifecycles = defineRule({
36303
35489
  }
36304
35490
  });
36305
35491
  //#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
35492
  //#region src/plugin/rules/architecture/no-legacy-context-api.ts
36522
35493
  const LEGACY_CONTEXT_NAMES = new Set([
36523
35494
  "childContextTypes",
@@ -36528,6 +35499,15 @@ const buildLegacyContextMessage = (memberName) => {
36528
35499
  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
35500
  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
35501
  };
35502
+ const isInsideClassBody = (node) => {
35503
+ let current = node.parent;
35504
+ while (current) {
35505
+ if (isNodeOfType(current, "ClassBody")) return true;
35506
+ if (isFunctionLike$2(current)) return false;
35507
+ current = current.parent;
35508
+ }
35509
+ return false;
35510
+ };
36531
35511
  const noLegacyContextApi = defineRule({
36532
35512
  id: "no-legacy-context-api",
36533
35513
  title: "Legacy context API",
@@ -36542,7 +35522,6 @@ const noLegacyContextApi = defineRule({
36542
35522
  if (!isNodeOfType(memberNode, "MethodDefinition") && !isNodeOfType(memberNode, "PropertyDefinition")) return;
36543
35523
  if (!isNodeOfType(memberNode.key, "Identifier")) return;
36544
35524
  if (!LEGACY_CONTEXT_NAMES.has(memberNode.key.name)) return;
36545
- if (memberNode.key.name === "getChildContext" ? memberNode.static : !memberNode.static) return;
36546
35525
  context.report({
36547
35526
  node: memberNode.key,
36548
35527
  message: buildLegacyContextMessage(memberNode.key.name)
@@ -36550,8 +35529,6 @@ const noLegacyContextApi = defineRule({
36550
35529
  };
36551
35530
  return {
36552
35531
  ClassBody(node) {
36553
- const classNode = node.parent;
36554
- if (!classNode || !isProvenReactClassComponent(classNode, context.scopes)) return;
36555
35532
  for (const member of node.body ?? []) checkMember(member);
36556
35533
  },
36557
35534
  AssignmentExpression(node) {
@@ -36561,11 +35538,9 @@ const noLegacyContextApi = defineRule({
36561
35538
  if (left.computed) return;
36562
35539
  if (!isNodeOfType(left.property, "Identifier")) return;
36563
35540
  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;
35541
+ if (!isNodeOfType(left.object, "Identifier")) return;
35542
+ if (!isUppercaseName(left.object.name)) return;
35543
+ if (isInsideClassBody(node)) return;
36569
35544
  context.report({
36570
35545
  node: left,
36571
35546
  message: buildLegacyContextMessage(left.property.name)
@@ -36769,10 +35744,10 @@ const getMethodCalls = (functionNode, scopes) => {
36769
35744
  const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, scopes, visitedSymbolIds, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
36770
35745
  if (visitedFunctionNodes.has(functionNode)) return false;
36771
35746
  visitedFunctionNodes.add(functionNode);
36772
- const usageFunction = findEnclosingFunction$1(usageNode);
35747
+ const usageFunction = findEnclosingFunction(usageNode);
36773
35748
  const immediateCall = getDirectCallForExpression(functionNode);
36774
35749
  if (immediateCall) {
36775
- const immediateCallFunction = findEnclosingFunction$1(immediateCall);
35750
+ const immediateCallFunction = findEnclosingFunction(immediateCall);
36776
35751
  if (immediateCallFunction === usageFunction) {
36777
35752
  const immediateCallStart = getRangeStart(immediateCall);
36778
35753
  return immediateCallStart === null || immediateCallStart < usageBoundary;
@@ -36781,7 +35756,7 @@ const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, sc
36781
35756
  return isFunctionInvokedBeforeUsage(immediateCallFunction, usageNode, usageBoundary, scopes, visitedSymbolIds, new Set(visitedFunctionNodes));
36782
35757
  }
36783
35758
  for (const methodCall of getMethodCalls(functionNode, scopes)) {
36784
- const methodCallFunction = findEnclosingFunction$1(methodCall);
35759
+ const methodCallFunction = findEnclosingFunction(methodCall);
36785
35760
  if (methodCallFunction === usageFunction) {
36786
35761
  const methodCallStart = getRangeStart(methodCall);
36787
35762
  if (methodCallStart === null || methodCallStart < usageBoundary) return true;
@@ -36804,7 +35779,7 @@ const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, sc
36804
35779
  if (scopes.symbolFor(child)?.declarationNode !== symbol.declarationNode) return;
36805
35780
  const call = getDirectCallForExpression(child);
36806
35781
  if (!call) return false;
36807
- const callFunction = findEnclosingFunction$1(call);
35782
+ const callFunction = findEnclosingFunction(call);
36808
35783
  if (callFunction === usageFunction) {
36809
35784
  const callStart = getRangeStart(call);
36810
35785
  wasInvokedBeforeUsage = callStart === null || callStart < usageBoundary;
@@ -36835,14 +35810,14 @@ const wasMutatedBeforeUsage = (symbol, usageNode, readNode, scopes, visitedMutat
36835
35810
  visitedMutationSymbolIds.add(symbol.id);
36836
35811
  const usageBoundary = inheritedUsageBoundary === void 0 ? getMutationUsageBoundary(usageNode, readNode) : inheritedUsageBoundary;
36837
35812
  if (typeof usageBoundary !== "number") return true;
36838
- const usageFunction = findEnclosingFunction$1(usageNode);
35813
+ const usageFunction = findEnclosingFunction(usageNode);
36839
35814
  return symbol.references.some((reference) => {
36840
35815
  const referenceStart = getRangeStart(reference.identifier);
36841
35816
  const simpleAlias = getSimpleAlias(reference.identifier, scopes);
36842
35817
  if (simpleAlias) return wasMutatedBeforeUsage(simpleAlias.symbol, usageNode, readNodesBySymbolId.get(simpleAlias.symbol.id) ?? simpleAlias.readNode, scopes, new Set(visitedMutationSymbolIds), usageBoundary, readNodesBySymbolId);
36843
35818
  if (!isPotentialMutationReference(reference.identifier, readNode)) return false;
36844
35819
  if (referenceStart === null) return true;
36845
- const mutationFunction = findEnclosingFunction$1(reference.identifier);
35820
+ const mutationFunction = findEnclosingFunction(reference.identifier);
36846
35821
  if (mutationFunction === usageFunction) return referenceStart < usageBoundary;
36847
35822
  if (!mutationFunction) return usageFunction !== null;
36848
35823
  if (usageFunction && isAstDescendant(usageFunction, mutationFunction)) return true;
@@ -37387,7 +36362,7 @@ const noMoment = defineRule({
37387
36362
  });
37388
36363
  //#endregion
37389
36364
  //#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.";
36365
+ const MESSAGE$18 = "This file declares several components, so each component is harder to find, test, and change.";
37391
36366
  const resolveSettings$16 = (settings) => {
37392
36367
  const reactDoctor = settings?.["react-doctor"];
37393
36368
  return { ignoreStateless: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noMultiComp ?? {} : {}).ignoreStateless ?? false };
@@ -37424,6 +36399,13 @@ const isReactNamespaceExpression = (node, scopes) => {
37424
36399
  return isReactNamespaceImport(node, scopes);
37425
36400
  };
37426
36401
  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));
36402
+ const getDestructuredPropertyName$1 = (symbol) => {
36403
+ const property = symbol.bindingIdentifier.parent;
36404
+ if (!property || !isNodeOfType(property, "Property") || !property.parent || !isNodeOfType(property.parent, "ObjectPattern")) return null;
36405
+ if (isNodeOfType(property.key, "Identifier") && !property.computed) return property.key.name;
36406
+ if (isNodeOfType(property.key, "Literal") && typeof property.key.value === "string") return property.key.value;
36407
+ return null;
36408
+ };
37427
36409
  const symbolMapsToHoc = (symbol, scopes, visitedSymbolIds) => {
37428
36410
  if (visitedSymbolIds.has(symbol.id)) return false;
37429
36411
  visitedSymbolIds.add(symbol.id);
@@ -37433,7 +36415,7 @@ const symbolMapsToHoc = (symbol, scopes, visitedSymbolIds) => {
37433
36415
  }
37434
36416
  const init = symbol.initializer;
37435
36417
  if (!init) return false;
37436
- const destructuredPropertyName = getDestructuredBindingPropertyName(symbol.bindingIdentifier);
36418
+ const destructuredPropertyName = getDestructuredPropertyName$1(symbol);
37437
36419
  if (destructuredPropertyName && REACT_HOC_NAMES.has(destructuredPropertyName) && isReactNamespaceExpression(init, scopes)) return true;
37438
36420
  if (isReactHocMemberReference(init, scopes)) return true;
37439
36421
  if (isNodeOfType(init, "Identifier")) {
@@ -37739,7 +36721,7 @@ const noMultiComp = defineRule({
37739
36721
  if (isSmallFeatureModule || isLargeFeatureModule || isVeryLargeFeatureModule) return;
37740
36722
  for (const component of flagged.slice(1)) context.report({
37741
36723
  node: component.reportNode,
37742
- message: MESSAGE$19
36724
+ message: MESSAGE$18
37743
36725
  });
37744
36726
  } };
37745
36727
  }
@@ -37952,7 +36934,7 @@ const resolveReducerFunction = (node, currentFilename) => {
37952
36934
  };
37953
36935
  //#endregion
37954
36936
  //#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.";
36937
+ const MESSAGE$17 = "This reducer changes state in place, so your update is silently skipped.";
37956
36938
  const SAME_REFERENCE_ARRAY_RETURN_METHODS = new Set([
37957
36939
  "copyWithin",
37958
36940
  "fill",
@@ -38161,7 +37143,7 @@ const analyzeReactUseReducerFunctionForStateMutation = (context, functionNode, r
38161
37143
  reportedNodes.add(options.crossFileConsumerCallSite);
38162
37144
  context.report({
38163
37145
  node: options.crossFileConsumerCallSite,
38164
- message: `${MESSAGE$18} (mutation in imported reducer at \`${options.crossFileSourceDisplay}\`)`
37146
+ message: `${MESSAGE$17} (mutation in imported reducer at \`${options.crossFileSourceDisplay}\`)`
38165
37147
  });
38166
37148
  return;
38167
37149
  }
@@ -38170,7 +37152,7 @@ const analyzeReactUseReducerFunctionForStateMutation = (context, functionNode, r
38170
37152
  reportedNodes.add(mutation.node);
38171
37153
  context.report({
38172
37154
  node: mutation.node,
38173
- message: MESSAGE$18
37155
+ message: MESSAGE$17
38174
37156
  });
38175
37157
  }
38176
37158
  };
@@ -38577,7 +37559,7 @@ const noNoninteractiveElementToInteractiveRole = defineRule({
38577
37559
  });
38578
37560
  //#endregion
38579
37561
  //#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.";
37562
+ const MESSAGE$16 = "Keyboard users get stuck focusing this element they can't act on because `tabIndex` makes it tabbable, so remove it.";
38581
37563
  const KEYBOARD_HANDLER_PROP_NAMES = [
38582
37564
  "onKeyDown",
38583
37565
  "onKeyUp",
@@ -38696,7 +37678,7 @@ const noNoninteractiveTabindex = defineRule({
38696
37678
  if (numeric === null) {
38697
37679
  if (isNodeOfType(tabIndexValue, "JSXExpressionContainer") && !settings.allowExpressionValues && !isKeyboardOperable(node) && !isFocusOperable(node) && !hasJsxSpreadAttribute$1(node.attributes)) context.report({
38698
37680
  node: tabIndex,
38699
- message: MESSAGE$17
37681
+ message: MESSAGE$16
38700
37682
  });
38701
37683
  return;
38702
37684
  }
@@ -38718,7 +37700,7 @@ const noNoninteractiveTabindex = defineRule({
38718
37700
  if (!roleAttribute) {
38719
37701
  context.report({
38720
37702
  node: tabIndex,
38721
- message: MESSAGE$17
37703
+ message: MESSAGE$16
38722
37704
  });
38723
37705
  return;
38724
37706
  }
@@ -38732,7 +37714,7 @@ const noNoninteractiveTabindex = defineRule({
38732
37714
  }
38733
37715
  context.report({
38734
37716
  node: tabIndex,
38735
- message: MESSAGE$17
37717
+ message: MESSAGE$16
38736
37718
  });
38737
37719
  } };
38738
37720
  }
@@ -39159,6 +38141,8 @@ const getWrapperHookWrappedFunction = (initializer) => {
39159
38141
  if (!wrapped || !isFunctionLike$2(wrapped)) return null;
39160
38142
  return wrapped;
39161
38143
  };
38144
+ const hasParameterDef = (ref) => Boolean(ref.resolved?.defs.some((def) => def.type === "Parameter"));
38145
+ const resolvesToFunctionBinding = (ref) => !hasParameterDef(ref) && Boolean(resolveToFunction(ref));
39162
38146
  const HANDLER_NAMED_PROP_PATTERN = /^(on|handle)[A-Z]/;
39163
38147
  const wrappedFunctionNotifiesParent = (analysis, wrappedFunction) => getDownstreamRefs(analysis, wrappedFunction).some((innerRef) => {
39164
38148
  if (!isProp(analysis, innerRef)) return false;
@@ -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();
@@ -39473,7 +38463,7 @@ const noPassDataToParent = defineRule({
39473
38463
  if (isConstant(argRef)) return false;
39474
38464
  if (isParentWiredHookResultRef(analysis, argRef)) return false;
39475
38465
  if (isParentWiredHookCalleeRef(analysis, argRef)) return false;
39476
- if (resolveToFunction(argRef)) return false;
38466
+ if (resolvesToFunctionBinding(argRef)) return false;
39477
38467
  const argIdentifier = argRef.identifier;
39478
38468
  if (isImportBindingRef(argRef) && !isCalleePosition(argIdentifier)) return false;
39479
38469
  if (isNodeOfType(argIdentifier, "Identifier") && argIdentifier.name === "undefined") return false;
@@ -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."
@@ -58372,26 +57113,6 @@ const stateInConstructor = defineRule({
58372
57113
  }
58373
57114
  });
58374
57115
  //#endregion
58375
- //#region src/plugin/utils/collect-jsx-runtime-imports.ts
58376
- const REACT_RUNTIME_PACKAGE_PREFIXES = ["react", "react-dom"];
58377
- const matchesPackage = (source, packageName) => source === packageName || source.startsWith(`${packageName}/`);
58378
- const collectJsxRuntimeImports = (program) => {
58379
- let hasReactRuntime = false;
58380
- let hasSolidRuntime = false;
58381
- for (const statement of program.body) {
58382
- if (!isNodeOfType(statement, "ImportDeclaration")) continue;
58383
- if (isTypeOnlyImport(statement)) continue;
58384
- const source = statement.source.value;
58385
- if (typeof source !== "string") continue;
58386
- if (matchesPackage(source, "solid-js")) hasSolidRuntime = true;
58387
- if (REACT_RUNTIME_PACKAGE_PREFIXES.some((packageName) => matchesPackage(source, packageName))) hasReactRuntime = true;
58388
- }
58389
- return {
58390
- hasReactRuntime,
58391
- hasSolidRuntime
58392
- };
58393
- };
58394
- //#endregion
58395
57116
  //#region src/plugin/rules/react-builtins/style-prop-object.ts
58396
57117
  const MESSAGE$1 = "Your styles don't render because you passed the `style` prop a string instead of an object.";
58397
57118
  const resolveSettings = (settings) => {
@@ -58453,13 +57174,6 @@ const isInvalidStyleExpression = (expression) => {
58453
57174
  }
58454
57175
  return false;
58455
57176
  };
58456
- const hasObjectValuedClassList = (openingElement) => openingElement.attributes.some((attribute) => {
58457
- if (!isNodeOfType(attribute, "JSXAttribute")) return false;
58458
- if (!isNodeOfType(attribute.name, "JSXIdentifier")) return false;
58459
- if (attribute.name.name !== "classList") return false;
58460
- if (!isNodeOfType(attribute.value, "JSXExpressionContainer")) return false;
58461
- return isNodeOfType(attribute.value.expression, "ObjectExpression");
58462
- });
58463
57177
  const stylePropObject = defineRule({
58464
57178
  id: "style-prop-object",
58465
57179
  title: "Style prop is not an object",
@@ -58469,21 +57183,8 @@ const stylePropObject = defineRule({
58469
57183
  create: (context) => {
58470
57184
  const { allow } = resolveSettings(context.settings);
58471
57185
  const allowSet = new Set(allow);
58472
- let fileIsProvenSolidJsx = false;
58473
57186
  return {
58474
- Program: (node) => {
58475
- const runtimeImports = collectJsxRuntimeImports(node);
58476
- let hasSolidSyntaxMarker = false;
58477
- if (!runtimeImports.hasReactRuntime && !runtimeImports.hasSolidRuntime) walkAst(node, (descendantNode) => {
58478
- if (isNodeOfType(descendantNode, "JSXOpeningElement") && hasObjectValuedClassList(descendantNode)) {
58479
- hasSolidSyntaxMarker = true;
58480
- return false;
58481
- }
58482
- });
58483
- fileIsProvenSolidJsx = !runtimeImports.hasReactRuntime && (runtimeImports.hasSolidRuntime || hasSolidSyntaxMarker);
58484
- },
58485
57187
  JSXOpeningElement(node) {
58486
- if (fileIsProvenSolidJsx) return;
58487
57188
  if (!isNodeOfType(node.name, "JSXIdentifier")) return;
58488
57189
  const elementName = resolveJsxElementType(node);
58489
57190
  if (elementName && allowSet.has(elementName)) return;
@@ -58514,7 +57215,6 @@ const stylePropObject = defineRule({
58514
57215
  }
58515
57216
  },
58516
57217
  CallExpression(node) {
58517
- if (fileIsProvenSolidJsx) return;
58518
57218
  if (!isCreateElementCall(node)) return;
58519
57219
  const firstArgument = node.arguments[0];
58520
57220
  if (!firstArgument) return;
@@ -59309,7 +58009,7 @@ const tanstackStartNoNavigateInRender = defineRule({
59309
58009
  const isReturnedFromCustomHook = (functionNode) => {
59310
58010
  const parent = functionNode.parent;
59311
58011
  if (isNodeOfType(parent, "ReturnStatement")) {
59312
- const outerFunction = findEnclosingFunction$1(parent);
58012
+ const outerFunction = findEnclosingFunction(parent);
59313
58013
  const hookName = outerFunction ? getFunctionBindingName$1(outerFunction) : null;
59314
58014
  return Boolean(hookName && HOOK_NAME_PATTERN$3.test(hookName));
59315
58015
  }
@@ -59326,13 +58026,13 @@ const tanstackStartNoNavigateInRender = defineRule({
59326
58026
  return parent.callee === functionNode || (parent.arguments ?? []).some((callArgument) => callArgument === functionNode);
59327
58027
  };
59328
58028
  const isDeferredNavigateCall = (callNode) => {
59329
- let enclosingFunction = findEnclosingFunction$1(callNode);
58029
+ let enclosingFunction = findEnclosingFunction(callNode);
59330
58030
  while (enclosingFunction) {
59331
58031
  if (isDeferredCallbackPosition(enclosingFunction)) return true;
59332
58032
  if (isWiredAsEventHandler(enclosingFunction)) return true;
59333
58033
  if (isReturnedFromCustomHook(enclosingFunction)) return true;
59334
58034
  if (!isSynchronouslyInvokedAnonymousWrapper(enclosingFunction)) return false;
59335
- enclosingFunction = findEnclosingFunction$1(enclosingFunction);
58035
+ enclosingFunction = findEnclosingFunction(enclosingFunction);
59336
58036
  }
59337
58037
  return false;
59338
58038
  };
@@ -63771,17 +62471,6 @@ const reactDoctorRules = [
63771
62471
  requires: [...new Set(["react", ...reactInJsxScope.requires ?? []])]
63772
62472
  }
63773
62473
  },
63774
- {
63775
- key: "react-doctor/react-markdown-unsanitized-raw-html",
63776
- id: "react-markdown-unsanitized-raw-html",
63777
- source: "react-doctor",
63778
- originallyExternal: false,
63779
- rule: {
63780
- ...reactMarkdownUnsanitizedRawHtml,
63781
- framework: "global",
63782
- category: "Security"
63783
- }
63784
- },
63785
62474
  {
63786
62475
  key: "react-doctor/redux-useselector-inline-derivation",
63787
62476
  id: "redux-useselector-inline-derivation",