react-doctor 0.9.0-dev.db9d300 → 0.9.1-dev.49c5c1e
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/README.md +2 -0
- package/dist/cli.js +998 -86
- package/dist/index.d.ts +2 -2
- package/dist/index.js +992 -81
- package/dist/lsp.js +995 -83
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7f26fa62-fe0c-5ae0-bc9c-97a0deb50b43")}catch(e){}}();
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as NodeChildProcess from "node:child_process";
|
|
5
5
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -64616,7 +64616,8 @@ var AmbiguousProjectError = class extends Error {
|
|
|
64616
64616
|
}
|
|
64617
64617
|
};
|
|
64618
64618
|
const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
|
|
64619
|
-
const
|
|
64619
|
+
const HTML_FILE_PATTERN = /\.html$/i;
|
|
64620
|
+
const SOURCE_FILE_PATTERN = /\.(?:tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
|
|
64620
64621
|
const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
64621
64622
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
64622
64623
|
const MINIFIED_SNIFF_BYTES = 65536;
|
|
@@ -64994,7 +64995,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
64994
64995
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
64995
64996
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
64996
64997
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
64997
|
-
const CORE_PACKAGE_VERSION = "0.9.
|
|
64998
|
+
const CORE_PACKAGE_VERSION = "0.9.1";
|
|
64998
64999
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
64999
65000
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
65000
65001
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -65379,6 +65380,7 @@ const frameworkMergeRank = (framework) => {
|
|
|
65379
65380
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
65380
65381
|
};
|
|
65381
65382
|
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
65383
|
+
const REACT_COMPILER_RUNTIME_PACKAGES = new Set(["react-compiler-runtime"]);
|
|
65382
65384
|
const NEXT_CONFIG_FILENAMES = [
|
|
65383
65385
|
"next.config.js",
|
|
65384
65386
|
"next.config.mjs",
|
|
@@ -65481,10 +65483,10 @@ const resolveImportedConfigFile = (fromFilePath, moduleSpecifier) => {
|
|
|
65481
65483
|
]).find(isFile) ?? null;
|
|
65482
65484
|
};
|
|
65483
65485
|
const parseConfigSourceFile = (filePath, content) => filePath.endsWith(".json") || Path.basename(filePath) === ".babelrc" ? ts.parseJsonText(filePath, content) : ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
65484
|
-
const getStaticPropertyName$
|
|
65486
|
+
const getStaticPropertyName$2 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
|
|
65485
65487
|
const isCommonJsConfigExportAssignment = (node, sourceFile) => ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && (node.left.getText(sourceFile) === "module.exports" || node.left.getText(sourceFile) === "exports.default");
|
|
65486
65488
|
const hasExportModifier = (node) => ts.canHaveModifiers(node) && Boolean(ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
|
|
65487
|
-
const getRequireModuleSpecifier = (expression) => {
|
|
65489
|
+
const getRequireModuleSpecifier$1 = (expression) => {
|
|
65488
65490
|
if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "require" || expression.arguments.length !== 1) return null;
|
|
65489
65491
|
const moduleSpecifier = expression.arguments[0];
|
|
65490
65492
|
return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
|
|
@@ -65497,7 +65499,7 @@ const hasTopLevelValueBinding = (sourceFile, bindingName) => sourceFile.statemen
|
|
|
65497
65499
|
const namedBindings = importClause?.namedBindings;
|
|
65498
65500
|
return namedBindings ? ts.isNamespaceImport(namedBindings) ? namedBindings.name.text === bindingName : namedBindings.elements.some((element) => element.name.text === bindingName) : false;
|
|
65499
65501
|
}
|
|
65500
|
-
if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) =>
|
|
65502
|
+
if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContainsIdentifier(declaration.name, bindingName));
|
|
65501
65503
|
return (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name?.text === bindingName;
|
|
65502
65504
|
});
|
|
65503
65505
|
const getImportBinding = (sourceFile, bindingName) => {
|
|
@@ -65528,24 +65530,24 @@ const getImportBinding = (sourceFile, bindingName) => {
|
|
|
65528
65530
|
for (const declaration of statement.declarationList.declarations) {
|
|
65529
65531
|
if (!declaration.initializer) continue;
|
|
65530
65532
|
if (ts.isIdentifier(declaration.name) && declaration.name.text === bindingName) {
|
|
65531
|
-
const directModuleSpecifier = getRequireModuleSpecifier(declaration.initializer);
|
|
65533
|
+
const directModuleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
|
|
65532
65534
|
if (directModuleSpecifier) return {
|
|
65533
65535
|
moduleSpecifier: directModuleSpecifier,
|
|
65534
65536
|
exportName: "default",
|
|
65535
65537
|
isNamespace: true
|
|
65536
65538
|
};
|
|
65537
|
-
if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier(declaration.initializer.expression) !== null) return {
|
|
65538
|
-
moduleSpecifier: getRequireModuleSpecifier(declaration.initializer.expression) ?? "",
|
|
65539
|
+
if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier$1(declaration.initializer.expression) !== null) return {
|
|
65540
|
+
moduleSpecifier: getRequireModuleSpecifier$1(declaration.initializer.expression) ?? "",
|
|
65539
65541
|
exportName: declaration.initializer.name.text,
|
|
65540
65542
|
isNamespace: false
|
|
65541
65543
|
};
|
|
65542
65544
|
}
|
|
65543
65545
|
if (!ts.isObjectBindingPattern(declaration.name)) continue;
|
|
65544
65546
|
const bindingElement = declaration.name.elements.find((element) => ts.isIdentifier(element.name) && element.name.text === bindingName);
|
|
65545
|
-
const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
|
|
65547
|
+
const moduleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
|
|
65546
65548
|
if (bindingElement && moduleSpecifier) return {
|
|
65547
65549
|
moduleSpecifier,
|
|
65548
|
-
exportName: bindingElement.propertyName ? getStaticPropertyName$
|
|
65550
|
+
exportName: bindingElement.propertyName ? getStaticPropertyName$2(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
|
|
65549
65551
|
isNamespace: false
|
|
65550
65552
|
};
|
|
65551
65553
|
}
|
|
@@ -65598,6 +65600,48 @@ const getScopedConfigBinding = (identifier) => {
|
|
|
65598
65600
|
};
|
|
65599
65601
|
};
|
|
65600
65602
|
const isCompilerTransformModule = (moduleSpecifier, exportName) => moduleSpecifier === "babel-plugin-react-compiler" && exportName === "default" || moduleSpecifier === "@vitejs/plugin-react" && exportName === "reactCompilerPreset";
|
|
65603
|
+
const NODE_MODULE_SPECIFIERS = new Set(["module", "node:module"]);
|
|
65604
|
+
const isConstantVariableInitializer = (node) => ts.isExpression(node) && ts.isVariableDeclaration(node.parent) && ts.isVariableDeclarationList(node.parent.parent) && Boolean(node.parent.parent.flags & ts.NodeFlags.Const);
|
|
65605
|
+
const isNodeCreateRequireCall = (node, analysis) => {
|
|
65606
|
+
if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertionExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isAwaitExpression(node)) return isNodeCreateRequireCall(node.expression, analysis);
|
|
65607
|
+
if (!ts.isCallExpression(node)) return false;
|
|
65608
|
+
const target = node.expression;
|
|
65609
|
+
if (ts.isIdentifier(target)) {
|
|
65610
|
+
if (analysis.localBindings.has(target.text) || getScopedConfigBinding(target).wasFound) return false;
|
|
65611
|
+
const importBinding = getImportBinding(analysis.sourceFile, target.text);
|
|
65612
|
+
return Boolean(importBinding && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier) && importBinding.exportName === "createRequire");
|
|
65613
|
+
}
|
|
65614
|
+
if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return false;
|
|
65615
|
+
if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "createRequire") return false;
|
|
65616
|
+
const createRequireReceiver = target.expression;
|
|
65617
|
+
if (ts.isCallExpression(createRequireReceiver)) {
|
|
65618
|
+
const requiredModuleSpecifier = getRequireModuleSpecifier$1(createRequireReceiver);
|
|
65619
|
+
if (requiredModuleSpecifier === null || !NODE_MODULE_SPECIFIERS.has(requiredModuleSpecifier) || !ts.isIdentifier(createRequireReceiver.expression)) return false;
|
|
65620
|
+
const requireIdentifier = createRequireReceiver.expression;
|
|
65621
|
+
return !analysis.localBindings.has(requireIdentifier.text) && !getScopedConfigBinding(requireIdentifier).wasFound && !hasTopLevelValueBinding(analysis.sourceFile, requireIdentifier.text);
|
|
65622
|
+
}
|
|
65623
|
+
if (!ts.isIdentifier(createRequireReceiver)) return false;
|
|
65624
|
+
if (analysis.localBindings.has(createRequireReceiver.text) || getScopedConfigBinding(createRequireReceiver).wasFound) return false;
|
|
65625
|
+
const importBinding = getImportBinding(analysis.sourceFile, createRequireReceiver.text);
|
|
65626
|
+
return Boolean(importBinding?.isNamespace && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier));
|
|
65627
|
+
};
|
|
65628
|
+
const getNodeRequireResolveModuleSpecifier = (callExpression, analysis) => {
|
|
65629
|
+
const [moduleSpecifierNode] = callExpression.arguments;
|
|
65630
|
+
if (!moduleSpecifierNode || !ts.isStringLiteralLike(moduleSpecifierNode)) return null;
|
|
65631
|
+
const target = callExpression.expression;
|
|
65632
|
+
if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
|
|
65633
|
+
if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "resolve") return null;
|
|
65634
|
+
if (isNodeCreateRequireCall(target.expression, analysis)) return moduleSpecifierNode.text;
|
|
65635
|
+
if (!ts.isIdentifier(target.expression)) return null;
|
|
65636
|
+
const resolverIdentifier = target.expression;
|
|
65637
|
+
if (analysis.localBindings.has(resolverIdentifier.text)) return null;
|
|
65638
|
+
const scopedBinding = getScopedConfigBinding(resolverIdentifier);
|
|
65639
|
+
const topLevelBinding = scopedBinding.wasFound ? null : getTopLevelBinding(analysis.sourceFile, resolverIdentifier.text);
|
|
65640
|
+
const resolverInitializer = scopedBinding.wasFound ? scopedBinding.initializer : topLevelBinding;
|
|
65641
|
+
if (resolverInitializer === null && !scopedBinding.wasFound && resolverIdentifier.text === "require" && !hasTopLevelValueBinding(analysis.sourceFile, resolverIdentifier.text) && getImportBinding(analysis.sourceFile, resolverIdentifier.text) === null) return moduleSpecifierNode.text;
|
|
65642
|
+
if (!resolverInitializer || !isConstantVariableInitializer(resolverInitializer) || !isNodeCreateRequireCall(resolverInitializer, analysis)) return null;
|
|
65643
|
+
return moduleSpecifierNode.text;
|
|
65644
|
+
};
|
|
65601
65645
|
const getAssignedPropertyInitializer = (identifier, propertyName) => {
|
|
65602
65646
|
let bindingScope = null;
|
|
65603
65647
|
let currentNode = identifier;
|
|
@@ -65706,7 +65750,7 @@ const getReactCompilerFlagState = (expression, analysis) => {
|
|
|
65706
65750
|
}
|
|
65707
65751
|
if (!ts.isObjectLiteralExpression(unwrappedExpression)) return null;
|
|
65708
65752
|
for (const property of [...unwrappedExpression.properties].reverse()) {
|
|
65709
|
-
if (ts.isPropertyAssignment(property) && getStaticPropertyName$
|
|
65753
|
+
if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
|
|
65710
65754
|
if (ts.isShorthandPropertyAssignment(property) && property.name.text === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.name, analysis) };
|
|
65711
65755
|
if (ts.isSpreadAssignment(property)) {
|
|
65712
65756
|
const spreadState = getReactCompilerFlagState(property.expression, analysis);
|
|
@@ -65732,8 +65776,8 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
|
|
|
65732
65776
|
}
|
|
65733
65777
|
if (!ts.isObjectLiteralExpression(resolvedExpression)) return null;
|
|
65734
65778
|
for (const property of [...resolvedExpression.properties].reverse()) {
|
|
65735
|
-
if (ts.isPropertyAssignment(property) && getStaticPropertyName$
|
|
65736
|
-
if (ts.isMethodDeclaration(property) && getStaticPropertyName$
|
|
65779
|
+
if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === propertyName) return property.initializer;
|
|
65780
|
+
if (ts.isMethodDeclaration(property) && getStaticPropertyName$2(property.name) === propertyName) return property;
|
|
65737
65781
|
if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property.name;
|
|
65738
65782
|
if (ts.isSpreadAssignment(property)) {
|
|
65739
65783
|
const spreadProperty = getSelectedObjectProperty(property.expression, propertyName, analysis, visitedExpressions);
|
|
@@ -65764,7 +65808,7 @@ const configExpressionMayDefineProperty = (expression, propertyName, analysis) =
|
|
|
65764
65808
|
return resolvedExpression.properties.some((property) => {
|
|
65765
65809
|
if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
|
|
65766
65810
|
if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
|
|
65767
|
-
const staticPropertyName = getStaticPropertyName$
|
|
65811
|
+
const staticPropertyName = getStaticPropertyName$2(property.name);
|
|
65768
65812
|
return staticPropertyName === null || staticPropertyName === propertyName;
|
|
65769
65813
|
}
|
|
65770
65814
|
return false;
|
|
@@ -65783,7 +65827,7 @@ const getExportedConfigNodes = (sourceFile, exportName) => {
|
|
|
65783
65827
|
continue;
|
|
65784
65828
|
}
|
|
65785
65829
|
if (ts.isExpressionStatement(statement) && isCommonJsConfigExportAssignment(statement.expression, sourceFile) && exportName !== "default" && ts.isObjectLiteralExpression(statement.expression.right)) for (const property of [...statement.expression.right.properties].reverse()) {
|
|
65786
|
-
if (ts.isPropertyAssignment(property) && getStaticPropertyName$
|
|
65830
|
+
if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === exportName) {
|
|
65787
65831
|
exportedNodes.push(property.initializer);
|
|
65788
65832
|
break;
|
|
65789
65833
|
}
|
|
@@ -65913,7 +65957,7 @@ const analyzeConfigCallTarget = (callExpression, analysis, allowCompilerTransfor
|
|
|
65913
65957
|
if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
|
|
65914
65958
|
const propertyName = ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null;
|
|
65915
65959
|
if (propertyName === null) return null;
|
|
65916
|
-
const requiredModuleSpecifier = getRequireModuleSpecifier(target.expression);
|
|
65960
|
+
const requiredModuleSpecifier = getRequireModuleSpecifier$1(target.expression);
|
|
65917
65961
|
if (requiredModuleSpecifier !== null) {
|
|
65918
65962
|
if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
|
|
65919
65963
|
if (!requiredModuleSpecifier.startsWith(".")) return null;
|
|
@@ -65942,10 +65986,10 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
|
|
|
65942
65986
|
const reactCompilerFlagState = excludedPropertyNames?.has("reactCompiler") ? null : getReactCompilerFlagState(node, analysis);
|
|
65943
65987
|
if (reactCompilerFlagState?.isEnabled) return true;
|
|
65944
65988
|
for (const [propertyIndex, property] of node.properties.entries()) if (ts.isPropertyAssignment(property)) {
|
|
65945
|
-
const propertyName = getStaticPropertyName$
|
|
65989
|
+
const propertyName = getStaticPropertyName$2(property.name);
|
|
65946
65990
|
if (propertyName && excludedPropertyNames?.has(propertyName)) continue;
|
|
65947
65991
|
if (propertyName === "reactCompiler") continue;
|
|
65948
|
-
if ((propertyName === "plugins" || propertyName === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, propertyName, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$
|
|
65992
|
+
if ((propertyName === "plugins" || propertyName === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, propertyName, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$2(laterProperty.name) === propertyName)) continue;
|
|
65949
65993
|
const propertyAllowsCompilerTransform = propertyName === "plugins" || propertyName === "presets";
|
|
65950
65994
|
if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer) && property.initializer.text.startsWith(".")) {
|
|
65951
65995
|
const extendedFilePath = resolveImportedConfigFile(analysis.filePath, property.initializer.text);
|
|
@@ -65955,12 +65999,12 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
|
|
|
65955
65999
|
} else if (ts.isShorthandPropertyAssignment(property)) {
|
|
65956
66000
|
if (excludedPropertyNames?.has(property.name.text)) continue;
|
|
65957
66001
|
if (property.name.text === "reactCompiler") continue;
|
|
65958
|
-
if ((property.name.text === "plugins" || property.name.text === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, property.name.text, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$
|
|
66002
|
+
if ((property.name.text === "plugins" || property.name.text === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, property.name.text, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$2(laterProperty.name) === property.name.text)) continue;
|
|
65959
66003
|
const propertyAllowsCompilerTransform = property.name.text === "plugins" || property.name.text === "presets";
|
|
65960
66004
|
if (analyzeConfigNode(property.name, analysis, propertyAllowsCompilerTransform, propertyAllowsCompilerTransform)) return true;
|
|
65961
66005
|
} else if (ts.isSpreadAssignment(property)) {
|
|
65962
66006
|
if (reactCompilerFlagState && getReactCompilerFlagState(property.expression, analysis) !== null) continue;
|
|
65963
|
-
if (node.properties.slice(propertyIndex + 1).some((laterProperty) => (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && (getStaticPropertyName$
|
|
66007
|
+
if (node.properties.slice(propertyIndex + 1).some((laterProperty) => (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && (getStaticPropertyName$2(laterProperty.name) === "plugins" || getStaticPropertyName$2(laterProperty.name) === "presets"))) continue;
|
|
65964
66008
|
if (analyzeConfigNode(property.expression, analysis, allowCompilerTransform, false, excludedPropertyNames)) return true;
|
|
65965
66009
|
}
|
|
65966
66010
|
return false;
|
|
@@ -65973,9 +66017,11 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
|
|
|
65973
66017
|
});
|
|
65974
66018
|
}
|
|
65975
66019
|
if (ts.isCallExpression(node)) {
|
|
66020
|
+
const resolvedModuleSpecifier = getNodeRequireResolveModuleSpecifier(node, analysis);
|
|
66021
|
+
if (resolvedModuleSpecifier !== null) return allowCompilerTransform && isCompilerTransformModule(resolvedModuleSpecifier, "default");
|
|
65976
66022
|
const callTargetResult = analyzeConfigCallTarget(node, analysis, allowCompilerTransform);
|
|
65977
66023
|
if (callTargetResult !== null) return callTargetResult;
|
|
65978
|
-
const directModuleSpecifier = getRequireModuleSpecifier(node);
|
|
66024
|
+
const directModuleSpecifier = getRequireModuleSpecifier$1(node);
|
|
65979
66025
|
const isRequireShadowed = analysis.localBindings.has("require") || ts.isIdentifier(node.expression) && getScopedConfigBinding(node.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require");
|
|
65980
66026
|
if (directModuleSpecifier && isRequireShadowed) return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
|
|
65981
66027
|
if (directModuleSpecifier && !isRequireShadowed) {
|
|
@@ -65997,7 +66043,7 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
|
|
|
65997
66043
|
return analyzeConfigNode(node.expression, analysis, allowCompilerTransform) || node.arguments.some((argument) => analyzeConfigNode(argument, analysis, false));
|
|
65998
66044
|
}
|
|
65999
66045
|
if (ts.isPropertyAccessExpression(node)) {
|
|
66000
|
-
const requiredModuleSpecifier = getRequireModuleSpecifier(node.expression);
|
|
66046
|
+
const requiredModuleSpecifier = getRequireModuleSpecifier$1(node.expression);
|
|
66001
66047
|
if (requiredModuleSpecifier) {
|
|
66002
66048
|
if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
|
|
66003
66049
|
if (requiredModuleSpecifier.startsWith(".")) {
|
|
@@ -66085,7 +66131,7 @@ const hasCompilerConfigurationInAncestors = (directory) => {
|
|
|
66085
66131
|
}
|
|
66086
66132
|
return false;
|
|
66087
66133
|
};
|
|
66088
|
-
const detectReactCompiler = (directory, packageJson) => hasCompilerConfiguration(directory, packageJson) || hasCompilerConfigurationInAncestors(directory);
|
|
66134
|
+
const detectReactCompiler = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_RUNTIME_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_RUNTIME_PACKAGES) || hasCompilerConfiguration(directory, packageJson) || hasCompilerConfigurationInAncestors(directory);
|
|
66089
66135
|
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
66090
66136
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
66091
66137
|
const filePath = Path.join(directory, filename);
|
|
@@ -69334,7 +69380,7 @@ const warn = (message) => {
|
|
|
69334
69380
|
runSync(warn$1(message));
|
|
69335
69381
|
};
|
|
69336
69382
|
const CONFIG_BASENAME = "doctor.config";
|
|
69337
|
-
const CONFIG_EXTENSIONS = [
|
|
69383
|
+
const CONFIG_EXTENSIONS$1 = [
|
|
69338
69384
|
"ts",
|
|
69339
69385
|
"mts",
|
|
69340
69386
|
"cts",
|
|
@@ -69438,7 +69484,7 @@ const loadLegacyConfig = (directory) => {
|
|
|
69438
69484
|
};
|
|
69439
69485
|
const loadConfigFromDirectory = async (directory) => {
|
|
69440
69486
|
let sawBrokenConfigFile = false;
|
|
69441
|
-
for (const extension of CONFIG_EXTENSIONS) {
|
|
69487
|
+
for (const extension of CONFIG_EXTENSIONS$1) {
|
|
69442
69488
|
const filePath = Path.join(directory, `${CONFIG_BASENAME}.${extension}`);
|
|
69443
69489
|
if (!isFile(filePath)) continue;
|
|
69444
69490
|
const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
|
|
@@ -69497,7 +69543,7 @@ const loadConfigWithSource = (rootDirectory) => {
|
|
|
69497
69543
|
return loadPromise;
|
|
69498
69544
|
};
|
|
69499
69545
|
const directoryHasCurrentConfig = (directory) => {
|
|
69500
|
-
for (const extension of CONFIG_EXTENSIONS) if (isFile(Path.join(directory, `${CONFIG_BASENAME}.${extension}`))) return true;
|
|
69546
|
+
for (const extension of CONFIG_EXTENSIONS$1) if (isFile(Path.join(directory, `${CONFIG_BASENAME}.${extension}`))) return true;
|
|
69501
69547
|
return readEmbeddedPackageJsonConfig(directory) !== null;
|
|
69502
69548
|
};
|
|
69503
69549
|
/**
|
|
@@ -70201,6 +70247,321 @@ const buildReactNativeDiagnostic = (input) => ({
|
|
|
70201
70247
|
column: input.column ?? 0,
|
|
70202
70248
|
category: input.category ?? "Correctness"
|
|
70203
70249
|
});
|
|
70250
|
+
const ANDROID_APP_BUILD_FILE_NAMES = ["build.gradle", "build.gradle.kts"];
|
|
70251
|
+
const BUILD_TYPES_BLOCK_PATTERN = /\bbuildTypes\s*\{/g;
|
|
70252
|
+
const RELEASE_STRING_MARKER = "__RD_RELEASE__";
|
|
70253
|
+
const RELEASE_BLOCK_PATTERNS = [/\brelease\s*\{/g, /\b(?:getByName|named)\s*\(\s*(?:["']release["']|__RD_RELEASE__)\s*\)\s*\{/g];
|
|
70254
|
+
const MINIFY_ASSIGNMENT_PATTERN = /\b(?:isMinifyEnabled|minifyEnabled)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
|
|
70255
|
+
const SHRINK_RESOURCES_ASSIGNMENT_PATTERN = /\b(?:isShrinkResources|shrinkResources)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
|
|
70256
|
+
const stripGradleComments = (contents) => {
|
|
70257
|
+
let result = "";
|
|
70258
|
+
let index = 0;
|
|
70259
|
+
let quote = null;
|
|
70260
|
+
while (index < contents.length) {
|
|
70261
|
+
const character = contents[index];
|
|
70262
|
+
const nextCharacter = contents[index + 1];
|
|
70263
|
+
if (quote !== null) {
|
|
70264
|
+
result += character;
|
|
70265
|
+
if (character === "\\") {
|
|
70266
|
+
result += nextCharacter ?? "";
|
|
70267
|
+
index += 2;
|
|
70268
|
+
continue;
|
|
70269
|
+
}
|
|
70270
|
+
if (character === quote) quote = null;
|
|
70271
|
+
index += 1;
|
|
70272
|
+
continue;
|
|
70273
|
+
}
|
|
70274
|
+
if (character === "\"" || character === "'") {
|
|
70275
|
+
quote = character;
|
|
70276
|
+
result += character;
|
|
70277
|
+
index += 1;
|
|
70278
|
+
continue;
|
|
70279
|
+
}
|
|
70280
|
+
if (character === "/" && nextCharacter === "/") {
|
|
70281
|
+
while (index < contents.length && contents[index] !== "\n") {
|
|
70282
|
+
result += " ";
|
|
70283
|
+
index += 1;
|
|
70284
|
+
}
|
|
70285
|
+
continue;
|
|
70286
|
+
}
|
|
70287
|
+
if (character === "/" && nextCharacter === "*") {
|
|
70288
|
+
result += " ";
|
|
70289
|
+
index += 2;
|
|
70290
|
+
while (index < contents.length && !(contents[index] === "*" && contents[index + 1] === "/")) {
|
|
70291
|
+
result += contents[index] === "\n" ? "\n" : " ";
|
|
70292
|
+
index += 1;
|
|
70293
|
+
}
|
|
70294
|
+
if (index < contents.length) {
|
|
70295
|
+
result += " ";
|
|
70296
|
+
index += 2;
|
|
70297
|
+
}
|
|
70298
|
+
continue;
|
|
70299
|
+
}
|
|
70300
|
+
result += character;
|
|
70301
|
+
index += 1;
|
|
70302
|
+
}
|
|
70303
|
+
return result;
|
|
70304
|
+
};
|
|
70305
|
+
const maskGradleStrings = (contents) => {
|
|
70306
|
+
let result = "";
|
|
70307
|
+
let index = 0;
|
|
70308
|
+
let quote = null;
|
|
70309
|
+
while (index < contents.length) {
|
|
70310
|
+
const character = contents[index];
|
|
70311
|
+
if (quote === null) {
|
|
70312
|
+
if (character === "\"" || character === "'") {
|
|
70313
|
+
quote = character;
|
|
70314
|
+
result += " ";
|
|
70315
|
+
} else result += character;
|
|
70316
|
+
index += 1;
|
|
70317
|
+
continue;
|
|
70318
|
+
}
|
|
70319
|
+
if (character === "\\") {
|
|
70320
|
+
result += " ";
|
|
70321
|
+
index += 2;
|
|
70322
|
+
continue;
|
|
70323
|
+
}
|
|
70324
|
+
if (character === quote) quote = null;
|
|
70325
|
+
result += character === "\n" ? "\n" : " ";
|
|
70326
|
+
index += 1;
|
|
70327
|
+
}
|
|
70328
|
+
return result;
|
|
70329
|
+
};
|
|
70330
|
+
const findBlockContents = (contents, pattern) => {
|
|
70331
|
+
const blocks = [];
|
|
70332
|
+
pattern.lastIndex = 0;
|
|
70333
|
+
let match = pattern.exec(contents);
|
|
70334
|
+
while (match !== null) {
|
|
70335
|
+
const openingBraceIndex = pattern.lastIndex - 1;
|
|
70336
|
+
let depth = 1;
|
|
70337
|
+
let index = openingBraceIndex + 1;
|
|
70338
|
+
let quote = null;
|
|
70339
|
+
while (index < contents.length && depth > 0) {
|
|
70340
|
+
const character = contents[index];
|
|
70341
|
+
if (quote !== null) {
|
|
70342
|
+
if (character === "\\") {
|
|
70343
|
+
index += 2;
|
|
70344
|
+
continue;
|
|
70345
|
+
}
|
|
70346
|
+
if (character === quote) quote = null;
|
|
70347
|
+
} else if (character === "\"" || character === "'") quote = character;
|
|
70348
|
+
else if (character === "{") depth += 1;
|
|
70349
|
+
else if (character === "}") depth -= 1;
|
|
70350
|
+
index += 1;
|
|
70351
|
+
}
|
|
70352
|
+
if (depth === 0) blocks.push(contents.slice(openingBraceIndex + 1, index - 1));
|
|
70353
|
+
match = pattern.exec(contents);
|
|
70354
|
+
}
|
|
70355
|
+
return blocks;
|
|
70356
|
+
};
|
|
70357
|
+
const getFinalStaticBoolean = (contents, pattern) => {
|
|
70358
|
+
pattern.lastIndex = 0;
|
|
70359
|
+
let finalValue = null;
|
|
70360
|
+
let match = pattern.exec(contents);
|
|
70361
|
+
while (match !== null) {
|
|
70362
|
+
const staticValue = match[1]?.trim().replace(/\)$/, "").trim();
|
|
70363
|
+
if (staticValue === "true") finalValue = true;
|
|
70364
|
+
else if (staticValue === "false") finalValue = false;
|
|
70365
|
+
else finalValue = null;
|
|
70366
|
+
match = pattern.exec(contents);
|
|
70367
|
+
}
|
|
70368
|
+
return finalValue;
|
|
70369
|
+
};
|
|
70370
|
+
const getReleaseBlocks = (contents) => findBlockContents(contents, BUILD_TYPES_BLOCK_PATTERN).flatMap((buildTypesBlock) => RELEASE_BLOCK_PATTERNS.flatMap((pattern) => findBlockContents(buildTypesBlock, pattern)));
|
|
70371
|
+
const readAndroidReleaseShrinking = (rootDirectory) => {
|
|
70372
|
+
for (const buildFileName of ANDROID_APP_BUILD_FILE_NAMES) {
|
|
70373
|
+
const filePath = Path.posix.join("android", "app", buildFileName);
|
|
70374
|
+
const absoluteFilePath = Path.join(rootDirectory, filePath);
|
|
70375
|
+
if (!isFile(absoluteFilePath)) continue;
|
|
70376
|
+
let contents;
|
|
70377
|
+
try {
|
|
70378
|
+
contents = stripGradleComments(NFS.readFileSync(absoluteFilePath, "utf-8"));
|
|
70379
|
+
} catch {
|
|
70380
|
+
return null;
|
|
70381
|
+
}
|
|
70382
|
+
const releaseBlocks = getReleaseBlocks(maskGradleStrings(contents.replace(/(["'])release\1/g, RELEASE_STRING_MARKER)));
|
|
70383
|
+
const [releaseBlock] = releaseBlocks;
|
|
70384
|
+
if (releaseBlock === void 0 || releaseBlocks.length !== 1) return null;
|
|
70385
|
+
const hasDisabledMinification = getFinalStaticBoolean(releaseBlock, MINIFY_ASSIGNMENT_PATTERN) === false;
|
|
70386
|
+
const hasDisabledResourceShrinking = getFinalStaticBoolean(releaseBlock, SHRINK_RESOURCES_ASSIGNMENT_PATTERN) === false;
|
|
70387
|
+
if (!hasDisabledMinification && !hasDisabledResourceShrinking) return null;
|
|
70388
|
+
return {
|
|
70389
|
+
filePath,
|
|
70390
|
+
hasDisabledMinification,
|
|
70391
|
+
hasDisabledResourceShrinking
|
|
70392
|
+
};
|
|
70393
|
+
}
|
|
70394
|
+
return null;
|
|
70395
|
+
};
|
|
70396
|
+
const checkReactNativeAndroidReleaseShrinking = (rootDirectory) => {
|
|
70397
|
+
const releaseShrinking = readAndroidReleaseShrinking(rootDirectory);
|
|
70398
|
+
if (releaseShrinking === null) return [];
|
|
70399
|
+
const disabledFeatures = [releaseShrinking.hasDisabledMinification ? "code minification" : null, releaseShrinking.hasDisabledResourceShrinking ? "resource shrinking" : null].filter((feature) => feature !== null);
|
|
70400
|
+
return [buildReactNativeDiagnostic({
|
|
70401
|
+
filePath: releaseShrinking.filePath,
|
|
70402
|
+
rule: "rn-android-release-shrinking-disabled",
|
|
70403
|
+
category: "Performance",
|
|
70404
|
+
message: `The Android release build explicitly disables ${disabledFeatures.join(" and ")}, leaving unreachable code or resources in the shipped app.`,
|
|
70405
|
+
help: "Enable release code minification and resource shrinking, then test the optimized build and add keep rules for libraries that require them."
|
|
70406
|
+
})];
|
|
70407
|
+
};
|
|
70408
|
+
const getTypescriptScriptKind = (fileName) => {
|
|
70409
|
+
if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
|
|
70410
|
+
if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
|
|
70411
|
+
if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
|
|
70412
|
+
return ts.ScriptKind.JS;
|
|
70413
|
+
};
|
|
70414
|
+
const unwrapTypescriptExpression = (expression) => {
|
|
70415
|
+
let currentExpression = expression;
|
|
70416
|
+
while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
|
|
70417
|
+
return currentExpression;
|
|
70418
|
+
};
|
|
70419
|
+
const BABEL_CONFIG_FILE_NAMES$1 = [
|
|
70420
|
+
"babel.config.js",
|
|
70421
|
+
"babel.config.cjs",
|
|
70422
|
+
"babel.config.mjs",
|
|
70423
|
+
"babel.config.ts",
|
|
70424
|
+
"babel.config.cts",
|
|
70425
|
+
"babel.config.json",
|
|
70426
|
+
".babelrc",
|
|
70427
|
+
".babelrc.js",
|
|
70428
|
+
".babelrc.cjs",
|
|
70429
|
+
".babelrc.mjs",
|
|
70430
|
+
".babelrc.cts",
|
|
70431
|
+
".babelrc.json"
|
|
70432
|
+
];
|
|
70433
|
+
const readUnknownPluginNames = (value) => {
|
|
70434
|
+
if (!Array.isArray(value)) return null;
|
|
70435
|
+
const pluginNames = [];
|
|
70436
|
+
for (const entry of value) {
|
|
70437
|
+
if (typeof entry === "string") {
|
|
70438
|
+
pluginNames.push(entry);
|
|
70439
|
+
continue;
|
|
70440
|
+
}
|
|
70441
|
+
if (Array.isArray(entry) && typeof entry[0] === "string") {
|
|
70442
|
+
pluginNames.push(entry[0]);
|
|
70443
|
+
continue;
|
|
70444
|
+
}
|
|
70445
|
+
return null;
|
|
70446
|
+
}
|
|
70447
|
+
return pluginNames;
|
|
70448
|
+
};
|
|
70449
|
+
const getStaticPropertyName$1 = (propertyName) => {
|
|
70450
|
+
if (ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName)) return propertyName.text;
|
|
70451
|
+
return null;
|
|
70452
|
+
};
|
|
70453
|
+
const getStaticPluginName = (expression) => {
|
|
70454
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
70455
|
+
if (ts.isStringLiteralLike(unwrappedExpression)) return unwrappedExpression.text;
|
|
70456
|
+
if (!ts.isArrayLiteralExpression(unwrappedExpression)) return null;
|
|
70457
|
+
const pluginExpression = unwrappedExpression.elements[0];
|
|
70458
|
+
return pluginExpression && ts.isStringLiteralLike(pluginExpression) ? pluginExpression.text : null;
|
|
70459
|
+
};
|
|
70460
|
+
const getPluginNamesFromObject = (objectExpression) => {
|
|
70461
|
+
if (objectExpression.properties.some((property) => ts.isSpreadAssignment(property))) return null;
|
|
70462
|
+
const pluginProperties = objectExpression.properties.filter((property) => ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === "plugins");
|
|
70463
|
+
if (pluginProperties.length !== 1) return pluginProperties.length === 0 ? [] : null;
|
|
70464
|
+
const pluginListExpression = unwrapTypescriptExpression(pluginProperties[0].initializer);
|
|
70465
|
+
if (!ts.isArrayLiteralExpression(pluginListExpression)) return null;
|
|
70466
|
+
const pluginNames = [];
|
|
70467
|
+
for (const element of pluginListExpression.elements) {
|
|
70468
|
+
if (ts.isSpreadElement(element)) return null;
|
|
70469
|
+
const pluginName = getStaticPluginName(element);
|
|
70470
|
+
if (pluginName === null) return null;
|
|
70471
|
+
pluginNames.push(pluginName);
|
|
70472
|
+
}
|
|
70473
|
+
return pluginNames;
|
|
70474
|
+
};
|
|
70475
|
+
const isModuleExports = (expression) => ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "module" && expression.name.text === "exports" || ts.isElementAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "module" && expression.argumentExpression !== void 0 && ts.isStringLiteralLike(expression.argumentExpression) && expression.argumentExpression.text === "exports";
|
|
70476
|
+
const getDirectExportedObject = (sourceFile) => {
|
|
70477
|
+
const exportedExpressions = [];
|
|
70478
|
+
for (const statement of sourceFile.statements) {
|
|
70479
|
+
if (ts.isExportAssignment(statement)) {
|
|
70480
|
+
exportedExpressions.push(statement.expression);
|
|
70481
|
+
continue;
|
|
70482
|
+
}
|
|
70483
|
+
if (ts.isExpressionStatement(statement) && ts.isBinaryExpression(statement.expression) && statement.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken && isModuleExports(statement.expression.left)) exportedExpressions.push(statement.expression.right);
|
|
70484
|
+
}
|
|
70485
|
+
if (exportedExpressions.length !== 1) return null;
|
|
70486
|
+
const exportedExpression = unwrapTypescriptExpression(exportedExpressions[0]);
|
|
70487
|
+
return ts.isObjectLiteralExpression(exportedExpression) ? exportedExpression : null;
|
|
70488
|
+
};
|
|
70489
|
+
const parseConfigPluginNames = (filePath, contents) => {
|
|
70490
|
+
try {
|
|
70491
|
+
const parsedJson = JSON.parse(contents);
|
|
70492
|
+
return isPlainObject(parsedJson) ? readUnknownPluginNames(parsedJson.plugins) : null;
|
|
70493
|
+
} catch {
|
|
70494
|
+
if (ts.transpileModule(contents, {
|
|
70495
|
+
fileName: filePath,
|
|
70496
|
+
reportDiagnostics: true,
|
|
70497
|
+
compilerOptions: { allowJs: true }
|
|
70498
|
+
}).diagnostics?.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) return null;
|
|
70499
|
+
const exportedObject = getDirectExportedObject(ts.createSourceFile(filePath, contents, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(filePath)));
|
|
70500
|
+
return exportedObject === null ? null : getPluginNamesFromObject(exportedObject);
|
|
70501
|
+
}
|
|
70502
|
+
};
|
|
70503
|
+
const readStaticBabelPluginNames = (rootDirectory) => {
|
|
70504
|
+
for (const fileName of BABEL_CONFIG_FILE_NAMES$1) {
|
|
70505
|
+
const absoluteFilePath = Path.join(rootDirectory, fileName);
|
|
70506
|
+
if (!isFile(absoluteFilePath)) continue;
|
|
70507
|
+
try {
|
|
70508
|
+
return {
|
|
70509
|
+
filePath: fileName,
|
|
70510
|
+
pluginNames: parseConfigPluginNames(fileName, NFS.readFileSync(absoluteFilePath, "utf-8"))
|
|
70511
|
+
};
|
|
70512
|
+
} catch {
|
|
70513
|
+
return {
|
|
70514
|
+
filePath: fileName,
|
|
70515
|
+
pluginNames: null
|
|
70516
|
+
};
|
|
70517
|
+
}
|
|
70518
|
+
}
|
|
70519
|
+
const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
|
|
70520
|
+
if (!isPlainObject(packageJson.babel)) return null;
|
|
70521
|
+
return {
|
|
70522
|
+
filePath: "package.json",
|
|
70523
|
+
pluginNames: readUnknownPluginNames(packageJson.babel.plugins)
|
|
70524
|
+
};
|
|
70525
|
+
};
|
|
70526
|
+
const REACT_COMPILER_PLUGIN_NAMES = new Set(["babel-plugin-react-compiler", "react-compiler"]);
|
|
70527
|
+
const REANIMATED_PLUGIN_NAME = "react-native-reanimated/plugin";
|
|
70528
|
+
const WORKLETS_PLUGIN_NAME = "react-native-worklets/plugin";
|
|
70529
|
+
const checkReactCompilerPluginOrder = (filePath, pluginNames) => {
|
|
70530
|
+
if (pluginNames.findIndex((pluginName) => REACT_COMPILER_PLUGIN_NAMES.has(pluginName)) <= 0) return [];
|
|
70531
|
+
return [buildReactNativeDiagnostic({
|
|
70532
|
+
filePath,
|
|
70533
|
+
rule: "rn-react-compiler-plugin-first",
|
|
70534
|
+
category: "Performance",
|
|
70535
|
+
message: "The React Compiler Babel plugin is not first, so an earlier transform can change component or hook code before the compiler analyzes it.",
|
|
70536
|
+
help: "Move `babel-plugin-react-compiler` to the first entry in the Babel `plugins` array."
|
|
70537
|
+
})];
|
|
70538
|
+
};
|
|
70539
|
+
const checkReanimatedPluginOrder = (project, filePath, pluginNames) => {
|
|
70540
|
+
const reanimatedMajorVersion = project.reanimatedVersion === null || project.reanimatedVersion === void 0 ? null : getLowestDependencyMajor(project.reanimatedVersion);
|
|
70541
|
+
if (reanimatedMajorVersion === null || reanimatedMajorVersion < 4) return [];
|
|
70542
|
+
const diagnostics = [];
|
|
70543
|
+
if (pluginNames.includes(REANIMATED_PLUGIN_NAME)) diagnostics.push(buildReactNativeDiagnostic({
|
|
70544
|
+
filePath,
|
|
70545
|
+
rule: "rn-reanimated-worklets-plugin-last",
|
|
70546
|
+
category: "Performance",
|
|
70547
|
+
message: "This Reanimated 4 project still uses `react-native-reanimated/plugin`, which was renamed to the Worklets Babel plugin.",
|
|
70548
|
+
help: "Replace it with `react-native-worklets/plugin` and keep that plugin last in the Babel `plugins` array."
|
|
70549
|
+
}));
|
|
70550
|
+
const workletsPluginIndex = pluginNames.lastIndexOf(WORKLETS_PLUGIN_NAME);
|
|
70551
|
+
if (workletsPluginIndex !== -1 && workletsPluginIndex !== pluginNames.length - 1) diagnostics.push(buildReactNativeDiagnostic({
|
|
70552
|
+
filePath,
|
|
70553
|
+
rule: "rn-reanimated-worklets-plugin-last",
|
|
70554
|
+
category: "Performance",
|
|
70555
|
+
message: "`react-native-worklets/plugin` is not last in the Babel `plugins` array, so later transforms can prevent worklets from being compiled correctly.",
|
|
70556
|
+
help: "Move `react-native-worklets/plugin` to the final entry in the Babel `plugins` array."
|
|
70557
|
+
}));
|
|
70558
|
+
return diagnostics;
|
|
70559
|
+
};
|
|
70560
|
+
const checkReactNativeBabelPluginOrder = (rootDirectory, project) => {
|
|
70561
|
+
const babelPlugins = readStaticBabelPluginNames(rootDirectory);
|
|
70562
|
+
if (babelPlugins === null || babelPlugins.pluginNames === null) return [];
|
|
70563
|
+
return [...checkReactCompilerPluginOrder(babelPlugins.filePath, babelPlugins.pluginNames), ...checkReanimatedPluginOrder(project, babelPlugins.filePath, babelPlugins.pluginNames)];
|
|
70564
|
+
};
|
|
70204
70565
|
const BUILDER_BOB_PACKAGE = "react-native-builder-bob";
|
|
70205
70566
|
const isBuilderBobLibrary = (packageJson) => {
|
|
70206
70567
|
const bobConfig = packageJson[BUILDER_BOB_PACKAGE];
|
|
@@ -70277,7 +70638,12 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
|
70277
70638
|
const isReactNativeProject = (project) => project.framework === "react-native" || project.framework === "expo" || project.hasReactNativeWorkspace || project.expoVersion !== null;
|
|
70278
70639
|
const checkReactNativeProject = (rootDirectory, project) => {
|
|
70279
70640
|
if (!isReactNativeProject(project)) return [];
|
|
70280
|
-
return [
|
|
70641
|
+
return [
|
|
70642
|
+
...checkReactNativeMetroBabelPreset(rootDirectory),
|
|
70643
|
+
...checkReactNativeBabelPluginOrder(rootDirectory, project),
|
|
70644
|
+
...checkReactNativeAndroidReleaseShrinking(rootDirectory),
|
|
70645
|
+
...checkReactNativeLibraryDependencies(rootDirectory)
|
|
70646
|
+
];
|
|
70281
70647
|
};
|
|
70282
70648
|
const RULE_KEY = "no-vulnerable-react-server-components";
|
|
70283
70649
|
const REACT_RSC_ADVISORIES_BY_MINOR = {
|
|
@@ -70428,17 +70794,6 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
|
|
|
70428
70794
|
}
|
|
70429
70795
|
return diagnostics;
|
|
70430
70796
|
};
|
|
70431
|
-
const getTypescriptScriptKind = (fileName) => {
|
|
70432
|
-
if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
|
|
70433
|
-
if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
|
|
70434
|
-
if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
|
|
70435
|
-
return ts.ScriptKind.JS;
|
|
70436
|
-
};
|
|
70437
|
-
const unwrapTypescriptExpression = (expression) => {
|
|
70438
|
-
let currentExpression = expression;
|
|
70439
|
-
while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
|
|
70440
|
-
return currentExpression;
|
|
70441
|
-
};
|
|
70442
70797
|
const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
|
|
70443
70798
|
isAnimationFunction: false,
|
|
70444
70799
|
isMotionComponent: false,
|
|
@@ -70994,7 +71349,11 @@ const buildCapabilities = (project) => {
|
|
|
70994
71349
|
capabilities.add(project.framework);
|
|
70995
71350
|
if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
|
|
70996
71351
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
70997
|
-
if (project.expoVersion !== null)
|
|
71352
|
+
if (project.expoVersion !== null) {
|
|
71353
|
+
capabilities.add("expo");
|
|
71354
|
+
const expoSdkMajorVersion = getLowestDependencyMajor(project.expoVersion);
|
|
71355
|
+
if (expoSdkMajorVersion !== null && expoSdkMajorVersion >= 54) capabilities.add("expo:54");
|
|
71356
|
+
}
|
|
70998
71357
|
if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
|
|
70999
71358
|
if (SSR_FRAMEWORKS.has(project.framework) || project.hasSsrDependency) capabilities.add("ssr");
|
|
71000
71359
|
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
@@ -71058,6 +71417,11 @@ const buildCapabilities = (project) => {
|
|
|
71058
71417
|
if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
|
|
71059
71418
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
71060
71419
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
71420
|
+
if (project.reanimatedVersion !== void 0 && project.reanimatedVersion !== null) {
|
|
71421
|
+
capabilities.add("reanimated");
|
|
71422
|
+
const reanimatedMajorVersion = getLowestDependencyMajor(project.reanimatedVersion);
|
|
71423
|
+
if (reanimatedMajorVersion !== null && reanimatedMajorVersion >= 4) capabilities.add("reanimated:4");
|
|
71424
|
+
}
|
|
71061
71425
|
if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
|
|
71062
71426
|
if (project.styledComponentsVersion) {
|
|
71063
71427
|
capabilities.add("styled-components");
|
|
@@ -72971,7 +73335,11 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
|
|
|
72971
73335
|
const ROOT_DIRECTORY_PLACEHOLDER = "<root>";
|
|
72972
73336
|
const normalizeConfigForHash = (config) => {
|
|
72973
73337
|
const clone = JSON.parse(JSON.stringify(config));
|
|
72974
|
-
if (clone?.settings?.["react-doctor"])
|
|
73338
|
+
if (clone?.settings?.["react-doctor"]) {
|
|
73339
|
+
const reactDoctorSettings = clone.settings["react-doctor"];
|
|
73340
|
+
reactDoctorSettings.rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
|
|
73341
|
+
if (Array.isArray(reactDoctorSettings.unpluginAutoImportRootDirectories)) reactDoctorSettings.unpluginAutoImportRootDirectories = [ROOT_DIRECTORY_PLACEHOLDER];
|
|
73342
|
+
}
|
|
72975
73343
|
if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
|
|
72976
73344
|
return clone;
|
|
72977
73345
|
};
|
|
@@ -73130,13 +73498,14 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
73130
73498
|
}
|
|
73131
73499
|
return enabled;
|
|
73132
73500
|
};
|
|
73133
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
73501
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, runtimeGlobals, unpluginAutoImportGlobalScopes, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
73134
73502
|
const hasIncludedTags = includedTags.size > 0;
|
|
73135
73503
|
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
73136
73504
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
73137
73505
|
const jsPlugins = [];
|
|
73138
73506
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
73139
73507
|
const capabilities = getCapabilities(project);
|
|
73508
|
+
const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
|
|
73140
73509
|
const enabledReactDoctorRules = {};
|
|
73141
73510
|
for (const registryEntry of REACT_DOCTOR_RULES) {
|
|
73142
73511
|
const rule = reactDoctorPlugin.rules[registryEntry.id];
|
|
@@ -73182,8 +73551,16 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
73182
73551
|
jsPlugins: [...jsPlugins, pluginPath],
|
|
73183
73552
|
settings: { "react-doctor": {
|
|
73184
73553
|
framework: project.framework,
|
|
73185
|
-
rootDirectory:
|
|
73554
|
+
rootDirectory: settingsRootDirectory,
|
|
73186
73555
|
capabilities: [...capabilities].sort(),
|
|
73556
|
+
...runtimeGlobals && runtimeGlobals.length > 0 ? { runtimeGlobals: [...runtimeGlobals] } : {},
|
|
73557
|
+
...unpluginAutoImportGlobalScopes && unpluginAutoImportGlobalScopes.length > 0 ? {
|
|
73558
|
+
unpluginAutoImportRootDirectories: [...new Set([settingsRootDirectory, project.rootDirectory])],
|
|
73559
|
+
unpluginAutoImportGlobalScopes: unpluginAutoImportGlobalScopes.map((scope) => ({
|
|
73560
|
+
directory: scope.directory,
|
|
73561
|
+
names: [...scope.names]
|
|
73562
|
+
}))
|
|
73563
|
+
} : {},
|
|
73187
73564
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
73188
73565
|
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
73189
73566
|
} },
|
|
@@ -73194,6 +73571,245 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
73194
73571
|
}
|
|
73195
73572
|
};
|
|
73196
73573
|
};
|
|
73574
|
+
const AUTO_IMPORT_ADAPTER_PATTERN = /^unplugin-auto-import\/(?:astro|esbuild|rollup|rolldown|rspack|vite|webpack)$/;
|
|
73575
|
+
const CONFIG_BASENAMES = [
|
|
73576
|
+
"astro.config",
|
|
73577
|
+
"esbuild.config",
|
|
73578
|
+
"rollup.config",
|
|
73579
|
+
"rolldown.config",
|
|
73580
|
+
"rspack.config",
|
|
73581
|
+
"vite.config",
|
|
73582
|
+
"webpack.config"
|
|
73583
|
+
];
|
|
73584
|
+
const CONFIG_EXTENSIONS = [
|
|
73585
|
+
".cjs",
|
|
73586
|
+
".cts",
|
|
73587
|
+
".js",
|
|
73588
|
+
".mjs",
|
|
73589
|
+
".mts",
|
|
73590
|
+
".ts"
|
|
73591
|
+
];
|
|
73592
|
+
const CONFIG_FILENAMES = new Set(CONFIG_BASENAMES.flatMap((basename) => CONFIG_EXTENSIONS.map((extension) => `${basename}${extension}`)));
|
|
73593
|
+
const DEFAULT_ESLINT_GLOBALS_PATH = ".eslintrc-auto-import.json";
|
|
73594
|
+
const SUPPORTED_GLOBAL_VALUES = new Set([
|
|
73595
|
+
true,
|
|
73596
|
+
false,
|
|
73597
|
+
"readable",
|
|
73598
|
+
"readonly",
|
|
73599
|
+
"writable",
|
|
73600
|
+
"writeable"
|
|
73601
|
+
]);
|
|
73602
|
+
const getStaticProperty = (objectExpression, propertyName) => objectExpression.properties.find((property) => {
|
|
73603
|
+
if (ts.isSpreadAssignment(property)) return false;
|
|
73604
|
+
const name = ts.isComputedPropertyName(property.name) ? unwrapTypescriptExpression(property.name.expression) : property.name;
|
|
73605
|
+
return (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) && name.text === propertyName;
|
|
73606
|
+
}) ?? null;
|
|
73607
|
+
const hasNonLiteralComputedProperty = (objectExpression) => objectExpression.properties.some((property) => !ts.isSpreadAssignment(property) && ts.isComputedPropertyName(property.name) && !ts.isStringLiteralLike(unwrapTypescriptExpression(property.name.expression)));
|
|
73608
|
+
const getStaticPropertyAssignment = (objectExpression, propertyName) => {
|
|
73609
|
+
const property = getStaticProperty(objectExpression, propertyName);
|
|
73610
|
+
return property && ts.isPropertyAssignment(property) ? property : null;
|
|
73611
|
+
};
|
|
73612
|
+
const getRequireModuleSpecifier = (expression) => {
|
|
73613
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
73614
|
+
if (ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === "default") return getRequireModuleSpecifier(unwrappedExpression.expression);
|
|
73615
|
+
if (!ts.isCallExpression(unwrappedExpression) || !ts.isIdentifier(unwrappedExpression.expression) || unwrappedExpression.expression.text !== "require" || unwrappedExpression.arguments.length !== 1) return null;
|
|
73616
|
+
const moduleSpecifier = unwrappedExpression.arguments[0];
|
|
73617
|
+
return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
|
|
73618
|
+
};
|
|
73619
|
+
const getRequiredPropertyModuleSpecifier = (expression, propertyName) => {
|
|
73620
|
+
const unwrappedExpression = unwrapTypescriptExpression(expression);
|
|
73621
|
+
return ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === propertyName ? getRequireModuleSpecifier(unwrappedExpression.expression) : null;
|
|
73622
|
+
};
|
|
73623
|
+
const isCommonJsExportAssignment = (node, sourceFile) => ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && (node.left.getText(sourceFile) === "module.exports" || node.left.getText(sourceFile) === "exports.default");
|
|
73624
|
+
const isTopLevelExpression = (node) => {
|
|
73625
|
+
let ancestor = node.parent;
|
|
73626
|
+
while (ancestor && !ts.isSourceFile(ancestor)) {
|
|
73627
|
+
if (ts.isExpressionStatement(ancestor)) return ts.isSourceFile(ancestor.parent);
|
|
73628
|
+
if (!ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isAwaitExpression(ancestor)) return false;
|
|
73629
|
+
ancestor = ancestor.parent;
|
|
73630
|
+
}
|
|
73631
|
+
return false;
|
|
73632
|
+
};
|
|
73633
|
+
const isInsideActiveConfigProperty = (node, propertyName, sourceFile, esbuildBindings, esbuildNamespaceBindings) => {
|
|
73634
|
+
let ancestor = node.parent;
|
|
73635
|
+
let didFindConfigProperty = false;
|
|
73636
|
+
while (ancestor && !ts.isSourceFile(ancestor)) {
|
|
73637
|
+
if (!didFindConfigProperty && !ts.isArrayLiteralExpression(ancestor) && !ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isPropertyAssignment(ancestor)) return false;
|
|
73638
|
+
if (ts.isPropertyAssignment(ancestor)) {
|
|
73639
|
+
const isConfigProperty = (ts.isIdentifier(ancestor.name) || ts.isStringLiteralLike(ancestor.name)) && ancestor.name.text === propertyName;
|
|
73640
|
+
if (didFindConfigProperty || !isConfigProperty) return false;
|
|
73641
|
+
if (!ts.isObjectLiteralExpression(ancestor.parent) || ancestor.parent.properties.some(ts.isSpreadAssignment)) return false;
|
|
73642
|
+
didFindConfigProperty = true;
|
|
73643
|
+
ancestor = ancestor.parent;
|
|
73644
|
+
continue;
|
|
73645
|
+
}
|
|
73646
|
+
if (didFindConfigProperty) {
|
|
73647
|
+
if (ts.isExportAssignment(ancestor)) return true;
|
|
73648
|
+
if (isCommonJsExportAssignment(ancestor, sourceFile)) return isTopLevelExpression(ancestor);
|
|
73649
|
+
if (propertyName === "plugins" && ts.isCallExpression(ancestor) && (ts.isIdentifier(ancestor.expression) ? esbuildBindings.has(ancestor.expression.text) : ts.isPropertyAccessExpression(ancestor.expression) && ancestor.expression.name.text === "build" && (ts.isIdentifier(ancestor.expression.expression) && esbuildNamespaceBindings.has(ancestor.expression.expression.text) || getRequireModuleSpecifier(ancestor.expression.expression) === "esbuild"))) return isTopLevelExpression(ancestor);
|
|
73650
|
+
if (!(ts.isObjectLiteralExpression(ancestor) || ts.isParenthesizedExpression(ancestor) || ts.isAsExpression(ancestor) || ts.isSatisfiesExpression(ancestor) || ts.isNonNullExpression(ancestor) || ts.isTypeAssertionExpression(ancestor) || ts.isCallExpression(ancestor) && ts.isIdentifier(ancestor.expression) && ancestor.expression.text === "defineConfig")) return false;
|
|
73651
|
+
}
|
|
73652
|
+
ancestor = ancestor.parent;
|
|
73653
|
+
}
|
|
73654
|
+
return false;
|
|
73655
|
+
};
|
|
73656
|
+
const getGlobalsPathFromActiveAutoImportCall = (callExpression, packageDirectory) => {
|
|
73657
|
+
const optionsExpression = callExpression.arguments[0];
|
|
73658
|
+
if (!optionsExpression) return null;
|
|
73659
|
+
const unwrappedOptions = unwrapTypescriptExpression(optionsExpression);
|
|
73660
|
+
if (!ts.isObjectLiteralExpression(unwrappedOptions)) return null;
|
|
73661
|
+
if (unwrappedOptions.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(unwrappedOptions)) return null;
|
|
73662
|
+
if (getStaticProperty(unwrappedOptions, "include") || getStaticProperty(unwrappedOptions, "exclude")) return null;
|
|
73663
|
+
const eslintrcProperty = getStaticPropertyAssignment(unwrappedOptions, "eslintrc");
|
|
73664
|
+
if (!eslintrcProperty) return null;
|
|
73665
|
+
const eslintrcExpression = unwrapTypescriptExpression(eslintrcProperty.initializer);
|
|
73666
|
+
if (!ts.isObjectLiteralExpression(eslintrcExpression)) return null;
|
|
73667
|
+
if (eslintrcExpression.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(eslintrcExpression)) return null;
|
|
73668
|
+
const enabledProperty = getStaticPropertyAssignment(eslintrcExpression, "enabled");
|
|
73669
|
+
if (!enabledProperty || unwrapTypescriptExpression(enabledProperty.initializer).kind !== ts.SyntaxKind.TrueKeyword) return null;
|
|
73670
|
+
const filepathProperty = getStaticProperty(eslintrcExpression, "filepath");
|
|
73671
|
+
if (!filepathProperty) return Path.join(packageDirectory, DEFAULT_ESLINT_GLOBALS_PATH);
|
|
73672
|
+
if (!ts.isPropertyAssignment(filepathProperty)) return null;
|
|
73673
|
+
const filepathExpression = unwrapTypescriptExpression(filepathProperty.initializer);
|
|
73674
|
+
return ts.isStringLiteralLike(filepathExpression) ? Path.resolve(packageDirectory, filepathExpression.text) : null;
|
|
73675
|
+
};
|
|
73676
|
+
const collectGlobalsPathsFromConfig = (configPath, packageDirectory) => {
|
|
73677
|
+
let sourceText;
|
|
73678
|
+
try {
|
|
73679
|
+
sourceText = NFS.readFileSync(configPath, "utf8");
|
|
73680
|
+
} catch {
|
|
73681
|
+
return {
|
|
73682
|
+
didFindActiveAutoImport: false,
|
|
73683
|
+
globalsPaths: []
|
|
73684
|
+
};
|
|
73685
|
+
}
|
|
73686
|
+
const sourceFile = ts.createSourceFile(configPath, sourceText, ts.ScriptTarget.Latest, true);
|
|
73687
|
+
const autoImportBindings = /* @__PURE__ */ new Map();
|
|
73688
|
+
const esbuildBindings = /* @__PURE__ */ new Set();
|
|
73689
|
+
const esbuildNamespaceBindings = /* @__PURE__ */ new Set();
|
|
73690
|
+
for (const statement of sourceFile.statements) {
|
|
73691
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteralLike(statement.moduleSpecifier)) {
|
|
73692
|
+
const moduleSpecifier = statement.moduleSpecifier.text;
|
|
73693
|
+
if (AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
|
|
73694
|
+
const defaultBinding = statement.importClause?.name;
|
|
73695
|
+
if (defaultBinding) autoImportBindings.set(defaultBinding.text, moduleSpecifier);
|
|
73696
|
+
}
|
|
73697
|
+
if (moduleSpecifier === "esbuild") {
|
|
73698
|
+
const defaultBinding = statement.importClause?.name;
|
|
73699
|
+
if (defaultBinding) esbuildNamespaceBindings.add(defaultBinding.text);
|
|
73700
|
+
const namedBindings = statement.importClause?.namedBindings;
|
|
73701
|
+
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
73702
|
+
for (const importSpecifier of namedBindings.elements) if ((importSpecifier.propertyName ?? importSpecifier.name).text === "build") esbuildBindings.add(importSpecifier.name.text);
|
|
73703
|
+
}
|
|
73704
|
+
if (namedBindings && ts.isNamespaceImport(namedBindings)) esbuildNamespaceBindings.add(namedBindings.name.text);
|
|
73705
|
+
}
|
|
73706
|
+
}
|
|
73707
|
+
if (!ts.isVariableStatement(statement)) continue;
|
|
73708
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
73709
|
+
if (!declaration.initializer) continue;
|
|
73710
|
+
const declarationName = ts.isIdentifier(declaration.name) ? declaration.name.text : null;
|
|
73711
|
+
const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
|
|
73712
|
+
if (declarationName && moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) autoImportBindings.set(declarationName, moduleSpecifier);
|
|
73713
|
+
if (moduleSpecifier === "esbuild") {
|
|
73714
|
+
if (declarationName) esbuildNamespaceBindings.add(declarationName);
|
|
73715
|
+
if (ts.isObjectBindingPattern(declaration.name)) for (const bindingElement of declaration.name.elements) {
|
|
73716
|
+
const importedName = bindingElement.propertyName ?? bindingElement.name;
|
|
73717
|
+
if (ts.isIdentifier(importedName) && importedName.text === "build" && ts.isIdentifier(bindingElement.name)) esbuildBindings.add(bindingElement.name.text);
|
|
73718
|
+
}
|
|
73719
|
+
}
|
|
73720
|
+
if (declarationName && getRequiredPropertyModuleSpecifier(declaration.initializer, "build") === "esbuild") esbuildBindings.add(declarationName);
|
|
73721
|
+
}
|
|
73722
|
+
}
|
|
73723
|
+
const globalsPaths = /* @__PURE__ */ new Set();
|
|
73724
|
+
let didFindActiveAutoImport = false;
|
|
73725
|
+
let didFindUnsafeActiveAutoImport = false;
|
|
73726
|
+
const visit = (node) => {
|
|
73727
|
+
if (ts.isCallExpression(node)) {
|
|
73728
|
+
const moduleSpecifier = ts.isIdentifier(node.expression) ? autoImportBindings.get(node.expression.text) : getRequireModuleSpecifier(node.expression);
|
|
73729
|
+
if (moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
|
|
73730
|
+
if (isInsideActiveConfigProperty(node, moduleSpecifier.endsWith("/astro") ? "integrations" : "plugins", sourceFile, esbuildBindings, esbuildNamespaceBindings)) {
|
|
73731
|
+
didFindActiveAutoImport = true;
|
|
73732
|
+
const globalsPath = getGlobalsPathFromActiveAutoImportCall(node, packageDirectory);
|
|
73733
|
+
if (globalsPath) globalsPaths.add(globalsPath);
|
|
73734
|
+
else didFindUnsafeActiveAutoImport = true;
|
|
73735
|
+
}
|
|
73736
|
+
}
|
|
73737
|
+
}
|
|
73738
|
+
ts.forEachChild(node, visit);
|
|
73739
|
+
};
|
|
73740
|
+
visit(sourceFile);
|
|
73741
|
+
return {
|
|
73742
|
+
didFindActiveAutoImport,
|
|
73743
|
+
globalsPaths: didFindUnsafeActiveAutoImport ? [] : [...globalsPaths]
|
|
73744
|
+
};
|
|
73745
|
+
};
|
|
73746
|
+
const collectGeneratedGlobalNames = (globalsPath, rootDirectory) => {
|
|
73747
|
+
const relativePath = Path.relative(rootDirectory, globalsPath);
|
|
73748
|
+
if (relativePath.startsWith("..") || Path.isAbsolute(relativePath)) return [];
|
|
73749
|
+
const parsed = failOpenReadJson(globalsPath, null);
|
|
73750
|
+
if (!isPlainObject(parsed) || !isPlainObject(parsed.globals)) return [];
|
|
73751
|
+
return Object.entries(parsed.globals).filter((entry) => entry[0].length > 0 && (typeof entry[1] === "boolean" || typeof entry[1] === "string") && SUPPORTED_GLOBAL_VALUES.has(entry[1])).map(([name]) => name).sort();
|
|
73752
|
+
};
|
|
73753
|
+
const findOwningPackageDirectory = (absoluteFilePath, rootDirectory, cache) => {
|
|
73754
|
+
let currentDirectory = Path.dirname(absoluteFilePath);
|
|
73755
|
+
const visitedDirectories = [];
|
|
73756
|
+
while (true) {
|
|
73757
|
+
const cachedDirectory = cache.get(currentDirectory);
|
|
73758
|
+
if (cachedDirectory !== void 0) {
|
|
73759
|
+
for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, cachedDirectory);
|
|
73760
|
+
return cachedDirectory;
|
|
73761
|
+
}
|
|
73762
|
+
const relativeDirectory = Path.relative(rootDirectory, currentDirectory);
|
|
73763
|
+
if (relativeDirectory.startsWith("..") || Path.isAbsolute(relativeDirectory)) {
|
|
73764
|
+
for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
|
|
73765
|
+
return null;
|
|
73766
|
+
}
|
|
73767
|
+
visitedDirectories.push(currentDirectory);
|
|
73768
|
+
if (NFS.existsSync(Path.join(currentDirectory, "package.json"))) {
|
|
73769
|
+
for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, currentDirectory);
|
|
73770
|
+
return currentDirectory;
|
|
73771
|
+
}
|
|
73772
|
+
if (currentDirectory === rootDirectory) {
|
|
73773
|
+
for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
|
|
73774
|
+
return null;
|
|
73775
|
+
}
|
|
73776
|
+
currentDirectory = Path.dirname(currentDirectory);
|
|
73777
|
+
}
|
|
73778
|
+
};
|
|
73779
|
+
const collectPackageGlobalNames = (packageDirectory, rootDirectory) => {
|
|
73780
|
+
let directoryEntries;
|
|
73781
|
+
try {
|
|
73782
|
+
directoryEntries = NFS.readdirSync(packageDirectory, { withFileTypes: true });
|
|
73783
|
+
} catch {
|
|
73784
|
+
return [];
|
|
73785
|
+
}
|
|
73786
|
+
const configuredGlobalsPaths = [];
|
|
73787
|
+
for (const entry of directoryEntries) {
|
|
73788
|
+
if (!entry.isFile() && !entry.isSymbolicLink() || !CONFIG_FILENAMES.has(entry.name)) continue;
|
|
73789
|
+
const configGlobalsPaths = collectGlobalsPathsFromConfig(Path.join(packageDirectory, entry.name), packageDirectory);
|
|
73790
|
+
if (configGlobalsPaths.didFindActiveAutoImport) configuredGlobalsPaths.push(configGlobalsPaths.globalsPaths.toSorted());
|
|
73791
|
+
}
|
|
73792
|
+
if (configuredGlobalsPaths.length === 0) return [];
|
|
73793
|
+
const globalsPaths = configuredGlobalsPaths[0];
|
|
73794
|
+
if (configuredGlobalsPaths.some((candidatePaths) => candidatePaths.length !== globalsPaths.length || candidatePaths.some((candidatePath, index) => candidatePath !== globalsPaths[index]))) return [];
|
|
73795
|
+
const names = /* @__PURE__ */ new Set();
|
|
73796
|
+
for (const globalsPath of globalsPaths) for (const name of collectGeneratedGlobalNames(globalsPath, rootDirectory)) names.add(name);
|
|
73797
|
+
return [...names].sort();
|
|
73798
|
+
};
|
|
73799
|
+
const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }) => {
|
|
73800
|
+
const absoluteRootDirectory = Path.resolve(rootDirectory);
|
|
73801
|
+
const packageDirectoryCache = /* @__PURE__ */ new Map();
|
|
73802
|
+
const packageDirectories = /* @__PURE__ */ new Set();
|
|
73803
|
+
for (const candidateFile of candidateFiles) {
|
|
73804
|
+
const packageDirectory = findOwningPackageDirectory(Path.resolve(absoluteRootDirectory, candidateFile), absoluteRootDirectory, packageDirectoryCache);
|
|
73805
|
+
if (packageDirectory) packageDirectories.add(packageDirectory);
|
|
73806
|
+
}
|
|
73807
|
+
const scopes = [...packageDirectories].map((packageDirectory) => ({
|
|
73808
|
+
directory: Path.relative(absoluteRootDirectory, packageDirectory).replaceAll("\\", "/"),
|
|
73809
|
+
names: collectPackageGlobalNames(packageDirectory, absoluteRootDirectory)
|
|
73810
|
+
})).sort((firstScope, secondScope) => firstScope.directory.localeCompare(secondScope.directory));
|
|
73811
|
+
return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
|
|
73812
|
+
};
|
|
73197
73813
|
const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
|
|
73198
73814
|
const decodeFileDiagnostics = (raw) => {
|
|
73199
73815
|
if (!Array.isArray(raw)) return null;
|
|
@@ -73516,6 +74132,12 @@ const appendReanimatedSharedValueHint = (help, rule, project) => {
|
|
|
73516
74132
|
if (!help) return REANIMATED_SHARED_VALUE_HINT;
|
|
73517
74133
|
return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
|
|
73518
74134
|
};
|
|
74135
|
+
const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
|
|
74136
|
+
const boundedOffset = Math.min(Math.max(utf8Offset, 0), sourceBuffer.length);
|
|
74137
|
+
let lineStartOffset = boundedOffset;
|
|
74138
|
+
while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
|
|
74139
|
+
return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
|
|
74140
|
+
};
|
|
73519
74141
|
const REDACTED_PLACEHOLDER = "<redacted>";
|
|
73520
74142
|
const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
|
|
73521
74143
|
const KNOWN_SECRET_RULES = [
|
|
@@ -74231,7 +74853,7 @@ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORI
|
|
|
74231
74853
|
* with empty text still carry a useful jump target, so they're kept
|
|
74232
74854
|
* with a neutral message.
|
|
74233
74855
|
*/
|
|
74234
|
-
const buildRelatedLocations = (labels, filePath) => {
|
|
74856
|
+
const buildRelatedLocations = (labels, filePath, sourceBuffer) => {
|
|
74235
74857
|
if (labels.length <= 1) return [];
|
|
74236
74858
|
const related = [];
|
|
74237
74859
|
for (let labelIndex = 1; labelIndex < labels.length; labelIndex++) {
|
|
@@ -74239,8 +74861,8 @@ const buildRelatedLocations = (labels, filePath) => {
|
|
|
74239
74861
|
if (!label?.span) continue;
|
|
74240
74862
|
related.push({
|
|
74241
74863
|
filePath,
|
|
74242
|
-
line: label.span.line ?? 0,
|
|
74243
|
-
column: label.span.column ?? 0,
|
|
74864
|
+
line: sourceBuffer === null ? label.span.line ?? 0 : lineOfUtf8Offset(sourceBuffer, label.span.offset),
|
|
74865
|
+
column: sourceBuffer === null ? label.span.column ?? 0 : columnOfUtf8Offset(sourceBuffer, label.span.offset),
|
|
74244
74866
|
offset: label.span.offset,
|
|
74245
74867
|
length: label.span.length,
|
|
74246
74868
|
message: label.label ?? ""
|
|
@@ -74260,7 +74882,7 @@ const isOxlintOutput = (value) => isRecord$1(value) && Array.isArray(value.diagn
|
|
|
74260
74882
|
* to the first `{`. Raises `OxlintOutputUnparseable` when the
|
|
74261
74883
|
* stdout isn't valid JSON or doesn't carry a `diagnostics` array.
|
|
74262
74884
|
*/
|
|
74263
|
-
const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
74885
|
+
const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
|
|
74264
74886
|
if (!stdout) return [];
|
|
74265
74887
|
const jsonStart = stdout.indexOf("{");
|
|
74266
74888
|
const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
|
|
@@ -74277,8 +74899,10 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
74277
74899
|
const sourceBufferCache = /* @__PURE__ */ new Map();
|
|
74278
74900
|
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
74279
74901
|
const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
74902
|
+
const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
|
|
74903
|
+
const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
|
|
74280
74904
|
const readSourceBuffer = (filename) => {
|
|
74281
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
74905
|
+
const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
|
|
74282
74906
|
const cached = sourceBufferCache.get(absolutePath);
|
|
74283
74907
|
if (cached !== void 0) return cached;
|
|
74284
74908
|
let sourceBuffer;
|
|
@@ -74291,7 +74915,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
74291
74915
|
return sourceBuffer;
|
|
74292
74916
|
};
|
|
74293
74917
|
const readSourceLines = (filename) => {
|
|
74294
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
74918
|
+
const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
|
|
74295
74919
|
const cached = sourceLinesCache.get(absolutePath);
|
|
74296
74920
|
if (cached !== void 0) return cached;
|
|
74297
74921
|
const sourceBuffer = readSourceBuffer(filename);
|
|
@@ -74300,27 +74924,30 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
74300
74924
|
return sourceLines;
|
|
74301
74925
|
};
|
|
74302
74926
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
74303
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
74927
|
+
const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
|
|
74304
74928
|
const cached = minifiedFileCache.get(absolutePath);
|
|
74305
74929
|
if (cached !== void 0) return cached;
|
|
74306
74930
|
const minified = isMinifiedSource(absolutePath);
|
|
74307
74931
|
minifiedFileCache.set(absolutePath, minified);
|
|
74308
74932
|
return minified;
|
|
74309
74933
|
};
|
|
74310
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
74934
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(resolveSourceFilename(diagnostic.filename)) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
74311
74935
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
74312
74936
|
const primaryLabel = diagnostic.labels[0];
|
|
74313
74937
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
74314
|
-
const
|
|
74938
|
+
const mappedSourceFilename = resolveMappedSourceFilename(diagnostic.filename);
|
|
74939
|
+
const normalizedFilePath = (mappedSourceFilename ?? diagnostic.filename).replaceAll("\\", "/");
|
|
74315
74940
|
const primarySpan = primaryLabel?.span;
|
|
74316
74941
|
const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
|
|
74317
|
-
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
|
|
74942
|
+
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath, mappedSourceFilename === void 0 ? null : sourceBuffer);
|
|
74318
74943
|
const category = resolveDiagnosticCategory(plugin, rule);
|
|
74319
74944
|
const matchByOccurrence = resolveMatchByOccurrence(rule, category);
|
|
74320
74945
|
const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
|
|
74321
|
-
const
|
|
74946
|
+
const primaryLineNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.line ?? 0;
|
|
74947
|
+
const primaryColumnNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? columnOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.column ?? 0;
|
|
74948
|
+
const primaryLineIndex = primarySpan ? primaryLineNumber - 1 : -1;
|
|
74322
74949
|
const primaryLine = sourceLines?.[primaryLineIndex];
|
|
74323
|
-
const primaryColumnIndex = primarySpan ?
|
|
74950
|
+
const primaryColumnIndex = primarySpan ? primaryColumnNumber - 1 : -1;
|
|
74324
74951
|
const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
|
|
74325
74952
|
const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
|
|
74326
74953
|
const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
|
|
@@ -74333,8 +74960,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
74333
74960
|
message: cleaned.message,
|
|
74334
74961
|
help: cleaned.help,
|
|
74335
74962
|
url: diagnostic.url,
|
|
74336
|
-
line:
|
|
74337
|
-
column:
|
|
74963
|
+
line: primaryLineNumber,
|
|
74964
|
+
column: primaryColumnNumber,
|
|
74338
74965
|
...primarySpan ? {
|
|
74339
74966
|
offset: primarySpan.offset,
|
|
74340
74967
|
length: primarySpan.length,
|
|
@@ -74522,7 +75149,11 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
74522
75149
|
* loop with a slimmer config in that case.
|
|
74523
75150
|
*/
|
|
74524
75151
|
const spawnLintBatches = async (input) => {
|
|
74525
|
-
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
75152
|
+
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
75153
|
+
const resolveSourcePath = (filePath) => {
|
|
75154
|
+
const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
|
|
75155
|
+
return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
|
|
75156
|
+
};
|
|
74526
75157
|
const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
|
|
74527
75158
|
let rescueDeadlineEpochMs;
|
|
74528
75159
|
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
|
|
@@ -74542,7 +75173,7 @@ const spawnLintBatches = async (input) => {
|
|
|
74542
75173
|
}
|
|
74543
75174
|
const batchArgs = [...baseArgs, ...batch];
|
|
74544
75175
|
try {
|
|
74545
|
-
return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
|
|
75176
|
+
return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath);
|
|
74546
75177
|
} catch (error) {
|
|
74547
75178
|
if (!isSplittableReactDoctorError(error)) throw error;
|
|
74548
75179
|
if (isPastDeadline()) {
|
|
@@ -74648,10 +75279,12 @@ const spawnLintBatches = async (input) => {
|
|
|
74648
75279
|
onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
|
|
74649
75280
|
};
|
|
74650
75281
|
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
74651
|
-
|
|
74652
|
-
|
|
75282
|
+
const droppedSourceFiles = [...new Set(droppedFiles.map(resolveSourcePath))];
|
|
75283
|
+
const deadlineSkippedSourceFiles = [...new Set(outcome.deadlineSkippedFiles.map(resolveSourcePath))];
|
|
75284
|
+
reportSkippedFiles(droppedSourceFiles, (fileListPreview) => `${droppedSourceFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
75285
|
+
reportSkippedFiles(deadlineSkippedSourceFiles, (fileListPreview) => `${deadlineSkippedSourceFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
74653
75286
|
const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
|
|
74654
|
-
input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
|
|
75287
|
+
input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)).map(resolveSourcePath))].sort());
|
|
74655
75288
|
return dedupeDiagnostics(diagnostics);
|
|
74656
75289
|
};
|
|
74657
75290
|
let didValidate = false;
|
|
@@ -74750,6 +75383,266 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
|
|
|
74750
75383
|
}
|
|
74751
75384
|
return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
|
|
74752
75385
|
};
|
|
75386
|
+
const THREE_MODULE_IMPORT_PATTERN = /\b(?:from\s*|import\s*(?:\(\s*)?|require\s*\(\s*)["']three(?:\/[^"']*)?["']/;
|
|
75387
|
+
const containsThreeModuleImport = (sourceText) => THREE_MODULE_IMPORT_PATTERN.test(sourceText);
|
|
75388
|
+
const COMMENT_OPEN = "<!--";
|
|
75389
|
+
const COMMENT_CLOSE = "-->";
|
|
75390
|
+
const FRONTMATTER_FENCE = "---";
|
|
75391
|
+
const SCRIPT_TAG_NAME = "script";
|
|
75392
|
+
const SCRIPT_OPEN = `<${SCRIPT_TAG_NAME}`;
|
|
75393
|
+
const SCRIPT_CLOSE = `</${SCRIPT_TAG_NAME}`;
|
|
75394
|
+
const TEMPLATE_TAG_NAME = "template";
|
|
75395
|
+
const TEMPLATE_CLOSE = `</${TEMPLATE_TAG_NAME}`;
|
|
75396
|
+
const JAVASCRIPT_MIME_TYPES = new Set([
|
|
75397
|
+
"application/ecmascript",
|
|
75398
|
+
"application/javascript",
|
|
75399
|
+
"application/x-ecmascript",
|
|
75400
|
+
"application/x-javascript",
|
|
75401
|
+
"text/ecmascript",
|
|
75402
|
+
"text/javascript",
|
|
75403
|
+
"text/javascript1.0",
|
|
75404
|
+
"text/javascript1.1",
|
|
75405
|
+
"text/javascript1.2",
|
|
75406
|
+
"text/javascript1.3",
|
|
75407
|
+
"text/javascript1.4",
|
|
75408
|
+
"text/javascript1.5",
|
|
75409
|
+
"text/jscript",
|
|
75410
|
+
"text/livescript",
|
|
75411
|
+
"text/x-ecmascript",
|
|
75412
|
+
"text/x-javascript"
|
|
75413
|
+
]);
|
|
75414
|
+
const RAW_TEXT_TAG_NAMES = new Set([
|
|
75415
|
+
"iframe",
|
|
75416
|
+
"noembed",
|
|
75417
|
+
"noframes",
|
|
75418
|
+
"noscript",
|
|
75419
|
+
"style",
|
|
75420
|
+
"textarea",
|
|
75421
|
+
"title",
|
|
75422
|
+
"xmp"
|
|
75423
|
+
]);
|
|
75424
|
+
const PLAINTEXT_TAG_NAME = "plaintext";
|
|
75425
|
+
const TAG_OPEN_UTF8_BYTE = "<".charCodeAt(0);
|
|
75426
|
+
const TAG_CLOSE_UTF8_BYTE = ">".charCodeAt(0);
|
|
75427
|
+
const SINGLE_QUOTE_UTF8_BYTE = "'".charCodeAt(0);
|
|
75428
|
+
const DOUBLE_QUOTE_UTF8_BYTE = "\"".charCodeAt(0);
|
|
75429
|
+
const ATTRIBUTE_ASSIGNMENT_UTF8_BYTE = "=".charCodeAt(0);
|
|
75430
|
+
const TAG_SELF_CLOSE_UTF8_BYTE = "/".charCodeAt(0);
|
|
75431
|
+
const TAB_UTF8_BYTE = " ".charCodeAt(0);
|
|
75432
|
+
const FORM_FEED_UTF8_BYTE = "\f".charCodeAt(0);
|
|
75433
|
+
const isHtmlWhitespace = (byte) => byte === TAB_UTF8_BYTE || byte === 10 || byte === FORM_FEED_UTF8_BYTE || byte === 13 || byte === 32;
|
|
75434
|
+
const matchesAsciiCaseInsensitive = (sourceBuffer, startByte, expected) => {
|
|
75435
|
+
if (startByte + expected.length > sourceBuffer.length) return false;
|
|
75436
|
+
for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex++) {
|
|
75437
|
+
const sourceByte = sourceBuffer[startByte + expectedIndex];
|
|
75438
|
+
if (sourceByte === void 0 || String.fromCharCode(sourceByte).toLowerCase() !== expected[expectedIndex]) return false;
|
|
75439
|
+
}
|
|
75440
|
+
return true;
|
|
75441
|
+
};
|
|
75442
|
+
const isTagBoundary = (byte) => byte === TAG_CLOSE_UTF8_BYTE || byte === TAG_SELF_CLOSE_UTF8_BYTE || isHtmlWhitespace(byte);
|
|
75443
|
+
const isPotentialTagStart = (byte) => {
|
|
75444
|
+
if (byte === void 0) return false;
|
|
75445
|
+
return /[A-Za-z!/?]/.test(String.fromCharCode(byte));
|
|
75446
|
+
};
|
|
75447
|
+
const findLineEnd = (sourceBuffer, lineStartByte) => {
|
|
75448
|
+
let byteIndex = lineStartByte;
|
|
75449
|
+
while (byteIndex < sourceBuffer.length && sourceBuffer[byteIndex] !== 10 && sourceBuffer[byteIndex] !== 13) byteIndex++;
|
|
75450
|
+
return byteIndex;
|
|
75451
|
+
};
|
|
75452
|
+
const findNextLineStart = (sourceBuffer, lineStartByte) => {
|
|
75453
|
+
const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
|
|
75454
|
+
if (sourceBuffer[lineEndByte] === 13 && sourceBuffer[lineEndByte + 1] === 10) return lineEndByte + 2;
|
|
75455
|
+
return Math.min(lineEndByte + 1, sourceBuffer.length);
|
|
75456
|
+
};
|
|
75457
|
+
const isFrontmatterFenceLine = (sourceBuffer, lineStartByte) => {
|
|
75458
|
+
if (!matchesAsciiCaseInsensitive(sourceBuffer, lineStartByte, FRONTMATTER_FENCE)) return false;
|
|
75459
|
+
const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
|
|
75460
|
+
for (let byteIndex = lineStartByte + 3; byteIndex < lineEndByte; byteIndex++) if (!isHtmlWhitespace(sourceBuffer[byteIndex])) return false;
|
|
75461
|
+
return true;
|
|
75462
|
+
};
|
|
75463
|
+
const findFrontmatterEnd = (sourceBuffer) => {
|
|
75464
|
+
if (!isFrontmatterFenceLine(sourceBuffer, 0)) return 0;
|
|
75465
|
+
const openingFenceEndByte = findLineEnd(sourceBuffer, 0);
|
|
75466
|
+
let lineStartByte = findNextLineStart(sourceBuffer, 0);
|
|
75467
|
+
while (lineStartByte < sourceBuffer.length) {
|
|
75468
|
+
if (isFrontmatterFenceLine(sourceBuffer, lineStartByte)) return findLineEnd(sourceBuffer, lineStartByte);
|
|
75469
|
+
lineStartByte = findNextLineStart(sourceBuffer, lineStartByte);
|
|
75470
|
+
}
|
|
75471
|
+
return openingFenceEndByte;
|
|
75472
|
+
};
|
|
75473
|
+
const maskByteRange = (maskedBuffer, startByte, endByte) => {
|
|
75474
|
+
for (let byteIndex = startByte; byteIndex < endByte; byteIndex++) {
|
|
75475
|
+
const byte = maskedBuffer[byteIndex];
|
|
75476
|
+
if (byte !== 10 && byte !== 13) maskedBuffer[byteIndex] = 32;
|
|
75477
|
+
}
|
|
75478
|
+
};
|
|
75479
|
+
const readStartTagName = (sourceBuffer, tagStartByte) => {
|
|
75480
|
+
const firstNameByte = sourceBuffer[tagStartByte + 1];
|
|
75481
|
+
if (firstNameByte === void 0 || !/[A-Za-z]/.test(String.fromCharCode(firstNameByte))) return null;
|
|
75482
|
+
let nameEndByte = tagStartByte + 2;
|
|
75483
|
+
while (nameEndByte < sourceBuffer.length && /[A-Za-z0-9:-]/.test(String.fromCharCode(sourceBuffer[nameEndByte] ?? 32))) nameEndByte++;
|
|
75484
|
+
return sourceBuffer.subarray(tagStartByte + 1, nameEndByte).toString("ascii").toLowerCase();
|
|
75485
|
+
};
|
|
75486
|
+
const findTagEnd = (sourceBuffer, startByte) => {
|
|
75487
|
+
let quoteByte = null;
|
|
75488
|
+
for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) {
|
|
75489
|
+
const byte = sourceBuffer[byteIndex];
|
|
75490
|
+
if (quoteByte !== null) {
|
|
75491
|
+
if (byte === quoteByte) quoteByte = null;
|
|
75492
|
+
continue;
|
|
75493
|
+
}
|
|
75494
|
+
if (byte === SINGLE_QUOTE_UTF8_BYTE || byte === DOUBLE_QUOTE_UTF8_BYTE) {
|
|
75495
|
+
quoteByte = byte;
|
|
75496
|
+
continue;
|
|
75497
|
+
}
|
|
75498
|
+
if (byte === TAG_CLOSE_UTF8_BYTE) return byteIndex;
|
|
75499
|
+
}
|
|
75500
|
+
return sourceBuffer.length;
|
|
75501
|
+
};
|
|
75502
|
+
const parseScriptAttributes = (sourceBuffer, attributesStartByte, tagEndByte) => {
|
|
75503
|
+
let byteIndex = attributesStartByte;
|
|
75504
|
+
let hasSource = false;
|
|
75505
|
+
let language = null;
|
|
75506
|
+
let scriptType = null;
|
|
75507
|
+
while (byteIndex < tagEndByte) {
|
|
75508
|
+
while (byteIndex < tagEndByte && (isHtmlWhitespace(sourceBuffer[byteIndex]) || sourceBuffer[byteIndex] === TAG_SELF_CLOSE_UTF8_BYTE)) byteIndex++;
|
|
75509
|
+
const attributeNameStartByte = byteIndex;
|
|
75510
|
+
while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== ATTRIBUTE_ASSIGNMENT_UTF8_BYTE && sourceBuffer[byteIndex] !== TAG_SELF_CLOSE_UTF8_BYTE) byteIndex++;
|
|
75511
|
+
const attributeName = sourceBuffer.subarray(attributeNameStartByte, byteIndex).toString("ascii").toLowerCase();
|
|
75512
|
+
while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
|
|
75513
|
+
let attributeValue = "";
|
|
75514
|
+
if (sourceBuffer[byteIndex] === ATTRIBUTE_ASSIGNMENT_UTF8_BYTE) {
|
|
75515
|
+
byteIndex++;
|
|
75516
|
+
while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
|
|
75517
|
+
const quoteByte = sourceBuffer[byteIndex];
|
|
75518
|
+
if (quoteByte === SINGLE_QUOTE_UTF8_BYTE || quoteByte === DOUBLE_QUOTE_UTF8_BYTE) {
|
|
75519
|
+
const valueStartByte = byteIndex + 1;
|
|
75520
|
+
byteIndex = valueStartByte;
|
|
75521
|
+
while (byteIndex < tagEndByte && sourceBuffer[byteIndex] !== quoteByte) byteIndex++;
|
|
75522
|
+
attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
|
|
75523
|
+
if (byteIndex < tagEndByte) byteIndex++;
|
|
75524
|
+
} else {
|
|
75525
|
+
const valueStartByte = byteIndex;
|
|
75526
|
+
while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== TAG_CLOSE_UTF8_BYTE) byteIndex++;
|
|
75527
|
+
attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
|
|
75528
|
+
}
|
|
75529
|
+
}
|
|
75530
|
+
if (attributeName === "src") hasSource = true;
|
|
75531
|
+
else if (attributeName === "type" && scriptType === null) scriptType = attributeValue;
|
|
75532
|
+
else if (attributeName === "language" && language === null) language = attributeValue;
|
|
75533
|
+
}
|
|
75534
|
+
return {
|
|
75535
|
+
hasSource,
|
|
75536
|
+
language,
|
|
75537
|
+
type: scriptType
|
|
75538
|
+
};
|
|
75539
|
+
};
|
|
75540
|
+
const isExecutableScript = (attributes) => {
|
|
75541
|
+
if (attributes.hasSource) return false;
|
|
75542
|
+
const type = attributes.type?.trim().toLowerCase() ?? "";
|
|
75543
|
+
if (type !== "") {
|
|
75544
|
+
const mimeType = type.split(";")[0]?.trim() ?? "";
|
|
75545
|
+
return mimeType === "module" || JAVASCRIPT_MIME_TYPES.has(mimeType);
|
|
75546
|
+
}
|
|
75547
|
+
const language = attributes.language?.trim().toLowerCase() ?? "";
|
|
75548
|
+
return language === "" || JAVASCRIPT_MIME_TYPES.has(`text/${language}`);
|
|
75549
|
+
};
|
|
75550
|
+
const findElementClose = (sourceBuffer, startByte, tagName) => {
|
|
75551
|
+
const closeTagStart = `</${tagName}`;
|
|
75552
|
+
for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) if (sourceBuffer[byteIndex] === TAG_OPEN_UTF8_BYTE && matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, closeTagStart) && isTagBoundary(sourceBuffer[byteIndex + closeTagStart.length])) return byteIndex;
|
|
75553
|
+
return sourceBuffer.length;
|
|
75554
|
+
};
|
|
75555
|
+
const prepareHtmlScriptSource = (sourceBuffer) => {
|
|
75556
|
+
const frontmatterEndByte = findFrontmatterEnd(sourceBuffer);
|
|
75557
|
+
let maskedBuffer = frontmatterEndByte > 0 ? Buffer.from(sourceBuffer) : null;
|
|
75558
|
+
if (maskedBuffer !== null) maskByteRange(maskedBuffer, 0, frontmatterEndByte);
|
|
75559
|
+
const executableScriptBodies = [];
|
|
75560
|
+
let byteIndex = frontmatterEndByte;
|
|
75561
|
+
let templateDepth = 0;
|
|
75562
|
+
while (byteIndex < sourceBuffer.length) {
|
|
75563
|
+
if (sourceBuffer[byteIndex] !== TAG_OPEN_UTF8_BYTE) {
|
|
75564
|
+
byteIndex++;
|
|
75565
|
+
continue;
|
|
75566
|
+
}
|
|
75567
|
+
if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, COMMENT_OPEN)) {
|
|
75568
|
+
const commentEndByte = sourceBuffer.indexOf(COMMENT_CLOSE, byteIndex + 4);
|
|
75569
|
+
byteIndex = commentEndByte === -1 ? sourceBuffer.length : commentEndByte + 3;
|
|
75570
|
+
continue;
|
|
75571
|
+
}
|
|
75572
|
+
if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, TEMPLATE_CLOSE) && isTagBoundary(sourceBuffer[byteIndex + TEMPLATE_CLOSE.length])) {
|
|
75573
|
+
const tagEndByte = findTagEnd(sourceBuffer, byteIndex + TEMPLATE_CLOSE.length);
|
|
75574
|
+
if (templateDepth > 0) templateDepth--;
|
|
75575
|
+
byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
|
|
75576
|
+
continue;
|
|
75577
|
+
}
|
|
75578
|
+
if (!matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, SCRIPT_OPEN) || !isTagBoundary(sourceBuffer[byteIndex + SCRIPT_OPEN.length])) {
|
|
75579
|
+
if (!isPotentialTagStart(sourceBuffer[byteIndex + 1])) {
|
|
75580
|
+
byteIndex++;
|
|
75581
|
+
continue;
|
|
75582
|
+
}
|
|
75583
|
+
const tagEndByte = findTagEnd(sourceBuffer, byteIndex + 1);
|
|
75584
|
+
const tagName = readStartTagName(sourceBuffer, byteIndex);
|
|
75585
|
+
if (tagName === PLAINTEXT_TAG_NAME) break;
|
|
75586
|
+
if (tagName === TEMPLATE_TAG_NAME) templateDepth++;
|
|
75587
|
+
if (tagName !== null && RAW_TEXT_TAG_NAMES.has(tagName)) {
|
|
75588
|
+
const closeTagStartByte = findElementClose(sourceBuffer, tagEndByte + 1, tagName);
|
|
75589
|
+
if (closeTagStartByte === sourceBuffer.length) break;
|
|
75590
|
+
const closeTagEndByte = findTagEnd(sourceBuffer, closeTagStartByte + tagName.length + 2);
|
|
75591
|
+
byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
|
|
75592
|
+
continue;
|
|
75593
|
+
}
|
|
75594
|
+
byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
|
|
75595
|
+
continue;
|
|
75596
|
+
}
|
|
75597
|
+
const tagEndByte = findTagEnd(sourceBuffer, byteIndex + SCRIPT_OPEN.length);
|
|
75598
|
+
if (tagEndByte === sourceBuffer.length) break;
|
|
75599
|
+
const bodyStartByte = tagEndByte + 1;
|
|
75600
|
+
const bodyEndByte = findElementClose(sourceBuffer, bodyStartByte, SCRIPT_TAG_NAME);
|
|
75601
|
+
const attributes = parseScriptAttributes(sourceBuffer, byteIndex + SCRIPT_OPEN.length, tagEndByte);
|
|
75602
|
+
if (attributes.hasSource || templateDepth > 0) {
|
|
75603
|
+
maskedBuffer ??= Buffer.from(sourceBuffer);
|
|
75604
|
+
maskByteRange(maskedBuffer, bodyStartByte, bodyEndByte);
|
|
75605
|
+
} else if (isExecutableScript(attributes)) executableScriptBodies.push(sourceBuffer.subarray(bodyStartByte, bodyEndByte));
|
|
75606
|
+
if (bodyEndByte === sourceBuffer.length) break;
|
|
75607
|
+
const closeTagEndByte = findTagEnd(sourceBuffer, bodyEndByte + SCRIPT_CLOSE.length);
|
|
75608
|
+
byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
|
|
75609
|
+
}
|
|
75610
|
+
return {
|
|
75611
|
+
executableScriptBodies,
|
|
75612
|
+
lintBuffer: maskedBuffer ?? sourceBuffer
|
|
75613
|
+
};
|
|
75614
|
+
};
|
|
75615
|
+
const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
|
|
75616
|
+
const lintFiles = [];
|
|
75617
|
+
const sourcePathByLintPath = /* @__PURE__ */ new Map();
|
|
75618
|
+
const sizeByLintPath = /* @__PURE__ */ new Map();
|
|
75619
|
+
const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
|
|
75620
|
+
let htmlFileIndex = 0;
|
|
75621
|
+
let hasThreeModuleImport = false;
|
|
75622
|
+
for (const candidateFile of candidateFiles) {
|
|
75623
|
+
if (!HTML_FILE_PATTERN.test(candidateFile)) {
|
|
75624
|
+
lintFiles.push(candidateFile);
|
|
75625
|
+
continue;
|
|
75626
|
+
}
|
|
75627
|
+
const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
|
|
75628
|
+
const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
|
|
75629
|
+
const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
|
|
75630
|
+
if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
|
|
75631
|
+
const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
|
|
75632
|
+
NFS.writeFileSync(lintPath, lintBuffer);
|
|
75633
|
+
lintFiles.push(lintPath);
|
|
75634
|
+
sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
|
|
75635
|
+
sizeByLintPath.set(lintPath, sourceBuffer.length);
|
|
75636
|
+
hasThreeModuleImport ||= executableScriptBodies.some((scriptBody) => containsThreeModuleImport(scriptBody.toString("utf8")));
|
|
75637
|
+
htmlFileIndex++;
|
|
75638
|
+
}
|
|
75639
|
+
return {
|
|
75640
|
+
lintFiles,
|
|
75641
|
+
sourcePathByLintPath,
|
|
75642
|
+
sizeByLintPath,
|
|
75643
|
+
hasThreeModuleImport
|
|
75644
|
+
};
|
|
75645
|
+
};
|
|
74753
75646
|
/**
|
|
74754
75647
|
* Atomically (re)writes the generated oxlintrc.json. Used twice in
|
|
74755
75648
|
* the runner: once for the primary scan, once for the
|
|
@@ -74910,6 +75803,8 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
74910
75803
|
const runOxlint = async (options) => {
|
|
74911
75804
|
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
74912
75805
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
75806
|
+
const runtimeGlobals = Array.isArray(userConfig?.runtimeGlobals) ? userConfig.runtimeGlobals.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
75807
|
+
let unpluginAutoImportGlobalScopes = [];
|
|
74913
75808
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
74914
75809
|
validateRuleRegistration();
|
|
74915
75810
|
resetManifestCaches();
|
|
@@ -74923,21 +75818,6 @@ const runOxlint = async (options) => {
|
|
|
74923
75818
|
const pluginPath = resolvePluginPath();
|
|
74924
75819
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
74925
75820
|
const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
74926
|
-
const buildConfig = (overrides) => createOxlintConfig({
|
|
74927
|
-
pluginPath,
|
|
74928
|
-
project,
|
|
74929
|
-
customRulesOnly,
|
|
74930
|
-
extendsPaths: overrides.extendsPaths,
|
|
74931
|
-
ignoredTags,
|
|
74932
|
-
includedTags,
|
|
74933
|
-
includeTagDefaults,
|
|
74934
|
-
serverAuthFunctionNames,
|
|
74935
|
-
severityControls,
|
|
74936
|
-
userPlugins,
|
|
74937
|
-
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
74938
|
-
ruleSelection: overrides.ruleSelection,
|
|
74939
|
-
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
74940
|
-
});
|
|
74941
75821
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
74942
75822
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
74943
75823
|
const configPath = Path.join(configDirectory, "oxlintrc.json");
|
|
@@ -74973,7 +75853,36 @@ const runOxlint = async (options) => {
|
|
|
74973
75853
|
await yieldToEventLoop();
|
|
74974
75854
|
const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
|
|
74975
75855
|
const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
|
|
75856
|
+
unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
|
|
75857
|
+
rootDirectory,
|
|
75858
|
+
candidateFiles
|
|
75859
|
+
});
|
|
75860
|
+
const preparedHtmlSources = prepareHtmlLintSources(rootDirectory, configDirectory, candidateFiles);
|
|
75861
|
+
const lintFiles = preparedHtmlSources.lintFiles;
|
|
75862
|
+
const hasHtmlFiles = preparedHtmlSources.sourcePathByLintPath.size > 0;
|
|
75863
|
+
const lintProject = !project.hasThree && preparedHtmlSources.hasThreeModuleImport ? {
|
|
75864
|
+
...project,
|
|
75865
|
+
hasThree: true
|
|
75866
|
+
} : project;
|
|
75867
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
75868
|
+
pluginPath,
|
|
75869
|
+
project: lintProject,
|
|
75870
|
+
customRulesOnly,
|
|
75871
|
+
extendsPaths: overrides.extendsPaths,
|
|
75872
|
+
ignoredTags,
|
|
75873
|
+
includedTags,
|
|
75874
|
+
includeTagDefaults,
|
|
75875
|
+
runtimeGlobals,
|
|
75876
|
+
unpluginAutoImportGlobalScopes,
|
|
75877
|
+
serverAuthFunctionNames,
|
|
75878
|
+
severityControls,
|
|
75879
|
+
userPlugins,
|
|
75880
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
75881
|
+
ruleSelection: overrides.ruleSelection,
|
|
75882
|
+
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
75883
|
+
});
|
|
74976
75884
|
const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
|
|
75885
|
+
if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedHtmlSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
|
|
74977
75886
|
const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
|
|
74978
75887
|
baseArgs: passBaseArgs,
|
|
74979
75888
|
files: passFiles,
|
|
@@ -75002,7 +75911,8 @@ const runOxlint = async (options) => {
|
|
|
75002
75911
|
fileBatches: passFileBatches,
|
|
75003
75912
|
rootDirectory,
|
|
75004
75913
|
nodeBinaryPath,
|
|
75005
|
-
project,
|
|
75914
|
+
project: lintProject,
|
|
75915
|
+
sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
|
|
75006
75916
|
onPartialFailure: reportPartialFailure,
|
|
75007
75917
|
onAnalyzedFiles: (filePaths) => {
|
|
75008
75918
|
analyzedFiles = filePaths;
|
|
@@ -75037,7 +75947,7 @@ const runOxlint = async (options) => {
|
|
|
75037
75947
|
};
|
|
75038
75948
|
}
|
|
75039
75949
|
};
|
|
75040
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
75950
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasHtmlFiles) {
|
|
75041
75951
|
const rulesetHash = computeRulesetHash({
|
|
75042
75952
|
config: buildConfig({
|
|
75043
75953
|
extendsPaths: [],
|
|
@@ -75195,14 +76105,15 @@ const runOxlint = async (options) => {
|
|
|
75195
76105
|
]);
|
|
75196
76106
|
}
|
|
75197
76107
|
const baseArgs = makeBaseArgs(configPath);
|
|
75198
|
-
const fileBatches = buildFileBatches(baseArgs,
|
|
76108
|
+
const fileBatches = buildFileBatches(baseArgs, lintFiles);
|
|
75199
76109
|
let analyzedFiles = [];
|
|
75200
76110
|
const runBatches = () => spawnLintBatches({
|
|
75201
76111
|
baseArgs,
|
|
75202
76112
|
fileBatches,
|
|
75203
76113
|
rootDirectory,
|
|
75204
76114
|
nodeBinaryPath,
|
|
75205
|
-
project,
|
|
76115
|
+
project: lintProject,
|
|
76116
|
+
sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
|
|
75206
76117
|
onPartialFailure,
|
|
75207
76118
|
onAnalyzedFiles: (filePaths) => {
|
|
75208
76119
|
analyzedFiles = filePaths;
|
|
@@ -77409,7 +78320,7 @@ const makeNoopConsole = () => ({
|
|
|
77409
78320
|
});
|
|
77410
78321
|
//#endregion
|
|
77411
78322
|
//#region src/cli/utils/version.ts
|
|
77412
|
-
const VERSION = "0.9.
|
|
78323
|
+
const VERSION = "0.9.1-dev.49c5c1e";
|
|
77413
78324
|
//#endregion
|
|
77414
78325
|
//#region src/cli/utils/json-mode.ts
|
|
77415
78326
|
let context = null;
|
|
@@ -77767,13 +78678,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
77767
78678
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
77768
78679
|
* standard `SENTRY_RELEASE` override.
|
|
77769
78680
|
*/
|
|
77770
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.
|
|
78681
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.1-dev.49c5c1e`;
|
|
77771
78682
|
/**
|
|
77772
78683
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
77773
78684
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
77774
78685
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
77775
78686
|
*/
|
|
77776
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.
|
|
78687
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.1-dev.49c5c1e") ? "development" : "production");
|
|
77777
78688
|
/**
|
|
77778
78689
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
77779
78690
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -90438,6 +91349,7 @@ const buildScanAttributes = (input) => {
|
|
|
90438
91349
|
rulesDisabled: ruleKeys.filter((key) => ruleOverrides[key] === "off").length,
|
|
90439
91350
|
fileCount: input.result?.scannedFileCount ?? null,
|
|
90440
91351
|
nonJsxFileCount: input.result?.analyzedFiles?.filter((filePath) => !JSX_FILE_PATTERN.test(filePath)).length ?? null,
|
|
91352
|
+
htmlFileCount: input.result?.analyzedFiles?.filter((filePath) => HTML_FILE_PATTERN.test(filePath)).length ?? null,
|
|
90441
91353
|
multilineDiagnosticCount: input.result?.diagnostics.filter((diagnostic) => (diagnostic.endLine ?? diagnostic.line) > diagnostic.line).length ?? null
|
|
90442
91354
|
});
|
|
90443
91355
|
};
|
|
@@ -96491,7 +97403,7 @@ ${highlighter.dim("Learn more:")}
|
|
|
96491
97403
|
${highlighter.info(CI_URL)}
|
|
96492
97404
|
`;
|
|
96493
97405
|
const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
|
|
96494
|
-
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
|
|
97406
|
+
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS and inline HTML script source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
|
|
96495
97407
|
program.action(inspectAction);
|
|
96496
97408
|
program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
|
|
96497
97409
|
program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
|
|
@@ -96571,4 +97483,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
96571
97483
|
export { toForwardSlashes as A, highlighter as B, buildRulePriorityMap as C, resolveBlockingLevel as D, formatLearnMoreLine as E, isCiEnvironment as F, sync as G, mergeReactDoctorConfigs as H, DIAGNOSTIC_CATEGORY_BUCKETS as I, void_ as K, Progress as L, isUnicodeSupported as M, METRIC as N, isReactDoctorWorkflowInstalled as O, TUI_REPORT_DETAIL_WIDTH_FRACTION as P, Reporter as R, hasLintHardFailure as S, formatFixRecipeLine as T, resolveScanTarget as U, mapWithConcurrency as V, runPromise as W, canAnimateOnboarding as _, resolveCliInspectOptions as a, buildCodeFrame as b, detectLaunchableAgents as c, launchCliAgent as d, isShareOptedOut as f, doctorFace as g, easeOutCubic as h, selectProjects as i, findNearestPackageDirectory as j, recordCount as k, CLI_AGENT_BINARIES as l, printFooter as m, shouldFailScanGate as n, countUniqueScannedFiles as o, inspect as p, succeed$3 as q, discoverWorkspacePackages as r, setUpGitHubActions as s, exitGracefully as t, copyToClipboard as u, computeProjectedScore as v, buildSortedRuleGroups as w, buildNoScoreMessage as x, formatElapsedTime as y, getCategoryImpact as z };
|
|
96572
97484
|
|
|
96573
97485
|
//# sourceMappingURL=cli.js.map
|
|
96574
|
-
//# debugId=
|
|
97486
|
+
//# debugId=7f26fa62-fe0c-5ae0-bc9c-97a0deb50b43
|