oxlint-plugin-react-doctor 0.7.9-dev.6325f9c → 0.7.9-dev.b30fb80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +127 -593
- 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
|
-
* cross-file rule must be added either here or to
|
|
18823
|
+
* excluded from fingerprinting and re-lint every file on every scan. Empty
|
|
18824
|
+
* today; a new cross-file rule must be added either here or to
|
|
18825
18825
|
* `CROSS_FILE_DEPENDENCY_COLLECTORS` (the core guard test enforces the
|
|
18826
18826
|
* partition), forcing a conscious classification.
|
|
18827
18827
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1819,70 +1819,8 @@ const flattenJsxName$1 = (node) => {
|
|
|
1819
1819
|
return null;
|
|
1820
1820
|
};
|
|
1821
1821
|
//#endregion
|
|
1822
|
-
//#region src/plugin/utils/
|
|
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();
|
|
@@ -8234,9 +8200,6 @@ const createMethodMutationAnalysis = (context) => {
|
|
|
8234
8200
|
};
|
|
8235
8201
|
};
|
|
8236
8202
|
//#endregion
|
|
8237
|
-
//#region src/plugin/utils/is-member-property.ts
|
|
8238
|
-
const isMemberProperty = (node, propertyName) => Boolean(node && isNodeOfType(node, "MemberExpression") && isNodeOfType(node.property, "Identifier") && node.property.name === propertyName);
|
|
8239
|
-
//#endregion
|
|
8240
8203
|
//#region src/plugin/utils/collect-function-return-statements.ts
|
|
8241
8204
|
const collectFunctionReturnStatements = (functionNode) => {
|
|
8242
8205
|
if (!isFunctionLike$1(functionNode) || !isNodeOfType(functionNode.body, "BlockStatement")) return [];
|
|
@@ -26523,489 +26486,6 @@ const hasEmailTemplateImport = (programRoot) => {
|
|
|
26523
26486
|
return found;
|
|
26524
26487
|
};
|
|
26525
26488
|
//#endregion
|
|
26526
|
-
//#region src/plugin/utils/build-generated-image-project-index.ts
|
|
26527
|
-
const GENERATED_IMAGE_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/i;
|
|
26528
|
-
const GENERATED_IMAGE_DECLARATION_FILE_PATTERN = /\.d\.[cm]?[jt]s$/i;
|
|
26529
|
-
const GENERATED_IMAGE_MDX_FILE_PATTERN = /\.mdx$/i;
|
|
26530
|
-
const GENERATED_IMAGE_IGNORED_DIRECTORY_NAMES = new Set([
|
|
26531
|
-
".angular",
|
|
26532
|
-
".astro",
|
|
26533
|
-
".cache",
|
|
26534
|
-
".contentlayer",
|
|
26535
|
-
".docusaurus",
|
|
26536
|
-
".expo",
|
|
26537
|
-
".git",
|
|
26538
|
-
".next",
|
|
26539
|
-
".nuxt",
|
|
26540
|
-
".output",
|
|
26541
|
-
".svelte-kit",
|
|
26542
|
-
".turbo",
|
|
26543
|
-
".vercel",
|
|
26544
|
-
"build",
|
|
26545
|
-
"coverage",
|
|
26546
|
-
"dist",
|
|
26547
|
-
"node_modules",
|
|
26548
|
-
"out",
|
|
26549
|
-
"storybook-static"
|
|
26550
|
-
]);
|
|
26551
|
-
const generatedImageScopeCache = /* @__PURE__ */ new WeakMap();
|
|
26552
|
-
const getGeneratedImageModuleScopes = (programNode) => {
|
|
26553
|
-
const cachedScopes = generatedImageScopeCache.get(programNode);
|
|
26554
|
-
if (cachedScopes) return cachedScopes;
|
|
26555
|
-
const scopes = analyzeScopes(programNode);
|
|
26556
|
-
generatedImageScopeCache.set(programNode, scopes);
|
|
26557
|
-
return scopes;
|
|
26558
|
-
};
|
|
26559
|
-
const listProductionSourceFiles = (rootDirectory) => {
|
|
26560
|
-
const sourceFilePaths = [];
|
|
26561
|
-
const pendingDirectories = [rootDirectory];
|
|
26562
|
-
let hasOpaqueMdxConsumerSurface = false;
|
|
26563
|
-
while (pendingDirectories.length > 0) {
|
|
26564
|
-
const currentDirectory = pendingDirectories.pop();
|
|
26565
|
-
if (!currentDirectory) continue;
|
|
26566
|
-
let entries;
|
|
26567
|
-
try {
|
|
26568
|
-
entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
|
|
26569
|
-
} catch {
|
|
26570
|
-
return null;
|
|
26571
|
-
}
|
|
26572
|
-
for (const entry of entries) {
|
|
26573
|
-
const absolutePath = path.join(currentDirectory, entry.name);
|
|
26574
|
-
const isIgnoredDirectoryName = GENERATED_IMAGE_IGNORED_DIRECTORY_NAMES.has(entry.name) || entry.name.startsWith(".") && entry.name !== ".dumi" && entry.name !== ".storybook";
|
|
26575
|
-
if (entry.isSymbolicLink() && isIgnoredDirectoryName) continue;
|
|
26576
|
-
if (entry.isSymbolicLink()) return null;
|
|
26577
|
-
if (entry.isDirectory()) {
|
|
26578
|
-
if (isIgnoredDirectoryName) continue;
|
|
26579
|
-
pendingDirectories.push(absolutePath);
|
|
26580
|
-
continue;
|
|
26581
|
-
}
|
|
26582
|
-
if (!entry.isFile() || isTestlikeFilename(absolutePath)) continue;
|
|
26583
|
-
if (GENERATED_IMAGE_MDX_FILE_PATTERN.test(entry.name)) {
|
|
26584
|
-
hasOpaqueMdxConsumerSurface = true;
|
|
26585
|
-
continue;
|
|
26586
|
-
}
|
|
26587
|
-
if (!GENERATED_IMAGE_SOURCE_FILE_PATTERN.test(entry.name)) continue;
|
|
26588
|
-
if (GENERATED_IMAGE_DECLARATION_FILE_PATTERN.test(entry.name)) continue;
|
|
26589
|
-
sourceFilePaths.push(normalizeFilename(absolutePath));
|
|
26590
|
-
}
|
|
26591
|
-
}
|
|
26592
|
-
return {
|
|
26593
|
-
sourceFilePaths,
|
|
26594
|
-
hasOpaqueMdxConsumerSurface
|
|
26595
|
-
};
|
|
26596
|
-
};
|
|
26597
|
-
const getRuntimeModuleSource = (node) => {
|
|
26598
|
-
if (isNodeOfType(node, "ImportDeclaration")) {
|
|
26599
|
-
if (isTypeOnlyImport(node)) return null;
|
|
26600
|
-
return typeof node.source.value === "string" ? node.source.value : null;
|
|
26601
|
-
}
|
|
26602
|
-
if (isNodeOfType(node, "ExportNamedDeclaration")) {
|
|
26603
|
-
if (node.exportKind === "type" || isEverySpecifierInlineType(node.specifiers, "ExportSpecifier", "exportKind")) return null;
|
|
26604
|
-
return node.source && typeof node.source.value === "string" ? node.source.value : null;
|
|
26605
|
-
}
|
|
26606
|
-
if (isNodeOfType(node, "ExportAllDeclaration")) {
|
|
26607
|
-
if (node.exportKind === "type") return null;
|
|
26608
|
-
return typeof node.source.value === "string" ? node.source.value : null;
|
|
26609
|
-
}
|
|
26610
|
-
if (isNodeOfType(node, "ImportExpression")) return isNodeOfType(node.source, "Literal") && typeof node.source.value === "string" ? node.source.value : null;
|
|
26611
|
-
if (isNodeOfType(node, "CallExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "require" && node.arguments.length === 1) {
|
|
26612
|
-
const source = node.arguments[0];
|
|
26613
|
-
return source && isNodeOfType(source, "Literal") && typeof source.value === "string" ? source.value : null;
|
|
26614
|
-
}
|
|
26615
|
-
return null;
|
|
26616
|
-
};
|
|
26617
|
-
const indexModuleSources = (module, consumerModulesByFilePath, resolvedSourcePathByNode, unresolvedRuntimeSources) => {
|
|
26618
|
-
walkAst(module.programNode, (node) => {
|
|
26619
|
-
const source = getRuntimeModuleSource(node);
|
|
26620
|
-
if (!source) return;
|
|
26621
|
-
const resolvedSourcePath = resolveModulePath(module.filePath, source);
|
|
26622
|
-
if (!resolvedSourcePath) {
|
|
26623
|
-
unresolvedRuntimeSources.add(source);
|
|
26624
|
-
return;
|
|
26625
|
-
}
|
|
26626
|
-
const normalizedSourcePath = normalizeFilename(resolvedSourcePath);
|
|
26627
|
-
resolvedSourcePathByNode.set(node, normalizedSourcePath);
|
|
26628
|
-
const consumerModules = consumerModulesByFilePath.get(normalizedSourcePath) ?? /* @__PURE__ */ new Set();
|
|
26629
|
-
consumerModules.add(module);
|
|
26630
|
-
consumerModulesByFilePath.set(normalizedSourcePath, consumerModules);
|
|
26631
|
-
});
|
|
26632
|
-
};
|
|
26633
|
-
const buildGeneratedImageProjectIndex = (rootDirectory, currentFilePath, currentProgramNode, currentScopes) => {
|
|
26634
|
-
const productionSourceFiles = listProductionSourceFiles(rootDirectory);
|
|
26635
|
-
if (!productionSourceFiles) return null;
|
|
26636
|
-
const modulesByFilePath = /* @__PURE__ */ new Map();
|
|
26637
|
-
for (const filePath of productionSourceFiles.sourceFilePaths) {
|
|
26638
|
-
if (filePath === currentFilePath) {
|
|
26639
|
-
modulesByFilePath.set(filePath, {
|
|
26640
|
-
filePath,
|
|
26641
|
-
programNode: currentProgramNode,
|
|
26642
|
-
scopes: currentScopes
|
|
26643
|
-
});
|
|
26644
|
-
continue;
|
|
26645
|
-
}
|
|
26646
|
-
const parsedProgram = parseSourceFile(filePath);
|
|
26647
|
-
if (!parsedProgram || !isNodeOfType(parsedProgram, "Program")) return null;
|
|
26648
|
-
modulesByFilePath.set(filePath, {
|
|
26649
|
-
filePath,
|
|
26650
|
-
programNode: parsedProgram,
|
|
26651
|
-
scopes: getGeneratedImageModuleScopes(parsedProgram)
|
|
26652
|
-
});
|
|
26653
|
-
}
|
|
26654
|
-
const consumerModulesByFilePath = /* @__PURE__ */ new Map();
|
|
26655
|
-
const resolvedSourcePathByNode = /* @__PURE__ */ new WeakMap();
|
|
26656
|
-
const unresolvedRuntimeSources = /* @__PURE__ */ new Set();
|
|
26657
|
-
for (const module of modulesByFilePath.values()) indexModuleSources(module, consumerModulesByFilePath, resolvedSourcePathByNode, unresolvedRuntimeSources);
|
|
26658
|
-
return {
|
|
26659
|
-
modulesByFilePath,
|
|
26660
|
-
consumerModulesByFilePath,
|
|
26661
|
-
resolvedSourcePathByNode,
|
|
26662
|
-
unresolvedRuntimeSources,
|
|
26663
|
-
hasOpaqueMdxConsumerSurface: productionSourceFiles.hasOpaqueMdxConsumerSurface
|
|
26664
|
-
};
|
|
26665
|
-
};
|
|
26666
|
-
//#endregion
|
|
26667
|
-
//#region src/plugin/utils/read-nearest-package-manifest.ts
|
|
26668
|
-
const cachedPackageDirectoryByFilename = /* @__PURE__ */ new Map();
|
|
26669
|
-
const cachedManifestByPackageDirectory = /* @__PURE__ */ new Map();
|
|
26670
|
-
const resetManifestCaches = () => {
|
|
26671
|
-
cachedPackageDirectoryByFilename.clear();
|
|
26672
|
-
cachedManifestByPackageDirectory.clear();
|
|
26673
|
-
};
|
|
26674
|
-
const findNearestPackageDirectory = (filename) => {
|
|
26675
|
-
if (!filename) return null;
|
|
26676
|
-
const fromCache = cachedPackageDirectoryByFilename.get(filename);
|
|
26677
|
-
if (fromCache !== void 0) {
|
|
26678
|
-
if (isProbeRecorderActive()) {
|
|
26679
|
-
let probedDirectory = path.dirname(filename);
|
|
26680
|
-
while (true) {
|
|
26681
|
-
recordExistenceProbe(path.join(probedDirectory, "package.json"));
|
|
26682
|
-
if (probedDirectory === fromCache) break;
|
|
26683
|
-
const parentDirectory = path.dirname(probedDirectory);
|
|
26684
|
-
if (parentDirectory === probedDirectory) break;
|
|
26685
|
-
probedDirectory = parentDirectory;
|
|
26686
|
-
}
|
|
26687
|
-
}
|
|
26688
|
-
return fromCache;
|
|
26689
|
-
}
|
|
26690
|
-
let currentDirectory = path.dirname(filename);
|
|
26691
|
-
while (true) {
|
|
26692
|
-
const candidatePackageJsonPath = path.join(currentDirectory, "package.json");
|
|
26693
|
-
recordExistenceProbe(candidatePackageJsonPath);
|
|
26694
|
-
let hasPackageJson = false;
|
|
26695
|
-
try {
|
|
26696
|
-
hasPackageJson = fs.statSync(candidatePackageJsonPath).isFile();
|
|
26697
|
-
} catch {
|
|
26698
|
-
hasPackageJson = false;
|
|
26699
|
-
}
|
|
26700
|
-
if (hasPackageJson) {
|
|
26701
|
-
cachedPackageDirectoryByFilename.set(filename, currentDirectory);
|
|
26702
|
-
return currentDirectory;
|
|
26703
|
-
}
|
|
26704
|
-
const parentDirectory = path.dirname(currentDirectory);
|
|
26705
|
-
if (parentDirectory === currentDirectory) {
|
|
26706
|
-
cachedPackageDirectoryByFilename.set(filename, null);
|
|
26707
|
-
return null;
|
|
26708
|
-
}
|
|
26709
|
-
currentDirectory = parentDirectory;
|
|
26710
|
-
}
|
|
26711
|
-
};
|
|
26712
|
-
const readNearestPackageManifest = (filename) => {
|
|
26713
|
-
const packageDirectory = findNearestPackageDirectory(filename);
|
|
26714
|
-
if (!packageDirectory) return null;
|
|
26715
|
-
return readPackageManifest(packageDirectory);
|
|
26716
|
-
};
|
|
26717
|
-
const readPackageManifest = (packageDirectory) => {
|
|
26718
|
-
const packageJsonPath = path.join(packageDirectory, "package.json");
|
|
26719
|
-
recordContentProbe(packageJsonPath);
|
|
26720
|
-
const cached = cachedManifestByPackageDirectory.get(packageDirectory);
|
|
26721
|
-
if (cached !== void 0) return cached;
|
|
26722
|
-
let manifest = null;
|
|
26723
|
-
try {
|
|
26724
|
-
const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
26725
|
-
if (typeof parsed === "object" && parsed !== null) manifest = parsed;
|
|
26726
|
-
} catch {
|
|
26727
|
-
manifest = null;
|
|
26728
|
-
}
|
|
26729
|
-
cachedManifestByPackageDirectory.set(packageDirectory, manifest);
|
|
26730
|
-
return manifest;
|
|
26731
|
-
};
|
|
26732
|
-
//#endregion
|
|
26733
|
-
//#region src/plugin/utils/is-exported-jsx-owned-by-generated-image-renderers.ts
|
|
26734
|
-
const getExportedSpecifierName = (specifier) => {
|
|
26735
|
-
const exported = specifier.exported;
|
|
26736
|
-
if (isNodeOfType(exported, "Identifier")) return exported.name;
|
|
26737
|
-
return isNodeOfType(exported, "Literal") && typeof exported.value === "string" ? exported.value : null;
|
|
26738
|
-
};
|
|
26739
|
-
const getImportedSpecifierName = (specifier) => {
|
|
26740
|
-
const local = specifier.local;
|
|
26741
|
-
if (isNodeOfType(local, "Identifier")) return local.name;
|
|
26742
|
-
return isNodeOfType(local, "Literal") && typeof local.value === "string" ? local.value : null;
|
|
26743
|
-
};
|
|
26744
|
-
const getImportSpecifierName = (specifier) => {
|
|
26745
|
-
if (isNodeOfType(specifier, "ImportDefaultSpecifier")) return "default";
|
|
26746
|
-
if (!isNodeOfType(specifier, "ImportSpecifier")) return null;
|
|
26747
|
-
const imported = specifier.imported;
|
|
26748
|
-
if (isNodeOfType(imported, "Identifier")) return imported.name;
|
|
26749
|
-
return isNodeOfType(imported, "Literal") && typeof imported.value === "string" ? imported.value : null;
|
|
26750
|
-
};
|
|
26751
|
-
const getDirectFunctionBindingIdentifier = (functionNode) => {
|
|
26752
|
-
if (isNodeOfType(functionNode, "FunctionDeclaration") && isNodeOfType(functionNode.id, "Identifier")) return functionNode.id;
|
|
26753
|
-
const functionValueRoot = findTransparentExpressionRoot(functionNode);
|
|
26754
|
-
const parent = functionValueRoot.parent;
|
|
26755
|
-
return isNodeOfType(parent, "VariableDeclarator") && parent.init === functionValueRoot && isNodeOfType(parent.id, "Identifier") ? parent.id : null;
|
|
26756
|
-
};
|
|
26757
|
-
const getExportNamesForFunction = (programNode, functionNode) => {
|
|
26758
|
-
const functionValueRoot = findTransparentExpressionRoot(functionNode);
|
|
26759
|
-
const bindingName = getDirectFunctionBindingIdentifier(functionNode)?.name ?? null;
|
|
26760
|
-
const exportedNames = /* @__PURE__ */ new Set();
|
|
26761
|
-
for (const statement of programNode.body) {
|
|
26762
|
-
if (isNodeOfType(statement, "ExportDefaultDeclaration")) {
|
|
26763
|
-
if (statement.declaration === functionValueRoot || bindingName && isNodeOfType(statement.declaration, "Identifier") && statement.declaration.name === bindingName) exportedNames.add("default");
|
|
26764
|
-
continue;
|
|
26765
|
-
}
|
|
26766
|
-
if (!isNodeOfType(statement, "ExportNamedDeclaration")) continue;
|
|
26767
|
-
const declaration = statement.declaration;
|
|
26768
|
-
if (declaration === functionValueRoot && bindingName) exportedNames.add(bindingName);
|
|
26769
|
-
if (declaration && isNodeOfType(declaration, "VariableDeclaration")) {
|
|
26770
|
-
for (const declarator of declaration.declarations) if (declarator.init === functionValueRoot && isNodeOfType(declarator.id, "Identifier")) exportedNames.add(declarator.id.name);
|
|
26771
|
-
}
|
|
26772
|
-
if (!bindingName || statement.source) continue;
|
|
26773
|
-
for (const specifier of statement.specifiers) {
|
|
26774
|
-
if (!isNodeOfType(specifier, "ExportSpecifier")) continue;
|
|
26775
|
-
if (getImportedSpecifierName(specifier) !== bindingName) continue;
|
|
26776
|
-
const exportedName = getExportedSpecifierName(specifier);
|
|
26777
|
-
if (exportedName) exportedNames.add(exportedName);
|
|
26778
|
-
}
|
|
26779
|
-
}
|
|
26780
|
-
return [...exportedNames];
|
|
26781
|
-
};
|
|
26782
|
-
const isTransparentGeneratedImageValueFlow = (expression, target) => {
|
|
26783
|
-
let current = findTransparentExpressionRoot(expression);
|
|
26784
|
-
while (current !== target) {
|
|
26785
|
-
const parent = current.parent;
|
|
26786
|
-
if (!parent) return false;
|
|
26787
|
-
if (!((isNodeOfType(parent, "JSXExpressionContainer") || isNodeOfType(parent, "JSXSpreadChild")) && parent.expression === current || (isNodeOfType(parent, "JSXElement") || isNodeOfType(parent, "JSXFragment")) && parent.children.some((child) => child === current) || isNodeOfType(parent, "ConditionalExpression") && (parent.consequent === current || parent.alternate === current) || isNodeOfType(parent, "LogicalExpression") && (parent.left === current || parent.right === current) || isNodeOfType(parent, "ArrayExpression") && parent.elements.some((element) => element === current) || isNodeOfType(parent, "SequenceExpression") && parent.expressions.at(-1) === current || isNodeOfType(parent, "AwaitExpression") && parent.argument === current)) return false;
|
|
26788
|
-
current = findTransparentExpressionRoot(parent);
|
|
26789
|
-
}
|
|
26790
|
-
return true;
|
|
26791
|
-
};
|
|
26792
|
-
const isInsideGeneratedImageRendererArgument = (expression, scopes) => {
|
|
26793
|
-
let cursor = expression;
|
|
26794
|
-
while (cursor?.parent) {
|
|
26795
|
-
const parent = cursor.parent;
|
|
26796
|
-
if (isFunctionLike$1(parent)) return false;
|
|
26797
|
-
if (isNodeOfType(parent, "CallExpression") || isNodeOfType(parent, "NewExpression")) {
|
|
26798
|
-
if (parent.arguments[0] && isTransparentGeneratedImageValueFlow(expression, parent.arguments[0]) && isGeneratedImageRendererCall(parent, scopes)) return true;
|
|
26799
|
-
}
|
|
26800
|
-
cursor = parent;
|
|
26801
|
-
}
|
|
26802
|
-
return false;
|
|
26803
|
-
};
|
|
26804
|
-
const getInvokedExpression = (identifier) => {
|
|
26805
|
-
const referenceExpression = findTransparentExpressionRoot(identifier);
|
|
26806
|
-
const parent = referenceExpression.parent;
|
|
26807
|
-
if (isNodeOfType(parent, "CallExpression") && parent.callee === referenceExpression) return parent;
|
|
26808
|
-
if (isNodeOfType(parent, "TaggedTemplateExpression") && parent.tag === referenceExpression) return parent;
|
|
26809
|
-
if ((isNodeOfType(parent, "JSXOpeningElement") || isNodeOfType(parent, "JSXClosingElement")) && parent.name === identifier) {
|
|
26810
|
-
const element = parent.parent;
|
|
26811
|
-
return isNodeOfType(element, "JSXElement") ? element : null;
|
|
26812
|
-
}
|
|
26813
|
-
return null;
|
|
26814
|
-
};
|
|
26815
|
-
const getForwardingFunction = (expression) => {
|
|
26816
|
-
const enclosingFunction = findEnclosingFunction$1(expression);
|
|
26817
|
-
if (!enclosingFunction) return null;
|
|
26818
|
-
if (isNodeOfType(enclosingFunction, "ArrowFunctionExpression") && !isNodeOfType(enclosingFunction.body, "BlockStatement") && isTransparentGeneratedImageValueFlow(expression, enclosingFunction.body)) return enclosingFunction;
|
|
26819
|
-
let cursor = expression.parent;
|
|
26820
|
-
while (cursor && cursor !== enclosingFunction) {
|
|
26821
|
-
if (isFunctionLike$1(cursor)) return null;
|
|
26822
|
-
if (isNodeOfType(cursor, "ReturnStatement") && cursor.argument && isTransparentGeneratedImageValueFlow(expression, cursor.argument)) return enclosingFunction;
|
|
26823
|
-
cursor = cursor.parent;
|
|
26824
|
-
}
|
|
26825
|
-
return null;
|
|
26826
|
-
};
|
|
26827
|
-
const enqueueExport = (state, filePath, exportedName) => {
|
|
26828
|
-
state.pendingExports.push({
|
|
26829
|
-
filePath: normalizeFilename(filePath),
|
|
26830
|
-
exportedName
|
|
26831
|
-
});
|
|
26832
|
-
};
|
|
26833
|
-
const classifyInvokedExpression = (module, expression, state) => {
|
|
26834
|
-
if (isInsideGeneratedImageRendererArgument(expression, module.scopes)) {
|
|
26835
|
-
state.didReachRenderer = true;
|
|
26836
|
-
return true;
|
|
26837
|
-
}
|
|
26838
|
-
const forwardingFunction = getForwardingFunction(expression);
|
|
26839
|
-
if (!forwardingFunction) return false;
|
|
26840
|
-
const exportedNames = getExportNamesForFunction(module.programNode, forwardingFunction);
|
|
26841
|
-
if (exportedNames.length === 0) return false;
|
|
26842
|
-
for (const exportedName of exportedNames) enqueueExport(state, module.filePath, exportedName);
|
|
26843
|
-
return true;
|
|
26844
|
-
};
|
|
26845
|
-
const classifySymbolReferences = (module, symbol, state, visitedSymbolIds) => {
|
|
26846
|
-
if (visitedSymbolIds.has(symbol.id)) return true;
|
|
26847
|
-
visitedSymbolIds.add(symbol.id);
|
|
26848
|
-
for (const reference of symbol.references) {
|
|
26849
|
-
if (reference.flag !== "read") return false;
|
|
26850
|
-
state.currentExportWasUsed = true;
|
|
26851
|
-
const identifier = reference.identifier;
|
|
26852
|
-
const invokedExpression = getInvokedExpression(identifier);
|
|
26853
|
-
if (invokedExpression) {
|
|
26854
|
-
if (!classifyInvokedExpression(module, invokedExpression, state)) return false;
|
|
26855
|
-
continue;
|
|
26856
|
-
}
|
|
26857
|
-
const parent = identifier.parent;
|
|
26858
|
-
if (isNodeOfType(parent, "ExportSpecifier") && parent.local === identifier) {
|
|
26859
|
-
const exportedName = getExportedSpecifierName(parent);
|
|
26860
|
-
if (!exportedName) return false;
|
|
26861
|
-
enqueueExport(state, module.filePath, exportedName);
|
|
26862
|
-
continue;
|
|
26863
|
-
}
|
|
26864
|
-
if (isNodeOfType(parent, "ExportDefaultDeclaration")) {
|
|
26865
|
-
enqueueExport(state, module.filePath, "default");
|
|
26866
|
-
continue;
|
|
26867
|
-
}
|
|
26868
|
-
if (isNodeOfType(parent, "VariableDeclarator") && parent.init === identifier && isNodeOfType(parent.id, "Identifier") && isNodeOfType(parent.parent, "VariableDeclaration") && parent.parent.kind === "const") {
|
|
26869
|
-
const aliasSymbol = module.scopes.symbolFor(parent.id);
|
|
26870
|
-
if (!aliasSymbol || !classifySymbolReferences(module, aliasSymbol, state, visitedSymbolIds)) return false;
|
|
26871
|
-
continue;
|
|
26872
|
-
}
|
|
26873
|
-
return false;
|
|
26874
|
-
}
|
|
26875
|
-
return true;
|
|
26876
|
-
};
|
|
26877
|
-
const classifyNamespaceImportReferences = (module, symbol, exportedName, state) => {
|
|
26878
|
-
for (const reference of symbol.references) {
|
|
26879
|
-
if (reference.flag !== "read") return false;
|
|
26880
|
-
const identifier = reference.identifier;
|
|
26881
|
-
const parent = identifier.parent;
|
|
26882
|
-
if (!isNodeOfType(parent, "MemberExpression") || parent.object !== identifier) return false;
|
|
26883
|
-
const propertyName = getStaticPropertyName(parent);
|
|
26884
|
-
if (propertyName === null) return false;
|
|
26885
|
-
if (propertyName !== exportedName) continue;
|
|
26886
|
-
state.currentExportWasUsed = true;
|
|
26887
|
-
const invokedExpression = getInvokedExpression(parent);
|
|
26888
|
-
if (!invokedExpression || !classifyInvokedExpression(module, invokedExpression, state)) return false;
|
|
26889
|
-
}
|
|
26890
|
-
return true;
|
|
26891
|
-
};
|
|
26892
|
-
const classifyImportsFromExport = (module, exportIdentity, state) => {
|
|
26893
|
-
for (const statement of module.programNode.body) {
|
|
26894
|
-
if (isNodeOfType(statement, "ImportDeclaration")) {
|
|
26895
|
-
if (state.projectIndex.resolvedSourcePathByNode.get(statement) !== exportIdentity.filePath) continue;
|
|
26896
|
-
if (statement.importKind === "type") continue;
|
|
26897
|
-
for (const specifier of statement.specifiers) {
|
|
26898
|
-
if (isNodeOfType(specifier, "ImportSpecifier") && specifier.importKind === "type") continue;
|
|
26899
|
-
if (isNodeOfType(specifier, "ImportNamespaceSpecifier")) {
|
|
26900
|
-
const namespaceSymbol = module.scopes.symbolFor(specifier.local);
|
|
26901
|
-
if (!namespaceSymbol || !classifyNamespaceImportReferences(module, namespaceSymbol, exportIdentity.exportedName, state)) return false;
|
|
26902
|
-
continue;
|
|
26903
|
-
}
|
|
26904
|
-
if (getImportSpecifierName(specifier) !== exportIdentity.exportedName) continue;
|
|
26905
|
-
const symbol = module.scopes.symbolFor(specifier.local);
|
|
26906
|
-
if (!symbol || !classifySymbolReferences(module, symbol, state, /* @__PURE__ */ new Set())) return false;
|
|
26907
|
-
}
|
|
26908
|
-
continue;
|
|
26909
|
-
}
|
|
26910
|
-
if ((isNodeOfType(statement, "ExportNamedDeclaration") || isNodeOfType(statement, "ExportAllDeclaration")) && statement.source && state.projectIndex.resolvedSourcePathByNode.get(statement) === exportIdentity.filePath) {
|
|
26911
|
-
if (isNodeOfType(statement, "ExportAllDeclaration")) {
|
|
26912
|
-
if (statement.exported) return false;
|
|
26913
|
-
state.currentExportWasUsed = true;
|
|
26914
|
-
enqueueExport(state, module.filePath, exportIdentity.exportedName);
|
|
26915
|
-
continue;
|
|
26916
|
-
}
|
|
26917
|
-
for (const specifier of statement.specifiers) {
|
|
26918
|
-
if (!isNodeOfType(specifier, "ExportSpecifier")) continue;
|
|
26919
|
-
if (getImportedSpecifierName(specifier) !== exportIdentity.exportedName) continue;
|
|
26920
|
-
const exportedName = getExportedSpecifierName(specifier);
|
|
26921
|
-
if (!exportedName) return false;
|
|
26922
|
-
state.currentExportWasUsed = true;
|
|
26923
|
-
enqueueExport(state, module.filePath, exportedName);
|
|
26924
|
-
}
|
|
26925
|
-
}
|
|
26926
|
-
}
|
|
26927
|
-
return true;
|
|
26928
|
-
};
|
|
26929
|
-
const hasOpaqueDynamicImportOfExport = (module, exportIdentity, projectIndex) => {
|
|
26930
|
-
let isOpaque = false;
|
|
26931
|
-
walkAst(module.programNode, (node) => {
|
|
26932
|
-
if (isOpaque) return false;
|
|
26933
|
-
if (isNodeOfType(node, "ImportExpression")) {
|
|
26934
|
-
if (projectIndex.resolvedSourcePathByNode.get(node) === exportIdentity.filePath) {
|
|
26935
|
-
isOpaque = true;
|
|
26936
|
-
return false;
|
|
26937
|
-
}
|
|
26938
|
-
}
|
|
26939
|
-
if (isNodeOfType(node, "CallExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "require" && node.arguments.length === 1) {
|
|
26940
|
-
if (projectIndex.resolvedSourcePathByNode.get(node) === exportIdentity.filePath) {
|
|
26941
|
-
isOpaque = true;
|
|
26942
|
-
return false;
|
|
26943
|
-
}
|
|
26944
|
-
}
|
|
26945
|
-
});
|
|
26946
|
-
return isOpaque;
|
|
26947
|
-
};
|
|
26948
|
-
const classifyLocalExportReferences = (module, exportIdentity, state) => {
|
|
26949
|
-
const exportedValue = findExportedValue(module.programNode, exportIdentity.exportedName);
|
|
26950
|
-
if (!exportedValue || !isFunctionLike$1(exportedValue)) return true;
|
|
26951
|
-
const bindingIdentifier = getDirectFunctionBindingIdentifier(exportedValue);
|
|
26952
|
-
if (!bindingIdentifier) return true;
|
|
26953
|
-
const symbol = module.scopes.symbolFor(bindingIdentifier);
|
|
26954
|
-
return symbol ? classifySymbolReferences(module, symbol, state, /* @__PURE__ */ new Set()) : false;
|
|
26955
|
-
};
|
|
26956
|
-
const hasOpaqueWorkspacePackageConsumer = (projectIndex, exportIdentity) => {
|
|
26957
|
-
const packageName = readNearestPackageManifest(exportIdentity.filePath)?.name;
|
|
26958
|
-
if (typeof packageName !== "string" || packageName.length === 0) return false;
|
|
26959
|
-
for (const unresolvedSource of projectIndex.unresolvedRuntimeSources) if (unresolvedSource === packageName || unresolvedSource.startsWith(`${packageName}/`)) return true;
|
|
26960
|
-
return false;
|
|
26961
|
-
};
|
|
26962
|
-
const createExportedJsxGeneratedImageOwnershipAnalyzer = (context) => {
|
|
26963
|
-
const filename = context.filename ? normalizeFilename(context.filename) : "";
|
|
26964
|
-
const rootDirectorySetting = getReactDoctorStringSetting(context.settings, "rootDirectory");
|
|
26965
|
-
const rootDirectory = rootDirectorySetting ? normalizeFilename(rootDirectorySetting).replace(/\/$/, "") : "";
|
|
26966
|
-
const isFileInsideRoot = Boolean(filename && rootDirectory) && (filename === rootDirectory || filename.startsWith(`${rootDirectory}/`));
|
|
26967
|
-
let projectIndex;
|
|
26968
|
-
return (jsxNode) => {
|
|
26969
|
-
if (!isFileInsideRoot) return false;
|
|
26970
|
-
const programNode = findProgramRoot(jsxNode);
|
|
26971
|
-
const enclosingFunction = findEnclosingFunction$1(jsxNode);
|
|
26972
|
-
if (!programNode || !enclosingFunction) return false;
|
|
26973
|
-
const initialExportNames = getExportNamesForFunction(programNode, enclosingFunction);
|
|
26974
|
-
if (initialExportNames.length === 0) return false;
|
|
26975
|
-
if (projectIndex === void 0) projectIndex = buildGeneratedImageProjectIndex(rootDirectory, filename, programNode, context.scopes);
|
|
26976
|
-
if (!projectIndex || projectIndex.hasOpaqueMdxConsumerSurface) return false;
|
|
26977
|
-
const state = {
|
|
26978
|
-
projectIndex,
|
|
26979
|
-
pendingExports: initialExportNames.map((exportedName) => ({
|
|
26980
|
-
filePath: filename,
|
|
26981
|
-
exportedName
|
|
26982
|
-
})),
|
|
26983
|
-
visitedExportKeys: /* @__PURE__ */ new Set(),
|
|
26984
|
-
currentExportWasUsed: false,
|
|
26985
|
-
didReachRenderer: false
|
|
26986
|
-
};
|
|
26987
|
-
while (state.pendingExports.length > 0) {
|
|
26988
|
-
const exportIdentity = state.pendingExports.pop();
|
|
26989
|
-
if (!exportIdentity) continue;
|
|
26990
|
-
const exportKey = `${exportIdentity.filePath}\0${exportIdentity.exportedName}`;
|
|
26991
|
-
if (state.visitedExportKeys.has(exportKey)) continue;
|
|
26992
|
-
state.visitedExportKeys.add(exportKey);
|
|
26993
|
-
state.currentExportWasUsed = false;
|
|
26994
|
-
if (hasOpaqueWorkspacePackageConsumer(projectIndex, exportIdentity)) return false;
|
|
26995
|
-
const ownerModule = projectIndex.modulesByFilePath.get(exportIdentity.filePath);
|
|
26996
|
-
if (!ownerModule || !classifyLocalExportReferences(ownerModule, exportIdentity, state)) return false;
|
|
26997
|
-
const consumerModules = projectIndex.consumerModulesByFilePath.get(exportIdentity.filePath) ?? [];
|
|
26998
|
-
for (const module of consumerModules) {
|
|
26999
|
-
if (module.filePath === exportIdentity.filePath) continue;
|
|
27000
|
-
if (hasOpaqueDynamicImportOfExport(module, exportIdentity, projectIndex)) return false;
|
|
27001
|
-
if (!classifyImportsFromExport(module, exportIdentity, state)) return false;
|
|
27002
|
-
}
|
|
27003
|
-
if (!state.currentExportWasUsed) return false;
|
|
27004
|
-
}
|
|
27005
|
-
return state.didReachRenderer;
|
|
27006
|
-
};
|
|
27007
|
-
};
|
|
27008
|
-
//#endregion
|
|
27009
26489
|
//#region src/plugin/rules/nextjs/nextjs-no-img-element.ts
|
|
27010
26490
|
const NON_OPTIMIZABLE_SRC_PREFIX_PATTERN = /^\s*(data:|blob:)/i;
|
|
27011
26491
|
const GENERATED_URL_NAME_PATTERN = /(data|object|blob)_?url/i;
|
|
@@ -27108,20 +26588,9 @@ const nextjsNoImgElement = defineRule({
|
|
|
27108
26588
|
recommendation: "Use `next/image` so users get optimized formats, responsive srcsets, and lazy loading instead of oversized image downloads.",
|
|
27109
26589
|
create: (context) => {
|
|
27110
26590
|
if (isGeneratedImageRenderContext(context)) return {};
|
|
27111
|
-
const generatedImageOwnershipByFunction = /* @__PURE__ */ new WeakMap();
|
|
27112
|
-
const isExportedJsxGeneratedImageOwned = createExportedJsxGeneratedImageOwnershipAnalyzer(context);
|
|
27113
26591
|
return { JSXOpeningElement(node) {
|
|
27114
26592
|
if (resolveJsxElementType(node) !== "img") return;
|
|
27115
26593
|
if (isGeneratedImageRenderContext(context, node)) return;
|
|
27116
|
-
const enclosingFunction = findEnclosingFunction$1(node);
|
|
27117
|
-
if (enclosingFunction) {
|
|
27118
|
-
let isGeneratedImageOwned = generatedImageOwnershipByFunction.get(enclosingFunction);
|
|
27119
|
-
if (isGeneratedImageOwned === void 0) {
|
|
27120
|
-
isGeneratedImageOwned = isExportedJsxGeneratedImageOwned(node);
|
|
27121
|
-
generatedImageOwnershipByFunction.set(enclosingFunction, isGeneratedImageOwned);
|
|
27122
|
-
}
|
|
27123
|
-
if (isGeneratedImageOwned) return;
|
|
27124
|
-
}
|
|
27125
26594
|
const programRoot = findProgramRoot(node);
|
|
27126
26595
|
if (programRoot && hasEmailTemplateImport(programRoot)) return;
|
|
27127
26596
|
const srcAttribute = findJsxAttribute(node.attributes, "src");
|
|
@@ -31561,6 +31030,72 @@ const isReactNativeDependencyName = (dependencyName) => {
|
|
|
31561
31030
|
return false;
|
|
31562
31031
|
};
|
|
31563
31032
|
//#endregion
|
|
31033
|
+
//#region src/plugin/utils/read-nearest-package-manifest.ts
|
|
31034
|
+
const cachedPackageDirectoryByFilename = /* @__PURE__ */ new Map();
|
|
31035
|
+
const cachedManifestByPackageDirectory = /* @__PURE__ */ new Map();
|
|
31036
|
+
const resetManifestCaches = () => {
|
|
31037
|
+
cachedPackageDirectoryByFilename.clear();
|
|
31038
|
+
cachedManifestByPackageDirectory.clear();
|
|
31039
|
+
};
|
|
31040
|
+
const findNearestPackageDirectory = (filename) => {
|
|
31041
|
+
if (!filename) return null;
|
|
31042
|
+
const fromCache = cachedPackageDirectoryByFilename.get(filename);
|
|
31043
|
+
if (fromCache !== void 0) {
|
|
31044
|
+
if (isProbeRecorderActive()) {
|
|
31045
|
+
let probedDirectory = path.dirname(filename);
|
|
31046
|
+
while (true) {
|
|
31047
|
+
recordExistenceProbe(path.join(probedDirectory, "package.json"));
|
|
31048
|
+
if (probedDirectory === fromCache) break;
|
|
31049
|
+
const parentDirectory = path.dirname(probedDirectory);
|
|
31050
|
+
if (parentDirectory === probedDirectory) break;
|
|
31051
|
+
probedDirectory = parentDirectory;
|
|
31052
|
+
}
|
|
31053
|
+
}
|
|
31054
|
+
return fromCache;
|
|
31055
|
+
}
|
|
31056
|
+
let currentDirectory = path.dirname(filename);
|
|
31057
|
+
while (true) {
|
|
31058
|
+
const candidatePackageJsonPath = path.join(currentDirectory, "package.json");
|
|
31059
|
+
recordExistenceProbe(candidatePackageJsonPath);
|
|
31060
|
+
let hasPackageJson = false;
|
|
31061
|
+
try {
|
|
31062
|
+
hasPackageJson = fs.statSync(candidatePackageJsonPath).isFile();
|
|
31063
|
+
} catch {
|
|
31064
|
+
hasPackageJson = false;
|
|
31065
|
+
}
|
|
31066
|
+
if (hasPackageJson) {
|
|
31067
|
+
cachedPackageDirectoryByFilename.set(filename, currentDirectory);
|
|
31068
|
+
return currentDirectory;
|
|
31069
|
+
}
|
|
31070
|
+
const parentDirectory = path.dirname(currentDirectory);
|
|
31071
|
+
if (parentDirectory === currentDirectory) {
|
|
31072
|
+
cachedPackageDirectoryByFilename.set(filename, null);
|
|
31073
|
+
return null;
|
|
31074
|
+
}
|
|
31075
|
+
currentDirectory = parentDirectory;
|
|
31076
|
+
}
|
|
31077
|
+
};
|
|
31078
|
+
const readNearestPackageManifest = (filename) => {
|
|
31079
|
+
const packageDirectory = findNearestPackageDirectory(filename);
|
|
31080
|
+
if (!packageDirectory) return null;
|
|
31081
|
+
return readPackageManifest(packageDirectory);
|
|
31082
|
+
};
|
|
31083
|
+
const readPackageManifest = (packageDirectory) => {
|
|
31084
|
+
const packageJsonPath = path.join(packageDirectory, "package.json");
|
|
31085
|
+
recordContentProbe(packageJsonPath);
|
|
31086
|
+
const cached = cachedManifestByPackageDirectory.get(packageDirectory);
|
|
31087
|
+
if (cached !== void 0) return cached;
|
|
31088
|
+
let manifest = null;
|
|
31089
|
+
try {
|
|
31090
|
+
const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
31091
|
+
if (typeof parsed === "object" && parsed !== null) manifest = parsed;
|
|
31092
|
+
} catch {
|
|
31093
|
+
manifest = null;
|
|
31094
|
+
}
|
|
31095
|
+
cachedManifestByPackageDirectory.set(packageDirectory, manifest);
|
|
31096
|
+
return manifest;
|
|
31097
|
+
};
|
|
31098
|
+
//#endregion
|
|
31564
31099
|
//#region src/plugin/utils/classify-package-platform.ts
|
|
31565
31100
|
const WEB_FRAMEWORK_DEPENDENCY_NAMES = new Set([
|
|
31566
31101
|
"next",
|
|
@@ -70561,7 +70096,6 @@ const CROSS_FILE_RULE_IDS = new Set([
|
|
|
70561
70096
|
"exhaustive-deps",
|
|
70562
70097
|
"no-barrel-import",
|
|
70563
70098
|
"nextjs-missing-metadata",
|
|
70564
|
-
"nextjs-no-img-element",
|
|
70565
70099
|
"nextjs-no-use-search-params-without-suspense",
|
|
70566
70100
|
"no-dynamic-import-path",
|
|
70567
70101
|
"no-full-lodash-import",
|
|
@@ -70793,12 +70327,12 @@ const CROSS_FILE_DEPENDENCY_COLLECTORS = new Map([
|
|
|
70793
70327
|
]);
|
|
70794
70328
|
/**
|
|
70795
70329
|
* Cross-file rules whose dependency set CANNOT be soundly bounded — they are
|
|
70796
|
-
* excluded from fingerprinting and re-lint every file on every scan.
|
|
70797
|
-
* cross-file rule must be added either here or to
|
|
70330
|
+
* excluded from fingerprinting and re-lint every file on every scan. Empty
|
|
70331
|
+
* today; a new cross-file rule must be added either here or to
|
|
70798
70332
|
* `CROSS_FILE_DEPENDENCY_COLLECTORS` (the core guard test enforces the
|
|
70799
70333
|
* partition), forcing a conscious classification.
|
|
70800
70334
|
*/
|
|
70801
|
-
const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["
|
|
70335
|
+
const UNBOUNDED_CROSS_FILE_RULE_IDS = new Set(["only-export-components"]);
|
|
70802
70336
|
/**
|
|
70803
70337
|
* Runs the collectors for `ruleIds` over one file and returns every
|
|
70804
70338
|
* filesystem probe they made — the file's cross-file dependency set.
|