oxlint-plugin-react-doctor 0.7.9-dev.6325f9c → 0.7.9-dev.9aa98b9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1819,70 +1819,8 @@ const flattenJsxName$1 = (node) => {
1819
1819
  return null;
1820
1820
  };
1821
1821
  //#endregion
1822
- //#region src/plugin/utils/get-static-property-name.ts
1823
- const getStaticPropertyName = (memberExpression) => {
1824
- const property = memberExpression.property;
1825
- if (!memberExpression.computed && isNodeOfType(property, "Identifier")) return property.name;
1826
- if (memberExpression.computed && isNodeOfType(property, "Literal")) return typeof property.value === "string" ? property.value : null;
1827
- if (memberExpression.computed && isNodeOfType(property, "TemplateLiteral") && property.expressions.length === 0) return property.quasis[0]?.value.cooked ?? property.quasis[0]?.value.raw ?? null;
1828
- return null;
1829
- };
1830
- //#endregion
1831
- //#region src/plugin/utils/is-generated-image-renderer-call.ts
1832
- const GENERATED_IMAGE_RENDERER_MODULES = [
1833
- "next/og",
1834
- "@vercel/og",
1835
- "satori"
1836
- ];
1837
- const IMAGE_RESPONSE_MODULES = new Set(["next/og", "@vercel/og"]);
1838
- const getImportDeclaration$1 = (node) => {
1839
- let current = node.parent;
1840
- while (current) {
1841
- if (isNodeOfType(current, "ImportDeclaration")) return current;
1842
- if (isNodeOfType(current, "Program")) return null;
1843
- current = current.parent;
1844
- }
1845
- return null;
1846
- };
1847
- const getImportSource = (declaration) => typeof declaration.source.value === "string" ? declaration.source.value : null;
1848
- const isNamedImport = (symbol, importedName, moduleSources) => {
1849
- if (symbol.kind !== "import") return false;
1850
- const declaration = symbol.declarationNode;
1851
- if (!isNodeOfType(declaration, "ImportSpecifier")) return false;
1852
- const importDeclaration = getImportDeclaration$1(declaration);
1853
- const source = importDeclaration ? getImportSource(importDeclaration) : null;
1854
- if (!source || !moduleSources.has(source)) return false;
1855
- const imported = declaration.imported;
1856
- return isNodeOfType(imported, "Identifier") && imported.name === importedName || isNodeOfType(imported, "Literal") && imported.value === importedName;
1857
- };
1858
- const isSatoriImport = (symbol) => {
1859
- if (symbol.kind !== "import") return false;
1860
- const declaration = symbol.declarationNode;
1861
- const importDeclaration = getImportDeclaration$1(declaration);
1862
- if (!importDeclaration || getImportSource(importDeclaration) !== "satori") return false;
1863
- if (isNodeOfType(declaration, "ImportDefaultSpecifier")) return true;
1864
- if (!isNodeOfType(declaration, "ImportSpecifier")) return false;
1865
- const imported = declaration.imported;
1866
- return isNodeOfType(imported, "Identifier") && imported.name === "satori" || isNodeOfType(imported, "Literal") && imported.value === "satori";
1867
- };
1868
- const isGeneratedImageRendererCall = (node, scopes) => {
1869
- if (!isNodeOfType(node, "CallExpression") && !isNodeOfType(node, "NewExpression")) return false;
1870
- const callee = stripParenExpression(node.callee);
1871
- if (isNodeOfType(callee, "Identifier")) {
1872
- const symbol = scopes.referenceFor(callee)?.resolvedSymbol ?? null;
1873
- return Boolean(symbol && (isNamedImport(symbol, "ImageResponse", IMAGE_RESPONSE_MODULES) || isSatoriImport(symbol)));
1874
- }
1875
- if (!isNodeOfType(callee, "MemberExpression")) return false;
1876
- if (getStaticPropertyName(callee) !== "ImageResponse") return false;
1877
- if (!isNodeOfType(callee.object, "Identifier")) return false;
1878
- const symbol = scopes.referenceFor(callee.object)?.resolvedSymbol ?? null;
1879
- if (!symbol || symbol.kind !== "import") return false;
1880
- const declaration = symbol.declarationNode;
1881
- if (!isNodeOfType(declaration, "ImportNamespaceSpecifier")) return false;
1882
- const importDeclaration = getImportDeclaration$1(declaration);
1883
- const source = importDeclaration ? getImportSource(importDeclaration) : null;
1884
- return Boolean(source && IMAGE_RESPONSE_MODULES.has(source));
1885
- };
1822
+ //#region src/plugin/utils/is-member-property.ts
1823
+ const isMemberProperty = (node, propertyName) => Boolean(node && isNodeOfType(node, "MemberExpression") && isNodeOfType(node.property, "Identifier") && node.property.name === propertyName);
1886
1824
  //#endregion
1887
1825
  //#region src/plugin/constants/nextjs.ts
1888
1826
  const NEXTJS_SOURCE_FILE_EXTENSION_GROUP = "(?:tsx?|jsx?|mts|mjs)";
@@ -1954,22 +1892,42 @@ const isNextjsMetadataImageRouteFilename = (rawFilename) => {
1954
1892
  const normalizeFilename = (filename) => filename.includes("\\") ? filename.replaceAll("\\", "/") : filename;
1955
1893
  //#endregion
1956
1894
  //#region src/plugin/utils/is-generated-image-render-context.ts
1895
+ const IMAGE_RESPONSE_MODULES = ["next/og", "@vercel/og"];
1896
+ const SATORI_MODULE = "satori";
1897
+ const GENERATED_IMAGE_MODULES = [...IMAGE_RESPONSE_MODULES, SATORI_MODULE];
1957
1898
  const generatedImageJsxCache = /* @__PURE__ */ new WeakMap();
1958
1899
  const isGeneratedImageRenderFilename = (rawFilename) => {
1959
1900
  if (!rawFilename) return false;
1960
1901
  return isNextjsMetadataImageRouteFilename(normalizeFilename(rawFilename));
1961
1902
  };
1903
+ const isImageResponseCallee = (contextNode, callee) => {
1904
+ if (isNodeOfType(callee, "Identifier")) return IMAGE_RESPONSE_MODULES.some((moduleSource) => getImportedNameFromModule(contextNode, callee.name, moduleSource) === "ImageResponse");
1905
+ if (!isMemberProperty(callee, "ImageResponse")) return false;
1906
+ if (!isNodeOfType(callee.object, "Identifier")) return false;
1907
+ const namespaceIdentifierName = callee.object.name;
1908
+ return IMAGE_RESPONSE_MODULES.some((moduleSource) => isNamespaceImportFromModule(contextNode, namespaceIdentifierName, moduleSource));
1909
+ };
1910
+ const isSatoriCallee = (contextNode, callee) => {
1911
+ if (!isNodeOfType(callee, "Identifier")) return false;
1912
+ if (getImportedNameFromModule(contextNode, callee.name, SATORI_MODULE) === "satori") return true;
1913
+ return isDefaultImportFromModule(contextNode, callee.name, SATORI_MODULE);
1914
+ };
1915
+ const isGeneratedImageRendererCall = (node) => {
1916
+ if (!isNodeOfType(node, "CallExpression") && !isNodeOfType(node, "NewExpression")) return false;
1917
+ if (!isNodeOfType(node.callee, "Identifier") && !isNodeOfType(node.callee, "MemberExpression")) return false;
1918
+ return isImageResponseCallee(node, node.callee) || isSatoriCallee(node, node.callee);
1919
+ };
1962
1920
  const isComponentIdentifierName = (name) => {
1963
1921
  const firstCharacter = name[0];
1964
1922
  return Boolean(firstCharacter && firstCharacter === firstCharacter.toUpperCase());
1965
1923
  };
1966
1924
  const isFunctionLike = (node) => Boolean(node && (isNodeOfType(node, "FunctionDeclaration") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "ArrowFunctionExpression")));
1967
- const markFunctionReturnJsx = (functionNode, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames) => {
1925
+ const markFunctionReturnJsx = (functionNode, programRoot, generatedImageJsxNodes, visitedComponentNames) => {
1968
1926
  if (!isFunctionLike(functionNode)) return;
1969
1927
  if (isNodeOfType(functionNode, "ArrowFunctionExpression")) {
1970
1928
  const body = stripParenExpression(functionNode.body);
1971
1929
  if (!isNodeOfType(body, "BlockStatement")) {
1972
- markGeneratedImageExpression(body, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
1930
+ markGeneratedImageExpression(body, programRoot, generatedImageJsxNodes, visitedComponentNames);
1973
1931
  return;
1974
1932
  }
1975
1933
  }
@@ -1979,7 +1937,7 @@ const markFunctionReturnJsx = (functionNode, programRoot, scopes, generatedImage
1979
1937
  if (descendantNode !== body && isFunctionLike(descendantNode)) return false;
1980
1938
  if (!isNodeOfType(descendantNode, "ReturnStatement")) return;
1981
1939
  if (!descendantNode.argument) return;
1982
- markGeneratedImageExpression(stripParenExpression(descendantNode.argument), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
1940
+ markGeneratedImageExpression(stripParenExpression(descendantNode.argument), programRoot, generatedImageJsxNodes, visitedComponentNames);
1983
1941
  });
1984
1942
  };
1985
1943
  const hasNormalJsxUsage = (programRoot, componentName, generatedImageJsxNodes) => {
@@ -1994,7 +1952,7 @@ const hasNormalJsxUsage = (programRoot, componentName, generatedImageJsxNodes) =
1994
1952
  });
1995
1953
  return hasNormalUsage;
1996
1954
  };
1997
- const markComponentRenderJsx = (programRoot, scopes, openingElement, generatedImageJsxNodes, visitedComponentNames) => {
1955
+ const markComponentRenderJsx = (programRoot, openingElement, generatedImageJsxNodes, visitedComponentNames) => {
1998
1956
  const tagName = flattenJsxName$1(openingElement.name);
1999
1957
  if (!tagName || tagName.includes(".") || !isComponentIdentifierName(tagName)) return;
2000
1958
  if (visitedComponentNames.has(tagName)) return;
@@ -2002,70 +1960,70 @@ const markComponentRenderJsx = (programRoot, scopes, openingElement, generatedIm
2002
1960
  const binding = findVariableInitializer(openingElement, tagName);
2003
1961
  if (!binding?.initializer) return;
2004
1962
  visitedComponentNames.add(tagName);
2005
- markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
1963
+ markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, generatedImageJsxNodes, visitedComponentNames);
2006
1964
  };
2007
- const isInsideGeneratedImageRendererArgument$1 = (node, scopes) => {
1965
+ const isInsideGeneratedImageRendererArgument = (node) => {
2008
1966
  let cursor = node.parent;
2009
1967
  while (cursor) {
2010
- if (isGeneratedImageRendererCall(cursor, scopes)) return true;
1968
+ if (isGeneratedImageRendererCall(cursor)) return true;
2011
1969
  cursor = cursor.parent ?? null;
2012
1970
  }
2013
1971
  return false;
2014
1972
  };
2015
- const hasNormalFunctionCallUsage = (programRoot, functionName, scopes) => {
1973
+ const hasNormalFunctionCallUsage = (programRoot, functionName) => {
2016
1974
  let hasNormalUsage = false;
2017
1975
  walkAst(programRoot, (descendantNode) => {
2018
1976
  if (hasNormalUsage) return false;
2019
1977
  if (!isNodeOfType(descendantNode, "CallExpression")) return;
2020
1978
  if (!isNodeOfType(descendantNode.callee, "Identifier")) return;
2021
1979
  if (descendantNode.callee.name !== functionName) return;
2022
- if (isInsideGeneratedImageRendererArgument$1(descendantNode, scopes)) return;
1980
+ if (isInsideGeneratedImageRendererArgument(descendantNode)) return;
2023
1981
  hasNormalUsage = true;
2024
1982
  return false;
2025
1983
  });
2026
1984
  return hasNormalUsage;
2027
1985
  };
2028
- const markJsxSubtree = (node, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames) => {
1986
+ const markJsxSubtree = (node, programRoot, generatedImageJsxNodes, visitedComponentNames) => {
2029
1987
  walkAst(node, (descendantNode) => {
2030
1988
  if (!isNodeOfType(descendantNode, "JSXOpeningElement")) return;
2031
1989
  generatedImageJsxNodes.add(descendantNode);
2032
- markComponentRenderJsx(programRoot, scopes, descendantNode, generatedImageJsxNodes, visitedComponentNames);
1990
+ markComponentRenderJsx(programRoot, descendantNode, generatedImageJsxNodes, visitedComponentNames);
2033
1991
  });
2034
1992
  };
2035
- const markGeneratedImageExpression = (expression, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames) => {
1993
+ const markGeneratedImageExpression = (expression, programRoot, generatedImageJsxNodes, visitedComponentNames) => {
2036
1994
  const unwrappedExpression = stripParenExpression(expression);
2037
1995
  if (isNodeOfType(unwrappedExpression, "JSXElement") || isNodeOfType(unwrappedExpression, "JSXFragment")) {
2038
- markJsxSubtree(unwrappedExpression, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
1996
+ markJsxSubtree(unwrappedExpression, programRoot, generatedImageJsxNodes, visitedComponentNames);
2039
1997
  return;
2040
1998
  }
2041
1999
  if (isFunctionLike(unwrappedExpression)) {
2042
- markFunctionReturnJsx(unwrappedExpression, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2000
+ markFunctionReturnJsx(unwrappedExpression, programRoot, generatedImageJsxNodes, visitedComponentNames);
2043
2001
  return;
2044
2002
  }
2045
2003
  if (isNodeOfType(unwrappedExpression, "ConditionalExpression")) {
2046
- markGeneratedImageExpression(unwrappedExpression.consequent, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2047
- markGeneratedImageExpression(unwrappedExpression.alternate, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2004
+ markGeneratedImageExpression(unwrappedExpression.consequent, programRoot, generatedImageJsxNodes, visitedComponentNames);
2005
+ markGeneratedImageExpression(unwrappedExpression.alternate, programRoot, generatedImageJsxNodes, visitedComponentNames);
2048
2006
  return;
2049
2007
  }
2050
2008
  if (isNodeOfType(unwrappedExpression, "LogicalExpression")) {
2051
- markGeneratedImageExpression(unwrappedExpression.left, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2052
- markGeneratedImageExpression(unwrappedExpression.right, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2009
+ markGeneratedImageExpression(unwrappedExpression.left, programRoot, generatedImageJsxNodes, visitedComponentNames);
2010
+ markGeneratedImageExpression(unwrappedExpression.right, programRoot, generatedImageJsxNodes, visitedComponentNames);
2053
2011
  return;
2054
2012
  }
2055
2013
  if (isNodeOfType(unwrappedExpression, "CallExpression")) {
2056
2014
  const callee = unwrappedExpression.callee;
2057
2015
  if (isFunctionLike(callee)) {
2058
- markFunctionReturnJsx(callee, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2016
+ markFunctionReturnJsx(callee, programRoot, generatedImageJsxNodes, visitedComponentNames);
2059
2017
  return;
2060
2018
  }
2061
2019
  if (!isNodeOfType(callee, "Identifier")) return;
2062
2020
  if (visitedComponentNames.has(callee.name)) return;
2063
2021
  if (hasNormalJsxUsage(programRoot, callee.name, generatedImageJsxNodes)) return;
2064
- if (hasNormalFunctionCallUsage(programRoot, callee.name, scopes)) return;
2022
+ if (hasNormalFunctionCallUsage(programRoot, callee.name)) return;
2065
2023
  const binding = findVariableInitializer(callee, callee.name);
2066
2024
  if (!binding?.initializer || !isFunctionLike(stripParenExpression(binding.initializer))) return;
2067
2025
  visitedComponentNames.add(callee.name);
2068
- markFunctionReturnJsx(stripParenExpression(binding.initializer), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2026
+ markFunctionReturnJsx(stripParenExpression(binding.initializer), programRoot, generatedImageJsxNodes, visitedComponentNames);
2069
2027
  return;
2070
2028
  }
2071
2029
  if (isNodeOfType(unwrappedExpression, "Identifier")) {
@@ -2073,17 +2031,16 @@ const markGeneratedImageExpression = (expression, programRoot, scopes, generated
2073
2031
  visitedComponentNames.add(unwrappedExpression.name);
2074
2032
  const binding = findVariableInitializer(unwrappedExpression, unwrappedExpression.name);
2075
2033
  if (!binding?.initializer) return;
2076
- markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
2034
+ markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, generatedImageJsxNodes, visitedComponentNames);
2077
2035
  }
2078
2036
  };
2079
- const collectGeneratedImageJsxNodes = (programRoot, scopes) => {
2037
+ const collectGeneratedImageJsxNodes = (programRoot) => {
2080
2038
  const cached = generatedImageJsxCache.get(programRoot);
2081
2039
  if (cached) return cached;
2082
2040
  const generatedImageJsxNodes = /* @__PURE__ */ new WeakSet();
2083
- if (hasImportFromModules(programRoot, GENERATED_IMAGE_RENDERER_MODULES)) walkAst(programRoot, (descendantNode) => {
2084
- if (!isNodeOfType(descendantNode, "CallExpression") && !isNodeOfType(descendantNode, "NewExpression")) return;
2085
- if (!isGeneratedImageRendererCall(descendantNode, scopes)) return;
2086
- for (const argument of descendantNode.arguments) markGeneratedImageExpression(argument, programRoot, scopes, generatedImageJsxNodes, /* @__PURE__ */ new Set());
2041
+ if (hasImportFromModules(programRoot, GENERATED_IMAGE_MODULES)) walkAst(programRoot, (descendantNode) => {
2042
+ if (!isGeneratedImageRendererCall(descendantNode)) return;
2043
+ for (const argument of descendantNode.arguments) markGeneratedImageExpression(argument, programRoot, generatedImageJsxNodes, /* @__PURE__ */ new Set());
2087
2044
  });
2088
2045
  generatedImageJsxCache.set(programRoot, generatedImageJsxNodes);
2089
2046
  return generatedImageJsxNodes;
@@ -2093,7 +2050,7 @@ const isGeneratedImageRenderContext = (context, node) => {
2093
2050
  if (!node) return false;
2094
2051
  const programRoot = findProgramRoot(node);
2095
2052
  if (!programRoot) return false;
2096
- const generatedImageJsxNodes = collectGeneratedImageJsxNodes(programRoot, context.scopes);
2053
+ const generatedImageJsxNodes = collectGeneratedImageJsxNodes(programRoot);
2097
2054
  if (generatedImageJsxNodes.has(node)) return true;
2098
2055
  if (isNodeOfType(node, "JSXElement")) return generatedImageJsxNodes.has(node.openingElement);
2099
2056
  return false;
@@ -4539,6 +4496,15 @@ const getDestructuredBindingPropertyName = (bindingIdentifier) => {
4539
4496
  return getStaticPropertyKeyName(property, { allowComputedString: true });
4540
4497
  };
4541
4498
  //#endregion
4499
+ //#region src/plugin/utils/get-static-property-name.ts
4500
+ const getStaticPropertyName = (memberExpression) => {
4501
+ const property = memberExpression.property;
4502
+ if (!memberExpression.computed && isNodeOfType(property, "Identifier")) return property.name;
4503
+ if (memberExpression.computed && isNodeOfType(property, "Literal")) return typeof property.value === "string" ? property.value : null;
4504
+ if (memberExpression.computed && isNodeOfType(property, "TemplateLiteral") && property.expressions.length === 0) return property.quasis[0]?.value.cooked ?? property.quasis[0]?.value.raw ?? null;
4505
+ return null;
4506
+ };
4507
+ //#endregion
4542
4508
  //#region src/plugin/utils/has-static-property-write-before.ts
4543
4509
  const equivalentSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
4544
4510
  const potentiallyAliasedSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
@@ -6239,23 +6205,6 @@ const asyncDeferAwait = defineRule({
6239
6205
  }
6240
6206
  });
6241
6207
  //#endregion
6242
- //#region src/plugin/utils/expression-reads-pattern-binding.ts
6243
- const expressionReadsPatternBinding = (expression, patterns, scopes) => {
6244
- const bindingSymbolIds = /* @__PURE__ */ new Set();
6245
- for (const pattern of patterns) walkAst(pattern, (child) => {
6246
- if (!isNodeOfType(child, "Identifier")) return;
6247
- const symbol = scopes.symbolFor(child);
6248
- if (symbol?.bindingIdentifier === child) bindingSymbolIds.add(symbol.id);
6249
- });
6250
- let didReadBinding = false;
6251
- walkAst(expression, (child) => {
6252
- if (didReadBinding || !isNodeOfType(child, "Identifier")) return;
6253
- const reference = scopes.referenceFor(child);
6254
- if (reference?.flag !== "write" && reference?.resolvedSymbol && bindingSymbolIds.has(reference.resolvedSymbol.id)) didReadBinding = true;
6255
- });
6256
- return didReadBinding;
6257
- };
6258
- //#endregion
6259
6208
  //#region src/plugin/utils/get-callee-identifier-trail.ts
6260
6209
  const getCalleeIdentifierTrail = (call) => {
6261
6210
  let entry = call;
@@ -6361,12 +6310,16 @@ const isInsideTransactionCallback = (node) => {
6361
6310
  return false;
6362
6311
  };
6363
6312
  const reportIfIndependent = (statements, context) => {
6364
- const declaredPatterns = [];
6313
+ const declaredNames = /* @__PURE__ */ new Set();
6365
6314
  for (const statement of statements) {
6366
6315
  const awaitArgument = getAwaitedCall(statement);
6367
6316
  if (!awaitArgument) continue;
6368
- if (expressionReadsPatternBinding(awaitArgument, declaredPatterns, context.scopes)) return;
6369
- if (isNodeOfType(statement, "VariableDeclaration") && statement.declarations[0]?.id) declaredPatterns.push(statement.declarations[0].id);
6317
+ let referencesEarlierResult = false;
6318
+ walkAst(awaitArgument, (child) => {
6319
+ if (isNodeOfType(child, "Identifier") && declaredNames.has(child.name)) referencesEarlierResult = true;
6320
+ });
6321
+ if (referencesEarlierResult) return;
6322
+ if (isNodeOfType(statement, "VariableDeclaration") && statement.declarations[0]?.id) collectPatternNames(statement.declarations[0].id, declaredNames);
6370
6323
  }
6371
6324
  context.report({
6372
6325
  node: statements[0],
@@ -8234,9 +8187,6 @@ const createMethodMutationAnalysis = (context) => {
8234
8187
  };
8235
8188
  };
8236
8189
  //#endregion
8237
- //#region src/plugin/utils/is-member-property.ts
8238
- const isMemberProperty = (node, propertyName) => Boolean(node && isNodeOfType(node, "MemberExpression") && isNodeOfType(node.property, "Identifier") && node.property.name === propertyName);
8239
- //#endregion
8240
8190
  //#region src/plugin/utils/collect-function-return-statements.ts
8241
8191
  const collectFunctionReturnStatements = (functionNode) => {
8242
8192
  if (!isFunctionLike$1(functionNode) || !isNodeOfType(functionNode.body, "BlockStatement")) return [];
@@ -8513,21 +8463,10 @@ const isDestructuredReactApiBinding = (identifier, apiNames, scopes, options) =>
8513
8463
  };
8514
8464
  const isReactApiCall = (node, apiNames, scopes, options = {}) => {
8515
8465
  if (!isNodeOfType(node, "CallExpression")) return false;
8516
- return isReactApiCallee(node.callee, apiNames, scopes, options, /* @__PURE__ */ new Set());
8517
- };
8518
- const isReactApiCallee = (rawCallee, apiNames, scopes, options, visitedSymbolIds) => {
8519
- const callee = stripParenExpression(rawCallee);
8520
- if (options.resolveConditionalAliases && isNodeOfType(callee, "ConditionalExpression")) return isReactApiCallee(callee.consequent, apiNames, scopes, options, new Set(visitedSymbolIds)) && isReactApiCallee(callee.alternate, apiNames, scopes, options, new Set(visitedSymbolIds));
8466
+ const callee = stripParenExpression(node.callee);
8521
8467
  if (isNodeOfType(callee, "Identifier")) {
8522
8468
  if (isNamedReactApiImport(callee, apiNames, scopes, Boolean(options.resolveNamedAliases))) return true;
8523
8469
  if (options.resolveNamedAliases && isDestructuredReactApiBinding(callee, apiNames, scopes, options)) return true;
8524
- if (options.resolveConditionalAliases) {
8525
- const symbol = scopes.symbolFor(callee);
8526
- if (symbol?.kind === "const" && symbol.initializer && !visitedSymbolIds.has(symbol.id)) {
8527
- visitedSymbolIds.add(symbol.id);
8528
- return isReactApiCallee(symbol.initializer, apiNames, scopes, options, visitedSymbolIds);
8529
- }
8530
- }
8531
8470
  return Boolean(options.allowUnboundBareCalls && includesApiName(apiNames, callee.name) && scopes.isGlobalReference(callee));
8532
8471
  }
8533
8472
  if (!isNodeOfType(callee, "MemberExpression") || !includesApiName(apiNames, getStaticPropertyName(callee) ?? "")) return false;
@@ -12384,10 +12323,6 @@ const isConstAliasOfGlobalArrayFrom = (node, scopes) => {
12384
12323
  };
12385
12324
  const executesDuringRender = (functionNode, scopes) => {
12386
12325
  const parent = functionNode.parent;
12387
- if (isNodeOfType(parent, "NewExpression")) {
12388
- const callee = stripParenExpression(parent.callee);
12389
- return Boolean(scopes && parent.arguments?.[0] === functionNode && isNodeOfType(callee, "Identifier") && callee.name === "Promise" && scopes.isGlobalReference(callee));
12390
- }
12391
12326
  if (!isNodeOfType(parent, "CallExpression")) return false;
12392
12327
  if (parent.callee === functionNode) return true;
12393
12328
  if ((scopes ? isReactApiCall(parent, REACT_RENDER_PHASE_HOOK_NAMES, scopes, { allowGlobalReactNamespace: true }) : isHookCall$2(parent, REACT_RENDER_PHASE_HOOK_NAMES)) && parent.arguments?.[0] === functionNode) return true;
@@ -26523,489 +26458,6 @@ const hasEmailTemplateImport = (programRoot) => {
26523
26458
  return found;
26524
26459
  };
26525
26460
  //#endregion
26526
- //#region src/plugin/utils/build-generated-image-project-index.ts
26527
- const GENERATED_IMAGE_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/i;
26528
- const GENERATED_IMAGE_DECLARATION_FILE_PATTERN = /\.d\.[cm]?[jt]s$/i;
26529
- const GENERATED_IMAGE_MDX_FILE_PATTERN = /\.mdx$/i;
26530
- const GENERATED_IMAGE_IGNORED_DIRECTORY_NAMES = new Set([
26531
- ".angular",
26532
- ".astro",
26533
- ".cache",
26534
- ".contentlayer",
26535
- ".docusaurus",
26536
- ".expo",
26537
- ".git",
26538
- ".next",
26539
- ".nuxt",
26540
- ".output",
26541
- ".svelte-kit",
26542
- ".turbo",
26543
- ".vercel",
26544
- "build",
26545
- "coverage",
26546
- "dist",
26547
- "node_modules",
26548
- "out",
26549
- "storybook-static"
26550
- ]);
26551
- const generatedImageScopeCache = /* @__PURE__ */ new WeakMap();
26552
- const getGeneratedImageModuleScopes = (programNode) => {
26553
- const cachedScopes = generatedImageScopeCache.get(programNode);
26554
- if (cachedScopes) return cachedScopes;
26555
- const scopes = analyzeScopes(programNode);
26556
- generatedImageScopeCache.set(programNode, scopes);
26557
- return scopes;
26558
- };
26559
- const listProductionSourceFiles = (rootDirectory) => {
26560
- const sourceFilePaths = [];
26561
- const pendingDirectories = [rootDirectory];
26562
- let hasOpaqueMdxConsumerSurface = false;
26563
- while (pendingDirectories.length > 0) {
26564
- const currentDirectory = pendingDirectories.pop();
26565
- if (!currentDirectory) continue;
26566
- let entries;
26567
- try {
26568
- entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
26569
- } catch {
26570
- return null;
26571
- }
26572
- for (const entry of entries) {
26573
- const absolutePath = path.join(currentDirectory, entry.name);
26574
- const isIgnoredDirectoryName = GENERATED_IMAGE_IGNORED_DIRECTORY_NAMES.has(entry.name) || entry.name.startsWith(".") && entry.name !== ".dumi" && entry.name !== ".storybook";
26575
- if (entry.isSymbolicLink() && isIgnoredDirectoryName) continue;
26576
- if (entry.isSymbolicLink()) return null;
26577
- if (entry.isDirectory()) {
26578
- if (isIgnoredDirectoryName) continue;
26579
- pendingDirectories.push(absolutePath);
26580
- continue;
26581
- }
26582
- if (!entry.isFile() || isTestlikeFilename(absolutePath)) continue;
26583
- if (GENERATED_IMAGE_MDX_FILE_PATTERN.test(entry.name)) {
26584
- hasOpaqueMdxConsumerSurface = true;
26585
- continue;
26586
- }
26587
- if (!GENERATED_IMAGE_SOURCE_FILE_PATTERN.test(entry.name)) continue;
26588
- if (GENERATED_IMAGE_DECLARATION_FILE_PATTERN.test(entry.name)) continue;
26589
- sourceFilePaths.push(normalizeFilename(absolutePath));
26590
- }
26591
- }
26592
- return {
26593
- sourceFilePaths,
26594
- hasOpaqueMdxConsumerSurface
26595
- };
26596
- };
26597
- const getRuntimeModuleSource = (node) => {
26598
- if (isNodeOfType(node, "ImportDeclaration")) {
26599
- if (isTypeOnlyImport(node)) return null;
26600
- return typeof node.source.value === "string" ? node.source.value : null;
26601
- }
26602
- if (isNodeOfType(node, "ExportNamedDeclaration")) {
26603
- if (node.exportKind === "type" || isEverySpecifierInlineType(node.specifiers, "ExportSpecifier", "exportKind")) return null;
26604
- return node.source && typeof node.source.value === "string" ? node.source.value : null;
26605
- }
26606
- if (isNodeOfType(node, "ExportAllDeclaration")) {
26607
- if (node.exportKind === "type") return null;
26608
- return typeof node.source.value === "string" ? node.source.value : null;
26609
- }
26610
- if (isNodeOfType(node, "ImportExpression")) return isNodeOfType(node.source, "Literal") && typeof node.source.value === "string" ? node.source.value : null;
26611
- if (isNodeOfType(node, "CallExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "require" && node.arguments.length === 1) {
26612
- const source = node.arguments[0];
26613
- return source && isNodeOfType(source, "Literal") && typeof source.value === "string" ? source.value : null;
26614
- }
26615
- return null;
26616
- };
26617
- const indexModuleSources = (module, consumerModulesByFilePath, resolvedSourcePathByNode, unresolvedRuntimeSources) => {
26618
- walkAst(module.programNode, (node) => {
26619
- const source = getRuntimeModuleSource(node);
26620
- if (!source) return;
26621
- const resolvedSourcePath = resolveModulePath(module.filePath, source);
26622
- if (!resolvedSourcePath) {
26623
- unresolvedRuntimeSources.add(source);
26624
- return;
26625
- }
26626
- const normalizedSourcePath = normalizeFilename(resolvedSourcePath);
26627
- resolvedSourcePathByNode.set(node, normalizedSourcePath);
26628
- const consumerModules = consumerModulesByFilePath.get(normalizedSourcePath) ?? /* @__PURE__ */ new Set();
26629
- consumerModules.add(module);
26630
- consumerModulesByFilePath.set(normalizedSourcePath, consumerModules);
26631
- });
26632
- };
26633
- const buildGeneratedImageProjectIndex = (rootDirectory, currentFilePath, currentProgramNode, currentScopes) => {
26634
- const productionSourceFiles = listProductionSourceFiles(rootDirectory);
26635
- if (!productionSourceFiles) return null;
26636
- const modulesByFilePath = /* @__PURE__ */ new Map();
26637
- for (const filePath of productionSourceFiles.sourceFilePaths) {
26638
- if (filePath === currentFilePath) {
26639
- modulesByFilePath.set(filePath, {
26640
- filePath,
26641
- programNode: currentProgramNode,
26642
- scopes: currentScopes
26643
- });
26644
- continue;
26645
- }
26646
- const parsedProgram = parseSourceFile(filePath);
26647
- if (!parsedProgram || !isNodeOfType(parsedProgram, "Program")) return null;
26648
- modulesByFilePath.set(filePath, {
26649
- filePath,
26650
- programNode: parsedProgram,
26651
- scopes: getGeneratedImageModuleScopes(parsedProgram)
26652
- });
26653
- }
26654
- const consumerModulesByFilePath = /* @__PURE__ */ new Map();
26655
- const resolvedSourcePathByNode = /* @__PURE__ */ new WeakMap();
26656
- const unresolvedRuntimeSources = /* @__PURE__ */ new Set();
26657
- for (const module of modulesByFilePath.values()) indexModuleSources(module, consumerModulesByFilePath, resolvedSourcePathByNode, unresolvedRuntimeSources);
26658
- return {
26659
- modulesByFilePath,
26660
- consumerModulesByFilePath,
26661
- resolvedSourcePathByNode,
26662
- unresolvedRuntimeSources,
26663
- hasOpaqueMdxConsumerSurface: productionSourceFiles.hasOpaqueMdxConsumerSurface
26664
- };
26665
- };
26666
- //#endregion
26667
- //#region src/plugin/utils/read-nearest-package-manifest.ts
26668
- const cachedPackageDirectoryByFilename = /* @__PURE__ */ new Map();
26669
- const cachedManifestByPackageDirectory = /* @__PURE__ */ new Map();
26670
- const resetManifestCaches = () => {
26671
- cachedPackageDirectoryByFilename.clear();
26672
- cachedManifestByPackageDirectory.clear();
26673
- };
26674
- const findNearestPackageDirectory = (filename) => {
26675
- if (!filename) return null;
26676
- const fromCache = cachedPackageDirectoryByFilename.get(filename);
26677
- if (fromCache !== void 0) {
26678
- if (isProbeRecorderActive()) {
26679
- let probedDirectory = path.dirname(filename);
26680
- while (true) {
26681
- recordExistenceProbe(path.join(probedDirectory, "package.json"));
26682
- if (probedDirectory === fromCache) break;
26683
- const parentDirectory = path.dirname(probedDirectory);
26684
- if (parentDirectory === probedDirectory) break;
26685
- probedDirectory = parentDirectory;
26686
- }
26687
- }
26688
- return fromCache;
26689
- }
26690
- let currentDirectory = path.dirname(filename);
26691
- while (true) {
26692
- const candidatePackageJsonPath = path.join(currentDirectory, "package.json");
26693
- recordExistenceProbe(candidatePackageJsonPath);
26694
- let hasPackageJson = false;
26695
- try {
26696
- hasPackageJson = fs.statSync(candidatePackageJsonPath).isFile();
26697
- } catch {
26698
- hasPackageJson = false;
26699
- }
26700
- if (hasPackageJson) {
26701
- cachedPackageDirectoryByFilename.set(filename, currentDirectory);
26702
- return currentDirectory;
26703
- }
26704
- const parentDirectory = path.dirname(currentDirectory);
26705
- if (parentDirectory === currentDirectory) {
26706
- cachedPackageDirectoryByFilename.set(filename, null);
26707
- return null;
26708
- }
26709
- currentDirectory = parentDirectory;
26710
- }
26711
- };
26712
- const readNearestPackageManifest = (filename) => {
26713
- const packageDirectory = findNearestPackageDirectory(filename);
26714
- if (!packageDirectory) return null;
26715
- return readPackageManifest(packageDirectory);
26716
- };
26717
- const readPackageManifest = (packageDirectory) => {
26718
- const packageJsonPath = path.join(packageDirectory, "package.json");
26719
- recordContentProbe(packageJsonPath);
26720
- const cached = cachedManifestByPackageDirectory.get(packageDirectory);
26721
- if (cached !== void 0) return cached;
26722
- let manifest = null;
26723
- try {
26724
- const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
26725
- if (typeof parsed === "object" && parsed !== null) manifest = parsed;
26726
- } catch {
26727
- manifest = null;
26728
- }
26729
- cachedManifestByPackageDirectory.set(packageDirectory, manifest);
26730
- return manifest;
26731
- };
26732
- //#endregion
26733
- //#region src/plugin/utils/is-exported-jsx-owned-by-generated-image-renderers.ts
26734
- const getExportedSpecifierName = (specifier) => {
26735
- const exported = specifier.exported;
26736
- if (isNodeOfType(exported, "Identifier")) return exported.name;
26737
- return isNodeOfType(exported, "Literal") && typeof exported.value === "string" ? exported.value : null;
26738
- };
26739
- const getImportedSpecifierName = (specifier) => {
26740
- const local = specifier.local;
26741
- if (isNodeOfType(local, "Identifier")) return local.name;
26742
- return isNodeOfType(local, "Literal") && typeof local.value === "string" ? local.value : null;
26743
- };
26744
- const getImportSpecifierName = (specifier) => {
26745
- if (isNodeOfType(specifier, "ImportDefaultSpecifier")) return "default";
26746
- if (!isNodeOfType(specifier, "ImportSpecifier")) return null;
26747
- const imported = specifier.imported;
26748
- if (isNodeOfType(imported, "Identifier")) return imported.name;
26749
- return isNodeOfType(imported, "Literal") && typeof imported.value === "string" ? imported.value : null;
26750
- };
26751
- const getDirectFunctionBindingIdentifier = (functionNode) => {
26752
- if (isNodeOfType(functionNode, "FunctionDeclaration") && isNodeOfType(functionNode.id, "Identifier")) return functionNode.id;
26753
- const functionValueRoot = findTransparentExpressionRoot(functionNode);
26754
- const parent = functionValueRoot.parent;
26755
- return isNodeOfType(parent, "VariableDeclarator") && parent.init === functionValueRoot && isNodeOfType(parent.id, "Identifier") ? parent.id : null;
26756
- };
26757
- const getExportNamesForFunction = (programNode, functionNode) => {
26758
- const functionValueRoot = findTransparentExpressionRoot(functionNode);
26759
- const bindingName = getDirectFunctionBindingIdentifier(functionNode)?.name ?? null;
26760
- const exportedNames = /* @__PURE__ */ new Set();
26761
- for (const statement of programNode.body) {
26762
- if (isNodeOfType(statement, "ExportDefaultDeclaration")) {
26763
- if (statement.declaration === functionValueRoot || bindingName && isNodeOfType(statement.declaration, "Identifier") && statement.declaration.name === bindingName) exportedNames.add("default");
26764
- continue;
26765
- }
26766
- if (!isNodeOfType(statement, "ExportNamedDeclaration")) continue;
26767
- const declaration = statement.declaration;
26768
- if (declaration === functionValueRoot && bindingName) exportedNames.add(bindingName);
26769
- if (declaration && isNodeOfType(declaration, "VariableDeclaration")) {
26770
- for (const declarator of declaration.declarations) if (declarator.init === functionValueRoot && isNodeOfType(declarator.id, "Identifier")) exportedNames.add(declarator.id.name);
26771
- }
26772
- if (!bindingName || statement.source) continue;
26773
- for (const specifier of statement.specifiers) {
26774
- if (!isNodeOfType(specifier, "ExportSpecifier")) continue;
26775
- if (getImportedSpecifierName(specifier) !== bindingName) continue;
26776
- const exportedName = getExportedSpecifierName(specifier);
26777
- if (exportedName) exportedNames.add(exportedName);
26778
- }
26779
- }
26780
- return [...exportedNames];
26781
- };
26782
- const isTransparentGeneratedImageValueFlow = (expression, target) => {
26783
- let current = findTransparentExpressionRoot(expression);
26784
- while (current !== target) {
26785
- const parent = current.parent;
26786
- if (!parent) return false;
26787
- if (!((isNodeOfType(parent, "JSXExpressionContainer") || isNodeOfType(parent, "JSXSpreadChild")) && parent.expression === current || (isNodeOfType(parent, "JSXElement") || isNodeOfType(parent, "JSXFragment")) && parent.children.some((child) => child === current) || isNodeOfType(parent, "ConditionalExpression") && (parent.consequent === current || parent.alternate === current) || isNodeOfType(parent, "LogicalExpression") && (parent.left === current || parent.right === current) || isNodeOfType(parent, "ArrayExpression") && parent.elements.some((element) => element === current) || isNodeOfType(parent, "SequenceExpression") && parent.expressions.at(-1) === current || isNodeOfType(parent, "AwaitExpression") && parent.argument === current)) return false;
26788
- current = findTransparentExpressionRoot(parent);
26789
- }
26790
- return true;
26791
- };
26792
- const isInsideGeneratedImageRendererArgument = (expression, scopes) => {
26793
- let cursor = expression;
26794
- while (cursor?.parent) {
26795
- const parent = cursor.parent;
26796
- if (isFunctionLike$1(parent)) return false;
26797
- if (isNodeOfType(parent, "CallExpression") || isNodeOfType(parent, "NewExpression")) {
26798
- if (parent.arguments[0] && isTransparentGeneratedImageValueFlow(expression, parent.arguments[0]) && isGeneratedImageRendererCall(parent, scopes)) return true;
26799
- }
26800
- cursor = parent;
26801
- }
26802
- return false;
26803
- };
26804
- const getInvokedExpression = (identifier) => {
26805
- const referenceExpression = findTransparentExpressionRoot(identifier);
26806
- const parent = referenceExpression.parent;
26807
- if (isNodeOfType(parent, "CallExpression") && parent.callee === referenceExpression) return parent;
26808
- if (isNodeOfType(parent, "TaggedTemplateExpression") && parent.tag === referenceExpression) return parent;
26809
- if ((isNodeOfType(parent, "JSXOpeningElement") || isNodeOfType(parent, "JSXClosingElement")) && parent.name === identifier) {
26810
- const element = parent.parent;
26811
- return isNodeOfType(element, "JSXElement") ? element : null;
26812
- }
26813
- return null;
26814
- };
26815
- const getForwardingFunction = (expression) => {
26816
- const enclosingFunction = findEnclosingFunction$1(expression);
26817
- if (!enclosingFunction) return null;
26818
- if (isNodeOfType(enclosingFunction, "ArrowFunctionExpression") && !isNodeOfType(enclosingFunction.body, "BlockStatement") && isTransparentGeneratedImageValueFlow(expression, enclosingFunction.body)) return enclosingFunction;
26819
- let cursor = expression.parent;
26820
- while (cursor && cursor !== enclosingFunction) {
26821
- if (isFunctionLike$1(cursor)) return null;
26822
- if (isNodeOfType(cursor, "ReturnStatement") && cursor.argument && isTransparentGeneratedImageValueFlow(expression, cursor.argument)) return enclosingFunction;
26823
- cursor = cursor.parent;
26824
- }
26825
- return null;
26826
- };
26827
- const enqueueExport = (state, filePath, exportedName) => {
26828
- state.pendingExports.push({
26829
- filePath: normalizeFilename(filePath),
26830
- exportedName
26831
- });
26832
- };
26833
- const classifyInvokedExpression = (module, expression, state) => {
26834
- if (isInsideGeneratedImageRendererArgument(expression, module.scopes)) {
26835
- state.didReachRenderer = true;
26836
- return true;
26837
- }
26838
- const forwardingFunction = getForwardingFunction(expression);
26839
- if (!forwardingFunction) return false;
26840
- const exportedNames = getExportNamesForFunction(module.programNode, forwardingFunction);
26841
- if (exportedNames.length === 0) return false;
26842
- for (const exportedName of exportedNames) enqueueExport(state, module.filePath, exportedName);
26843
- return true;
26844
- };
26845
- const classifySymbolReferences = (module, symbol, state, visitedSymbolIds) => {
26846
- if (visitedSymbolIds.has(symbol.id)) return true;
26847
- visitedSymbolIds.add(symbol.id);
26848
- for (const reference of symbol.references) {
26849
- if (reference.flag !== "read") return false;
26850
- state.currentExportWasUsed = true;
26851
- const identifier = reference.identifier;
26852
- const invokedExpression = getInvokedExpression(identifier);
26853
- if (invokedExpression) {
26854
- if (!classifyInvokedExpression(module, invokedExpression, state)) return false;
26855
- continue;
26856
- }
26857
- const parent = identifier.parent;
26858
- if (isNodeOfType(parent, "ExportSpecifier") && parent.local === identifier) {
26859
- const exportedName = getExportedSpecifierName(parent);
26860
- if (!exportedName) return false;
26861
- enqueueExport(state, module.filePath, exportedName);
26862
- continue;
26863
- }
26864
- if (isNodeOfType(parent, "ExportDefaultDeclaration")) {
26865
- enqueueExport(state, module.filePath, "default");
26866
- continue;
26867
- }
26868
- if (isNodeOfType(parent, "VariableDeclarator") && parent.init === identifier && isNodeOfType(parent.id, "Identifier") && isNodeOfType(parent.parent, "VariableDeclaration") && parent.parent.kind === "const") {
26869
- const aliasSymbol = module.scopes.symbolFor(parent.id);
26870
- if (!aliasSymbol || !classifySymbolReferences(module, aliasSymbol, state, visitedSymbolIds)) return false;
26871
- continue;
26872
- }
26873
- return false;
26874
- }
26875
- return true;
26876
- };
26877
- const classifyNamespaceImportReferences = (module, symbol, exportedName, state) => {
26878
- for (const reference of symbol.references) {
26879
- if (reference.flag !== "read") return false;
26880
- const identifier = reference.identifier;
26881
- const parent = identifier.parent;
26882
- if (!isNodeOfType(parent, "MemberExpression") || parent.object !== identifier) return false;
26883
- const propertyName = getStaticPropertyName(parent);
26884
- if (propertyName === null) return false;
26885
- if (propertyName !== exportedName) continue;
26886
- state.currentExportWasUsed = true;
26887
- const invokedExpression = getInvokedExpression(parent);
26888
- if (!invokedExpression || !classifyInvokedExpression(module, invokedExpression, state)) return false;
26889
- }
26890
- return true;
26891
- };
26892
- const classifyImportsFromExport = (module, exportIdentity, state) => {
26893
- for (const statement of module.programNode.body) {
26894
- if (isNodeOfType(statement, "ImportDeclaration")) {
26895
- if (state.projectIndex.resolvedSourcePathByNode.get(statement) !== exportIdentity.filePath) continue;
26896
- if (statement.importKind === "type") continue;
26897
- for (const specifier of statement.specifiers) {
26898
- if (isNodeOfType(specifier, "ImportSpecifier") && specifier.importKind === "type") continue;
26899
- if (isNodeOfType(specifier, "ImportNamespaceSpecifier")) {
26900
- const namespaceSymbol = module.scopes.symbolFor(specifier.local);
26901
- if (!namespaceSymbol || !classifyNamespaceImportReferences(module, namespaceSymbol, exportIdentity.exportedName, state)) return false;
26902
- continue;
26903
- }
26904
- if (getImportSpecifierName(specifier) !== exportIdentity.exportedName) continue;
26905
- const symbol = module.scopes.symbolFor(specifier.local);
26906
- if (!symbol || !classifySymbolReferences(module, symbol, state, /* @__PURE__ */ new Set())) return false;
26907
- }
26908
- continue;
26909
- }
26910
- if ((isNodeOfType(statement, "ExportNamedDeclaration") || isNodeOfType(statement, "ExportAllDeclaration")) && statement.source && state.projectIndex.resolvedSourcePathByNode.get(statement) === exportIdentity.filePath) {
26911
- if (isNodeOfType(statement, "ExportAllDeclaration")) {
26912
- if (statement.exported) return false;
26913
- state.currentExportWasUsed = true;
26914
- enqueueExport(state, module.filePath, exportIdentity.exportedName);
26915
- continue;
26916
- }
26917
- for (const specifier of statement.specifiers) {
26918
- if (!isNodeOfType(specifier, "ExportSpecifier")) continue;
26919
- if (getImportedSpecifierName(specifier) !== exportIdentity.exportedName) continue;
26920
- const exportedName = getExportedSpecifierName(specifier);
26921
- if (!exportedName) return false;
26922
- state.currentExportWasUsed = true;
26923
- enqueueExport(state, module.filePath, exportedName);
26924
- }
26925
- }
26926
- }
26927
- return true;
26928
- };
26929
- const hasOpaqueDynamicImportOfExport = (module, exportIdentity, projectIndex) => {
26930
- let isOpaque = false;
26931
- walkAst(module.programNode, (node) => {
26932
- if (isOpaque) return false;
26933
- if (isNodeOfType(node, "ImportExpression")) {
26934
- if (projectIndex.resolvedSourcePathByNode.get(node) === exportIdentity.filePath) {
26935
- isOpaque = true;
26936
- return false;
26937
- }
26938
- }
26939
- if (isNodeOfType(node, "CallExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "require" && node.arguments.length === 1) {
26940
- if (projectIndex.resolvedSourcePathByNode.get(node) === exportIdentity.filePath) {
26941
- isOpaque = true;
26942
- return false;
26943
- }
26944
- }
26945
- });
26946
- return isOpaque;
26947
- };
26948
- const classifyLocalExportReferences = (module, exportIdentity, state) => {
26949
- const exportedValue = findExportedValue(module.programNode, exportIdentity.exportedName);
26950
- if (!exportedValue || !isFunctionLike$1(exportedValue)) return true;
26951
- const bindingIdentifier = getDirectFunctionBindingIdentifier(exportedValue);
26952
- if (!bindingIdentifier) return true;
26953
- const symbol = module.scopes.symbolFor(bindingIdentifier);
26954
- return symbol ? classifySymbolReferences(module, symbol, state, /* @__PURE__ */ new Set()) : false;
26955
- };
26956
- const hasOpaqueWorkspacePackageConsumer = (projectIndex, exportIdentity) => {
26957
- const packageName = readNearestPackageManifest(exportIdentity.filePath)?.name;
26958
- if (typeof packageName !== "string" || packageName.length === 0) return false;
26959
- for (const unresolvedSource of projectIndex.unresolvedRuntimeSources) if (unresolvedSource === packageName || unresolvedSource.startsWith(`${packageName}/`)) return true;
26960
- return false;
26961
- };
26962
- const createExportedJsxGeneratedImageOwnershipAnalyzer = (context) => {
26963
- const filename = context.filename ? normalizeFilename(context.filename) : "";
26964
- const rootDirectorySetting = getReactDoctorStringSetting(context.settings, "rootDirectory");
26965
- const rootDirectory = rootDirectorySetting ? normalizeFilename(rootDirectorySetting).replace(/\/$/, "") : "";
26966
- const isFileInsideRoot = Boolean(filename && rootDirectory) && (filename === rootDirectory || filename.startsWith(`${rootDirectory}/`));
26967
- let projectIndex;
26968
- return (jsxNode) => {
26969
- if (!isFileInsideRoot) return false;
26970
- const programNode = findProgramRoot(jsxNode);
26971
- const enclosingFunction = findEnclosingFunction$1(jsxNode);
26972
- if (!programNode || !enclosingFunction) return false;
26973
- const initialExportNames = getExportNamesForFunction(programNode, enclosingFunction);
26974
- if (initialExportNames.length === 0) return false;
26975
- if (projectIndex === void 0) projectIndex = buildGeneratedImageProjectIndex(rootDirectory, filename, programNode, context.scopes);
26976
- if (!projectIndex || projectIndex.hasOpaqueMdxConsumerSurface) return false;
26977
- const state = {
26978
- projectIndex,
26979
- pendingExports: initialExportNames.map((exportedName) => ({
26980
- filePath: filename,
26981
- exportedName
26982
- })),
26983
- visitedExportKeys: /* @__PURE__ */ new Set(),
26984
- currentExportWasUsed: false,
26985
- didReachRenderer: false
26986
- };
26987
- while (state.pendingExports.length > 0) {
26988
- const exportIdentity = state.pendingExports.pop();
26989
- if (!exportIdentity) continue;
26990
- const exportKey = `${exportIdentity.filePath}\0${exportIdentity.exportedName}`;
26991
- if (state.visitedExportKeys.has(exportKey)) continue;
26992
- state.visitedExportKeys.add(exportKey);
26993
- state.currentExportWasUsed = false;
26994
- if (hasOpaqueWorkspacePackageConsumer(projectIndex, exportIdentity)) return false;
26995
- const ownerModule = projectIndex.modulesByFilePath.get(exportIdentity.filePath);
26996
- if (!ownerModule || !classifyLocalExportReferences(ownerModule, exportIdentity, state)) return false;
26997
- const consumerModules = projectIndex.consumerModulesByFilePath.get(exportIdentity.filePath) ?? [];
26998
- for (const module of consumerModules) {
26999
- if (module.filePath === exportIdentity.filePath) continue;
27000
- if (hasOpaqueDynamicImportOfExport(module, exportIdentity, projectIndex)) return false;
27001
- if (!classifyImportsFromExport(module, exportIdentity, state)) return false;
27002
- }
27003
- if (!state.currentExportWasUsed) return false;
27004
- }
27005
- return state.didReachRenderer;
27006
- };
27007
- };
27008
- //#endregion
27009
26461
  //#region src/plugin/rules/nextjs/nextjs-no-img-element.ts
27010
26462
  const NON_OPTIMIZABLE_SRC_PREFIX_PATTERN = /^\s*(data:|blob:)/i;
27011
26463
  const GENERATED_URL_NAME_PATTERN = /(data|object|blob)_?url/i;
@@ -27108,20 +26560,9 @@ const nextjsNoImgElement = defineRule({
27108
26560
  recommendation: "Use `next/image` so users get optimized formats, responsive srcsets, and lazy loading instead of oversized image downloads.",
27109
26561
  create: (context) => {
27110
26562
  if (isGeneratedImageRenderContext(context)) return {};
27111
- const generatedImageOwnershipByFunction = /* @__PURE__ */ new WeakMap();
27112
- const isExportedJsxGeneratedImageOwned = createExportedJsxGeneratedImageOwnershipAnalyzer(context);
27113
26563
  return { JSXOpeningElement(node) {
27114
26564
  if (resolveJsxElementType(node) !== "img") return;
27115
26565
  if (isGeneratedImageRenderContext(context, node)) return;
27116
- const enclosingFunction = findEnclosingFunction$1(node);
27117
- if (enclosingFunction) {
27118
- let isGeneratedImageOwned = generatedImageOwnershipByFunction.get(enclosingFunction);
27119
- if (isGeneratedImageOwned === void 0) {
27120
- isGeneratedImageOwned = isExportedJsxGeneratedImageOwned(node);
27121
- generatedImageOwnershipByFunction.set(enclosingFunction, isGeneratedImageOwned);
27122
- }
27123
- if (isGeneratedImageOwned) return;
27124
- }
27125
26566
  const programRoot = findProgramRoot(node);
27126
26567
  if (programRoot && hasEmailTemplateImport(programRoot)) return;
27127
26568
  const srcAttribute = findJsxAttribute(node.attributes, "src");
@@ -30371,143 +29812,18 @@ const ARITHMETIC_KEY_OPERATORS = new Set([
30371
29812
  "%"
30372
29813
  ]);
30373
29814
  const bindingMutationResultsByProgram = /* @__PURE__ */ new WeakMap();
30374
- const UNKNOWN_STATIC_KEY_BRANCH_VALUE = {
30375
- isNullish: null,
30376
- isTruthy: null
30377
- };
30378
- const mergeStaticKeyBranchValues = (firstValue, secondValue) => ({
30379
- isNullish: firstValue.isNullish === secondValue.isNullish ? firstValue.isNullish : null,
30380
- isTruthy: firstValue.isTruthy === secondValue.isTruthy ? firstValue.isTruthy : null
30381
- });
30382
- const readStaticKeyBranchValue = (expression, depth) => {
30383
- if (depth > TYPE_RESOLUTION_DEPTH_LIMIT) return null;
30384
- const node = stripParenExpression(expression);
30385
- if (isNodeOfType(node, "Literal")) return {
30386
- isNullish: node.value === null,
30387
- isTruthy: Boolean(node.value)
30388
- };
30389
- if (isNodeOfType(node, "ArrayExpression") || isNodeOfType(node, "ObjectExpression") || isNodeOfType(node, "ArrowFunctionExpression") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "ClassExpression") || isNodeOfType(node, "NewExpression")) return {
30390
- isNullish: false,
30391
- isTruthy: true
30392
- };
30393
- if (isNodeOfType(node, "TemplateLiteral")) return {
30394
- isNullish: false,
30395
- isTruthy: (node.quasis ?? []).some((quasi) => typeof quasi.value?.cooked === "string" && quasi.value.cooked.length > 0) ? true : null
30396
- };
30397
- if (isNodeOfType(node, "BinaryExpression")) return {
30398
- isNullish: false,
30399
- isTruthy: null
30400
- };
30401
- if (isNodeOfType(node, "Identifier")) {
30402
- const binding = findVariableInitializer(node, node.name);
30403
- if (!binding) {
30404
- if (node.name === "undefined") return {
30405
- isNullish: true,
30406
- isTruthy: false
30407
- };
30408
- if (node.name === "NaN") return {
30409
- isNullish: false,
30410
- isTruthy: false
30411
- };
30412
- if (node.name === "Infinity") return {
30413
- isNullish: false,
30414
- isTruthy: true
30415
- };
30416
- return null;
30417
- }
30418
- if (!isConstDeclaredBinding(binding) || !binding.initializer) return null;
30419
- const declarator = binding.bindingIdentifier.parent;
30420
- if (!declarator || !isNodeOfType(declarator, "VariableDeclarator") || declarator.id !== binding.bindingIdentifier || declarator.init !== binding.initializer) return null;
30421
- return readStaticKeyBranchValue(binding.initializer, depth + 1);
30422
- }
30423
- if (isNodeOfType(node, "CallExpression") && isNodeOfType(node.callee, "Identifier")) {
30424
- if (!Boolean(findVariableInitializer(node.callee, node.callee.name)) && STRING_COERCION_FUNCTIONS.has(node.callee.name)) return {
30425
- isNullish: false,
30426
- isTruthy: null
30427
- };
30428
- }
30429
- if (isNodeOfType(node, "UnaryExpression")) {
30430
- if (node.operator === "void") return {
30431
- isNullish: true,
30432
- isTruthy: false
30433
- };
30434
- if (node.operator === "typeof") return {
30435
- isNullish: false,
30436
- isTruthy: true
30437
- };
30438
- if (node.operator === "+" || node.operator === "-" || node.operator === "~") return {
30439
- isNullish: false,
30440
- isTruthy: null
30441
- };
30442
- if (node.operator !== "!") return null;
30443
- const argumentValue = readStaticKeyBranchValue(node.argument, depth + 1);
30444
- if (!argumentValue || argumentValue.isTruthy === null) return null;
30445
- return {
30446
- isNullish: false,
30447
- isTruthy: !argumentValue.isTruthy
30448
- };
30449
- }
30450
- if (isNodeOfType(node, "SequenceExpression")) {
30451
- const finalExpression = node.expressions.at(-1);
30452
- return finalExpression ? readStaticKeyBranchValue(finalExpression, depth + 1) : null;
30453
- }
30454
- if (isNodeOfType(node, "LogicalExpression")) {
30455
- const leftValue = readStaticKeyBranchValue(node.left, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE;
30456
- if (node.operator === "&&" && leftValue.isTruthy !== null) return leftValue.isTruthy ? readStaticKeyBranchValue(node.right, depth + 1) : leftValue;
30457
- if (node.operator === "||" && leftValue.isTruthy !== null) return leftValue.isTruthy ? leftValue : readStaticKeyBranchValue(node.right, depth + 1);
30458
- if (node.operator === "??" && leftValue.isNullish !== null) return leftValue.isNullish ? readStaticKeyBranchValue(node.right, depth + 1) : leftValue;
30459
- const rightValue = readStaticKeyBranchValue(node.right, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE;
30460
- if (node.operator === "||") return {
30461
- isNullish: rightValue.isNullish === false ? false : null,
30462
- isTruthy: rightValue.isTruthy === true ? true : null
30463
- };
30464
- if (node.operator === "&&") return {
30465
- isNullish: leftValue.isNullish === false && rightValue.isNullish === false ? false : null,
30466
- isTruthy: rightValue.isTruthy === false ? false : null
30467
- };
30468
- return {
30469
- isNullish: rightValue.isNullish === false ? false : null,
30470
- isTruthy: leftValue.isTruthy !== null && leftValue.isTruthy === rightValue.isTruthy ? leftValue.isTruthy : null
30471
- };
30472
- }
30473
- if (isNodeOfType(node, "ConditionalExpression")) {
30474
- const testValue = readStaticKeyBranchValue(node.test, depth + 1);
30475
- if (testValue?.isTruthy !== null && testValue?.isTruthy !== void 0) return readStaticKeyBranchValue(testValue.isTruthy ? node.consequent : node.alternate, depth + 1);
30476
- return mergeStaticKeyBranchValues(readStaticKeyBranchValue(node.consequent, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE, readStaticKeyBranchValue(node.alternate, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE);
30477
- }
30478
- return null;
30479
- };
30480
- const extractCandidateIdentifiers = (expression, depth = 0) => {
30481
- if (depth > TYPE_RESOLUTION_DEPTH_LIMIT) return [];
29815
+ const extractCandidateIdentifiers = (expression) => {
30482
29816
  const node = stripParenExpression(expression);
30483
29817
  if (isNodeOfType(node, "Identifier")) return [node];
30484
- if (isNodeOfType(node, "UnaryExpression") && (node.operator === "-" || node.operator === "+" || node.operator === "~") && node.argument) return extractCandidateIdentifiers(node.argument, depth + 1);
29818
+ if (isNodeOfType(node, "UnaryExpression") && (node.operator === "-" || node.operator === "+" || node.operator === "~") && isNodeOfType(node.argument, "Identifier")) return [node.argument];
30485
29819
  if (isNodeOfType(node, "TemplateLiteral")) {
30486
29820
  const identifiers = [];
30487
- for (const templateExpression of node.expressions ?? []) identifiers.push(...extractCandidateIdentifiers(templateExpression, depth + 1));
29821
+ for (const templateExpression of node.expressions ?? []) if (isNodeOfType(templateExpression, "Identifier")) identifiers.push(templateExpression);
30488
29822
  return identifiers;
30489
29823
  }
30490
- if (isNodeOfType(node, "LogicalExpression")) {
30491
- const leftValue = readStaticKeyBranchValue(node.left, 0);
30492
- if (leftValue) {
30493
- if (node.operator === "&&" && leftValue.isTruthy !== null) return extractCandidateIdentifiers(leftValue.isTruthy ? node.right : node.left, depth + 1);
30494
- if (node.operator === "||" && leftValue.isTruthy !== null) return extractCandidateIdentifiers(leftValue.isTruthy ? node.left : node.right, depth + 1);
30495
- if (node.operator === "??" && leftValue.isNullish !== null) return extractCandidateIdentifiers(leftValue.isNullish ? node.right : node.left, depth + 1);
30496
- }
30497
- return [...extractCandidateIdentifiers(node.left, depth + 1), ...extractCandidateIdentifiers(node.right, depth + 1)];
30498
- }
30499
- if (isNodeOfType(node, "ConditionalExpression")) {
30500
- const testValue = readStaticKeyBranchValue(node.test, 0);
30501
- if (testValue && testValue.isTruthy !== null) return extractCandidateIdentifiers(testValue.isTruthy ? node.consequent : node.alternate, depth + 1);
30502
- return [...extractCandidateIdentifiers(node.consequent, depth + 1), ...extractCandidateIdentifiers(node.alternate, depth + 1)];
30503
- }
30504
- if (isNodeOfType(node, "SequenceExpression")) {
30505
- const finalExpression = node.expressions.at(-1);
30506
- return finalExpression ? extractCandidateIdentifiers(finalExpression, depth + 1) : [];
30507
- }
30508
29824
  if (isNodeOfType(node, "CallExpression")) {
30509
- if (isNodeOfType(node.callee, "MemberExpression") && isNodeOfType(node.callee.property, "Identifier") && node.callee.property.name === "toString") return extractCandidateIdentifiers(node.callee.object, depth + 1);
30510
- if (isNodeOfType(node.callee, "Identifier") && STRING_COERCION_FUNCTIONS.has(node.callee.name) && !findVariableInitializer(node.callee, node.callee.name) && node.arguments?.[0]) return extractCandidateIdentifiers(node.arguments[0], depth + 1);
29825
+ if (isNodeOfType(node.callee, "MemberExpression") && isNodeOfType(node.callee.object, "Identifier") && isNodeOfType(node.callee.property, "Identifier") && node.callee.property.name === "toString") return [node.callee.object];
29826
+ if (isNodeOfType(node.callee, "Identifier") && STRING_COERCION_FUNCTIONS.has(node.callee.name) && isNodeOfType(node.arguments?.[0], "Identifier")) return [node.arguments[0]];
30511
29827
  return [];
30512
29828
  }
30513
29829
  if (isNodeOfType(node, "BinaryExpression")) {
@@ -31561,6 +30877,72 @@ const isReactNativeDependencyName = (dependencyName) => {
31561
30877
  return false;
31562
30878
  };
31563
30879
  //#endregion
30880
+ //#region src/plugin/utils/read-nearest-package-manifest.ts
30881
+ const cachedPackageDirectoryByFilename = /* @__PURE__ */ new Map();
30882
+ const cachedManifestByPackageDirectory = /* @__PURE__ */ new Map();
30883
+ const resetManifestCaches = () => {
30884
+ cachedPackageDirectoryByFilename.clear();
30885
+ cachedManifestByPackageDirectory.clear();
30886
+ };
30887
+ const findNearestPackageDirectory = (filename) => {
30888
+ if (!filename) return null;
30889
+ const fromCache = cachedPackageDirectoryByFilename.get(filename);
30890
+ if (fromCache !== void 0) {
30891
+ if (isProbeRecorderActive()) {
30892
+ let probedDirectory = path.dirname(filename);
30893
+ while (true) {
30894
+ recordExistenceProbe(path.join(probedDirectory, "package.json"));
30895
+ if (probedDirectory === fromCache) break;
30896
+ const parentDirectory = path.dirname(probedDirectory);
30897
+ if (parentDirectory === probedDirectory) break;
30898
+ probedDirectory = parentDirectory;
30899
+ }
30900
+ }
30901
+ return fromCache;
30902
+ }
30903
+ let currentDirectory = path.dirname(filename);
30904
+ while (true) {
30905
+ const candidatePackageJsonPath = path.join(currentDirectory, "package.json");
30906
+ recordExistenceProbe(candidatePackageJsonPath);
30907
+ let hasPackageJson = false;
30908
+ try {
30909
+ hasPackageJson = fs.statSync(candidatePackageJsonPath).isFile();
30910
+ } catch {
30911
+ hasPackageJson = false;
30912
+ }
30913
+ if (hasPackageJson) {
30914
+ cachedPackageDirectoryByFilename.set(filename, currentDirectory);
30915
+ return currentDirectory;
30916
+ }
30917
+ const parentDirectory = path.dirname(currentDirectory);
30918
+ if (parentDirectory === currentDirectory) {
30919
+ cachedPackageDirectoryByFilename.set(filename, null);
30920
+ return null;
30921
+ }
30922
+ currentDirectory = parentDirectory;
30923
+ }
30924
+ };
30925
+ const readNearestPackageManifest = (filename) => {
30926
+ const packageDirectory = findNearestPackageDirectory(filename);
30927
+ if (!packageDirectory) return null;
30928
+ return readPackageManifest(packageDirectory);
30929
+ };
30930
+ const readPackageManifest = (packageDirectory) => {
30931
+ const packageJsonPath = path.join(packageDirectory, "package.json");
30932
+ recordContentProbe(packageJsonPath);
30933
+ const cached = cachedManifestByPackageDirectory.get(packageDirectory);
30934
+ if (cached !== void 0) return cached;
30935
+ let manifest = null;
30936
+ try {
30937
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
30938
+ if (typeof parsed === "object" && parsed !== null) manifest = parsed;
30939
+ } catch {
30940
+ manifest = null;
30941
+ }
30942
+ cachedManifestByPackageDirectory.set(packageDirectory, manifest);
30943
+ return manifest;
30944
+ };
30945
+ //#endregion
31564
30946
  //#region src/plugin/utils/classify-package-platform.ts
31565
30947
  const WEB_FRAMEWORK_DEPENDENCY_NAMES = new Set([
31566
30948
  "next",
@@ -32594,7 +31976,6 @@ const createStateTriggerReachability = ({ analysis, context, effectFunction }) =
32594
31976
  };
32595
31977
  //#endregion
32596
31978
  //#region src/plugin/rules/state-and-effects/no-chain-state-updates.ts
32597
- const APPLICABLE_EFFECT_HOOK_NAMES = new Set(["useEffect", "useLayoutEffect"]);
32598
31979
  const getUseStateDeclarator = (ref) => (ref.resolved?.defs ?? []).map((def) => def.node).find((node) => isNodeOfType(node, "VariableDeclarator") && isNodeOfType(node.id, "ArrayPattern")) ?? null;
32599
31980
  const isDeclaredWithin = (node, container) => {
32600
31981
  let walker = node;
@@ -32646,12 +32027,7 @@ const noChainStateUpdates = defineRule({
32646
32027
  tags: ["test-noise"],
32647
32028
  recommendation: "Set all the related state together in the event handler that starts it, instead of having one useEffect react to a state change and set more state. See https://react.dev/learn/you-might-not-need-an-effect#chains-of-computations",
32648
32029
  create: (context) => ({ CallExpression(node) {
32649
- if (!isReactApiCall(node, APPLICABLE_EFFECT_HOOK_NAMES, context.scopes, {
32650
- allowGlobalReactNamespace: true,
32651
- allowUnboundBareCalls: true,
32652
- resolveConditionalAliases: true,
32653
- resolveNamedAliases: true
32654
- })) return;
32030
+ if (!isUseEffect(node)) return;
32655
32031
  const analysis = getProgramAnalysis(node);
32656
32032
  if (!analysis) return;
32657
32033
  if (hasCleanup(analysis, node)) return;
@@ -42629,7 +42005,7 @@ const getRefBindingProvenance = (analysis, receiver, isReactUseRefCall) => {
42629
42005
  variables
42630
42006
  };
42631
42007
  };
42632
- const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactUseRefCall, isReactUseEffectCall) => {
42008
+ const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactUseRefCall) => {
42633
42009
  const callee = stripParenExpression(callExpression.callee);
42634
42010
  if (!isNodeOfType(callee, "MemberExpression") || getStaticMemberPropertyName(callee) !== "current") return null;
42635
42011
  const bindingProvenance = getRefBindingProvenance(analysis, stripParenExpression(callee.object), isReactUseRefCall);
@@ -42637,9 +42013,7 @@ const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactU
42637
42013
  const { refCall, variables } = bindingProvenance;
42638
42014
  const componentFunction = findEnclosingFunction$1(effectCall);
42639
42015
  if (!componentFunction || !isFunctionLike$1(componentFunction) || !isComponentFunction$1(componentFunction) || !isNodeOfType(componentFunction.body, "BlockStatement")) return null;
42640
- const notificationEffectStatement = getDirectComponentBodyStatement(effectCall, componentFunction.body);
42641
- const notificationEffectRoot = findTransparentExpressionRoot(effectCall);
42642
- if (!notificationEffectStatement || !isNodeOfType(notificationEffectStatement, "ExpressionStatement") || notificationEffectRoot.parent !== notificationEffectStatement || !isReactUseEffectCall(effectCall)) return null;
42016
+ if (!getDirectComponentBodyStatement(effectCall, componentFunction.body)) return null;
42643
42017
  const callbackPropNames = /* @__PURE__ */ new Set();
42644
42018
  const initializer = refCall.arguments?.[0];
42645
42019
  const initializerCallbackName = initializer ? getParentCallbackPropName(analysis, initializer) : null;
@@ -42657,20 +42031,9 @@ const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactU
42657
42031
  const assignment = getRefMemberAssignment(identifier);
42658
42032
  if (!assignment) continue;
42659
42033
  const assignmentStatement = findTransparentExpressionRoot(assignment).parent;
42660
- if (assignment.operator !== "=" || !assignmentStatement || !isNodeOfType(assignmentStatement, "ExpressionStatement")) return null;
42034
+ if (assignment.operator !== "=" || !assignmentStatement || !isNodeOfType(assignmentStatement, "ExpressionStatement") || assignmentStatement.parent !== componentFunction.body) return null;
42661
42035
  const assignedCallbackName = getParentCallbackPropName(analysis, assignment.right);
42662
42036
  if (!assignedCallbackName) return null;
42663
- if (assignmentStatement.parent !== componentFunction.body) {
42664
- if (!initializerCallbackName || assignedCallbackName !== initializerCallbackName) return null;
42665
- const assignmentEffectBody = assignmentStatement.parent;
42666
- if (!assignmentEffectBody || !isNodeOfType(assignmentEffectBody, "BlockStatement")) return null;
42667
- const assignmentEffectFunction = assignmentEffectBody.parent;
42668
- if (!assignmentEffectFunction || !isFunctionLike$1(assignmentEffectFunction) || assignmentEffectFunction.body !== assignmentEffectBody) return null;
42669
- const assignmentEffectCall = findTransparentExpressionRoot(assignmentEffectFunction).parent;
42670
- if (!assignmentEffectCall || !isNodeOfType(assignmentEffectCall, "CallExpression") || !isReactUseEffectCall(assignmentEffectCall) || getEffectFn(analysis, assignmentEffectCall) !== assignmentEffectFunction) return null;
42671
- const assignmentEffectStatement = getDirectComponentBodyStatement(assignmentEffectCall, componentFunction.body);
42672
- if (!assignmentEffectStatement || !isNodeOfType(assignmentEffectStatement, "ExpressionStatement") || assignmentEffectCall.parent !== assignmentEffectStatement || assignmentEffectStatement.range[0] >= notificationEffectStatement.range[0]) return null;
42673
- }
42674
42037
  callbackPropNames.add(assignedCallbackName);
42675
42038
  }
42676
42039
  return callbackPropNames.size > 0 ? { callbackPropNames } : null;
@@ -42883,10 +42246,6 @@ const noPassDataToParent = defineRule({
42883
42246
  allowGlobalReactNamespace: true,
42884
42247
  allowUnboundBareCalls: true
42885
42248
  });
42886
- const isReactUseEffectCall = (node) => isReactApiCall(node, "useEffect", context.scopes, {
42887
- allowGlobalReactNamespace: true,
42888
- allowUnboundBareCalls: true
42889
- });
42890
42249
  return { CallExpression(node) {
42891
42250
  if (!isUseEffect(node)) return;
42892
42251
  const analysis = getProgramAnalysis(node);
@@ -42899,7 +42258,7 @@ const noPassDataToParent = defineRule({
42899
42258
  for (const ref of effectFnRefs) {
42900
42259
  const callExpr = getCallExpr(ref);
42901
42260
  if (!callExpr || !isNodeOfType(callExpr, "CallExpression")) continue;
42902
- const callbackRefProvenance = getCallbackRefProvenance(analysis, node, callExpr, isReactUseRefCall, isReactUseEffectCall);
42261
+ const callbackRefProvenance = getCallbackRefProvenance(analysis, node, callExpr, isReactUseRefCall);
42903
42262
  if (isRefCall(analysis, ref) && !callbackRefProvenance) continue;
42904
42263
  if (!isSynchronous(ref.identifier, effectFn)) continue;
42905
42264
  const calleeNode = unwrapChainExpression(callExpr.callee);
@@ -44461,9 +43820,9 @@ const isInsideComponentContext = (node) => {
44461
43820
  }
44462
43821
  return false;
44463
43822
  };
44464
- const getFunctionFromDeclaration = (node) => {
44465
- if (isFunctionLike$1(node)) return node;
44466
- if (isNodeOfType(node, "VariableDeclarator") && node.init && isFunctionLike$1(node.init)) return node.init;
43823
+ const functionBodyOf = (node) => {
43824
+ if (isFunctionLike$1(node)) return node.body ?? null;
43825
+ if (isNodeOfType(node, "VariableDeclarator") && node.init && isFunctionLike$1(node.init)) return node.init.body ?? null;
44467
43826
  return null;
44468
43827
  };
44469
43828
  const isHookCallee = (callee) => {
@@ -44471,43 +43830,23 @@ const isHookCallee = (callee) => {
44471
43830
  if (isNodeOfType(callee, "MemberExpression") && !callee.computed && isNodeOfType(callee.object, "Identifier") && isUppercaseName(callee.object.name) && isNodeOfType(callee.property, "Identifier")) return isReactHookName(callee.property.name);
44472
43831
  return false;
44473
43832
  };
44474
- const containsReachableHookCall = (functionNode, rootFunction, context, visitedFunctions) => {
44475
- if (!isFunctionLike$1(functionNode) || visitedFunctions.has(functionNode)) return false;
44476
- visitedFunctions.add(functionNode);
44477
- let didFindReachableHook = false;
44478
- walkAst(functionNode.body, (child) => {
44479
- if (didFindReachableHook) return false;
44480
- if (isFunctionLike$1(child) && !executesDuringRender(child, context.scopes)) return false;
44481
- if (!isNodeOfType(child, "CallExpression") && !isNodeOfType(child, "NewExpression")) return;
44482
- if (isNodeOfType(child, "CallExpression")) {
44483
- if (isHookCallee(child.callee)) {
44484
- didFindReachableHook = true;
44485
- return false;
44486
- }
44487
- const calledFunction = resolveExactLocalFunction(child.callee, context.scopes);
44488
- if (calledFunction && isAstDescendant(calledFunction, rootFunction) && containsReachableHookCall(calledFunction, rootFunction, context, visitedFunctions)) {
44489
- didFindReachableHook = true;
44490
- return false;
44491
- }
44492
- }
44493
- for (const callArgument of child.arguments ?? []) {
44494
- if (!executesDuringRender(callArgument, context.scopes)) continue;
44495
- const callbackFunction = resolveExactLocalFunction(callArgument, context.scopes);
44496
- if (callbackFunction && isAstDescendant(callbackFunction, rootFunction) && containsReachableHookCall(callbackFunction, rootFunction, context, visitedFunctions)) {
44497
- didFindReachableHook = true;
44498
- return false;
44499
- }
44500
- }
43833
+ const containsHookCall = (body) => {
43834
+ let found = false;
43835
+ walkAst(body, (child) => {
43836
+ if (found) return false;
43837
+ if (child !== body && isFunctionLike$1(child) && isComponentFunction$1(child)) return false;
43838
+ if (!isNodeOfType(child, "CallExpression")) return;
43839
+ if (isHookCallee(child.callee)) found = true;
44501
43840
  });
44502
- return didFindReachableHook;
43841
+ return found;
44503
43842
  };
44504
- const isHookCallingRenderHelper = (symbol, context) => {
43843
+ const isHookCallingRenderHelper = (symbol) => {
44505
43844
  if (!symbol) return false;
44506
43845
  const declaration = symbol.declarationNode;
44507
43846
  if (!isNodeOfType(declaration, "FunctionDeclaration") && !isNodeOfType(declaration, "VariableDeclarator")) return false;
44508
- const functionNode = getFunctionFromDeclaration(declaration);
44509
- if (!functionNode) return false;
44510
- return containsReachableHookCall(functionNode, functionNode, context, /* @__PURE__ */ new Set());
43847
+ const body = functionBodyOf(declaration);
43848
+ if (!body) return false;
43849
+ return containsHookCall(body);
44511
43850
  };
44512
43851
  const noRenderInRender = defineRule({
44513
43852
  id: "no-render-in-render",
@@ -44522,7 +43861,7 @@ const noRenderInRender = defineRule({
44522
43861
  const calleeName = expression.callee.name;
44523
43862
  if (!RENDER_FUNCTION_PATTERN.test(calleeName)) return;
44524
43863
  if (!isInsideComponentContext(node)) return;
44525
- if (!isHookCallingRenderHelper(context.scopes.symbolFor(expression.callee), context)) return;
43864
+ if (!isHookCallingRenderHelper(context.scopes.symbolFor(expression.callee))) return;
44526
43865
  context.report({
44527
43866
  node: expression,
44528
43867
  message: `"${calleeName}()" hides a component behind an inline call, so pull it into its own component and render it as JSX so React can track it.`
@@ -63505,19 +62844,29 @@ const serverNoMutableModuleState = defineRule({
63505
62844
  });
63506
62845
  //#endregion
63507
62846
  //#region src/plugin/rules/server/server-sequential-independent-await.ts
62847
+ const collectDeclaredNames = (declaration) => {
62848
+ const names = /* @__PURE__ */ new Set();
62849
+ if (!isNodeOfType(declaration, "VariableDeclaration")) return names;
62850
+ for (const declarator of declaration.declarations ?? []) collectPatternNames(declarator.id, names);
62851
+ return names;
62852
+ };
63508
62853
  const declarationStartsWithAwait = (declaration) => {
63509
62854
  if (!isNodeOfType(declaration, "VariableDeclaration")) return false;
63510
62855
  for (const declarator of declaration.declarations ?? []) if (isNodeOfType(declarator.init, "AwaitExpression")) return true;
63511
62856
  return false;
63512
62857
  };
63513
- const declarationReadsAnyPatternBinding = (declaration, patterns, context) => {
63514
- if (patterns.length === 0) return false;
62858
+ const declarationReadsAnyName = (declaration, names) => {
62859
+ if (names.size === 0) return false;
63515
62860
  if (!isNodeOfType(declaration, "VariableDeclaration")) return false;
62861
+ let didRead = false;
63516
62862
  for (const declarator of declaration.declarations ?? []) {
63517
62863
  if (!declarator.init) continue;
63518
- if (expressionReadsPatternBinding(declarator.init, patterns, context.scopes)) return true;
62864
+ walkAst(declarator.init, (child) => {
62865
+ if (didRead) return;
62866
+ if (isNodeOfType(child, "Identifier") && names.has(child.name)) didRead = true;
62867
+ });
63519
62868
  }
63520
- return false;
62869
+ return didRead;
63521
62870
  };
63522
62871
  const GATE_LEADING_VERBS = new Set([
63523
62872
  "require",
@@ -63591,11 +62940,11 @@ const serverSequentialIndependentAwait = defineRule({
63591
62940
  const currentStatement = statements[statementIndex];
63592
62941
  if (!isNodeOfType(currentStatement, "VariableDeclaration")) continue;
63593
62942
  if (!declarationStartsWithAwait(currentStatement)) continue;
63594
- const declaredPatterns = currentStatement.declarations.map((declarator) => declarator.id);
62943
+ const declaredNames = collectDeclaredNames(currentStatement);
63595
62944
  const nextStatement = statements[statementIndex + 1];
63596
62945
  if (!isNodeOfType(nextStatement, "VariableDeclaration")) continue;
63597
62946
  if (!declarationStartsWithAwait(nextStatement)) continue;
63598
- if (declarationReadsAnyPatternBinding(nextStatement, declaredPatterns, context)) continue;
62947
+ if (declarationReadsAnyName(nextStatement, declaredNames)) continue;
63599
62948
  if (declarationAwaitsExistingPromise(nextStatement)) continue;
63600
62949
  if (declarationAwaitsRequestScopedCall(currentStatement) || declarationAwaitsRequestScopedCall(nextStatement)) continue;
63601
62950
  if (declarationAwaitsGate(currentStatement, context)) continue;
@@ -70561,7 +69910,6 @@ const CROSS_FILE_RULE_IDS = new Set([
70561
69910
  "exhaustive-deps",
70562
69911
  "no-barrel-import",
70563
69912
  "nextjs-missing-metadata",
70564
- "nextjs-no-img-element",
70565
69913
  "nextjs-no-use-search-params-without-suspense",
70566
69914
  "no-dynamic-import-path",
70567
69915
  "no-full-lodash-import",
@@ -70793,12 +70141,12 @@ const CROSS_FILE_DEPENDENCY_COLLECTORS = new Map([
70793
70141
  ]);
70794
70142
  /**
70795
70143
  * Cross-file rules whose dependency set CANNOT be soundly bounded — they are
70796
- * excluded from fingerprinting and re-lint every file on every scan. A new
70797
- * cross-file rule must be added either here or to
70144
+ * excluded from fingerprinting and re-lint every file on every scan. Empty
70145
+ * today; a new cross-file rule must be added either here or to
70798
70146
  * `CROSS_FILE_DEPENDENCY_COLLECTORS` (the core guard test enforces the
70799
70147
  * partition), forcing a conscious classification.
70800
70148
  */
70801
- const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["nextjs-no-img-element", "only-export-components"]);
70149
+ const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["only-export-components"]);
70802
70150
  /**
70803
70151
  * Runs the collectors for `ruleIds` over one file and returns every
70804
70152
  * filesystem probe they made — the file's cross-file dependency set.