oxlint-plugin-react-doctor 0.7.9-dev.61111f1 → 0.7.9-dev.6325f9c
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 +2 -2
- package/dist/index.js +614 -131
- package/package.json +1 -1
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.
|
|
18824
|
-
*
|
|
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
|
|
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,8 +1819,70 @@ const flattenJsxName$1 = (node) => {
|
|
|
1819
1819
|
return null;
|
|
1820
1820
|
};
|
|
1821
1821
|
//#endregion
|
|
1822
|
-
//#region src/plugin/utils/
|
|
1823
|
-
const
|
|
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
|
+
};
|
|
1824
1886
|
//#endregion
|
|
1825
1887
|
//#region src/plugin/constants/nextjs.ts
|
|
1826
1888
|
const NEXTJS_SOURCE_FILE_EXTENSION_GROUP = "(?:tsx?|jsx?|mts|mjs)";
|
|
@@ -1892,42 +1954,22 @@ const isNextjsMetadataImageRouteFilename = (rawFilename) => {
|
|
|
1892
1954
|
const normalizeFilename = (filename) => filename.includes("\\") ? filename.replaceAll("\\", "/") : filename;
|
|
1893
1955
|
//#endregion
|
|
1894
1956
|
//#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];
|
|
1898
1957
|
const generatedImageJsxCache = /* @__PURE__ */ new WeakMap();
|
|
1899
1958
|
const isGeneratedImageRenderFilename = (rawFilename) => {
|
|
1900
1959
|
if (!rawFilename) return false;
|
|
1901
1960
|
return isNextjsMetadataImageRouteFilename(normalizeFilename(rawFilename));
|
|
1902
1961
|
};
|
|
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
|
-
};
|
|
1920
1962
|
const isComponentIdentifierName = (name) => {
|
|
1921
1963
|
const firstCharacter = name[0];
|
|
1922
1964
|
return Boolean(firstCharacter && firstCharacter === firstCharacter.toUpperCase());
|
|
1923
1965
|
};
|
|
1924
1966
|
const isFunctionLike = (node) => Boolean(node && (isNodeOfType(node, "FunctionDeclaration") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "ArrowFunctionExpression")));
|
|
1925
|
-
const markFunctionReturnJsx = (functionNode, programRoot, generatedImageJsxNodes, visitedComponentNames) => {
|
|
1967
|
+
const markFunctionReturnJsx = (functionNode, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames) => {
|
|
1926
1968
|
if (!isFunctionLike(functionNode)) return;
|
|
1927
1969
|
if (isNodeOfType(functionNode, "ArrowFunctionExpression")) {
|
|
1928
1970
|
const body = stripParenExpression(functionNode.body);
|
|
1929
1971
|
if (!isNodeOfType(body, "BlockStatement")) {
|
|
1930
|
-
markGeneratedImageExpression(body, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
1972
|
+
markGeneratedImageExpression(body, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
1931
1973
|
return;
|
|
1932
1974
|
}
|
|
1933
1975
|
}
|
|
@@ -1937,7 +1979,7 @@ const markFunctionReturnJsx = (functionNode, programRoot, generatedImageJsxNodes
|
|
|
1937
1979
|
if (descendantNode !== body && isFunctionLike(descendantNode)) return false;
|
|
1938
1980
|
if (!isNodeOfType(descendantNode, "ReturnStatement")) return;
|
|
1939
1981
|
if (!descendantNode.argument) return;
|
|
1940
|
-
markGeneratedImageExpression(stripParenExpression(descendantNode.argument), programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
1982
|
+
markGeneratedImageExpression(stripParenExpression(descendantNode.argument), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
1941
1983
|
});
|
|
1942
1984
|
};
|
|
1943
1985
|
const hasNormalJsxUsage = (programRoot, componentName, generatedImageJsxNodes) => {
|
|
@@ -1952,7 +1994,7 @@ const hasNormalJsxUsage = (programRoot, componentName, generatedImageJsxNodes) =
|
|
|
1952
1994
|
});
|
|
1953
1995
|
return hasNormalUsage;
|
|
1954
1996
|
};
|
|
1955
|
-
const markComponentRenderJsx = (programRoot, openingElement, generatedImageJsxNodes, visitedComponentNames) => {
|
|
1997
|
+
const markComponentRenderJsx = (programRoot, scopes, openingElement, generatedImageJsxNodes, visitedComponentNames) => {
|
|
1956
1998
|
const tagName = flattenJsxName$1(openingElement.name);
|
|
1957
1999
|
if (!tagName || tagName.includes(".") || !isComponentIdentifierName(tagName)) return;
|
|
1958
2000
|
if (visitedComponentNames.has(tagName)) return;
|
|
@@ -1960,70 +2002,70 @@ const markComponentRenderJsx = (programRoot, openingElement, generatedImageJsxNo
|
|
|
1960
2002
|
const binding = findVariableInitializer(openingElement, tagName);
|
|
1961
2003
|
if (!binding?.initializer) return;
|
|
1962
2004
|
visitedComponentNames.add(tagName);
|
|
1963
|
-
markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2005
|
+
markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
1964
2006
|
};
|
|
1965
|
-
const isInsideGeneratedImageRendererArgument = (node) => {
|
|
2007
|
+
const isInsideGeneratedImageRendererArgument$1 = (node, scopes) => {
|
|
1966
2008
|
let cursor = node.parent;
|
|
1967
2009
|
while (cursor) {
|
|
1968
|
-
if (isGeneratedImageRendererCall(cursor)) return true;
|
|
2010
|
+
if (isGeneratedImageRendererCall(cursor, scopes)) return true;
|
|
1969
2011
|
cursor = cursor.parent ?? null;
|
|
1970
2012
|
}
|
|
1971
2013
|
return false;
|
|
1972
2014
|
};
|
|
1973
|
-
const hasNormalFunctionCallUsage = (programRoot, functionName) => {
|
|
2015
|
+
const hasNormalFunctionCallUsage = (programRoot, functionName, scopes) => {
|
|
1974
2016
|
let hasNormalUsage = false;
|
|
1975
2017
|
walkAst(programRoot, (descendantNode) => {
|
|
1976
2018
|
if (hasNormalUsage) return false;
|
|
1977
2019
|
if (!isNodeOfType(descendantNode, "CallExpression")) return;
|
|
1978
2020
|
if (!isNodeOfType(descendantNode.callee, "Identifier")) return;
|
|
1979
2021
|
if (descendantNode.callee.name !== functionName) return;
|
|
1980
|
-
if (isInsideGeneratedImageRendererArgument(descendantNode)) return;
|
|
2022
|
+
if (isInsideGeneratedImageRendererArgument$1(descendantNode, scopes)) return;
|
|
1981
2023
|
hasNormalUsage = true;
|
|
1982
2024
|
return false;
|
|
1983
2025
|
});
|
|
1984
2026
|
return hasNormalUsage;
|
|
1985
2027
|
};
|
|
1986
|
-
const markJsxSubtree = (node, programRoot, generatedImageJsxNodes, visitedComponentNames) => {
|
|
2028
|
+
const markJsxSubtree = (node, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames) => {
|
|
1987
2029
|
walkAst(node, (descendantNode) => {
|
|
1988
2030
|
if (!isNodeOfType(descendantNode, "JSXOpeningElement")) return;
|
|
1989
2031
|
generatedImageJsxNodes.add(descendantNode);
|
|
1990
|
-
markComponentRenderJsx(programRoot, descendantNode, generatedImageJsxNodes, visitedComponentNames);
|
|
2032
|
+
markComponentRenderJsx(programRoot, scopes, descendantNode, generatedImageJsxNodes, visitedComponentNames);
|
|
1991
2033
|
});
|
|
1992
2034
|
};
|
|
1993
|
-
const markGeneratedImageExpression = (expression, programRoot, generatedImageJsxNodes, visitedComponentNames) => {
|
|
2035
|
+
const markGeneratedImageExpression = (expression, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames) => {
|
|
1994
2036
|
const unwrappedExpression = stripParenExpression(expression);
|
|
1995
2037
|
if (isNodeOfType(unwrappedExpression, "JSXElement") || isNodeOfType(unwrappedExpression, "JSXFragment")) {
|
|
1996
|
-
markJsxSubtree(unwrappedExpression, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2038
|
+
markJsxSubtree(unwrappedExpression, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
1997
2039
|
return;
|
|
1998
2040
|
}
|
|
1999
2041
|
if (isFunctionLike(unwrappedExpression)) {
|
|
2000
|
-
markFunctionReturnJsx(unwrappedExpression, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2042
|
+
markFunctionReturnJsx(unwrappedExpression, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2001
2043
|
return;
|
|
2002
2044
|
}
|
|
2003
2045
|
if (isNodeOfType(unwrappedExpression, "ConditionalExpression")) {
|
|
2004
|
-
markGeneratedImageExpression(unwrappedExpression.consequent, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2005
|
-
markGeneratedImageExpression(unwrappedExpression.alternate, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2046
|
+
markGeneratedImageExpression(unwrappedExpression.consequent, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2047
|
+
markGeneratedImageExpression(unwrappedExpression.alternate, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2006
2048
|
return;
|
|
2007
2049
|
}
|
|
2008
2050
|
if (isNodeOfType(unwrappedExpression, "LogicalExpression")) {
|
|
2009
|
-
markGeneratedImageExpression(unwrappedExpression.left, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2010
|
-
markGeneratedImageExpression(unwrappedExpression.right, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2051
|
+
markGeneratedImageExpression(unwrappedExpression.left, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2052
|
+
markGeneratedImageExpression(unwrappedExpression.right, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2011
2053
|
return;
|
|
2012
2054
|
}
|
|
2013
2055
|
if (isNodeOfType(unwrappedExpression, "CallExpression")) {
|
|
2014
2056
|
const callee = unwrappedExpression.callee;
|
|
2015
2057
|
if (isFunctionLike(callee)) {
|
|
2016
|
-
markFunctionReturnJsx(callee, programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2058
|
+
markFunctionReturnJsx(callee, programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2017
2059
|
return;
|
|
2018
2060
|
}
|
|
2019
2061
|
if (!isNodeOfType(callee, "Identifier")) return;
|
|
2020
2062
|
if (visitedComponentNames.has(callee.name)) return;
|
|
2021
2063
|
if (hasNormalJsxUsage(programRoot, callee.name, generatedImageJsxNodes)) return;
|
|
2022
|
-
if (hasNormalFunctionCallUsage(programRoot, callee.name)) return;
|
|
2064
|
+
if (hasNormalFunctionCallUsage(programRoot, callee.name, scopes)) return;
|
|
2023
2065
|
const binding = findVariableInitializer(callee, callee.name);
|
|
2024
2066
|
if (!binding?.initializer || !isFunctionLike(stripParenExpression(binding.initializer))) return;
|
|
2025
2067
|
visitedComponentNames.add(callee.name);
|
|
2026
|
-
markFunctionReturnJsx(stripParenExpression(binding.initializer), programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2068
|
+
markFunctionReturnJsx(stripParenExpression(binding.initializer), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2027
2069
|
return;
|
|
2028
2070
|
}
|
|
2029
2071
|
if (isNodeOfType(unwrappedExpression, "Identifier")) {
|
|
@@ -2031,16 +2073,17 @@ const markGeneratedImageExpression = (expression, programRoot, generatedImageJsx
|
|
|
2031
2073
|
visitedComponentNames.add(unwrappedExpression.name);
|
|
2032
2074
|
const binding = findVariableInitializer(unwrappedExpression, unwrappedExpression.name);
|
|
2033
2075
|
if (!binding?.initializer) return;
|
|
2034
|
-
markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, generatedImageJsxNodes, visitedComponentNames);
|
|
2076
|
+
markGeneratedImageExpression(stripParenExpression(binding.initializer), programRoot, scopes, generatedImageJsxNodes, visitedComponentNames);
|
|
2035
2077
|
}
|
|
2036
2078
|
};
|
|
2037
|
-
const collectGeneratedImageJsxNodes = (programRoot) => {
|
|
2079
|
+
const collectGeneratedImageJsxNodes = (programRoot, scopes) => {
|
|
2038
2080
|
const cached = generatedImageJsxCache.get(programRoot);
|
|
2039
2081
|
if (cached) return cached;
|
|
2040
2082
|
const generatedImageJsxNodes = /* @__PURE__ */ new WeakSet();
|
|
2041
|
-
if (hasImportFromModules(programRoot,
|
|
2042
|
-
if (!
|
|
2043
|
-
|
|
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());
|
|
2044
2087
|
});
|
|
2045
2088
|
generatedImageJsxCache.set(programRoot, generatedImageJsxNodes);
|
|
2046
2089
|
return generatedImageJsxNodes;
|
|
@@ -2050,7 +2093,7 @@ const isGeneratedImageRenderContext = (context, node) => {
|
|
|
2050
2093
|
if (!node) return false;
|
|
2051
2094
|
const programRoot = findProgramRoot(node);
|
|
2052
2095
|
if (!programRoot) return false;
|
|
2053
|
-
const generatedImageJsxNodes = collectGeneratedImageJsxNodes(programRoot);
|
|
2096
|
+
const generatedImageJsxNodes = collectGeneratedImageJsxNodes(programRoot, context.scopes);
|
|
2054
2097
|
if (generatedImageJsxNodes.has(node)) return true;
|
|
2055
2098
|
if (isNodeOfType(node, "JSXElement")) return generatedImageJsxNodes.has(node.openingElement);
|
|
2056
2099
|
return false;
|
|
@@ -4496,15 +4539,6 @@ const getDestructuredBindingPropertyName = (bindingIdentifier) => {
|
|
|
4496
4539
|
return getStaticPropertyKeyName(property, { allowComputedString: true });
|
|
4497
4540
|
};
|
|
4498
4541
|
//#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
|
|
4508
4542
|
//#region src/plugin/utils/has-static-property-write-before.ts
|
|
4509
4543
|
const equivalentSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
|
|
4510
4544
|
const potentiallyAliasedSymbolsByAnalysis = /* @__PURE__ */ new WeakMap();
|
|
@@ -8200,6 +8234,9 @@ const createMethodMutationAnalysis = (context) => {
|
|
|
8200
8234
|
};
|
|
8201
8235
|
};
|
|
8202
8236
|
//#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
|
|
8203
8240
|
//#region src/plugin/utils/collect-function-return-statements.ts
|
|
8204
8241
|
const collectFunctionReturnStatements = (functionNode) => {
|
|
8205
8242
|
if (!isFunctionLike$1(functionNode) || !isNodeOfType(functionNode.body, "BlockStatement")) return [];
|
|
@@ -26486,6 +26523,489 @@ const hasEmailTemplateImport = (programRoot) => {
|
|
|
26486
26523
|
return found;
|
|
26487
26524
|
};
|
|
26488
26525
|
//#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
|
|
26489
27009
|
//#region src/plugin/rules/nextjs/nextjs-no-img-element.ts
|
|
26490
27010
|
const NON_OPTIMIZABLE_SRC_PREFIX_PATTERN = /^\s*(data:|blob:)/i;
|
|
26491
27011
|
const GENERATED_URL_NAME_PATTERN = /(data|object|blob)_?url/i;
|
|
@@ -26588,9 +27108,20 @@ const nextjsNoImgElement = defineRule({
|
|
|
26588
27108
|
recommendation: "Use `next/image` so users get optimized formats, responsive srcsets, and lazy loading instead of oversized image downloads.",
|
|
26589
27109
|
create: (context) => {
|
|
26590
27110
|
if (isGeneratedImageRenderContext(context)) return {};
|
|
27111
|
+
const generatedImageOwnershipByFunction = /* @__PURE__ */ new WeakMap();
|
|
27112
|
+
const isExportedJsxGeneratedImageOwned = createExportedJsxGeneratedImageOwnershipAnalyzer(context);
|
|
26591
27113
|
return { JSXOpeningElement(node) {
|
|
26592
27114
|
if (resolveJsxElementType(node) !== "img") return;
|
|
26593
27115
|
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
|
+
}
|
|
26594
27125
|
const programRoot = findProgramRoot(node);
|
|
26595
27126
|
if (programRoot && hasEmailTemplateImport(programRoot)) return;
|
|
26596
27127
|
const srcAttribute = findJsxAttribute(node.attributes, "src");
|
|
@@ -31030,72 +31561,6 @@ const isReactNativeDependencyName = (dependencyName) => {
|
|
|
31030
31561
|
return false;
|
|
31031
31562
|
};
|
|
31032
31563
|
//#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
|
|
31099
31564
|
//#region src/plugin/utils/classify-package-platform.ts
|
|
31100
31565
|
const WEB_FRAMEWORK_DEPENDENCY_NAMES = new Set([
|
|
31101
31566
|
"next",
|
|
@@ -42164,7 +42629,7 @@ const getRefBindingProvenance = (analysis, receiver, isReactUseRefCall) => {
|
|
|
42164
42629
|
variables
|
|
42165
42630
|
};
|
|
42166
42631
|
};
|
|
42167
|
-
const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactUseRefCall) => {
|
|
42632
|
+
const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactUseRefCall, isReactUseEffectCall) => {
|
|
42168
42633
|
const callee = stripParenExpression(callExpression.callee);
|
|
42169
42634
|
if (!isNodeOfType(callee, "MemberExpression") || getStaticMemberPropertyName(callee) !== "current") return null;
|
|
42170
42635
|
const bindingProvenance = getRefBindingProvenance(analysis, stripParenExpression(callee.object), isReactUseRefCall);
|
|
@@ -42172,7 +42637,9 @@ const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactU
|
|
|
42172
42637
|
const { refCall, variables } = bindingProvenance;
|
|
42173
42638
|
const componentFunction = findEnclosingFunction$1(effectCall);
|
|
42174
42639
|
if (!componentFunction || !isFunctionLike$1(componentFunction) || !isComponentFunction$1(componentFunction) || !isNodeOfType(componentFunction.body, "BlockStatement")) return null;
|
|
42175
|
-
|
|
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;
|
|
42176
42643
|
const callbackPropNames = /* @__PURE__ */ new Set();
|
|
42177
42644
|
const initializer = refCall.arguments?.[0];
|
|
42178
42645
|
const initializerCallbackName = initializer ? getParentCallbackPropName(analysis, initializer) : null;
|
|
@@ -42190,9 +42657,20 @@ const getCallbackRefProvenance = (analysis, effectCall, callExpression, isReactU
|
|
|
42190
42657
|
const assignment = getRefMemberAssignment(identifier);
|
|
42191
42658
|
if (!assignment) continue;
|
|
42192
42659
|
const assignmentStatement = findTransparentExpressionRoot(assignment).parent;
|
|
42193
|
-
if (assignment.operator !== "=" || !assignmentStatement || !isNodeOfType(assignmentStatement, "ExpressionStatement")
|
|
42660
|
+
if (assignment.operator !== "=" || !assignmentStatement || !isNodeOfType(assignmentStatement, "ExpressionStatement")) return null;
|
|
42194
42661
|
const assignedCallbackName = getParentCallbackPropName(analysis, assignment.right);
|
|
42195
42662
|
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
|
+
}
|
|
42196
42674
|
callbackPropNames.add(assignedCallbackName);
|
|
42197
42675
|
}
|
|
42198
42676
|
return callbackPropNames.size > 0 ? { callbackPropNames } : null;
|
|
@@ -42405,6 +42883,10 @@ const noPassDataToParent = defineRule({
|
|
|
42405
42883
|
allowGlobalReactNamespace: true,
|
|
42406
42884
|
allowUnboundBareCalls: true
|
|
42407
42885
|
});
|
|
42886
|
+
const isReactUseEffectCall = (node) => isReactApiCall(node, "useEffect", context.scopes, {
|
|
42887
|
+
allowGlobalReactNamespace: true,
|
|
42888
|
+
allowUnboundBareCalls: true
|
|
42889
|
+
});
|
|
42408
42890
|
return { CallExpression(node) {
|
|
42409
42891
|
if (!isUseEffect(node)) return;
|
|
42410
42892
|
const analysis = getProgramAnalysis(node);
|
|
@@ -42417,7 +42899,7 @@ const noPassDataToParent = defineRule({
|
|
|
42417
42899
|
for (const ref of effectFnRefs) {
|
|
42418
42900
|
const callExpr = getCallExpr(ref);
|
|
42419
42901
|
if (!callExpr || !isNodeOfType(callExpr, "CallExpression")) continue;
|
|
42420
|
-
const callbackRefProvenance = getCallbackRefProvenance(analysis, node, callExpr, isReactUseRefCall);
|
|
42902
|
+
const callbackRefProvenance = getCallbackRefProvenance(analysis, node, callExpr, isReactUseRefCall, isReactUseEffectCall);
|
|
42421
42903
|
if (isRefCall(analysis, ref) && !callbackRefProvenance) continue;
|
|
42422
42904
|
if (!isSynchronous(ref.identifier, effectFn)) continue;
|
|
42423
42905
|
const calleeNode = unwrapChainExpression(callExpr.callee);
|
|
@@ -70079,6 +70561,7 @@ const CROSS_FILE_RULE_IDS = new Set([
|
|
|
70079
70561
|
"exhaustive-deps",
|
|
70080
70562
|
"no-barrel-import",
|
|
70081
70563
|
"nextjs-missing-metadata",
|
|
70564
|
+
"nextjs-no-img-element",
|
|
70082
70565
|
"nextjs-no-use-search-params-without-suspense",
|
|
70083
70566
|
"no-dynamic-import-path",
|
|
70084
70567
|
"no-full-lodash-import",
|
|
@@ -70310,12 +70793,12 @@ const CROSS_FILE_DEPENDENCY_COLLECTORS = new Map([
|
|
|
70310
70793
|
]);
|
|
70311
70794
|
/**
|
|
70312
70795
|
* Cross-file rules whose dependency set CANNOT be soundly bounded — they are
|
|
70313
|
-
* excluded from fingerprinting and re-lint every file on every scan.
|
|
70314
|
-
*
|
|
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
|
|
70315
70798
|
* `CROSS_FILE_DEPENDENCY_COLLECTORS` (the core guard test enforces the
|
|
70316
70799
|
* partition), forcing a conscious classification.
|
|
70317
70800
|
*/
|
|
70318
|
-
const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["only-export-components"]);
|
|
70801
|
+
const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["nextjs-no-img-element", "only-export-components"]);
|
|
70319
70802
|
/**
|
|
70320
70803
|
* Runs the collectors for `ruleIds` over one file and returns every
|
|
70321
70804
|
* filesystem probe they made — the file's cross-file dependency set.
|