oxlint-plugin-react-doctor 0.7.7-dev.9c612c5 → 0.7.7-dev.9fc93f8

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 (2) hide show
  1. package/dist/index.js +556 -1362
  2. 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
  });
@@ -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
  };
@@ -6427,6 +5989,23 @@ 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") && !isNodeOfType(node, "MemberExpression")) return null;
5995
+ const key = isNodeOfType(node, "MemberExpression") ? node.property : node.key;
5996
+ if (node.computed) {
5997
+ if (options.allowComputedString && isNodeOfType(key, "Literal") && typeof key.value === "string") return key.value;
5998
+ if (options.allowComputedString && isNodeOfType(key, "TemplateLiteral") && key.expressions.length === 0) return key.quasis[0]?.value.cooked ?? key.quasis[0]?.value.raw ?? null;
5999
+ return null;
6000
+ }
6001
+ if (isNodeOfType(key, "Identifier")) return key.name;
6002
+ if (isNodeOfType(key, "Literal")) {
6003
+ if (typeof key.value === "string") return key.value;
6004
+ if (options.stringifyNonStringLiterals) return String(key.value);
6005
+ }
6006
+ return null;
6007
+ };
6008
+ //#endregion
6430
6009
  //#region src/plugin/utils/are-expressions-structurally-equal.ts
6431
6010
  const areExpressionsStructurallyEqual = (a, b) => {
6432
6011
  if (!a || !b) return a === b;
@@ -7110,6 +6689,15 @@ const getDirectConstInitializer = (symbol) => {
7110
6689
  return symbol.initializer;
7111
6690
  };
7112
6691
  //#endregion
6692
+ //#region src/plugin/utils/get-static-property-name.ts
6693
+ const getStaticPropertyName = (memberExpression) => {
6694
+ const property = memberExpression.property;
6695
+ if (!memberExpression.computed && isNodeOfType(property, "Identifier")) return property.name;
6696
+ if (memberExpression.computed && isNodeOfType(property, "Literal")) return typeof property.value === "string" ? property.value : null;
6697
+ if (memberExpression.computed && isNodeOfType(property, "TemplateLiteral") && property.expressions.length === 0) return property.quasis[0]?.value.cooked ?? property.quasis[0]?.value.raw ?? null;
6698
+ return null;
6699
+ };
6700
+ //#endregion
7113
6701
  //#region src/plugin/utils/get-range-start.ts
7114
6702
  const getRangeStart = (node) => {
7115
6703
  const rangeStart = node.range?.[0];
@@ -7505,6 +7093,16 @@ const collectFunctionReturnStatements = (functionNode) => {
7505
7093
  return returnStatements;
7506
7094
  };
7507
7095
  //#endregion
7096
+ //#region src/plugin/utils/find-enclosing-function.ts
7097
+ const findEnclosingFunction = (node) => {
7098
+ let cursor = node.parent;
7099
+ while (cursor) {
7100
+ if (isFunctionLike$2(cursor)) return cursor;
7101
+ cursor = cursor.parent ?? null;
7102
+ }
7103
+ return null;
7104
+ };
7105
+ //#endregion
7508
7106
  //#region src/plugin/utils/statement-always-exits.ts
7509
7107
  const statementAlwaysExits = (statement) => {
7510
7108
  if (isNodeOfType(statement, "ReturnStatement") || isNodeOfType(statement, "ThrowStatement")) return true;
@@ -7550,8 +7148,8 @@ const applyDefinitions = (incomingDefinitions, definitions) => {
7550
7148
  const collectPossibleAssignedExpressions = (symbol, referenceNode, controlFlow) => {
7551
7149
  if (!REASSIGNABLE_BINDING_KINDS.has(symbol.kind)) return symbol.initializer ? [symbol.initializer] : [];
7552
7150
  if (!controlFlow) return [];
7553
- const referenceFunction = findEnclosingFunction$1(referenceNode);
7554
- if (findEnclosingFunction$1(symbol.bindingIdentifier) !== referenceFunction) return [];
7151
+ const referenceFunction = findEnclosingFunction(referenceNode);
7152
+ if (findEnclosingFunction(symbol.bindingIdentifier) !== referenceFunction) return [];
7555
7153
  if (!referenceFunction) return [];
7556
7154
  const functionControlFlow = controlFlow.cfgFor(referenceFunction);
7557
7155
  if (!functionControlFlow) return [];
@@ -7575,7 +7173,7 @@ const collectPossibleAssignedExpressions = (symbol, referenceNode, controlFlow)
7575
7173
  if (symbol.initializer) addDefinition(symbol.initializer, symbol.bindingIdentifier, bindingPosition);
7576
7174
  for (const reference of symbol.references) {
7577
7175
  const writePosition = getRangeStart(reference.identifier);
7578
- if (reference.flag === "read" || findEnclosingFunction$1(reference.identifier) !== referenceFunction || writePosition === null || writePosition >= referencePosition) continue;
7176
+ if (reference.flag === "read" || findEnclosingFunction(reference.identifier) !== referenceFunction || writePosition === null || writePosition >= referencePosition) continue;
7579
7177
  const assignedExpression = getAssignedExpressionForWrite(reference.identifier);
7580
7178
  if (!assignedExpression) continue;
7581
7179
  addDefinition(assignedExpression, reference.identifier, writePosition);
@@ -9247,7 +8845,6 @@ const HTML_FOR_ATTRIBUTE = "htmlFor";
9247
8845
  const LABEL_ELEMENT = "label";
9248
8846
  const LABEL_COMPONENT_NAME = "Label";
9249
8847
  const POLYMORPHIC_COMPONENT_PROP = "component";
9250
- const TITLE_ATTRIBUTE = "title";
9251
8848
  const WRAPPER_LABEL_PROP = "label";
9252
8849
  const SELECT_ELEMENT = "select";
9253
8850
  const DEFAULT_DEPTH = 5;
@@ -9293,96 +8890,6 @@ const hasNonEmptyPropValue = (attribute) => {
9293
8890
  }
9294
8891
  return true;
9295
8892
  };
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
8893
  const toAttributeMatchKey = (kind, value) => {
9387
8894
  const trimmedValue = value.trim();
9388
8895
  return trimmedValue.length > 0 ? `${kind}:${trimmedValue}` : null;
@@ -9639,7 +9146,6 @@ const controlHasAssociatedLabel = defineRule({
9639
9146
  if (typeValue === "submit" || typeValue === "reset") return;
9640
9147
  if (typeValue === "button" && hasNonEmptyPropValue(hasJsxPropIgnoreCase(opening.attributes, "value"))) return;
9641
9148
  }
9642
- if (isDomElement && hasNonEmptyNativeTitle(getLastJsxPropIgnoreCase(opening.attributes, TITLE_ATTRIBUTE), context.scopes)) return;
9643
9149
  if (supportsPlaceholderNameFallback(tagName, opening) && hasNonEmptyPropValue(hasJsxPropIgnoreCase(opening.attributes, "placeholder"))) return;
9644
9150
  if (hasLabellingProp(opening.attributes, settings.labelAttributes)) return;
9645
9151
  if (isInsideJsxAttribute(node)) return;
@@ -11589,7 +11095,7 @@ const componentOrHookDisplayNameForFunction = (functionNode) => {
11589
11095
  //#endregion
11590
11096
  //#region src/plugin/utils/enclosing-component-or-hook-name.ts
11591
11097
  const enclosingComponentOrHookName = (node) => {
11592
- const functionNode = findEnclosingFunction$1(node);
11098
+ const functionNode = findEnclosingFunction(node);
11593
11099
  return functionNode ? componentOrHookDisplayNameForFunction(functionNode) : null;
11594
11100
  };
11595
11101
  //#endregion
@@ -11646,11 +11152,11 @@ const executesDuringRender = (functionNode, scopes) => {
11646
11152
  //#endregion
11647
11153
  //#region src/plugin/utils/find-render-phase-component-or-hook.ts
11648
11154
  const findRenderPhaseComponentOrHook = (node, scopes) => {
11649
- let functionNode = findEnclosingFunction$1(node);
11155
+ let functionNode = findEnclosingFunction(node);
11650
11156
  while (functionNode) {
11651
11157
  if (componentOrHookDisplayNameForFunction(functionNode)) return functionNode;
11652
11158
  if (!executesDuringRender(functionNode, scopes)) return null;
11653
- functionNode = findEnclosingFunction$1(functionNode);
11159
+ functionNode = findEnclosingFunction(functionNode);
11654
11160
  }
11655
11161
  return null;
11656
11162
  };
@@ -11899,13 +11405,13 @@ const findSubscribeLikeUsages = (callback, context) => {
11899
11405
  };
11900
11406
  const doMatchingNodesCoverEveryPathAfterUsage = (usageNode, matchingNodes, context) => {
11901
11407
  let pathAnchor = usageNode;
11902
- let pathOwner = findEnclosingFunction$1(pathAnchor);
11408
+ let pathOwner = findEnclosingFunction(pathAnchor);
11903
11409
  while (pathOwner && isSynchronousIteratorCallback(pathOwner)) {
11904
11410
  if (matchingNodes.length > 0 && matchingNodes.every((matchingNode) => context.cfg.enclosingFunction(matchingNode) === pathOwner)) break;
11905
11411
  const iteratorCall = pathOwner.parent;
11906
11412
  if (!isNodeOfType(iteratorCall, "CallExpression")) break;
11907
11413
  pathAnchor = iteratorCall;
11908
- pathOwner = findEnclosingFunction$1(pathAnchor);
11414
+ pathOwner = findEnclosingFunction(pathAnchor);
11909
11415
  }
11910
11416
  const owner = context.cfg.enclosingFunction(pathAnchor);
11911
11417
  if (!owner) return false;
@@ -12134,7 +11640,7 @@ const findCollectionMappingCall = (callbackNode) => {
12134
11640
  return callee.property.name === "map" && callNode.arguments?.[0] === callbackNode ? callNode : null;
12135
11641
  };
12136
11642
  const findMappedResourceCollectionKey = (resourceNode, context) => {
12137
- const callbackNode = findEnclosingFunction$1(resourceNode);
11643
+ const callbackNode = findEnclosingFunction(resourceNode);
12138
11644
  if (!callbackNode || !isNodeOfType(callbackNode, "ArrowFunctionExpression") && !isNodeOfType(callbackNode, "FunctionExpression")) return null;
12139
11645
  const mappingCall = findCollectionMappingCall(callbackNode);
12140
11646
  if (!mappingCall) return null;
@@ -12245,10 +11751,10 @@ const findSingleDirectInvocation = (functionNode, caller, context) => {
12245
11751
  });
12246
11752
  if (invocationCalls.length !== 1) return null;
12247
11753
  const invocationCall = invocationCalls[0];
12248
- return findEnclosingFunction$1(invocationCall) === caller && isNodeReachableWithinFunction(invocationCall, context) ? invocationCall : null;
11754
+ return findEnclosingFunction(invocationCall) === caller && isNodeReachableWithinFunction(invocationCall, context) ? invocationCall : null;
12249
11755
  };
12250
11756
  const resolveCleanupPathAnchor = (usageNode, effectCallback, context) => {
12251
- const usageFunction = findEnclosingFunction$1(usageNode);
11757
+ const usageFunction = findEnclosingFunction(usageNode);
12252
11758
  if (!usageFunction || usageFunction === effectCallback) return usageNode;
12253
11759
  return findSingleDirectInvocation(usageFunction, effectCallback, context) ?? usageNode;
12254
11760
  };
@@ -12263,7 +11769,7 @@ const resolveSingleAssignedCleanupFunction = (expression, usage, context) => {
12263
11769
  const assignmentReference = assignmentReferences[0];
12264
11770
  const assignmentTarget = findTransparentExpressionRoot(assignmentReference.identifier);
12265
11771
  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;
11772
+ if (!isNodeOfType(assignmentNode, "AssignmentExpression") || assignmentNode.operator !== "=" || assignmentNode.left !== assignmentTarget || findEnclosingFunction(assignmentNode) !== findEnclosingFunction(usage.node) || !doMatchingNodesCoverEveryPathAfterUsage(usage.node, [assignmentNode], context)) return null;
12267
11773
  const assignedValue = stripParenExpression(assignmentNode.right);
12268
11774
  return isFunctionLike$2(assignedValue) ? assignedValue : null;
12269
11775
  };
@@ -12352,12 +11858,12 @@ const hasRerunReleaseBeforeUsage = (callback, usage, context) => {
12352
11858
  return doMatchingNodesCoverEveryPathFromFunctionEntry(callback, matchingReleaseAnchors, context);
12353
11859
  };
12354
11860
  const hasStableUnmountCleanupForUsage = (callback, usage, context) => {
12355
- const componentFunction = findEnclosingFunction$1(callback);
11861
+ const componentFunction = findEnclosingFunction(callback);
12356
11862
  if (!componentFunction || !isNodeOfType(componentFunction, "ArrowFunctionExpression") && !isNodeOfType(componentFunction, "FunctionExpression") && !isNodeOfType(componentFunction, "FunctionDeclaration")) return false;
12357
11863
  let didFindUnmountCleanup = false;
12358
11864
  walkAst(componentFunction.body, (child) => {
12359
11865
  if (didFindUnmountCleanup) return false;
12360
- if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction$1(child) !== componentFunction) return;
11866
+ if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction(child) !== componentFunction) return;
12361
11867
  if (!isHookCall$2(child, CLEANUP_EFFECT_HOOK_NAMES)) return;
12362
11868
  const dependencyList = child.arguments?.[1];
12363
11869
  if (!isNodeOfType(dependencyList, "ArrayExpression") || dependencyList.elements.length > 0) return;
@@ -12453,7 +11959,7 @@ const deferredUsageWritesGuardBeforeUsage = (callback, usageNode, guardState, co
12453
11959
  return didWriteGuard;
12454
11960
  };
12455
11961
  const hasGuardedDeferredCleanup = (callback, usage, cleanupReturns, context) => {
12456
- const usageFunction = findEnclosingFunction$1(usage.node);
11962
+ const usageFunction = findEnclosingFunction(usage.node);
12457
11963
  const promiseChainCall = usageFunction ? getPromiseChainCallForCallback(usageFunction) : null;
12458
11964
  if (usage.handleKey === null || !usageFunction || usageFunction === callback || !promiseChainCall || !collectEffectInvokedFunctions(callback).has(usageFunction) || !doMatchingNodesCoverEveryPathAfterUsage(promiseChainCall, cleanupReturns, context)) return false;
12459
11965
  return collectDeferredUsageGuardStates(usageFunction, usage.node, context).some((guardState) => !deferredUsageWritesGuardBeforeUsage(usageFunction, usage.node, guardState, context) && cleanupReturns.every((cleanupReturn) => cleanupReturnInvalidatesGuard(cleanupReturn, guardState, context)));
@@ -12461,7 +11967,7 @@ const hasGuardedDeferredCleanup = (callback, usage, cleanupReturns, context) =>
12461
11967
  const effectHasCleanupForUsage = (callback, usage, context) => {
12462
11968
  if (!isNodeOfType(callback, "ArrowFunctionExpression") && !isNodeOfType(callback, "FunctionExpression")) return false;
12463
11969
  if (callback.async) return false;
12464
- if (usage.kind === "subscribe" && findEnclosingFunction$1(usage.node) === callback && doesResourceResultEscape(usage.node, true) && isCleanupReturningSubscribeLikeCallExpression(usage.node)) return true;
11970
+ if (usage.kind === "subscribe" && findEnclosingFunction(usage.node) === callback && doesResourceResultEscape(usage.node, true) && isCleanupReturningSubscribeLikeCallExpression(usage.node)) return true;
12465
11971
  if (!isNodeOfType(callback.body, "BlockStatement")) return callback.body === usage.node && isCleanupReturningSubscribeLikeCallExpression(callback.body);
12466
11972
  const matchingCleanupReturns = [];
12467
11973
  walkInsideStatementBlocks(callback.body, (child) => {
@@ -12630,7 +12136,7 @@ const isReturnedEffectCleanupFunction = (functionNode) => {
12630
12136
  parentNode = currentNode.parent;
12631
12137
  }
12632
12138
  if (!isNodeOfType(parentNode, "ReturnStatement") || parentNode.argument !== currentNode) return false;
12633
- const effectCallback = findEnclosingFunction$1(parentNode);
12139
+ const effectCallback = findEnclosingFunction(parentNode);
12634
12140
  const effectCall = effectCallback?.parent;
12635
12141
  return Boolean(effectCallback && isNodeOfType(effectCall, "CallExpression") && isHookCall$2(effectCall, CLEANUP_EFFECT_HOOK_NAMES));
12636
12142
  };
@@ -12640,13 +12146,13 @@ const isPotentiallyReachableFunction = (functionNode, context) => {
12640
12146
  if (!bindingIdentifier) return false;
12641
12147
  const symbol = context.scopes.symbolFor(bindingIdentifier);
12642
12148
  if (!symbol) return false;
12643
- return symbol.references.some((reference) => findEnclosingFunction$1(reference.identifier) !== functionNode);
12149
+ return symbol.references.some((reference) => findEnclosingFunction(reference.identifier) !== functionNode);
12644
12150
  };
12645
12151
  const isReleaseReachableForUsage = (releaseNode, usage, context) => {
12646
12152
  if (!isNodeReachableWithinFunction(releaseNode, context)) return false;
12647
- const releaseFunction = findEnclosingFunction$1(releaseNode);
12153
+ const releaseFunction = findEnclosingFunction(releaseNode);
12648
12154
  if (!releaseFunction) return true;
12649
- if (releaseFunction === findEnclosingFunction$1(usage.node)) return true;
12155
+ if (releaseFunction === findEnclosingFunction(usage.node)) return true;
12650
12156
  return isPotentiallyReachableFunction(releaseFunction, context);
12651
12157
  };
12652
12158
  const fileContainsReleaseForUsage = (usage, context) => {
@@ -12829,10 +12335,10 @@ const cleanupFunctionReleasesRefOwnedUsage = (cleanupFunction, componentFunction
12829
12335
  }
12830
12336
  if (assignedKey !== storage.refCurrentKey) return;
12831
12337
  const assignedValue = stripParenExpression(child.right);
12832
- if (isNodeOfType(assignedValue, "Literal") && assignedValue.value === null && findEnclosingFunction$1(child) === cleanupFunction) return;
12338
+ if (isNodeOfType(assignedValue, "Literal") && assignedValue.value === null && findEnclosingFunction(child) === cleanupFunction) return;
12833
12339
  const assignedSessionProperties = (isNodeOfType(assignedValue, "ObjectExpression") ? assignedValue : null)?.properties ?? [];
12834
12340
  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) {
12341
+ if (findEnclosingFunction(child) !== retainedFunction || !storesMatchingHandler) {
12836
12342
  hasUnsafeRefWrite = true;
12837
12343
  return false;
12838
12344
  }
@@ -12853,12 +12359,12 @@ const effectReturnsRefOwnedCleanup = (effectCallback, componentFunction, retaine
12853
12359
  return doMatchingNodesCoverEveryPathFromFunctionEntry(effectCallback, matchingReturns, context);
12854
12360
  };
12855
12361
  const hasGuaranteedRefOwnedUnmountCleanup = (retainedFunction, usage, context) => {
12856
- const componentFunction = findEnclosingFunction$1(retainedFunction);
12362
+ const componentFunction = findEnclosingFunction(retainedFunction);
12857
12363
  if (!componentFunction || !isFunctionLike$2(componentFunction)) return false;
12858
12364
  let didFindCleanupEffect = false;
12859
12365
  walkAst(componentFunction.body, (child) => {
12860
12366
  if (didFindCleanupEffect) return false;
12861
- if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction$1(child) !== componentFunction || !isReactApiCall(child, "useEffect", context.scopes)) return;
12367
+ if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction(child) !== componentFunction || !isReactApiCall(child, "useEffect", context.scopes)) return;
12862
12368
  const effectStatement = findTransparentExpressionRoot(child).parent;
12863
12369
  if (!isNodeOfType(effectStatement, "ExpressionStatement") || effectStatement.parent !== componentFunction.body) return;
12864
12370
  const effectCallback = getEffectCallback(child);
@@ -13712,202 +13218,6 @@ const resolveExhaustiveDepsSettings = (settings) => {
13712
13218
  };
13713
13219
  };
13714
13220
  //#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
13221
  //#region src/plugin/rules/react-builtins/exhaustive-deps-suppression.ts
13912
13222
  const DISABLE_COMMENT_RULE_NAME_PATTERN$1 = /(?:^|[\s,/])exhaustive-deps(?:$|[\s,:])/;
13913
13223
  const DISABLE_NEXT_LINE_PATTERN$1 = /\b(?:eslint|oxlint)-disable-next-line\b([^\n]*)/;
@@ -13979,6 +13289,25 @@ const isExhaustiveDepsSuppressedAt = (filename, nodeStartOffset) => {
13979
13289
  return index.suppressedLines.has(lineForOffset$1(nodeStartOffset, index.utf16NewlineOffsets)) || index.suppressedLines.has(lineForOffset$1(nodeStartOffset, index.utf8NewlineOffsets));
13980
13290
  };
13981
13291
  //#endregion
13292
+ //#region src/plugin/utils/is-ast-descendant.ts
13293
+ /**
13294
+ * True when `inner` is `outer` itself or any descendant in the AST
13295
+ * `parent` chain. Walks `inner.parent` upward and stops at either a
13296
+ * match (`true`) or the chain's root (`false`).
13297
+ *
13298
+ * Was duplicated byte-identical in:
13299
+ * - exhaustive-deps-symbol-stability.ts
13300
+ * - semantic/closure-captures.ts
13301
+ */
13302
+ const isAstDescendant = (inner, outer) => {
13303
+ let current = inner;
13304
+ while (current) {
13305
+ if (current === outer) return true;
13306
+ current = current.parent ?? null;
13307
+ }
13308
+ return false;
13309
+ };
13310
+ //#endregion
13982
13311
  //#region src/plugin/rules/react-builtins/exhaustive-deps-symbol-stability.ts
13983
13312
  /**
13984
13313
  * Symbol-stability helpers consumed by the `exhaustive-deps` rule.
@@ -14159,7 +13488,6 @@ const EFFECT_HOOKS_ALLOWING_EXTRA_REACTIVE_DEPS = new Set([
14159
13488
  "useLayoutEffect",
14160
13489
  "useInsertionEffect"
14161
13490
  ]);
14162
- const SOLE_WRITER_GUARD_HOOKS = new Set(["useEffect", "useLayoutEffect"]);
14163
13491
  const buildAdditionalHooksRegex = (additional) => {
14164
13492
  if (!additional) return null;
14165
13493
  try {
@@ -14296,7 +13624,7 @@ const stringifyMemberChain = (node) => {
14296
13624
  }
14297
13625
  return null;
14298
13626
  };
14299
- const collectCaptureDepKeys = (callback, scopes, declaredExactBindingKeys, allowSoleWriterEffectGuards = false) => {
13627
+ const collectCaptureDepKeys = (callback, scopes, declaredExactBindingKeys) => {
14300
13628
  const keys = /* @__PURE__ */ new Set();
14301
13629
  const stableCapturedNames = /* @__PURE__ */ new Set();
14302
13630
  const moduleScopeCapturedNames = /* @__PURE__ */ new Set();
@@ -14307,10 +13635,6 @@ const collectCaptureDepKeys = (callback, scopes, declaredExactBindingKeys, allow
14307
13635
  const symbol = reference.resolvedSymbol;
14308
13636
  if (!symbol) continue;
14309
13637
  if (isRecursiveInitializerCapture(symbol, callback)) continue;
14310
- if (allowSoleWriterEffectGuards && isSoleWriterEffectGuardCapture(symbol, callback, scopes)) {
14311
- stableCapturedNames.add(symbol.name);
14312
- continue;
14313
- }
14314
13638
  if (symbolHasStableValue(symbol, scopes)) {
14315
13639
  stableCapturedNames.add(symbol.name);
14316
13640
  continue;
@@ -14983,7 +14307,7 @@ If the missing value is recreated every render, move it inside the hook or stabi
14983
14307
  if (isNodeOfType(stripped, "Identifier")) declaredExactBindingKeys.add(key);
14984
14308
  declaredKeyToReportNode.set(key, elementNode);
14985
14309
  }
14986
- const { keys: captureKeys, stableCapturedNames, moduleScopeCapturedNames, outerFunctionCapturedNames } = collectCaptureDepKeys(callbackToAnalyze ?? callbackArgument, context.scopes, declaredExactBindingKeys, SOLE_WRITER_GUARD_HOOKS.has(hookName));
14310
+ const { keys: captureKeys, stableCapturedNames, moduleScopeCapturedNames, outerFunctionCapturedNames } = collectCaptureDepKeys(callbackToAnalyze ?? callbackArgument, context.scopes, declaredExactBindingKeys);
14987
14311
  for (const forcedCaptureKey of forcedCaptureKeys) captureKeys.add(forcedCaptureKey);
14988
14312
  addAggregatePropsDependency(captureKeys, declaredKeys, callbackToAnalyze ?? callbackArgument, context.scopes);
14989
14313
  const missingCaptureKeys = [];
@@ -16797,14 +16121,14 @@ const isBindingInvokedOnRenderPath = (root, bindingName) => {
16797
16121
  if (didFindRenderPathInvocation) return false;
16798
16122
  if (!isNodeOfType(node, "CallExpression")) return;
16799
16123
  if (!isNodeOfType(node.callee, "Identifier") || node.callee.name !== bindingName) return;
16800
- let enclosingFunction = findEnclosingFunction$1(node);
16124
+ let enclosingFunction = findEnclosingFunction(node);
16801
16125
  while (enclosingFunction) {
16802
16126
  if (isDeferredCallbackPosition$1(enclosingFunction) || getHandlerNamedBindingName(enclosingFunction)) return;
16803
16127
  if (containingFunctionIsComponentOrHook(enclosingFunction)) {
16804
16128
  didFindRenderPathInvocation = true;
16805
16129
  return;
16806
16130
  }
16807
- enclosingFunction = findEnclosingFunction$1(enclosingFunction);
16131
+ enclosingFunction = findEnclosingFunction(enclosingFunction);
16808
16132
  }
16809
16133
  });
16810
16134
  return didFindRenderPathInvocation;
@@ -16839,7 +16163,7 @@ const jotaiSelectAtomInRenderBody = defineRule({
16839
16163
  };
16840
16164
  return { CallExpression(node) {
16841
16165
  if (!isImportedSelectAtom(node)) return;
16842
- const nearestFunctionLike = findEnclosingFunction$1(node);
16166
+ const nearestFunctionLike = findEnclosingFunction(node);
16843
16167
  if (!nearestFunctionLike) return;
16844
16168
  if (isDeferredCallback(nearestFunctionLike)) return;
16845
16169
  if (isBindingUsedAsHandler(nearestFunctionLike)) return;
@@ -17836,7 +17160,7 @@ const isPersistentCacheSetWrite = (callExpression, newExpression, enclosingFunct
17836
17160
  return !isAstDescendant(receiverBinding.scopeOwner, enclosingFunction);
17837
17161
  };
17838
17162
  const isInsideCacheMemo = (node) => {
17839
- const enclosingFunction = findEnclosingFunction$1(node);
17163
+ const enclosingFunction = findEnclosingFunction(node);
17840
17164
  let child = node;
17841
17165
  let cursor = node.parent ?? null;
17842
17166
  while (cursor) {
@@ -17874,7 +17198,7 @@ const getFunctionName = (functionNode) => {
17874
17198
  return null;
17875
17199
  };
17876
17200
  const isUncacheableOptionsMergeUtility = (node) => {
17877
- const enclosingFunction = findEnclosingFunction$1(node);
17201
+ const enclosingFunction = findEnclosingFunction(node);
17878
17202
  if (!enclosingFunction || !isFunctionLike$2(enclosingFunction)) return false;
17879
17203
  const functionName = getFunctionName(enclosingFunction);
17880
17204
  if (!functionName || isComponentOrHookName(functionName)) return false;
@@ -18065,6 +17389,13 @@ const isSafeStatefulReplaceAllSearch = (node, flags, context) => {
18065
17389
  const callee = stripParenExpression(replaceAllCall.callee);
18066
17390
  return isNodeOfType(callee, "MemberExpression") && !callee.computed && !callee.optional && !replaceAllCall.optional && isNodeOfType(callee.property, "Identifier") && callee.property.name === "replaceAll" && isProvenNativeStringReceiver(callee.object, context);
18067
17391
  };
17392
+ const getDestructuredBindingPropertyName = (bindingIdentifier) => {
17393
+ let bindingNode = bindingIdentifier;
17394
+ if (isNodeOfType(bindingNode.parent, "AssignmentPattern") && bindingNode.parent.left === bindingNode) bindingNode = bindingNode.parent;
17395
+ const property = bindingNode.parent;
17396
+ if (!isNodeOfType(property, "Property") || property.value !== bindingNode || !isNodeOfType(property.parent, "ObjectPattern")) return null;
17397
+ return getStaticPropertyKeyName(property, { allowComputedString: true });
17398
+ };
18068
17399
  const extendGlobalPath = (basePath, propertyName) => {
18069
17400
  if (basePath === "global") {
18070
17401
  if (propertyName === null || GLOBAL_OBJECT_NAMES.has(propertyName)) return "global";
@@ -18354,89 +17685,7 @@ const collectEarlierAndGuardOperands = (node) => {
18354
17685
  return earlierOperands;
18355
17686
  };
18356
17687
  //#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
17688
  //#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
17689
  const findIndexedArrayObject = (callbackBody, indexParameterName) => {
18441
17690
  let indexedArrayObject = null;
18442
17691
  walkAst(callbackBody, (child) => {
@@ -18651,7 +17900,6 @@ const jsLengthCheckFirst = defineRule({
18651
17900
  const resolvedReceiverSource = resolveComparedArraySource(receiverArrayObject, node);
18652
17901
  const resolvedIndexedSource = resolveComparedArraySource(indexedArrayObject, node);
18653
17902
  if (areExpressionsStructurallyEqual(resolvedReceiverSource, resolvedIndexedSource)) return;
18654
- if (areEqualCardinalityObjectProjections(receiverArrayObject, indexedArrayObject, context) || areEqualCardinalityObjectProjections(resolvedReceiverSource, resolvedIndexedSource, context)) return;
18655
17903
  const comparedArrayPairs = [[receiverArrayObject, indexedArrayObject], [resolvedReceiverSource, resolvedIndexedSource]];
18656
17904
  if (collectEarlierAndGuardOperands(node).some((guardOperand) => comparedArrayPairs.some(([receiverSide, indexedSide]) => isLengthComparison(guardOperand, receiverSide, indexedSide, LENGTH_ANY_COMPARISON_OPERATORS)))) return;
18657
17905
  if (collectEarlierOrOperands(node).some((guardOperand) => comparedArrayPairs.some(([receiverSide, indexedSide]) => isLengthComparison(guardOperand, receiverSide, indexedSide, LENGTH_MISMATCH_OPERATORS)))) return;
@@ -24529,6 +23777,32 @@ const hasDirective = (programNode, directive) => {
24529
23777
  return Boolean(programNode.body?.some((statement) => isNodeOfType(statement, "ExpressionStatement") && isNodeOfType(statement.expression, "Literal") && statement.expression.value === directive));
24530
23778
  };
24531
23779
  //#endregion
23780
+ //#region src/plugin/utils/unwrap-object-integrity-expression.ts
23781
+ const OBJECT_INTEGRITY_METHOD_NAMES = new Set([
23782
+ "freeze",
23783
+ "seal",
23784
+ "preventExtensions"
23785
+ ]);
23786
+ const OBJECT_FREEZE_OR_SEAL_METHOD_NAMES = new Set(["freeze", "seal"]);
23787
+ const getObjectIntegrityMethodName = (node, scopes, methodNames = OBJECT_INTEGRITY_METHOD_NAMES) => {
23788
+ const expression = stripParenExpression(node);
23789
+ if (!isNodeOfType(expression, "CallExpression")) return null;
23790
+ const callee = stripParenExpression(expression.callee);
23791
+ const receiver = isNodeOfType(callee, "MemberExpression") ? stripParenExpression(callee.object) : callee;
23792
+ 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;
23793
+ return callee.property.name;
23794
+ };
23795
+ const unwrapObjectIntegrityExpression = (node, scopes, methodNames = OBJECT_INTEGRITY_METHOD_NAMES) => {
23796
+ let expression = stripParenExpression(node);
23797
+ while (isNodeOfType(expression, "CallExpression")) {
23798
+ if (!getObjectIntegrityMethodName(expression, scopes, methodNames)) break;
23799
+ const wrappedExpression = expression.arguments[0];
23800
+ if (!wrappedExpression || isNodeOfType(wrappedExpression, "SpreadElement")) break;
23801
+ expression = stripParenExpression(wrappedExpression);
23802
+ }
23803
+ return expression;
23804
+ };
23805
+ //#endregion
24532
23806
  //#region src/plugin/rules/nextjs/nextjs-async-client-component.ts
24533
23807
  const nextjsAsyncClientComponent = defineRule({
24534
23808
  id: "nextjs-async-client-component",
@@ -26868,7 +26142,7 @@ const isIndependentWriterIdentifier = (componentFunction, identifier, includeDef
26868
26142
  };
26869
26143
  const hasUserInputSetterWriter = (setterRef, effectNode, includeDeferredWriters = false) => {
26870
26144
  if (!setterRef.resolved) return false;
26871
- const componentFunction = findEnclosingFunction$1(effectNode);
26145
+ const componentFunction = findEnclosingFunction(effectNode);
26872
26146
  if (!componentFunction) return false;
26873
26147
  for (const reference of setterRef.resolved.references) {
26874
26148
  if (reference.init) continue;
@@ -29641,6 +28915,138 @@ const noBarrelImport = defineRule({
29641
28915
  }
29642
28916
  });
29643
28917
  //#endregion
28918
+ //#region src/plugin/utils/has-static-property-write-before.ts
28919
+ const equivalentSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
28920
+ const CONDITIONAL_EXECUTION_NODE_TYPES = new Set([
28921
+ "CatchClause",
28922
+ "ConditionalExpression",
28923
+ "DoWhileStatement",
28924
+ "ForInStatement",
28925
+ "ForOfStatement",
28926
+ "ForStatement",
28927
+ "IfStatement",
28928
+ "LogicalExpression",
28929
+ "SwitchCase",
28930
+ "SwitchStatement",
28931
+ "TryStatement",
28932
+ "WhileStatement"
28933
+ ]);
28934
+ const getResolvedStaticPropertyName = (memberExpression, scopes) => {
28935
+ if (!isNodeOfType(memberExpression, "MemberExpression")) return null;
28936
+ const directPropertyName = getStaticPropertyName(memberExpression);
28937
+ if (directPropertyName || !memberExpression.computed) return directPropertyName;
28938
+ const property = stripParenExpression(memberExpression.property);
28939
+ if (!isNodeOfType(property, "Identifier")) return null;
28940
+ const propertySymbol = resolveConstIdentifierAlias(property, scopes);
28941
+ const initializer = propertySymbol?.initializer ? stripParenExpression(propertySymbol.initializer) : null;
28942
+ return initializer && isNodeOfType(initializer, "Literal") && typeof initializer.value === "string" ? initializer.value : null;
28943
+ };
28944
+ const collectScopeSymbols = (scope, symbols) => {
28945
+ symbols.push(...scope.symbols);
28946
+ for (const childScope of scope.children) collectScopeSymbols(childScope, symbols);
28947
+ };
28948
+ const getEquivalentSymbols = (identifier, scopes) => {
28949
+ const rootSymbol = resolveConstIdentifierAlias(identifier, scopes);
28950
+ if (!rootSymbol) return [];
28951
+ let symbolsByRootId = equivalentSymbolsByAnalysis.get(scopes);
28952
+ if (!symbolsByRootId) {
28953
+ symbolsByRootId = /* @__PURE__ */ new Map();
28954
+ equivalentSymbolsByAnalysis.set(scopes, symbolsByRootId);
28955
+ }
28956
+ const cachedSymbols = symbolsByRootId.get(rootSymbol.id);
28957
+ if (cachedSymbols) return cachedSymbols;
28958
+ const allSymbols = [];
28959
+ collectScopeSymbols(scopes.rootScope, allSymbols);
28960
+ const equivalentSymbols = allSymbols.filter((symbol) => resolveConstIdentifierAlias(symbol.bindingIdentifier, scopes)?.id === rootSymbol.id);
28961
+ symbolsByRootId.set(rootSymbol.id, equivalentSymbols);
28962
+ return equivalentSymbols;
28963
+ };
28964
+ const findExecutionBoundary = (node) => {
28965
+ let current = node;
28966
+ while (current) {
28967
+ if (isFunctionLike$2(current) || isNodeOfType(current, "Program")) return current;
28968
+ current = current.parent ?? null;
28969
+ }
28970
+ return null;
28971
+ };
28972
+ const isOnUnconditionalPath = (node, boundary) => {
28973
+ let current = node.parent ?? null;
28974
+ while (current && current !== boundary) {
28975
+ if (CONDITIONAL_EXECUTION_NODE_TYPES.has(current.type)) return false;
28976
+ current = current.parent ?? null;
28977
+ }
28978
+ return current === boundary;
28979
+ };
28980
+ const findFunctionBindingIdentifier = (functionNode) => {
28981
+ if (isNodeOfType(functionNode, "FunctionDeclaration")) return functionNode.id ?? null;
28982
+ const parent = functionNode.parent;
28983
+ if (parent && isNodeOfType(parent, "VariableDeclarator") && parent.init === functionNode && isNodeOfType(parent.id, "Identifier")) return parent.id;
28984
+ return null;
28985
+ };
28986
+ const findDirectCall = (identifier) => {
28987
+ let callee = identifier;
28988
+ let parent = callee.parent;
28989
+ while (parent && stripParenExpression(parent) === identifier) {
28990
+ callee = parent;
28991
+ parent = callee.parent;
28992
+ }
28993
+ return parent && isNodeOfType(parent, "CallExpression") && parent.callee === callee ? parent : null;
28994
+ };
28995
+ const isFunctionSynchronouslyInvokedBefore = (functionNode, referenceNode, scopes, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
28996
+ if (visitedFunctionNodes.has(functionNode) || !isFunctionLike$2(functionNode) || functionNode.generator) return false;
28997
+ visitedFunctionNodes.add(functionNode);
28998
+ const referenceBoundary = findExecutionBoundary(referenceNode);
28999
+ if (!referenceBoundary) return false;
29000
+ const invocationCalls = [];
29001
+ const bindingIdentifier = findFunctionBindingIdentifier(functionNode);
29002
+ if (bindingIdentifier) for (const symbol of getEquivalentSymbols(bindingIdentifier, scopes)) for (const reference of symbol.references) {
29003
+ const call = findDirectCall(reference.identifier);
29004
+ if (call) invocationCalls.push(call);
29005
+ }
29006
+ else {
29007
+ const call = findDirectCall(functionNode);
29008
+ if (call) invocationCalls.push(call);
29009
+ }
29010
+ return invocationCalls.some((call) => {
29011
+ if (call.range[0] >= referenceNode.range[0]) return false;
29012
+ const callBoundary = findExecutionBoundary(call);
29013
+ if (!callBoundary) return false;
29014
+ if (callBoundary === referenceBoundary) return true;
29015
+ if (!isFunctionLike$2(callBoundary)) return false;
29016
+ return isFunctionSynchronouslyInvokedBefore(callBoundary, referenceNode, scopes, new Set(visitedFunctionNodes));
29017
+ });
29018
+ };
29019
+ const isMemberWriteTarget = (memberExpression) => {
29020
+ const parent = memberExpression.parent;
29021
+ if (!parent) return false;
29022
+ if (isNodeOfType(parent, "AssignmentExpression")) return parent.left === memberExpression;
29023
+ if (isNodeOfType(parent, "UpdateExpression")) return parent.argument === memberExpression;
29024
+ return isNodeOfType(parent, "UnaryExpression") && parent.operator === "delete" && parent.argument === memberExpression;
29025
+ };
29026
+ const symbolHasStaticPropertyWriteBefore = (symbol, propertyName, referenceNode, scopes) => symbol.references.some((reference) => {
29027
+ let parent = reference.identifier.parent;
29028
+ while (parent && stripParenExpression(parent) === reference.identifier) parent = parent.parent;
29029
+ if (!parent || !isNodeOfType(parent, "MemberExpression") || stripParenExpression(parent.object) !== reference.identifier || getResolvedStaticPropertyName(parent, scopes) !== propertyName || !isMemberWriteTarget(parent)) return false;
29030
+ const writeBoundary = findExecutionBoundary(parent);
29031
+ const referenceBoundary = findExecutionBoundary(referenceNode);
29032
+ if (!writeBoundary || !referenceBoundary || !isOnUnconditionalPath(parent, writeBoundary)) return false;
29033
+ if (writeBoundary === referenceBoundary) return parent.range[0] < referenceNode.range[0];
29034
+ return isFunctionLike$2(writeBoundary) && isFunctionSynchronouslyInvokedBefore(writeBoundary, referenceNode, scopes);
29035
+ });
29036
+ const hasStaticPropertyWriteBefore = (identifier, propertyName, referenceNode, scopes) => {
29037
+ if (!isNodeOfType(identifier, "Identifier")) return false;
29038
+ return getEquivalentSymbols(identifier, scopes).some((symbol) => symbolHasStaticPropertyWriteBefore(symbol, propertyName, referenceNode, scopes));
29039
+ };
29040
+ //#endregion
29041
+ //#region src/plugin/utils/has-symbol-write-before.ts
29042
+ const hasSymbolWriteBefore = (symbol, referenceNode, scopes) => symbol.references.some((reference) => {
29043
+ if (reference.flag === "read") return false;
29044
+ const writeFunction = findEnclosingFunction(reference.identifier);
29045
+ if (writeFunction === findEnclosingFunction(referenceNode)) return reference.identifier.range[0] < referenceNode.range[0];
29046
+ if (!writeFunction) return true;
29047
+ return isFunctionSynchronouslyInvokedBefore(writeFunction, referenceNode, scopes);
29048
+ });
29049
+ //#endregion
29644
29050
  //#region src/plugin/utils/has-stable-call-target.ts
29645
29051
  const hasStableCallTarget = (callExpression, scopes) => {
29646
29052
  if (!isNodeOfType(callExpression, "CallExpression")) return false;
@@ -30109,8 +29515,8 @@ const isUseMemoCallbackArgument = (functionNode) => {
30109
29515
  return isReactFunctionCall(parent, "useMemo");
30110
29516
  };
30111
29517
  const findEnclosingRenderFunction = (node) => {
30112
- let enclosingFunction = findEnclosingFunction$1(node);
30113
- while (enclosingFunction && isUseMemoCallbackArgument(enclosingFunction)) enclosingFunction = findEnclosingFunction$1(enclosingFunction);
29518
+ let enclosingFunction = findEnclosingFunction(node);
29519
+ while (enclosingFunction && isUseMemoCallbackArgument(enclosingFunction)) enclosingFunction = findEnclosingFunction(enclosingFunction);
30114
29520
  return enclosingFunction;
30115
29521
  };
30116
29522
  const noCreateRefInFunctionComponent = defineRule({
@@ -31161,7 +30567,7 @@ const getEnclosingEffectHookCallback = (node, componentFunction) => {
31161
30567
  const isEffectDrivenResync = (useStateCall) => {
31162
30568
  const setterName = getStateSetterName(useStateCall);
31163
30569
  if (!setterName) return false;
31164
- const componentFunction = findEnclosingFunction$1(useStateCall);
30570
+ const componentFunction = findEnclosingFunction(useStateCall);
31165
30571
  if (!componentFunction) return false;
31166
30572
  let isExempt = false;
31167
30573
  walkAst(componentFunction, (child) => {
@@ -31265,7 +30671,7 @@ const isDraftReseedOrRenderAdjusted = (useStateCall, isPropName) => {
31265
30671
  const setterName = getStateSetterName(useStateCall);
31266
30672
  if (!setterName) return false;
31267
30673
  const stateValueName = getStateValueName(useStateCall);
31268
- const componentFunction = findEnclosingFunction$1(useStateCall);
30674
+ const componentFunction = findEnclosingFunction(useStateCall);
31269
30675
  if (!componentFunction) return false;
31270
30676
  let isExempt = false;
31271
30677
  walkAst(componentFunction, (child) => {
@@ -31311,7 +30717,7 @@ const noDerivedUseState = defineRule({
31311
30717
  if (isDraftReseedOrRenderAdjusted(node, propStackTracker.isPropName)) return;
31312
30718
  if (isEffectDrivenResync(node)) return;
31313
30719
  if (isNextjsDataFetchingPage(node)) return;
31314
- const componentFunction = findEnclosingFunction$1(node);
30720
+ const componentFunction = findEnclosingFunction(node);
31315
30721
  if (componentFunction) {
31316
30722
  if (isDefaultedDestructuredProp(componentFunction, propName)) return;
31317
30723
  if (isDraftCommittedToParent(componentFunction, getStateValueName(node), propStackTracker.isPropName)) return;
@@ -32786,29 +32192,6 @@ const isReturnOnlyStatement = (node) => {
32786
32192
  return isNodeOfType(node, "BlockStatement") && (node.body?.length ?? 0) === 1 && isNodeOfType(node.body?.[0], "ReturnStatement");
32787
32193
  };
32788
32194
  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
32195
  const doesGuardMatchDependency = (guardExpression, dependencyExpression) => {
32813
32196
  const unwrappedDependencyExpression = unwrapChainExpression$1(dependencyExpression);
32814
32197
  if (!unwrappedDependencyExpression) return false;
@@ -32816,69 +32199,6 @@ const doesGuardMatchDependency = (guardExpression, dependencyExpression) => {
32816
32199
  return isNodeOfType(unwrappedDependencyExpression, "Identifier") && unwrappedDependencyExpression.name === guardExpression.rootIdentifierName;
32817
32200
  };
32818
32201
  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
32202
  const isEqualityToLiteralGuard = (guardExpression) => {
32883
32203
  const parent = guardExpression.expression.parent;
32884
32204
  if (!isNodeOfType(parent, "BinaryExpression")) return false;
@@ -32943,35 +32263,18 @@ const noEffectEventHandler = defineRule({
32943
32263
  if (statements.length === 0) return;
32944
32264
  const soleStatement = statements[0];
32945
32265
  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));
32266
+ const guardExpressions = [];
32267
+ collectGuardExpressions(soleStatement.test, guardExpressions);
32268
+ const matchingPropGuardExpressions = guardExpressions.filter((guardExpression) => hasDependencyMatch(guardExpression, dependencyExpressions) && propStackTracker.isPropName(guardExpression.rootIdentifierName, node));
32951
32269
  if (matchingPropGuardExpressions.length === 0) return;
32952
32270
  const isSingleGuardedEventLikeStatement = statements.length === 1 && hasEventLikeNode(soleStatement.consequent);
32953
32271
  const isEarlyReturnGuardedEventLikeBody = statements.length > 1 && !soleStatement.alternate && isReturnOnlyStatement(soleStatement.consequent) && hasEventLikeRemainingStatements(statements.slice(1));
32954
32272
  if (!isSingleGuardedEventLikeStatement && !isEarlyReturnGuardedEventLikeBody) return;
32955
32273
  if (isEarlyReturnGuardedEventLikeBody && !isSingleGuardedEventLikeStatement && matchingPropGuardExpressions.every(isEqualityToLiteralGuard)) return;
32956
- if (initialGuardExpressions.some((guardExpression) => !matchingPropGuardExpressions.some((matchingGuardExpression) => matchingGuardExpression.expression === guardExpression.expression))) {
32274
+ if (guardExpressions.some((guardExpression) => !matchingPropGuardExpressions.some((matchingGuardExpression) => matchingGuardExpression.expression === guardExpression.expression))) {
32957
32275
  const matchingPropRootNames = new Set(matchingPropGuardExpressions.map((guardExpression) => guardExpression.rootIdentifierName));
32958
32276
  if (!(isSingleGuardedEventLikeStatement ? doesEventLikeCallReferenceAnyRoot(soleStatement.consequent, matchingPropRootNames) : doesAnyEventLikeCallReferenceAnyRoot(statements.slice(1), matchingPropRootNames))) return;
32959
32277
  }
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
32278
  context.report({
32976
32279
  node,
32977
32280
  message: "This useEffect is simulating an event handler, which costs an extra render & runs late."
@@ -33252,7 +32555,7 @@ const isFunctionUsedOutsideHandlers = (analysis, functionNode, componentFunction
33252
32555
  if (isInsideInlineEventHandler(identifier, componentFunction)) return false;
33253
32556
  const parent = identifier.parent;
33254
32557
  if (parent && isNodeOfType(parent, "CallExpression") && parent.callee === identifier) {
33255
- if (findEnclosingFunction$1(parent) === functionNode) return false;
32558
+ if (findEnclosingFunction(parent) === functionNode) return false;
33256
32559
  if (isInsideProvenEventHandler(analysis, parent, componentFunction, false)) return false;
33257
32560
  }
33258
32561
  return true;
@@ -33298,7 +32601,7 @@ const isStateWrittenOnlyFromEventHandlers = (analysis, stateReference) => {
33298
32601
  if (!setterVariable) return false;
33299
32602
  const stateDeclarator = getUseStateDecl(analysis, stateReference);
33300
32603
  if (!stateDeclarator) return false;
33301
- const componentFunction = findEnclosingFunction$1(stateDeclarator);
32604
+ const componentFunction = findEnclosingFunction(stateDeclarator);
33302
32605
  if (!componentFunction) return false;
33303
32606
  let hasWriter = false;
33304
32607
  for (const reference of setterVariable.references) {
@@ -34360,8 +33663,8 @@ const isAwaitedInFunction = (request, functionNode) => {
34360
33663
  return false;
34361
33664
  };
34362
33665
  const isCompletionSinkForRequest = (completionSink, request) => {
34363
- const requestFunction = findEnclosingFunction$1(request);
34364
- const completionSinkFunction = findEnclosingFunction$1(completionSink);
33666
+ const requestFunction = findEnclosingFunction(request);
33667
+ const completionSinkFunction = findEnclosingFunction(completionSink);
34365
33668
  if (!requestFunction || !completionSinkFunction) return false;
34366
33669
  if (requestFunction === completionSinkFunction) {
34367
33670
  if (!isAwaitedInFunction(request, requestFunction)) return false;
@@ -34648,6 +33951,13 @@ const isPublishedLibraryPackage = (filename) => {
34648
33951
  return manifest.private !== true && typeof manifest.peerDependencies === "object" && manifest.peerDependencies !== null && "react" in manifest.peerDependencies;
34649
33952
  };
34650
33953
  //#endregion
33954
+ //#region src/plugin/utils/is-type-only-import.ts
33955
+ const isEverySpecifierInlineType = (specifiers, specifierType, kindField) => {
33956
+ if (!specifiers || specifiers.length === 0) return false;
33957
+ return specifiers.every((specifier) => isNodeOfType(specifier, specifierType) && specifier[kindField] === "type");
33958
+ };
33959
+ const isTypeOnlyImport = (node) => node.importKind === "type" || isEverySpecifierInlineType(node.specifiers, "ImportSpecifier", "importKind");
33960
+ //#endregion
34651
33961
  //#region src/plugin/rules/bundle-size/no-full-lodash-import.ts
34652
33962
  const isLibraryDevPage = (filename) => {
34653
33963
  if (!filename) return false;
@@ -35211,7 +34521,7 @@ const isInRenderedOutput = (node, componentOrHookNode, scopes) => {
35211
34521
  return attribute ? !isEventHandlerAttribute(attribute) : true;
35212
34522
  }
35213
34523
  if (isNodeOfType(parentNode, "ReturnStatement")) {
35214
- if (findEnclosingFunction$1(parentNode) === componentOrHookNode) return true;
34524
+ if (findEnclosingFunction(parentNode) === componentOrHookNode) return true;
35215
34525
  }
35216
34526
  if (parentNode === componentOrHookNode) return isFunctionLike$2(componentOrHookNode) && !isNodeOfType(componentOrHookNode.body, "BlockStatement") && componentOrHookNode.body === currentNode;
35217
34527
  if (isFunctionLike$2(parentNode) && !executesDuringRender(parentNode, scopes)) return false;
@@ -35334,7 +34644,7 @@ const noHydrationBranchOnBrowserGlobal = defineRule({
35334
34644
  if (consequentValues.length === 0 || alternateValues.length === 0) return;
35335
34645
  const componentOrHookNode = findRenderPhaseComponentOrHook(node.test, context.scopes);
35336
34646
  if (!componentOrHookNode) return;
35337
- const enclosingFunction = findEnclosingFunction$1(node);
34647
+ const enclosingFunction = findEnclosingFunction(node);
35338
34648
  if (enclosingFunction !== componentOrHookNode && (!enclosingFunction || !isInRenderedOutput(enclosingFunction, componentOrHookNode, context.scopes))) return;
35339
34649
  for (const consequentValue of consequentValues) for (const alternateValue of alternateValues) {
35340
34650
  if (!isRenderedValue(consequentValue) && !isRenderedValue(alternateValue)) continue;
@@ -35782,10 +35092,10 @@ const isInsideInstanceField = (node) => {
35782
35092
  return false;
35783
35093
  };
35784
35094
  const isOneShotModuleInitialization = (node, context) => {
35785
- let functionNode = findEnclosingFunction$1(node);
35095
+ let functionNode = findEnclosingFunction(node);
35786
35096
  while (functionNode) {
35787
35097
  if (!executesDuringRender(functionNode, context.scopes)) return false;
35788
- functionNode = findEnclosingFunction$1(functionNode);
35098
+ functionNode = findEnclosingFunction(functionNode);
35789
35099
  }
35790
35100
  return !isInsideInstanceField(node);
35791
35101
  };
@@ -36303,221 +35613,6 @@ const noLegacyClassLifecycles = defineRule({
36303
35613
  }
36304
35614
  });
36305
35615
  //#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
35616
  //#region src/plugin/rules/architecture/no-legacy-context-api.ts
36522
35617
  const LEGACY_CONTEXT_NAMES = new Set([
36523
35618
  "childContextTypes",
@@ -36528,6 +35623,15 @@ const buildLegacyContextMessage = (memberName) => {
36528
35623
  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
35624
  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
35625
  };
35626
+ const isInsideClassBody = (node) => {
35627
+ let current = node.parent;
35628
+ while (current) {
35629
+ if (isNodeOfType(current, "ClassBody")) return true;
35630
+ if (isFunctionLike$2(current)) return false;
35631
+ current = current.parent;
35632
+ }
35633
+ return false;
35634
+ };
36531
35635
  const noLegacyContextApi = defineRule({
36532
35636
  id: "no-legacy-context-api",
36533
35637
  title: "Legacy context API",
@@ -36542,7 +35646,6 @@ const noLegacyContextApi = defineRule({
36542
35646
  if (!isNodeOfType(memberNode, "MethodDefinition") && !isNodeOfType(memberNode, "PropertyDefinition")) return;
36543
35647
  if (!isNodeOfType(memberNode.key, "Identifier")) return;
36544
35648
  if (!LEGACY_CONTEXT_NAMES.has(memberNode.key.name)) return;
36545
- if (memberNode.key.name === "getChildContext" ? memberNode.static : !memberNode.static) return;
36546
35649
  context.report({
36547
35650
  node: memberNode.key,
36548
35651
  message: buildLegacyContextMessage(memberNode.key.name)
@@ -36550,8 +35653,6 @@ const noLegacyContextApi = defineRule({
36550
35653
  };
36551
35654
  return {
36552
35655
  ClassBody(node) {
36553
- const classNode = node.parent;
36554
- if (!classNode || !isProvenReactClassComponent(classNode, context.scopes)) return;
36555
35656
  for (const member of node.body ?? []) checkMember(member);
36556
35657
  },
36557
35658
  AssignmentExpression(node) {
@@ -36561,11 +35662,9 @@ const noLegacyContextApi = defineRule({
36561
35662
  if (left.computed) return;
36562
35663
  if (!isNodeOfType(left.property, "Identifier")) return;
36563
35664
  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;
35665
+ if (!isNodeOfType(left.object, "Identifier")) return;
35666
+ if (!isUppercaseName(left.object.name)) return;
35667
+ if (isInsideClassBody(node)) return;
36569
35668
  context.report({
36570
35669
  node: left,
36571
35670
  message: buildLegacyContextMessage(left.property.name)
@@ -36769,10 +35868,10 @@ const getMethodCalls = (functionNode, scopes) => {
36769
35868
  const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, scopes, visitedSymbolIds, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
36770
35869
  if (visitedFunctionNodes.has(functionNode)) return false;
36771
35870
  visitedFunctionNodes.add(functionNode);
36772
- const usageFunction = findEnclosingFunction$1(usageNode);
35871
+ const usageFunction = findEnclosingFunction(usageNode);
36773
35872
  const immediateCall = getDirectCallForExpression(functionNode);
36774
35873
  if (immediateCall) {
36775
- const immediateCallFunction = findEnclosingFunction$1(immediateCall);
35874
+ const immediateCallFunction = findEnclosingFunction(immediateCall);
36776
35875
  if (immediateCallFunction === usageFunction) {
36777
35876
  const immediateCallStart = getRangeStart(immediateCall);
36778
35877
  return immediateCallStart === null || immediateCallStart < usageBoundary;
@@ -36781,7 +35880,7 @@ const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, sc
36781
35880
  return isFunctionInvokedBeforeUsage(immediateCallFunction, usageNode, usageBoundary, scopes, visitedSymbolIds, new Set(visitedFunctionNodes));
36782
35881
  }
36783
35882
  for (const methodCall of getMethodCalls(functionNode, scopes)) {
36784
- const methodCallFunction = findEnclosingFunction$1(methodCall);
35883
+ const methodCallFunction = findEnclosingFunction(methodCall);
36785
35884
  if (methodCallFunction === usageFunction) {
36786
35885
  const methodCallStart = getRangeStart(methodCall);
36787
35886
  if (methodCallStart === null || methodCallStart < usageBoundary) return true;
@@ -36804,7 +35903,7 @@ const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, sc
36804
35903
  if (scopes.symbolFor(child)?.declarationNode !== symbol.declarationNode) return;
36805
35904
  const call = getDirectCallForExpression(child);
36806
35905
  if (!call) return false;
36807
- const callFunction = findEnclosingFunction$1(call);
35906
+ const callFunction = findEnclosingFunction(call);
36808
35907
  if (callFunction === usageFunction) {
36809
35908
  const callStart = getRangeStart(call);
36810
35909
  wasInvokedBeforeUsage = callStart === null || callStart < usageBoundary;
@@ -36835,14 +35934,14 @@ const wasMutatedBeforeUsage = (symbol, usageNode, readNode, scopes, visitedMutat
36835
35934
  visitedMutationSymbolIds.add(symbol.id);
36836
35935
  const usageBoundary = inheritedUsageBoundary === void 0 ? getMutationUsageBoundary(usageNode, readNode) : inheritedUsageBoundary;
36837
35936
  if (typeof usageBoundary !== "number") return true;
36838
- const usageFunction = findEnclosingFunction$1(usageNode);
35937
+ const usageFunction = findEnclosingFunction(usageNode);
36839
35938
  return symbol.references.some((reference) => {
36840
35939
  const referenceStart = getRangeStart(reference.identifier);
36841
35940
  const simpleAlias = getSimpleAlias(reference.identifier, scopes);
36842
35941
  if (simpleAlias) return wasMutatedBeforeUsage(simpleAlias.symbol, usageNode, readNodesBySymbolId.get(simpleAlias.symbol.id) ?? simpleAlias.readNode, scopes, new Set(visitedMutationSymbolIds), usageBoundary, readNodesBySymbolId);
36843
35942
  if (!isPotentialMutationReference(reference.identifier, readNode)) return false;
36844
35943
  if (referenceStart === null) return true;
36845
- const mutationFunction = findEnclosingFunction$1(reference.identifier);
35944
+ const mutationFunction = findEnclosingFunction(reference.identifier);
36846
35945
  if (mutationFunction === usageFunction) return referenceStart < usageBoundary;
36847
35946
  if (!mutationFunction) return usageFunction !== null;
36848
35947
  if (usageFunction && isAstDescendant(usageFunction, mutationFunction)) return true;
@@ -37424,6 +36523,13 @@ const isReactNamespaceExpression = (node, scopes) => {
37424
36523
  return isReactNamespaceImport(node, scopes);
37425
36524
  };
37426
36525
  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));
36526
+ const getDestructuredPropertyName$1 = (symbol) => {
36527
+ const property = symbol.bindingIdentifier.parent;
36528
+ if (!property || !isNodeOfType(property, "Property") || !property.parent || !isNodeOfType(property.parent, "ObjectPattern")) return null;
36529
+ if (isNodeOfType(property.key, "Identifier") && !property.computed) return property.key.name;
36530
+ if (isNodeOfType(property.key, "Literal") && typeof property.key.value === "string") return property.key.value;
36531
+ return null;
36532
+ };
37427
36533
  const symbolMapsToHoc = (symbol, scopes, visitedSymbolIds) => {
37428
36534
  if (visitedSymbolIds.has(symbol.id)) return false;
37429
36535
  visitedSymbolIds.add(symbol.id);
@@ -37433,7 +36539,7 @@ const symbolMapsToHoc = (symbol, scopes, visitedSymbolIds) => {
37433
36539
  }
37434
36540
  const init = symbol.initializer;
37435
36541
  if (!init) return false;
37436
- const destructuredPropertyName = getDestructuredBindingPropertyName(symbol.bindingIdentifier);
36542
+ const destructuredPropertyName = getDestructuredPropertyName$1(symbol);
37437
36543
  if (destructuredPropertyName && REACT_HOC_NAMES.has(destructuredPropertyName) && isReactNamespaceExpression(init, scopes)) return true;
37438
36544
  if (isReactHocMemberReference(init, scopes)) return true;
37439
36545
  if (isNodeOfType(init, "Identifier")) {
@@ -39187,6 +38293,12 @@ const getDeclarationKind = (declarator) => {
39187
38293
  return declaration && isNodeOfType(declaration, "VariableDeclaration") ? declaration.kind : null;
39188
38294
  };
39189
38295
  const hasMutableBindingWrite = (reference) => Boolean(reference.resolved?.references.some((candidateReference) => candidateReference.isWrite() && !candidateReference.init));
38296
+ const getDestructuredPropertyName = (bindingIdentifier) => {
38297
+ const property = bindingIdentifier.parent;
38298
+ if (!property || !isNodeOfType(property, "Property")) return null;
38299
+ if (property.computed) return isNodeOfType(property.key, "Literal") && typeof property.key.value === "string" ? String(property.key.value) : null;
38300
+ return isNodeOfType(property.key, "Identifier") ? property.key.name : null;
38301
+ };
39190
38302
  const getParentCallbackPropName = (analysis, expression, visitedVariables = /* @__PURE__ */ new Set()) => {
39191
38303
  const unwrappedExpression = stripParenExpression(expression);
39192
38304
  if (isNodeOfType(unwrappedExpression, "Identifier")) {
@@ -39196,7 +38308,7 @@ const getParentCallbackPropName = (analysis, expression, visitedVariables = /* @
39196
38308
  if (isProp(analysis, callbackReference)) {
39197
38309
  if (isWholePropsObjectReference(analysis, callbackReference)) return null;
39198
38310
  const bindingIdentifier = callbackVariable.defs.find((definition) => definition.type === "Parameter")?.name;
39199
- return (bindingIdentifier && getDestructuredBindingPropertyName(bindingIdentifier)) ?? unwrappedExpression.name;
38311
+ return (bindingIdentifier && getDestructuredPropertyName(bindingIdentifier)) ?? unwrappedExpression.name;
39200
38312
  }
39201
38313
  if (hasMutableBindingWrite(callbackReference)) return null;
39202
38314
  const definitions = callbackVariable.defs.map((definition) => definition.node).filter((definitionNode) => isNodeOfType(definitionNode, "VariableDeclarator"));
@@ -39206,7 +38318,7 @@ const getParentCallbackPropName = (analysis, expression, visitedVariables = /* @
39206
38318
  visitedVariables.add(callbackVariable);
39207
38319
  if (isNodeOfType(declarator.id, "ObjectPattern")) {
39208
38320
  const bindingIdentifier = callbackVariable.defs[0]?.name;
39209
- const propertyName = bindingIdentifier ? getDestructuredBindingPropertyName(bindingIdentifier) : null;
38321
+ const propertyName = bindingIdentifier ? getDestructuredPropertyName(bindingIdentifier) : null;
39210
38322
  const propsReference = getDownstreamRefs(analysis, declarator.init).find((candidateReference) => isWholePropsObjectReference(analysis, candidateReference));
39211
38323
  return propertyName && propsReference ? propertyName : null;
39212
38324
  }
@@ -39309,7 +38421,7 @@ const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactU
39309
38421
  const bindingProvenance = getRefBindingProvenance(analysis, stripParenExpression(callee.object), isReactUseRefCall);
39310
38422
  if (!bindingProvenance) return null;
39311
38423
  const { refCall, variables } = bindingProvenance;
39312
- const componentFunction = findEnclosingFunction$1(effectCall);
38424
+ const componentFunction = findEnclosingFunction(effectCall);
39313
38425
  if (!componentFunction || !isFunctionLike$2(componentFunction) || !isComponentFunction$1(componentFunction) || !isNodeOfType(componentFunction.body, "BlockStatement")) return null;
39314
38426
  if (!getDirectComponentBodyStatement(effectCall, componentFunction.body)) return null;
39315
38427
  const callbackPropNames = /* @__PURE__ */ new Set();
@@ -39765,25 +38877,14 @@ const isPropsChildrenLength = (node, scopes) => {
39765
38877
  const unwrappedNode = stripParenExpression(node);
39766
38878
  return isNodeOfType(unwrappedNode, "MemberExpression") && !unwrappedNode.computed && isNodeOfType(unwrappedNode.property, "Identifier") && unwrappedNode.property.name === "length" && resolvesToPropsChildren(stripParenExpression(unwrappedNode.object), scopes);
39767
38879
  };
39768
- const resolveStaticNumericValue = (node, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
39769
- const unwrappedNode = stripParenExpression(node);
39770
- if (isNodeOfType(unwrappedNode, "Literal") && typeof unwrappedNode.value === "number") return Number.isFinite(unwrappedNode.value) ? unwrappedNode.value : null;
39771
- if (!isNodeOfType(unwrappedNode, "Identifier")) return null;
39772
- const symbol = scopes.symbolFor(unwrappedNode);
39773
- if (!symbol || visitedSymbolIds.has(symbol.id)) return null;
39774
- const initializer = getDirectConstInitializer(symbol);
39775
- if (!initializer) return null;
39776
- return resolveStaticNumericValue(initializer, scopes, new Set(visitedSymbolIds).add(symbol.id));
39777
- };
39778
38880
  const isLargeTextLengthComparison = (node, scopes) => {
39779
38881
  const unwrappedNode = stripParenExpression(node);
39780
38882
  if (!isNodeOfType(unwrappedNode, "BinaryExpression")) return false;
39781
38883
  const leftIsLength = isPropsChildrenLength(unwrappedNode.left, scopes);
39782
38884
  const rightIsLength = isPropsChildrenLength(unwrappedNode.right, scopes);
39783
38885
  const thresholdNode = leftIsLength ? unwrappedNode.right : unwrappedNode.left;
39784
- if (!leftIsLength && !rightIsLength) return false;
39785
- const thresholdValue = resolveStaticNumericValue(thresholdNode, scopes);
39786
- if (thresholdValue === null || thresholdValue < 1e3) return false;
38886
+ if (!leftIsLength && !rightIsLength || !isNodeOfType(thresholdNode, "Literal")) return false;
38887
+ if (typeof thresholdNode.value !== "number" || thresholdNode.value < 1e3) return false;
39787
38888
  return leftIsLength ? unwrappedNode.operator === ">" || unwrappedNode.operator === ">=" : unwrappedNode.operator === "<" || unwrappedNode.operator === "<=";
39788
38889
  };
39789
38890
  const isLargeStringOptimizationGuard = (comparison, scopes) => {
@@ -40156,6 +39257,174 @@ const noPropCallbackInRender = defineRule({
40156
39257
  } })
40157
39258
  });
40158
39259
  //#endregion
39260
+ //#region src/plugin/utils/is-proven-react-class-component.ts
39261
+ const REACT_COMPONENT_CLASS_NAMES = new Set(["Component", "PureComponent"]);
39262
+ const isReactComponentClassValue = (node, scopes, visitedClassNodes, visitedSymbolIds) => {
39263
+ const expression = stripParenExpression(node);
39264
+ if (isNodeOfType(expression, "MemberExpression")) {
39265
+ const propertyName = getStaticPropertyName(expression);
39266
+ const receiver = stripParenExpression(expression.object);
39267
+ return Boolean(propertyName && REACT_COMPONENT_CLASS_NAMES.has(propertyName) && isNodeOfType(receiver, "Identifier") && !hasStaticPropertyWriteBefore(receiver, propertyName, expression, scopes) && isReactNamespaceImport(receiver, scopes));
39268
+ }
39269
+ if (isNodeOfType(expression, "ClassExpression")) return isProvenReactClassComponent(expression, scopes, visitedClassNodes, visitedSymbolIds);
39270
+ if (!isNodeOfType(expression, "Identifier")) return false;
39271
+ const symbol = scopes.symbolFor(expression);
39272
+ if (!symbol || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, expression, scopes)) return false;
39273
+ visitedSymbolIds.add(symbol.id);
39274
+ if (isImportedFromReact(symbol)) {
39275
+ const importedName = getImportedName(symbol.declarationNode);
39276
+ return Boolean(importedName && REACT_COMPONENT_CLASS_NAMES.has(importedName));
39277
+ }
39278
+ if (isNodeOfType(symbol.declarationNode, "ClassDeclaration") || isNodeOfType(symbol.declarationNode, "ClassExpression")) return isProvenReactClassComponent(symbol.declarationNode, scopes, visitedClassNodes, visitedSymbolIds);
39279
+ return Boolean(symbol.kind === "const" && symbol.initializer && isReactComponentClassValue(symbol.initializer, scopes, visitedClassNodes, visitedSymbolIds));
39280
+ };
39281
+ const isProvenReactClassComponent = (classNode, scopes, visitedClassNodes = /* @__PURE__ */ new Set(), visitedSymbolIds = /* @__PURE__ */ new Set()) => {
39282
+ if (!isNodeOfType(classNode, "ClassDeclaration") && !isNodeOfType(classNode, "ClassExpression") || visitedClassNodes.has(classNode) || !classNode.superClass) return false;
39283
+ visitedClassNodes.add(classNode);
39284
+ return isReactComponentClassValue(classNode.superClass, scopes, visitedClassNodes, visitedSymbolIds);
39285
+ };
39286
+ //#endregion
39287
+ //#region src/plugin/utils/function-contains-proven-react-hook-call.ts
39288
+ const functionContainsProvenReactHookCall = (functionNode, scopes) => {
39289
+ if (!isFunctionLike$2(functionNode)) return false;
39290
+ let containsReactHookCall = false;
39291
+ walkAst(functionNode.body, (node) => {
39292
+ if (containsReactHookCall) return false;
39293
+ if (node !== functionNode.body && (isFunctionLike$2(node) || isNodeOfType(node, "ClassDeclaration") || isNodeOfType(node, "ClassExpression"))) return false;
39294
+ if (isNodeOfType(node, "CallExpression") && isReactApiCall(node, BUILTIN_HOOK_NAMES, scopes, { resolveNamedAliases: true })) {
39295
+ containsReactHookCall = true;
39296
+ return false;
39297
+ }
39298
+ });
39299
+ return containsReactHookCall;
39300
+ };
39301
+ //#endregion
39302
+ //#region src/plugin/utils/function-returns-props-children.ts
39303
+ const functionReturnsPropsChildren = (functionNode, scopes, controlFlow) => {
39304
+ if (!isFunctionLike$2(functionNode) || functionNode.params.length === 0) return false;
39305
+ const firstParameter = stripParenExpression(functionNode.params[0]);
39306
+ const firstParameterPattern = isNodeOfType(firstParameter, "AssignmentPattern") ? stripParenExpression(firstParameter.left) : firstParameter;
39307
+ const propsParameterSymbol = isNodeOfType(firstParameterPattern, "Identifier") ? scopes.symbolFor(firstParameterPattern) : null;
39308
+ const childrenBindingSymbolIds = /* @__PURE__ */ new Set();
39309
+ if (isNodeOfType(firstParameterPattern, "ObjectPattern")) {
39310
+ for (const property of firstParameterPattern.properties) if (isNodeOfType(property, "Property") && getStaticPropertyKeyName(property, { allowComputedString: true }) === "children") {
39311
+ const propertyValue = stripParenExpression(property.value);
39312
+ const childrenBinding = isNodeOfType(propertyValue, "AssignmentPattern") ? stripParenExpression(propertyValue.left) : propertyValue;
39313
+ if (!isNodeOfType(childrenBinding, "Identifier")) continue;
39314
+ const childrenBindingSymbol = scopes.symbolFor(childrenBinding);
39315
+ if (childrenBindingSymbol) childrenBindingSymbolIds.add(childrenBindingSymbol.id);
39316
+ }
39317
+ }
39318
+ return functionReturnsMatchingExpression(functionNode, scopes, (expression) => {
39319
+ const candidate = stripParenExpression(expression);
39320
+ if (isNodeOfType(candidate, "Identifier")) {
39321
+ const symbol = scopes.symbolFor(candidate);
39322
+ return Boolean(symbol && childrenBindingSymbolIds.has(symbol.id) && !hasSymbolWriteBefore(symbol, candidate, scopes));
39323
+ }
39324
+ if (!isNodeOfType(candidate, "MemberExpression")) return false;
39325
+ if (getStaticPropertyName(candidate) !== "children") return false;
39326
+ const receiver = stripParenExpression(candidate.object);
39327
+ if (!isNodeOfType(receiver, "Identifier")) return false;
39328
+ const receiverSymbol = scopes.symbolFor(receiver);
39329
+ if (!receiverSymbol || !propsParameterSymbol) return false;
39330
+ return receiverSymbol.id === propsParameterSymbol.id && !hasSymbolWriteBefore(receiverSymbol, candidate, scopes) && !hasStaticPropertyWriteBefore(receiver, "children", candidate, scopes);
39331
+ }, controlFlow);
39332
+ };
39333
+ //#endregion
39334
+ //#region src/plugin/utils/function-returns-only-null.ts
39335
+ const isNullExpression = (expression) => {
39336
+ const candidate = stripParenExpression(expression);
39337
+ return isNodeOfType(candidate, "Literal") && candidate.value === null;
39338
+ };
39339
+ const functionReturnsOnlyNull = (functionNode) => {
39340
+ if (!isFunctionLike$2(functionNode)) return false;
39341
+ if (!isNodeOfType(functionNode.body, "BlockStatement")) return isNullExpression(functionNode.body);
39342
+ const returnStatements = collectFunctionReturnStatements(functionNode);
39343
+ return returnStatements.length > 0 && returnStatements.every((returnStatement) => Boolean(returnStatement.argument && isNullExpression(returnStatement.argument)));
39344
+ };
39345
+ //#endregion
39346
+ //#region src/plugin/utils/is-proven-styled-component-expression.ts
39347
+ const findFactoryRoot = (node) => {
39348
+ const candidate = stripParenExpression(node);
39349
+ if (isNodeOfType(candidate, "Identifier")) return candidate;
39350
+ if (isNodeOfType(candidate, "MemberExpression")) return findFactoryRoot(candidate.object);
39351
+ if (isNodeOfType(candidate, "CallExpression")) return findFactoryRoot(candidate.callee);
39352
+ return null;
39353
+ };
39354
+ const findFactoryPropertyName = (node) => {
39355
+ const candidate = stripParenExpression(node);
39356
+ if (isNodeOfType(candidate, "MemberExpression")) return findFactoryPropertyName(candidate.object) ?? getStaticPropertyName(candidate);
39357
+ if (isNodeOfType(candidate, "CallExpression")) return findFactoryPropertyName(candidate.callee);
39358
+ return null;
39359
+ };
39360
+ const isProvenStyledComponentExpression = (expression, scopes) => {
39361
+ const candidate = stripParenExpression(expression);
39362
+ if (!isNodeOfType(candidate, "TaggedTemplateExpression")) return false;
39363
+ const factoryRoot = findFactoryRoot(candidate.tag);
39364
+ if (!factoryRoot) return false;
39365
+ const factoryPropertyName = findFactoryPropertyName(candidate.tag);
39366
+ if (factoryPropertyName && hasStaticPropertyWriteBefore(factoryRoot, factoryPropertyName, candidate, scopes)) return false;
39367
+ const symbol = resolveConstIdentifierAlias(factoryRoot, scopes);
39368
+ if (!symbol || symbol.kind !== "import") return false;
39369
+ if (!(isNodeOfType(symbol.declarationNode, "ImportDefaultSpecifier") || getImportedName(symbol.declarationNode) === "styled")) return false;
39370
+ const importDeclaration = symbol.declarationNode.parent;
39371
+ return Boolean(importDeclaration && isNodeOfType(importDeclaration, "ImportDeclaration") && importDeclaration.source.value === "styled-components");
39372
+ };
39373
+ //#endregion
39374
+ //#region src/plugin/utils/is-proven-react-component-symbol.ts
39375
+ const REACT_COMPONENT_HOC_NAMES = new Set(["memo", "forwardRef"]);
39376
+ const functionHasComponentEvidence = (functionNode, scopes, controlFlow) => functionContainsReactRenderOutput(functionNode, scopes, controlFlow) || functionReturnsPropsChildren(functionNode, scopes, controlFlow) || functionContainsProvenReactHookCall(functionNode, scopes) && functionReturnsOnlyNull(functionNode);
39377
+ const isProvenReactComponentExpression = (expression, scopes, controlFlow, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
39378
+ const candidate = stripParenExpression(expression);
39379
+ if (isInlineFunctionExpression(candidate)) return functionHasComponentEvidence(candidate, scopes, controlFlow);
39380
+ if (isNodeOfType(candidate, "ClassExpression")) return isProvenReactClassComponent(candidate, scopes);
39381
+ if (isProvenStyledComponentExpression(candidate, scopes)) return true;
39382
+ if (isNodeOfType(candidate, "Identifier")) {
39383
+ const symbol = scopes.symbolFor(candidate);
39384
+ if (!symbol || visitedSymbolIds.has(symbol.id) || hasSymbolWriteBefore(symbol, candidate, scopes)) return false;
39385
+ visitedSymbolIds.add(symbol.id);
39386
+ if (isNodeOfType(symbol.declarationNode, "FunctionDeclaration")) return functionHasComponentEvidence(symbol.declarationNode, scopes, controlFlow);
39387
+ if (isNodeOfType(symbol.declarationNode, "ClassDeclaration") || isNodeOfType(symbol.declarationNode, "ClassExpression")) return isProvenReactClassComponent(symbol.declarationNode, scopes);
39388
+ return Boolean(symbol.initializer && isProvenReactComponentExpression(symbol.initializer, scopes, controlFlow, visitedSymbolIds));
39389
+ }
39390
+ if (!isNodeOfType(candidate, "CallExpression")) return false;
39391
+ if (!hasStableCallTarget(candidate, scopes)) return false;
39392
+ if (isReactApiCall(candidate, REACT_COMPONENT_HOC_NAMES, scopes, { resolveNamedAliases: true })) {
39393
+ const wrappedComponent = candidate.arguments[0];
39394
+ return Boolean(wrappedComponent && !isNodeOfType(wrappedComponent, "SpreadElement") && isProvenReactComponentExpression(wrappedComponent, scopes, controlFlow, visitedSymbolIds));
39395
+ }
39396
+ if (!isReactApiCall(candidate, "useMemo", scopes, { resolveNamedAliases: true })) return false;
39397
+ const factory = candidate.arguments[0];
39398
+ if (!factory || isNodeOfType(factory, "SpreadElement")) return false;
39399
+ const unwrappedFactory = stripParenExpression(factory);
39400
+ if (!isInlineFunctionExpression(unwrappedFactory)) return false;
39401
+ if (!isNodeOfType(unwrappedFactory.body, "BlockStatement")) return isProvenReactComponentExpression(unwrappedFactory.body, scopes, controlFlow, visitedSymbolIds);
39402
+ const returnStatements = collectFunctionReturnStatements(unwrappedFactory);
39403
+ const returnedExpression = returnStatements[0]?.argument;
39404
+ return Boolean(returnStatements.length === 1 && returnedExpression && isProvenReactComponentExpression(returnedExpression, scopes, controlFlow, visitedSymbolIds));
39405
+ };
39406
+ const isProvenReactComponentSymbol = (symbol, scopes, controlFlow, componentReference) => {
39407
+ const candidateSymbols = symbol.kind === "ts-module" ? symbol.scope.symbols.filter((candidateSymbol) => candidateSymbol.name === symbol.name && candidateSymbol.kind !== "ts-module") : [symbol];
39408
+ for (const candidateSymbol of candidateSymbols) {
39409
+ if (hasSymbolWriteBefore(candidateSymbol, componentReference, scopes)) continue;
39410
+ if (isComponentDeclaration(candidateSymbol.declarationNode)) {
39411
+ if (functionHasComponentEvidence(candidateSymbol.declarationNode, scopes, controlFlow)) return true;
39412
+ continue;
39413
+ }
39414
+ const initializer = candidateSymbol.initializer ? stripParenExpression(candidateSymbol.initializer) : null;
39415
+ if (isNodeOfType(candidateSymbol.declarationNode, "VariableDeclarator") && isNodeOfType(candidateSymbol.declarationNode.id, "Identifier") && isUppercaseName(candidateSymbol.declarationNode.id.name) && initializer) {
39416
+ if (isProvenReactComponentExpression(initializer, scopes, controlFlow)) return true;
39417
+ continue;
39418
+ }
39419
+ if (isNodeOfType(candidateSymbol.declarationNode, "ClassDeclaration") || isNodeOfType(candidateSymbol.declarationNode, "ClassExpression")) {
39420
+ if (isProvenReactClassComponent(candidateSymbol.declarationNode, scopes)) return true;
39421
+ continue;
39422
+ }
39423
+ if (initializer && isNodeOfType(initializer, "ClassExpression") && isProvenReactClassComponent(initializer, scopes)) return true;
39424
+ }
39425
+ return false;
39426
+ };
39427
+ //#endregion
40159
39428
  //#region src/plugin/rules/architecture/no-prop-types.ts
40160
39429
  const PROP_TYPES_PROPERTY = "propTypes";
40161
39430
  const isPropTypesKey = (key, computed) => {
@@ -40308,7 +39577,7 @@ const isModuleScopedBinding = (identifier) => {
40308
39577
  const binding = findVariableInitializer(identifier, identifier.name);
40309
39578
  if (!binding) return false;
40310
39579
  if (isNodeOfType(binding.scopeOwner, "Program")) return true;
40311
- if (isNodeOfType(binding.scopeOwner, "BlockStatement")) return findEnclosingFunction$1(binding.scopeOwner) === null;
39580
+ if (isNodeOfType(binding.scopeOwner, "BlockStatement")) return findEnclosingFunction(binding.scopeOwner) === null;
40312
39581
  return false;
40313
39582
  };
40314
39583
  const looksLikeFreshUpdateExpression = (expression) => {
@@ -42225,9 +41494,9 @@ const isReturnedFromAnyEffectInScope = (functionNode, ownerScope) => {
42225
41494
  return isReturnedFromEffect;
42226
41495
  };
42227
41496
  const isInsideEffectCleanupReturn = (node, ownerScope) => {
42228
- let functionNode = findEnclosingFunction$1(node);
41497
+ let functionNode = findEnclosingFunction(node);
42229
41498
  while (functionNode) {
42230
- const outerFunction = findEnclosingFunction$1(functionNode);
41499
+ const outerFunction = findEnclosingFunction(functionNode);
42231
41500
  if (outerFunction && isEffectCallbackFunction(outerFunction) && isFunctionReturnedFromEffectCallback(functionNode, outerFunction)) return true;
42232
41501
  if (isReturnedFromAnyEffectInScope(functionNode, ownerScope)) return true;
42233
41502
  functionNode = outerFunction;
@@ -42235,7 +41504,7 @@ const isInsideEffectCleanupReturn = (node, ownerScope) => {
42235
41504
  return false;
42236
41505
  };
42237
41506
  const hasRefCurrentReassignmentAfterClear = (clearCall, refName) => {
42238
- const enclosingFunction = findEnclosingFunction$1(clearCall);
41507
+ const enclosingFunction = findEnclosingFunction(clearCall);
42239
41508
  if (!isFunctionLike$2(enclosingFunction)) return false;
42240
41509
  if (!isNodeOfType(enclosingFunction.body, "BlockStatement")) return false;
42241
41510
  const clearStart = getRangeStart(clearCall);
@@ -43065,7 +42334,7 @@ const isInsideAvailabilityGuard = (node, browserGlobalName, context) => {
43065
42334
  return false;
43066
42335
  };
43067
42336
  const isAfterAvailabilityEarlyExit = (node, componentOrHookNode, browserGlobalName, context) => {
43068
- const enclosingFunction = findEnclosingFunction$1(node);
42337
+ const enclosingFunction = findEnclosingFunction(node);
43069
42338
  if (!enclosingFunction || enclosingFunction !== componentOrHookNode && !executesDuringRender(enclosingFunction, context.scopes) || !isFunctionLike$2(enclosingFunction) || !isNodeOfType(enclosingFunction.body, "BlockStatement")) return false;
43070
42339
  let currentNode = node;
43071
42340
  while (currentNode !== enclosingFunction) {
@@ -44332,11 +43601,7 @@ const resolveSettings$8 = (settings) => {
44332
43601
  propNamePattern: ruleSettings.propNamePattern ?? "render*"
44333
43602
  };
44334
43603
  };
44335
- const isReactCreateElementCall = (node, scopes) => isReactApiCall(node, "createElement", scopes, {
44336
- allowGlobalReactNamespace: true,
44337
- resolveNamedAliases: true
44338
- });
44339
- const expressionContainsJsxOrCreateElement = (root, scopes) => {
43604
+ const expressionContainsJsxOrCreateElement = (root) => {
44340
43605
  let found = false;
44341
43606
  walkAst(root, (node) => {
44342
43607
  if (found) return false;
@@ -44345,17 +43610,17 @@ const expressionContainsJsxOrCreateElement = (root, scopes) => {
44345
43610
  found = true;
44346
43611
  return false;
44347
43612
  }
44348
- if (isNodeOfType(node, "CallExpression") && isReactCreateElementCall(node, scopes)) {
43613
+ if (isNodeOfType(node, "CallExpression") && isCreateElementCall(node)) {
44349
43614
  found = true;
44350
43615
  return false;
44351
43616
  }
44352
43617
  });
44353
43618
  return found;
44354
43619
  };
44355
- const functionContainsJsxOrCreateElement = (functionNode, scopes, controlFlow) => expressionContainsJsxOrCreateElement(functionNode, scopes) || functionReturnsMatchingExpression(functionNode, scopes, (expression) => expressionContainsJsxOrCreateElement(expression, scopes), controlFlow);
44356
- const isReactClassComponent = (classNode, scopes) => {
43620
+ const functionContainsJsxOrCreateElement = (functionNode, scopes, controlFlow) => expressionContainsJsxOrCreateElement(functionNode) || functionReturnsMatchingExpression(functionNode, scopes, expressionContainsJsxOrCreateElement, controlFlow);
43621
+ const isReactClassComponent = (classNode) => {
44357
43622
  if (isEs6Component(classNode)) return true;
44358
- return expressionContainsJsxOrCreateElement(classNode, scopes);
43623
+ return expressionContainsJsxOrCreateElement(classNode);
44359
43624
  };
44360
43625
  const findEnclosingComponent = (node, scopes, controlFlow) => {
44361
43626
  let walker = node.parent;
@@ -44372,7 +43637,7 @@ const findEnclosingComponent = (node, scopes, controlFlow) => {
44372
43637
  };
44373
43638
  }
44374
43639
  if (isNodeOfType(walker, "ClassDeclaration") || isNodeOfType(walker, "ClassExpression")) {
44375
- if (walker.id && isReactComponentName(walker.id.name) && isReactClassComponent(walker, scopes)) return {
43640
+ if (walker.id && isReactComponentName(walker.id.name) && isReactClassComponent(walker)) return {
44376
43641
  component: walker,
44377
43642
  name: walker.id.name
44378
43643
  };
@@ -44461,12 +43726,12 @@ const isObjectCallbackCandidate = (node) => {
44461
43726
  }
44462
43727
  return false;
44463
43728
  };
44464
- const hocCallContainsComponent = (call, scopes) => {
43729
+ const hocCallContainsComponent = (call) => {
44465
43730
  const firstArgument = call.arguments[0];
44466
43731
  if (!firstArgument) return false;
44467
- if (isNodeOfType(firstArgument, "FunctionExpression") || isNodeOfType(firstArgument, "ArrowFunctionExpression") || isNodeOfType(firstArgument, "ClassExpression")) return expressionContainsJsxOrCreateElement(firstArgument, scopes);
44468
- if (isNodeOfType(firstArgument, "CallExpression") && isHocCallee$1(firstArgument)) return hocCallContainsComponent(firstArgument, scopes);
44469
- return expressionContainsJsxOrCreateElement(firstArgument, scopes);
43732
+ if (isNodeOfType(firstArgument, "FunctionExpression") || isNodeOfType(firstArgument, "ArrowFunctionExpression") || isNodeOfType(firstArgument, "ClassExpression")) return expressionContainsJsxOrCreateElement(firstArgument);
43733
+ if (isNodeOfType(firstArgument, "CallExpression") && isHocCallee$1(firstArgument)) return hocCallContainsComponent(firstArgument);
43734
+ return expressionContainsJsxOrCreateElement(firstArgument);
44470
43735
  };
44471
43736
  const isFirstArgumentOfHocCall = (node) => {
44472
43737
  const parent = node.parent;
@@ -44499,35 +43764,19 @@ const isReturnOfMapCallback = (node) => {
44499
43764
  }
44500
43765
  return false;
44501
43766
  };
43767
+ const isCloneElementCall = (node) => {
43768
+ if (!isNodeOfType(node, "CallExpression")) return false;
43769
+ const callee = node.callee;
43770
+ if (isNodeOfType(callee, "Identifier")) return callee.name === "cloneElement";
43771
+ return isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier") && callee.property.name === "cloneElement";
43772
+ };
44502
43773
  const TS_VALUE_PASSTHROUGH_TYPES = new Set([
44503
43774
  "TSAsExpression",
44504
43775
  "TSNonNullExpression",
44505
43776
  "TSSatisfiesExpression",
44506
43777
  "TSTypeAssertion"
44507
43778
  ]);
44508
- const ELEMENT_TYPE_PROP_NAMES = new Set([
44509
- "as",
44510
- "body",
44511
- "calendarcontainer",
44512
- "component",
44513
- "fallback",
44514
- "tooltip"
44515
- ]);
44516
- const isElementTypeJsxAttribute = (node) => {
44517
- if (!isNodeOfType(node, "JSXAttribute")) return false;
44518
- if (!isNodeOfType(node.name, "JSXIdentifier")) return false;
44519
- const attributeName = node.name.name;
44520
- return ELEMENT_TYPE_PROP_NAMES.has(attributeName.toLowerCase()) || attributeName.endsWith("Component");
44521
- };
44522
- const isReactUseMemoCallback = (call, valueNode, scopes) => call.arguments[0] === valueNode && isReactApiCall(call, "useMemo", scopes, {
44523
- allowGlobalReactNamespace: true,
44524
- resolveNamedAliases: true
44525
- });
44526
- const isReactLazyCall = (call, scopes) => isReactApiCall(call, "lazy", scopes, {
44527
- allowGlobalReactNamespace: true,
44528
- resolveNamedAliases: true
44529
- });
44530
- const isRenderFlowingReadReference = (identifier, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
43779
+ const isRenderFlowingReadReference = (identifier) => {
44531
43780
  let valueNode = identifier;
44532
43781
  let parent = valueNode.parent;
44533
43782
  while (parent) {
@@ -44537,26 +43786,20 @@ const isRenderFlowingReadReference = (identifier, scopes, visitedSymbols = /* @_
44537
43786
  continue;
44538
43787
  }
44539
43788
  switch (parent.type) {
44540
- case "JSXOpeningElement": return parent.name === valueNode;
44541
- case "JSXExpressionContainer": return Boolean(parent.parent && isElementTypeJsxAttribute(parent.parent));
44542
- case "ReturnStatement": return false;
44543
- case "ArrowFunctionExpression": return false;
43789
+ case "JSXExpressionContainer":
43790
+ case "ReturnStatement": return true;
43791
+ case "ArrowFunctionExpression": return parent.body === valueNode;
44544
43792
  case "CallExpression":
44545
43793
  if (parent.callee === valueNode) return false;
44546
- if (isReactUseMemoCallback(parent, valueNode, scopes)) return false;
44547
- if (isReactCreateElementCall(parent, scopes)) return true;
43794
+ if (isCreateElementCall(parent) || isCloneElementCall(parent)) return true;
44548
43795
  valueNode = parent;
44549
43796
  parent = parent.parent;
44550
43797
  continue;
44551
- case "VariableDeclarator": {
44552
- if (parent.init !== valueNode || !isNodeOfType(parent.id, "Identifier")) return false;
44553
- const aliasSymbol = scopes.symbolFor(parent.id);
44554
- if (!aliasSymbol || aliasSymbol.kind !== "const" || visitedSymbols.has(aliasSymbol.id)) return false;
44555
- const nextVisitedSymbols = new Set(visitedSymbols);
44556
- nextVisitedSymbols.add(aliasSymbol.id);
44557
- return aliasSymbol.references.some((reference) => reference.flag === "read" && isRenderFlowingReadReference(reference.identifier, scopes, nextVisitedSymbols));
43798
+ case "VariableDeclarator": return parent.init === valueNode && isNodeOfType(parent.id, "Identifier") && isReactComponentName(parent.id.name);
43799
+ case "AssignmentExpression": {
43800
+ const assignmentTarget = parent.left;
43801
+ return parent.right === valueNode && isNodeOfType(assignmentTarget, "Identifier") && isReactComponentName(assignmentTarget.name);
44558
43802
  }
44559
- case "AssignmentExpression": return false;
44560
43803
  case "Property":
44561
43804
  if (parent.value !== valueNode) return false;
44562
43805
  valueNode = parent;
@@ -44594,7 +43837,6 @@ const noUnstableNestedComponents = defineRule({
44594
43837
  severity: "warn",
44595
43838
  recommendation: "Move nested components to module scope so React does not remount them and lose state on every render.",
44596
43839
  category: "Performance",
44597
- tags: ["react-jsx-only"],
44598
43840
  create: (context) => {
44599
43841
  const settings = resolveSettings$8(context.settings);
44600
43842
  const renderPropRegex = compileGlob(settings.propNamePattern);
@@ -44657,7 +43899,7 @@ const noUnstableNestedComponents = defineRule({
44657
43899
  },
44658
43900
  Identifier(node) {
44659
43901
  if (!isReactComponentName(node.name)) return;
44660
- if (!isRenderFlowingReadReference(node, context.scopes)) return;
43902
+ if (!isRenderFlowingReadReference(node)) return;
44661
43903
  recordInstantiation(node, node.name);
44662
43904
  },
44663
43905
  FunctionDeclaration: checkFunctionLike,
@@ -44666,33 +43908,28 @@ const noUnstableNestedComponents = defineRule({
44666
43908
  ClassDeclaration(node) {
44667
43909
  if (!node.id) return;
44668
43910
  if (!isReactComponentName(node.id.name)) return;
44669
- if (!isReactClassComponent(node, context.scopes)) return;
43911
+ if (!isReactClassComponent(node)) return;
44670
43912
  enqueueCandidate(node, null);
44671
43913
  },
44672
43914
  ClassExpression(node) {
44673
43915
  const inferredName = node.id?.name ?? inferFunctionLikeName(node);
44674
43916
  if (!inferredName || !isReactComponentName(inferredName)) return;
44675
- if (!isReactClassComponent(node, context.scopes)) return;
43917
+ if (!isReactClassComponent(node)) return;
44676
43918
  enqueueCandidate(node, null);
44677
43919
  },
44678
43920
  CallExpression(node) {
44679
- if (isReactCreateElementCall(node, context.scopes)) {
43921
+ if (isCreateElementCall(node)) {
44680
43922
  const firstArgument = node.arguments[0];
44681
43923
  if (firstArgument && isNodeOfType(firstArgument, "Identifier")) recordInstantiation(firstArgument, firstArgument.name);
44682
43924
  else if (firstArgument && isNodeOfType(firstArgument, "MemberExpression")) recordMemberChainInstantiation(firstArgument);
44683
43925
  }
44684
- const isReactLazy = isReactLazyCall(node, context.scopes);
44685
- if (!isReactLazy && !isHocCallee$1(node)) return;
44686
- if (!isReactLazy && !hocCallContainsComponent(node, context.scopes)) return;
44687
- const inferredName = inferFunctionLikeName(node);
44688
- const propInfo = isComponentDeclaredInProp(node);
44689
- if (propInfo === null && (!inferredName || !isReactComponentName(inferredName))) return;
44690
- enqueueCandidate(node, propInfo === null ? inferredName : null);
43926
+ if (!isHocCallee$1(node)) return;
43927
+ if (!hocCallContainsComponent(node)) return;
43928
+ enqueueCandidate(node, null);
44691
43929
  },
44692
43930
  "Program:exit"() {
44693
43931
  for (const report of queuedReports) {
44694
43932
  if (report.requiredInstantiationName !== null) {
44695
- if ((report.requiredInstantiationBinding ? context.scopes.symbolFor(report.requiredInstantiationBinding) : null)?.references.some((reference) => reference.flag === "write" || reference.flag === "read-write")) continue;
44696
43933
  if (!(report.requiredInstantiationBinding !== null ? instantiatedBindingIdentifiers.has(report.requiredInstantiationBinding) : instantiatedComponentNames.has(report.requiredInstantiationName))) continue;
44697
43934
  }
44698
43935
  context.report({
@@ -45725,7 +44962,7 @@ const findChildrenDestructuringFunction = (identifier, scopes) => {
45725
44962
  const symbol = scopes.symbolFor(identifier);
45726
44963
  if (symbol) {
45727
44964
  if (symbol.kind !== "parameter") return null;
45728
- const declaringFunction = findEnclosingFunction$1(symbol.bindingIdentifier);
44965
+ const declaringFunction = findEnclosingFunction(symbol.bindingIdentifier);
45729
44966
  if (declaringFunction && destructuresChildrenAsFirstParam(declaringFunction)) return declaringFunction;
45730
44967
  return null;
45731
44968
  }
@@ -45771,7 +45008,7 @@ const isChildrenMemberExpression = (node, scopes) => {
45771
45008
  const symbol = scopes.symbolFor(propsObject);
45772
45009
  if (symbol) {
45773
45010
  if (symbol.kind !== "parameter") return false;
45774
- const declaringFunction = findEnclosingFunction$1(symbol.bindingIdentifier);
45011
+ const declaringFunction = findEnclosingFunction(symbol.bindingIdentifier);
45775
45012
  return declaringFunction ? isDeclaringFunctionComponentLike(declaringFunction) : false;
45776
45013
  }
45777
45014
  return hasComponentLikeAncestorFunction(node);
@@ -46423,7 +45660,7 @@ const doesFunctionReturnsObjectLiteral = (functionNode) => {
46423
45660
  //#endregion
46424
45661
  //#region src/plugin/utils/enclosing-component-or-hook-scope.ts
46425
45662
  const enclosingComponentOrHookScope = (startNode, ownScopeFor) => {
46426
- const functionNode = findEnclosingFunction$1(startNode);
45663
+ const functionNode = findEnclosingFunction(startNode);
46427
45664
  if (!functionNode) return null;
46428
45665
  const displayName = componentOrHookDisplayNameForFunction(functionNode);
46429
45666
  if (!displayName) return null;
@@ -47485,7 +46722,7 @@ const isTanstackQuerySource = (source) => TANSTACK_QUERY_PACKAGE_PATTERN.test(so
47485
46722
  //#region src/plugin/rules/tanstack-query/query-destructure-result.ts
47486
46723
  const isHookReturnForwardingSpread = (objectExpression) => {
47487
46724
  const objectParent = objectExpression.parent;
47488
- const enclosingFunction = findEnclosingFunction$1(objectExpression);
46725
+ const enclosingFunction = findEnclosingFunction(objectExpression);
47489
46726
  if (!enclosingFunction) return false;
47490
46727
  if (!(isNodeOfType(objectParent, "ReturnStatement") || isNodeOfType(enclosingFunction, "ArrowFunctionExpression") && enclosingFunction.body === objectExpression)) return false;
47491
46728
  const enclosingName = componentOrHookDisplayNameForFunction(enclosingFunction);
@@ -47863,10 +47100,10 @@ const hasSuspensionBefore = (functionNode, boundary, context) => {
47863
47100
  return hasSuspension;
47864
47101
  };
47865
47102
  const isFunctionAncestor = (ancestor, functionNode) => {
47866
- let enclosingFunction = findEnclosingFunction$1(functionNode);
47103
+ let enclosingFunction = findEnclosingFunction(functionNode);
47867
47104
  while (enclosingFunction) {
47868
47105
  if (enclosingFunction === ancestor) return true;
47869
- enclosingFunction = findEnclosingFunction$1(enclosingFunction);
47106
+ enclosingFunction = findEnclosingFunction(enclosingFunction);
47870
47107
  }
47871
47108
  return false;
47872
47109
  };
@@ -47888,7 +47125,7 @@ const functionInvokesTarget = (callerFunction, targetFunction, context, visitedF
47888
47125
  return invokesTarget;
47889
47126
  };
47890
47127
  const isFunctionInvokedBefore = (invokedFunction, boundary, context) => {
47891
- const boundaryFunction = findEnclosingFunction$1(boundary);
47128
+ const boundaryFunction = findEnclosingFunction(boundary);
47892
47129
  const boundaryStart = getRangeStart(boundary);
47893
47130
  if (!boundaryFunction || boundaryStart === null) return false;
47894
47131
  let isInvokedBefore = false;
@@ -47925,11 +47162,11 @@ const isFunctionInvokedAfter = (invokedFunction, boundary, callerFunction, conte
47925
47162
  const isWriteExecutedBefore = (writeNode, boundary, context, deferredExecutionFunction) => {
47926
47163
  const writeStart = getRangeStart(writeNode);
47927
47164
  const boundaryStart = getRangeStart(boundary);
47928
- const writeFunction = findEnclosingFunction$1(writeNode);
47165
+ const writeFunction = findEnclosingFunction(writeNode);
47929
47166
  const writeExecutionBoundary = writeFunction ?? findProgramRoot(writeNode);
47930
47167
  if (writeStart === null || boundaryStart === null || !writeExecutionBoundary || !isNodeReachableWithinFunction(writeNode, context) || !isUnconditionallyExecuted(writeNode, writeExecutionBoundary, context)) return false;
47931
- const boundaryFunction = findEnclosingFunction$1(boundary);
47932
- const renderFunction = deferredExecutionFunction ? findEnclosingFunction$1(deferredExecutionFunction) : null;
47168
+ const boundaryFunction = findEnclosingFunction(boundary);
47169
+ const renderFunction = deferredExecutionFunction ? findEnclosingFunction(deferredExecutionFunction) : null;
47933
47170
  if (writeFunction === boundaryFunction) return writeStart < boundaryStart;
47934
47171
  if (!writeFunction) return writeStart < boundaryStart;
47935
47172
  if (boundaryFunction && isFunctionAncestor(writeFunction, boundaryFunction)) {
@@ -48201,8 +47438,8 @@ const queryStableQueryClient = defineRule({
48201
47438
  create: (context) => ({ NewExpression(node) {
48202
47439
  if (!isNodeOfType(node.callee, "Identifier") || node.callee.name !== "QueryClient") return;
48203
47440
  if (isStableHookWrapperArgument(node)) return;
48204
- let enclosingFunction = findEnclosingFunction$1(node);
48205
- while (enclosingFunction && isImmediatelyInvokedFunction(enclosingFunction)) enclosingFunction = findEnclosingFunction$1(enclosingFunction);
47441
+ let enclosingFunction = findEnclosingFunction(node);
47442
+ while (enclosingFunction && isImmediatelyInvokedFunction(enclosingFunction)) enclosingFunction = findEnclosingFunction(enclosingFunction);
48206
47443
  if (!enclosingFunction) return;
48207
47444
  if (!isComponentFunction(enclosingFunction)) return;
48208
47445
  context.report({
@@ -48297,7 +47534,7 @@ const reactCompilerNoManualMemoization = defineRule({
48297
47534
  const comparatorArgument = node.arguments?.[1];
48298
47535
  if (comparatorArgument && !isNullishComparatorArgument(comparatorArgument)) return;
48299
47536
  } else {
48300
- const enclosingFunction = findEnclosingFunction$1(node);
47537
+ const enclosingFunction = findEnclosingFunction(node);
48301
47538
  if (!enclosingFunction || !isCompilerInferableFunction(enclosingFunction)) return;
48302
47539
  }
48303
47540
  const removalMessage = REMOVAL_MESSAGE_BY_REACT_API_NAME.get(apiName);
@@ -51402,7 +50639,7 @@ const isReactNativeDimensionsCallee = (node, callee) => {
51402
50639
  };
51403
50640
  const STYLE_FACTORY_CALLEE_PATTERN$1 = /(?:^|\.)(?:make|create)(?:Use)?Styles$/;
51404
50641
  const isInsideStyleFactoryCallback = (node) => {
51405
- const enclosingFunction = findEnclosingFunction$1(node);
50642
+ const enclosingFunction = findEnclosingFunction(node);
51406
50643
  if (!enclosingFunction) return false;
51407
50644
  const callExpression = enclosingFunction.parent;
51408
50645
  if (!callExpression || !isNodeOfType(callExpression, "CallExpression")) return false;
@@ -58258,14 +57495,12 @@ const declarationAwaitsRequestScopedCall = (declaration) => {
58258
57495
  }
58259
57496
  return false;
58260
57497
  };
58261
- const declarationAwaitsGate = (declaration, context) => {
57498
+ const declarationAwaitsGate = (declaration) => {
58262
57499
  if (!isNodeOfType(declaration, "VariableDeclaration")) return false;
58263
57500
  for (const declarator of declaration.declarations ?? []) {
58264
57501
  if (!isNodeOfType(declarator.init, "AwaitExpression")) continue;
58265
57502
  const argument = declarator.init.argument;
58266
57503
  if (!isNodeOfType(argument, "CallExpression")) continue;
58267
- if (hasPossibleStaticMemberCallWrite(argument, context.scopes)) return true;
58268
- if (getOrderIndependentLocalFunction(argument, context.scopes) !== null) continue;
58269
57504
  const calleeName = getCalleeName$2(argument);
58270
57505
  if (!calleeName) continue;
58271
57506
  if (isAuthGuardName(calleeName)) return true;
@@ -58293,7 +57528,7 @@ const serverSequentialIndependentAwait = defineRule({
58293
57528
  if (declarationReadsAnyName(nextStatement, declaredNames)) continue;
58294
57529
  if (declarationAwaitsExistingPromise(nextStatement)) continue;
58295
57530
  if (declarationAwaitsRequestScopedCall(currentStatement) || declarationAwaitsRequestScopedCall(nextStatement)) continue;
58296
- if (declarationAwaitsGate(currentStatement, context)) continue;
57531
+ if (declarationAwaitsGate(currentStatement)) continue;
58297
57532
  context.report({
58298
57533
  node: nextStatement,
58299
57534
  message: "This await doesn't use the previous result, so your users wait twice as long for nothing."
@@ -58383,26 +57618,6 @@ const stateInConstructor = defineRule({
58383
57618
  }
58384
57619
  });
58385
57620
  //#endregion
58386
- //#region src/plugin/utils/collect-jsx-runtime-imports.ts
58387
- const REACT_RUNTIME_PACKAGE_PREFIXES = ["react", "react-dom"];
58388
- const matchesPackage = (source, packageName) => source === packageName || source.startsWith(`${packageName}/`);
58389
- const collectJsxRuntimeImports = (program) => {
58390
- let hasReactRuntime = false;
58391
- let hasSolidRuntime = false;
58392
- for (const statement of program.body) {
58393
- if (!isNodeOfType(statement, "ImportDeclaration")) continue;
58394
- if (isTypeOnlyImport(statement)) continue;
58395
- const source = statement.source.value;
58396
- if (typeof source !== "string") continue;
58397
- if (matchesPackage(source, "solid-js")) hasSolidRuntime = true;
58398
- if (REACT_RUNTIME_PACKAGE_PREFIXES.some((packageName) => matchesPackage(source, packageName))) hasReactRuntime = true;
58399
- }
58400
- return {
58401
- hasReactRuntime,
58402
- hasSolidRuntime
58403
- };
58404
- };
58405
- //#endregion
58406
57621
  //#region src/plugin/rules/react-builtins/style-prop-object.ts
58407
57622
  const MESSAGE$1 = "Your styles don't render because you passed the `style` prop a string instead of an object.";
58408
57623
  const resolveSettings = (settings) => {
@@ -58464,13 +57679,6 @@ const isInvalidStyleExpression = (expression) => {
58464
57679
  }
58465
57680
  return false;
58466
57681
  };
58467
- const hasObjectValuedClassList = (openingElement) => openingElement.attributes.some((attribute) => {
58468
- if (!isNodeOfType(attribute, "JSXAttribute")) return false;
58469
- if (!isNodeOfType(attribute.name, "JSXIdentifier")) return false;
58470
- if (attribute.name.name !== "classList") return false;
58471
- if (!isNodeOfType(attribute.value, "JSXExpressionContainer")) return false;
58472
- return isNodeOfType(attribute.value.expression, "ObjectExpression");
58473
- });
58474
57682
  const stylePropObject = defineRule({
58475
57683
  id: "style-prop-object",
58476
57684
  title: "Style prop is not an object",
@@ -58480,21 +57688,8 @@ const stylePropObject = defineRule({
58480
57688
  create: (context) => {
58481
57689
  const { allow } = resolveSettings(context.settings);
58482
57690
  const allowSet = new Set(allow);
58483
- let fileIsProvenSolidJsx = false;
58484
57691
  return {
58485
- Program: (node) => {
58486
- const runtimeImports = collectJsxRuntimeImports(node);
58487
- let hasSolidSyntaxMarker = false;
58488
- if (!runtimeImports.hasReactRuntime && !runtimeImports.hasSolidRuntime) walkAst(node, (descendantNode) => {
58489
- if (isNodeOfType(descendantNode, "JSXOpeningElement") && hasObjectValuedClassList(descendantNode)) {
58490
- hasSolidSyntaxMarker = true;
58491
- return false;
58492
- }
58493
- });
58494
- fileIsProvenSolidJsx = !runtimeImports.hasReactRuntime && (runtimeImports.hasSolidRuntime || hasSolidSyntaxMarker);
58495
- },
58496
57692
  JSXOpeningElement(node) {
58497
- if (fileIsProvenSolidJsx) return;
58498
57693
  if (!isNodeOfType(node.name, "JSXIdentifier")) return;
58499
57694
  const elementName = resolveJsxElementType(node);
58500
57695
  if (elementName && allowSet.has(elementName)) return;
@@ -58525,7 +57720,6 @@ const stylePropObject = defineRule({
58525
57720
  }
58526
57721
  },
58527
57722
  CallExpression(node) {
58528
- if (fileIsProvenSolidJsx) return;
58529
57723
  if (!isCreateElementCall(node)) return;
58530
57724
  const firstArgument = node.arguments[0];
58531
57725
  if (!firstArgument) return;
@@ -59320,7 +58514,7 @@ const tanstackStartNoNavigateInRender = defineRule({
59320
58514
  const isReturnedFromCustomHook = (functionNode) => {
59321
58515
  const parent = functionNode.parent;
59322
58516
  if (isNodeOfType(parent, "ReturnStatement")) {
59323
- const outerFunction = findEnclosingFunction$1(parent);
58517
+ const outerFunction = findEnclosingFunction(parent);
59324
58518
  const hookName = outerFunction ? getFunctionBindingName$1(outerFunction) : null;
59325
58519
  return Boolean(hookName && HOOK_NAME_PATTERN$3.test(hookName));
59326
58520
  }
@@ -59337,13 +58531,13 @@ const tanstackStartNoNavigateInRender = defineRule({
59337
58531
  return parent.callee === functionNode || (parent.arguments ?? []).some((callArgument) => callArgument === functionNode);
59338
58532
  };
59339
58533
  const isDeferredNavigateCall = (callNode) => {
59340
- let enclosingFunction = findEnclosingFunction$1(callNode);
58534
+ let enclosingFunction = findEnclosingFunction(callNode);
59341
58535
  while (enclosingFunction) {
59342
58536
  if (isDeferredCallbackPosition(enclosingFunction)) return true;
59343
58537
  if (isWiredAsEventHandler(enclosingFunction)) return true;
59344
58538
  if (isReturnedFromCustomHook(enclosingFunction)) return true;
59345
58539
  if (!isSynchronouslyInvokedAnonymousWrapper(enclosingFunction)) return false;
59346
- enclosingFunction = findEnclosingFunction$1(enclosingFunction);
58540
+ enclosingFunction = findEnclosingFunction(enclosingFunction);
59347
58541
  }
59348
58542
  return false;
59349
58543
  };