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