oxlint-plugin-react-doctor 0.7.9-dev.6325f9c → 0.7.9-dev.b30fb80

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.d.ts CHANGED
@@ -18820,8 +18820,8 @@ type CrossFileDependencyCollector = (input: CrossFileDependencyCollectorInput) =
18820
18820
  declare const CROSS_FILE_DEPENDENCY_COLLECTORS: ReadonlyMap<string, CrossFileDependencyCollector>;
18821
18821
  /**
18822
18822
  * Cross-file rules whose dependency set CANNOT be soundly bounded — they are
18823
- * excluded from fingerprinting and re-lint every file on every scan. A new
18824
- * cross-file rule must be added either here or to
18823
+ * excluded from fingerprinting and re-lint every file on every scan. Empty
18824
+ * today; a new cross-file rule must be added either here or to
18825
18825
  * `CROSS_FILE_DEPENDENCY_COLLECTORS` (the core guard test enforces the
18826
18826
  * partition), forcing a conscious classification.
18827
18827
  */
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();
@@ -8234,9 +8200,6 @@ const createMethodMutationAnalysis = (context) => {
8234
8200
  };
8235
8201
  };
8236
8202
  //#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
8203
  //#region src/plugin/utils/collect-function-return-statements.ts
8241
8204
  const collectFunctionReturnStatements = (functionNode) => {
8242
8205
  if (!isFunctionLike$1(functionNode) || !isNodeOfType(functionNode.body, "BlockStatement")) return [];
@@ -26523,489 +26486,6 @@ const hasEmailTemplateImport = (programRoot) => {
26523
26486
  return found;
26524
26487
  };
26525
26488
  //#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
26489
  //#region src/plugin/rules/nextjs/nextjs-no-img-element.ts
27010
26490
  const NON_OPTIMIZABLE_SRC_PREFIX_PATTERN = /^\s*(data:|blob:)/i;
27011
26491
  const GENERATED_URL_NAME_PATTERN = /(data|object|blob)_?url/i;
@@ -27108,20 +26588,9 @@ const nextjsNoImgElement = defineRule({
27108
26588
  recommendation: "Use `next/image` so users get optimized formats, responsive srcsets, and lazy loading instead of oversized image downloads.",
27109
26589
  create: (context) => {
27110
26590
  if (isGeneratedImageRenderContext(context)) return {};
27111
- const generatedImageOwnershipByFunction = /* @__PURE__ */ new WeakMap();
27112
- const isExportedJsxGeneratedImageOwned = createExportedJsxGeneratedImageOwnershipAnalyzer(context);
27113
26591
  return { JSXOpeningElement(node) {
27114
26592
  if (resolveJsxElementType(node) !== "img") return;
27115
26593
  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
26594
  const programRoot = findProgramRoot(node);
27126
26595
  if (programRoot && hasEmailTemplateImport(programRoot)) return;
27127
26596
  const srcAttribute = findJsxAttribute(node.attributes, "src");
@@ -31561,6 +31030,72 @@ const isReactNativeDependencyName = (dependencyName) => {
31561
31030
  return false;
31562
31031
  };
31563
31032
  //#endregion
31033
+ //#region src/plugin/utils/read-nearest-package-manifest.ts
31034
+ const cachedPackageDirectoryByFilename = /* @__PURE__ */ new Map();
31035
+ const cachedManifestByPackageDirectory = /* @__PURE__ */ new Map();
31036
+ const resetManifestCaches = () => {
31037
+ cachedPackageDirectoryByFilename.clear();
31038
+ cachedManifestByPackageDirectory.clear();
31039
+ };
31040
+ const findNearestPackageDirectory = (filename) => {
31041
+ if (!filename) return null;
31042
+ const fromCache = cachedPackageDirectoryByFilename.get(filename);
31043
+ if (fromCache !== void 0) {
31044
+ if (isProbeRecorderActive()) {
31045
+ let probedDirectory = path.dirname(filename);
31046
+ while (true) {
31047
+ recordExistenceProbe(path.join(probedDirectory, "package.json"));
31048
+ if (probedDirectory === fromCache) break;
31049
+ const parentDirectory = path.dirname(probedDirectory);
31050
+ if (parentDirectory === probedDirectory) break;
31051
+ probedDirectory = parentDirectory;
31052
+ }
31053
+ }
31054
+ return fromCache;
31055
+ }
31056
+ let currentDirectory = path.dirname(filename);
31057
+ while (true) {
31058
+ const candidatePackageJsonPath = path.join(currentDirectory, "package.json");
31059
+ recordExistenceProbe(candidatePackageJsonPath);
31060
+ let hasPackageJson = false;
31061
+ try {
31062
+ hasPackageJson = fs.statSync(candidatePackageJsonPath).isFile();
31063
+ } catch {
31064
+ hasPackageJson = false;
31065
+ }
31066
+ if (hasPackageJson) {
31067
+ cachedPackageDirectoryByFilename.set(filename, currentDirectory);
31068
+ return currentDirectory;
31069
+ }
31070
+ const parentDirectory = path.dirname(currentDirectory);
31071
+ if (parentDirectory === currentDirectory) {
31072
+ cachedPackageDirectoryByFilename.set(filename, null);
31073
+ return null;
31074
+ }
31075
+ currentDirectory = parentDirectory;
31076
+ }
31077
+ };
31078
+ const readNearestPackageManifest = (filename) => {
31079
+ const packageDirectory = findNearestPackageDirectory(filename);
31080
+ if (!packageDirectory) return null;
31081
+ return readPackageManifest(packageDirectory);
31082
+ };
31083
+ const readPackageManifest = (packageDirectory) => {
31084
+ const packageJsonPath = path.join(packageDirectory, "package.json");
31085
+ recordContentProbe(packageJsonPath);
31086
+ const cached = cachedManifestByPackageDirectory.get(packageDirectory);
31087
+ if (cached !== void 0) return cached;
31088
+ let manifest = null;
31089
+ try {
31090
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
31091
+ if (typeof parsed === "object" && parsed !== null) manifest = parsed;
31092
+ } catch {
31093
+ manifest = null;
31094
+ }
31095
+ cachedManifestByPackageDirectory.set(packageDirectory, manifest);
31096
+ return manifest;
31097
+ };
31098
+ //#endregion
31564
31099
  //#region src/plugin/utils/classify-package-platform.ts
31565
31100
  const WEB_FRAMEWORK_DEPENDENCY_NAMES = new Set([
31566
31101
  "next",
@@ -70561,7 +70096,6 @@ const CROSS_FILE_RULE_IDS = new Set([
70561
70096
  "exhaustive-deps",
70562
70097
  "no-barrel-import",
70563
70098
  "nextjs-missing-metadata",
70564
- "nextjs-no-img-element",
70565
70099
  "nextjs-no-use-search-params-without-suspense",
70566
70100
  "no-dynamic-import-path",
70567
70101
  "no-full-lodash-import",
@@ -70793,12 +70327,12 @@ const CROSS_FILE_DEPENDENCY_COLLECTORS = new Map([
70793
70327
  ]);
70794
70328
  /**
70795
70329
  * 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
70330
+ * excluded from fingerprinting and re-lint every file on every scan. Empty
70331
+ * today; a new cross-file rule must be added either here or to
70798
70332
  * `CROSS_FILE_DEPENDENCY_COLLECTORS` (the core guard test enforces the
70799
70333
  * partition), forcing a conscious classification.
70800
70334
  */
70801
- const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["nextjs-no-img-element", "only-export-components"]);
70335
+ const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["only-export-components"]);
70802
70336
  /**
70803
70337
  * Runs the collectors for `ruleIds` over one file and returns every
70804
70338
  * filesystem probe they made — the file's cross-file dependency set.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.7.9-dev.6325f9c",
3
+ "version": "0.7.9-dev.b30fb80",
4
4
  "description": "React Doctor rules for oxlint.",
5
5
  "keywords": [
6
6
  "accessibility",