react-doctor 0.9.0 → 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/dist/lsp.js CHANGED
@@ -61478,7 +61478,8 @@ var AmbiguousProjectError = class extends Error {
61478
61478
  }
61479
61479
  };
61480
61480
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
61481
- const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
61481
+ const HTML_FILE_PATTERN = /\.html$/i;
61482
+ const SOURCE_FILE_PATTERN = /\.(?:tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
61482
61483
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
61483
61484
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
61484
61485
  const MINIFIED_SNIFF_BYTES = 65536;
@@ -61844,7 +61845,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
61844
61845
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
61845
61846
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
61846
61847
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
61847
- const CORE_PACKAGE_VERSION = "0.9.0";
61848
+ const CORE_PACKAGE_VERSION = "0.9.1";
61848
61849
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
61849
61850
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
61850
61851
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -62235,6 +62236,7 @@ const frameworkMergeRank = (framework) => {
62235
62236
  return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
62236
62237
  };
62237
62238
  const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
62239
+ const REACT_COMPILER_RUNTIME_PACKAGES = new Set(["react-compiler-runtime"]);
62238
62240
  const NEXT_CONFIG_FILENAMES = [
62239
62241
  "next.config.js",
62240
62242
  "next.config.mjs",
@@ -62337,10 +62339,10 @@ const resolveImportedConfigFile = (fromFilePath, moduleSpecifier) => {
62337
62339
  ]).find(isFile) ?? null;
62338
62340
  };
62339
62341
  const parseConfigSourceFile = (filePath, content) => filePath.endsWith(".json") || Path.basename(filePath) === ".babelrc" ? ts.parseJsonText(filePath, content) : ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
62340
- const getStaticPropertyName$1 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
62342
+ const getStaticPropertyName$2 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
62341
62343
  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");
62342
62344
  const hasExportModifier = (node) => ts.canHaveModifiers(node) && Boolean(ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
62343
- const getRequireModuleSpecifier = (expression) => {
62345
+ const getRequireModuleSpecifier$1 = (expression) => {
62344
62346
  if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "require" || expression.arguments.length !== 1) return null;
62345
62347
  const moduleSpecifier = expression.arguments[0];
62346
62348
  return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
@@ -62353,7 +62355,7 @@ const hasTopLevelValueBinding = (sourceFile, bindingName) => sourceFile.statemen
62353
62355
  const namedBindings = importClause?.namedBindings;
62354
62356
  return namedBindings ? ts.isNamespaceImport(namedBindings) ? namedBindings.name.text === bindingName : namedBindings.elements.some((element) => element.name.text === bindingName) : false;
62355
62357
  }
62356
- if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === bindingName);
62358
+ if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContainsIdentifier(declaration.name, bindingName));
62357
62359
  return (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name?.text === bindingName;
62358
62360
  });
62359
62361
  const getImportBinding = (sourceFile, bindingName) => {
@@ -62384,24 +62386,24 @@ const getImportBinding = (sourceFile, bindingName) => {
62384
62386
  for (const declaration of statement.declarationList.declarations) {
62385
62387
  if (!declaration.initializer) continue;
62386
62388
  if (ts.isIdentifier(declaration.name) && declaration.name.text === bindingName) {
62387
- const directModuleSpecifier = getRequireModuleSpecifier(declaration.initializer);
62389
+ const directModuleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
62388
62390
  if (directModuleSpecifier) return {
62389
62391
  moduleSpecifier: directModuleSpecifier,
62390
62392
  exportName: "default",
62391
62393
  isNamespace: true
62392
62394
  };
62393
- if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier(declaration.initializer.expression) !== null) return {
62394
- moduleSpecifier: getRequireModuleSpecifier(declaration.initializer.expression) ?? "",
62395
+ if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier$1(declaration.initializer.expression) !== null) return {
62396
+ moduleSpecifier: getRequireModuleSpecifier$1(declaration.initializer.expression) ?? "",
62395
62397
  exportName: declaration.initializer.name.text,
62396
62398
  isNamespace: false
62397
62399
  };
62398
62400
  }
62399
62401
  if (!ts.isObjectBindingPattern(declaration.name)) continue;
62400
62402
  const bindingElement = declaration.name.elements.find((element) => ts.isIdentifier(element.name) && element.name.text === bindingName);
62401
- const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
62403
+ const moduleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
62402
62404
  if (bindingElement && moduleSpecifier) return {
62403
62405
  moduleSpecifier,
62404
- exportName: bindingElement.propertyName ? getStaticPropertyName$1(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
62406
+ exportName: bindingElement.propertyName ? getStaticPropertyName$2(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
62405
62407
  isNamespace: false
62406
62408
  };
62407
62409
  }
@@ -62454,6 +62456,48 @@ const getScopedConfigBinding = (identifier) => {
62454
62456
  };
62455
62457
  };
62456
62458
  const isCompilerTransformModule = (moduleSpecifier, exportName) => moduleSpecifier === "babel-plugin-react-compiler" && exportName === "default" || moduleSpecifier === "@vitejs/plugin-react" && exportName === "reactCompilerPreset";
62459
+ const NODE_MODULE_SPECIFIERS = new Set(["module", "node:module"]);
62460
+ const isConstantVariableInitializer = (node) => ts.isExpression(node) && ts.isVariableDeclaration(node.parent) && ts.isVariableDeclarationList(node.parent.parent) && Boolean(node.parent.parent.flags & ts.NodeFlags.Const);
62461
+ const isNodeCreateRequireCall = (node, analysis) => {
62462
+ if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertionExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isAwaitExpression(node)) return isNodeCreateRequireCall(node.expression, analysis);
62463
+ if (!ts.isCallExpression(node)) return false;
62464
+ const target = node.expression;
62465
+ if (ts.isIdentifier(target)) {
62466
+ if (analysis.localBindings.has(target.text) || getScopedConfigBinding(target).wasFound) return false;
62467
+ const importBinding = getImportBinding(analysis.sourceFile, target.text);
62468
+ return Boolean(importBinding && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier) && importBinding.exportName === "createRequire");
62469
+ }
62470
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return false;
62471
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "createRequire") return false;
62472
+ const createRequireReceiver = target.expression;
62473
+ if (ts.isCallExpression(createRequireReceiver)) {
62474
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(createRequireReceiver);
62475
+ if (requiredModuleSpecifier === null || !NODE_MODULE_SPECIFIERS.has(requiredModuleSpecifier) || !ts.isIdentifier(createRequireReceiver.expression)) return false;
62476
+ const requireIdentifier = createRequireReceiver.expression;
62477
+ return !analysis.localBindings.has(requireIdentifier.text) && !getScopedConfigBinding(requireIdentifier).wasFound && !hasTopLevelValueBinding(analysis.sourceFile, requireIdentifier.text);
62478
+ }
62479
+ if (!ts.isIdentifier(createRequireReceiver)) return false;
62480
+ if (analysis.localBindings.has(createRequireReceiver.text) || getScopedConfigBinding(createRequireReceiver).wasFound) return false;
62481
+ const importBinding = getImportBinding(analysis.sourceFile, createRequireReceiver.text);
62482
+ return Boolean(importBinding?.isNamespace && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier));
62483
+ };
62484
+ const getNodeRequireResolveModuleSpecifier = (callExpression, analysis) => {
62485
+ const [moduleSpecifierNode] = callExpression.arguments;
62486
+ if (!moduleSpecifierNode || !ts.isStringLiteralLike(moduleSpecifierNode)) return null;
62487
+ const target = callExpression.expression;
62488
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
62489
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "resolve") return null;
62490
+ if (isNodeCreateRequireCall(target.expression, analysis)) return moduleSpecifierNode.text;
62491
+ if (!ts.isIdentifier(target.expression)) return null;
62492
+ const resolverIdentifier = target.expression;
62493
+ if (analysis.localBindings.has(resolverIdentifier.text)) return null;
62494
+ const scopedBinding = getScopedConfigBinding(resolverIdentifier);
62495
+ const topLevelBinding = scopedBinding.wasFound ? null : getTopLevelBinding(analysis.sourceFile, resolverIdentifier.text);
62496
+ const resolverInitializer = scopedBinding.wasFound ? scopedBinding.initializer : topLevelBinding;
62497
+ if (resolverInitializer === null && !scopedBinding.wasFound && resolverIdentifier.text === "require" && !hasTopLevelValueBinding(analysis.sourceFile, resolverIdentifier.text) && getImportBinding(analysis.sourceFile, resolverIdentifier.text) === null) return moduleSpecifierNode.text;
62498
+ if (!resolverInitializer || !isConstantVariableInitializer(resolverInitializer) || !isNodeCreateRequireCall(resolverInitializer, analysis)) return null;
62499
+ return moduleSpecifierNode.text;
62500
+ };
62457
62501
  const getAssignedPropertyInitializer = (identifier, propertyName) => {
62458
62502
  let bindingScope = null;
62459
62503
  let currentNode = identifier;
@@ -62562,7 +62606,7 @@ const getReactCompilerFlagState = (expression, analysis) => {
62562
62606
  }
62563
62607
  if (!ts.isObjectLiteralExpression(unwrappedExpression)) return null;
62564
62608
  for (const property of [...unwrappedExpression.properties].reverse()) {
62565
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
62609
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
62566
62610
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.name, analysis) };
62567
62611
  if (ts.isSpreadAssignment(property)) {
62568
62612
  const spreadState = getReactCompilerFlagState(property.expression, analysis);
@@ -62588,8 +62632,8 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
62588
62632
  }
62589
62633
  if (!ts.isObjectLiteralExpression(resolvedExpression)) return null;
62590
62634
  for (const property of [...resolvedExpression.properties].reverse()) {
62591
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === propertyName) return property.initializer;
62592
- if (ts.isMethodDeclaration(property) && getStaticPropertyName$1(property.name) === propertyName) return property;
62635
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === propertyName) return property.initializer;
62636
+ if (ts.isMethodDeclaration(property) && getStaticPropertyName$2(property.name) === propertyName) return property;
62593
62637
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property.name;
62594
62638
  if (ts.isSpreadAssignment(property)) {
62595
62639
  const spreadProperty = getSelectedObjectProperty(property.expression, propertyName, analysis, visitedExpressions);
@@ -62620,7 +62664,7 @@ const configExpressionMayDefineProperty = (expression, propertyName, analysis) =
62620
62664
  return resolvedExpression.properties.some((property) => {
62621
62665
  if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
62622
62666
  if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
62623
- const staticPropertyName = getStaticPropertyName$1(property.name);
62667
+ const staticPropertyName = getStaticPropertyName$2(property.name);
62624
62668
  return staticPropertyName === null || staticPropertyName === propertyName;
62625
62669
  }
62626
62670
  return false;
@@ -62639,7 +62683,7 @@ const getExportedConfigNodes = (sourceFile, exportName) => {
62639
62683
  continue;
62640
62684
  }
62641
62685
  if (ts.isExpressionStatement(statement) && isCommonJsConfigExportAssignment(statement.expression, sourceFile) && exportName !== "default" && ts.isObjectLiteralExpression(statement.expression.right)) for (const property of [...statement.expression.right.properties].reverse()) {
62642
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === exportName) {
62686
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === exportName) {
62643
62687
  exportedNodes.push(property.initializer);
62644
62688
  break;
62645
62689
  }
@@ -62769,7 +62813,7 @@ const analyzeConfigCallTarget = (callExpression, analysis, allowCompilerTransfor
62769
62813
  if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
62770
62814
  const propertyName = ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null;
62771
62815
  if (propertyName === null) return null;
62772
- const requiredModuleSpecifier = getRequireModuleSpecifier(target.expression);
62816
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(target.expression);
62773
62817
  if (requiredModuleSpecifier !== null) {
62774
62818
  if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62775
62819
  if (!requiredModuleSpecifier.startsWith(".")) return null;
@@ -62798,10 +62842,10 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62798
62842
  const reactCompilerFlagState = excludedPropertyNames?.has("reactCompiler") ? null : getReactCompilerFlagState(node, analysis);
62799
62843
  if (reactCompilerFlagState?.isEnabled) return true;
62800
62844
  for (const [propertyIndex, property] of node.properties.entries()) if (ts.isPropertyAssignment(property)) {
62801
- const propertyName = getStaticPropertyName$1(property.name);
62845
+ const propertyName = getStaticPropertyName$2(property.name);
62802
62846
  if (propertyName && excludedPropertyNames?.has(propertyName)) continue;
62803
62847
  if (propertyName === "reactCompiler") continue;
62804
- 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$1(laterProperty.name) === propertyName)) continue;
62848
+ 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;
62805
62849
  const propertyAllowsCompilerTransform = propertyName === "plugins" || propertyName === "presets";
62806
62850
  if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer) && property.initializer.text.startsWith(".")) {
62807
62851
  const extendedFilePath = resolveImportedConfigFile(analysis.filePath, property.initializer.text);
@@ -62811,12 +62855,12 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62811
62855
  } else if (ts.isShorthandPropertyAssignment(property)) {
62812
62856
  if (excludedPropertyNames?.has(property.name.text)) continue;
62813
62857
  if (property.name.text === "reactCompiler") continue;
62814
- 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$1(laterProperty.name) === property.name.text)) continue;
62858
+ 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;
62815
62859
  const propertyAllowsCompilerTransform = property.name.text === "plugins" || property.name.text === "presets";
62816
62860
  if (analyzeConfigNode(property.name, analysis, propertyAllowsCompilerTransform, propertyAllowsCompilerTransform)) return true;
62817
62861
  } else if (ts.isSpreadAssignment(property)) {
62818
62862
  if (reactCompilerFlagState && getReactCompilerFlagState(property.expression, analysis) !== null) continue;
62819
- if (node.properties.slice(propertyIndex + 1).some((laterProperty) => (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && (getStaticPropertyName$1(laterProperty.name) === "plugins" || getStaticPropertyName$1(laterProperty.name) === "presets"))) continue;
62863
+ 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;
62820
62864
  if (analyzeConfigNode(property.expression, analysis, allowCompilerTransform, false, excludedPropertyNames)) return true;
62821
62865
  }
62822
62866
  return false;
@@ -62829,9 +62873,11 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62829
62873
  });
62830
62874
  }
62831
62875
  if (ts.isCallExpression(node)) {
62876
+ const resolvedModuleSpecifier = getNodeRequireResolveModuleSpecifier(node, analysis);
62877
+ if (resolvedModuleSpecifier !== null) return allowCompilerTransform && isCompilerTransformModule(resolvedModuleSpecifier, "default");
62832
62878
  const callTargetResult = analyzeConfigCallTarget(node, analysis, allowCompilerTransform);
62833
62879
  if (callTargetResult !== null) return callTargetResult;
62834
- const directModuleSpecifier = getRequireModuleSpecifier(node);
62880
+ const directModuleSpecifier = getRequireModuleSpecifier$1(node);
62835
62881
  const isRequireShadowed = analysis.localBindings.has("require") || ts.isIdentifier(node.expression) && getScopedConfigBinding(node.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require");
62836
62882
  if (directModuleSpecifier && isRequireShadowed) return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
62837
62883
  if (directModuleSpecifier && !isRequireShadowed) {
@@ -62853,7 +62899,7 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62853
62899
  return analyzeConfigNode(node.expression, analysis, allowCompilerTransform) || node.arguments.some((argument) => analyzeConfigNode(argument, analysis, false));
62854
62900
  }
62855
62901
  if (ts.isPropertyAccessExpression(node)) {
62856
- const requiredModuleSpecifier = getRequireModuleSpecifier(node.expression);
62902
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(node.expression);
62857
62903
  if (requiredModuleSpecifier) {
62858
62904
  if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62859
62905
  if (requiredModuleSpecifier.startsWith(".")) {
@@ -62941,7 +62987,7 @@ const hasCompilerConfigurationInAncestors = (directory) => {
62941
62987
  }
62942
62988
  return false;
62943
62989
  };
62944
- const detectReactCompiler = (directory, packageJson) => hasCompilerConfiguration(directory, packageJson) || hasCompilerConfigurationInAncestors(directory);
62990
+ const detectReactCompiler = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_RUNTIME_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_RUNTIME_PACKAGES) || hasCompilerConfiguration(directory, packageJson) || hasCompilerConfigurationInAncestors(directory);
62945
62991
  const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
62946
62992
  const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
62947
62993
  const filePath = Path.join(directory, filename);
@@ -66164,7 +66210,7 @@ const warn = (message) => {
66164
66210
  runSync(warn$1(message));
66165
66211
  };
66166
66212
  const CONFIG_BASENAME = "doctor.config";
66167
- const CONFIG_EXTENSIONS = [
66213
+ const CONFIG_EXTENSIONS$1 = [
66168
66214
  "ts",
66169
66215
  "mts",
66170
66216
  "cts",
@@ -66268,7 +66314,7 @@ const loadLegacyConfig = (directory) => {
66268
66314
  };
66269
66315
  const loadConfigFromDirectory = async (directory) => {
66270
66316
  let sawBrokenConfigFile = false;
66271
- for (const extension of CONFIG_EXTENSIONS) {
66317
+ for (const extension of CONFIG_EXTENSIONS$1) {
66272
66318
  const filePath = Path.join(directory, `${CONFIG_BASENAME}.${extension}`);
66273
66319
  if (!isFile(filePath)) continue;
66274
66320
  const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
@@ -66955,6 +67001,321 @@ const buildReactNativeDiagnostic = (input) => ({
66955
67001
  column: input.column ?? 0,
66956
67002
  category: input.category ?? "Correctness"
66957
67003
  });
67004
+ const ANDROID_APP_BUILD_FILE_NAMES = ["build.gradle", "build.gradle.kts"];
67005
+ const BUILD_TYPES_BLOCK_PATTERN = /\bbuildTypes\s*\{/g;
67006
+ const RELEASE_STRING_MARKER = "__RD_RELEASE__";
67007
+ const RELEASE_BLOCK_PATTERNS = [/\brelease\s*\{/g, /\b(?:getByName|named)\s*\(\s*(?:["']release["']|__RD_RELEASE__)\s*\)\s*\{/g];
67008
+ const MINIFY_ASSIGNMENT_PATTERN = /\b(?:isMinifyEnabled|minifyEnabled)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
67009
+ const SHRINK_RESOURCES_ASSIGNMENT_PATTERN = /\b(?:isShrinkResources|shrinkResources)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
67010
+ const stripGradleComments = (contents) => {
67011
+ let result = "";
67012
+ let index = 0;
67013
+ let quote = null;
67014
+ while (index < contents.length) {
67015
+ const character = contents[index];
67016
+ const nextCharacter = contents[index + 1];
67017
+ if (quote !== null) {
67018
+ result += character;
67019
+ if (character === "\\") {
67020
+ result += nextCharacter ?? "";
67021
+ index += 2;
67022
+ continue;
67023
+ }
67024
+ if (character === quote) quote = null;
67025
+ index += 1;
67026
+ continue;
67027
+ }
67028
+ if (character === "\"" || character === "'") {
67029
+ quote = character;
67030
+ result += character;
67031
+ index += 1;
67032
+ continue;
67033
+ }
67034
+ if (character === "/" && nextCharacter === "/") {
67035
+ while (index < contents.length && contents[index] !== "\n") {
67036
+ result += " ";
67037
+ index += 1;
67038
+ }
67039
+ continue;
67040
+ }
67041
+ if (character === "/" && nextCharacter === "*") {
67042
+ result += " ";
67043
+ index += 2;
67044
+ while (index < contents.length && !(contents[index] === "*" && contents[index + 1] === "/")) {
67045
+ result += contents[index] === "\n" ? "\n" : " ";
67046
+ index += 1;
67047
+ }
67048
+ if (index < contents.length) {
67049
+ result += " ";
67050
+ index += 2;
67051
+ }
67052
+ continue;
67053
+ }
67054
+ result += character;
67055
+ index += 1;
67056
+ }
67057
+ return result;
67058
+ };
67059
+ const maskGradleStrings = (contents) => {
67060
+ let result = "";
67061
+ let index = 0;
67062
+ let quote = null;
67063
+ while (index < contents.length) {
67064
+ const character = contents[index];
67065
+ if (quote === null) {
67066
+ if (character === "\"" || character === "'") {
67067
+ quote = character;
67068
+ result += " ";
67069
+ } else result += character;
67070
+ index += 1;
67071
+ continue;
67072
+ }
67073
+ if (character === "\\") {
67074
+ result += " ";
67075
+ index += 2;
67076
+ continue;
67077
+ }
67078
+ if (character === quote) quote = null;
67079
+ result += character === "\n" ? "\n" : " ";
67080
+ index += 1;
67081
+ }
67082
+ return result;
67083
+ };
67084
+ const findBlockContents = (contents, pattern) => {
67085
+ const blocks = [];
67086
+ pattern.lastIndex = 0;
67087
+ let match = pattern.exec(contents);
67088
+ while (match !== null) {
67089
+ const openingBraceIndex = pattern.lastIndex - 1;
67090
+ let depth = 1;
67091
+ let index = openingBraceIndex + 1;
67092
+ let quote = null;
67093
+ while (index < contents.length && depth > 0) {
67094
+ const character = contents[index];
67095
+ if (quote !== null) {
67096
+ if (character === "\\") {
67097
+ index += 2;
67098
+ continue;
67099
+ }
67100
+ if (character === quote) quote = null;
67101
+ } else if (character === "\"" || character === "'") quote = character;
67102
+ else if (character === "{") depth += 1;
67103
+ else if (character === "}") depth -= 1;
67104
+ index += 1;
67105
+ }
67106
+ if (depth === 0) blocks.push(contents.slice(openingBraceIndex + 1, index - 1));
67107
+ match = pattern.exec(contents);
67108
+ }
67109
+ return blocks;
67110
+ };
67111
+ const getFinalStaticBoolean = (contents, pattern) => {
67112
+ pattern.lastIndex = 0;
67113
+ let finalValue = null;
67114
+ let match = pattern.exec(contents);
67115
+ while (match !== null) {
67116
+ const staticValue = match[1]?.trim().replace(/\)$/, "").trim();
67117
+ if (staticValue === "true") finalValue = true;
67118
+ else if (staticValue === "false") finalValue = false;
67119
+ else finalValue = null;
67120
+ match = pattern.exec(contents);
67121
+ }
67122
+ return finalValue;
67123
+ };
67124
+ const getReleaseBlocks = (contents) => findBlockContents(contents, BUILD_TYPES_BLOCK_PATTERN).flatMap((buildTypesBlock) => RELEASE_BLOCK_PATTERNS.flatMap((pattern) => findBlockContents(buildTypesBlock, pattern)));
67125
+ const readAndroidReleaseShrinking = (rootDirectory) => {
67126
+ for (const buildFileName of ANDROID_APP_BUILD_FILE_NAMES) {
67127
+ const filePath = Path.posix.join("android", "app", buildFileName);
67128
+ const absoluteFilePath = Path.join(rootDirectory, filePath);
67129
+ if (!isFile(absoluteFilePath)) continue;
67130
+ let contents;
67131
+ try {
67132
+ contents = stripGradleComments(NFS.readFileSync(absoluteFilePath, "utf-8"));
67133
+ } catch {
67134
+ return null;
67135
+ }
67136
+ const releaseBlocks = getReleaseBlocks(maskGradleStrings(contents.replace(/(["'])release\1/g, RELEASE_STRING_MARKER)));
67137
+ const [releaseBlock] = releaseBlocks;
67138
+ if (releaseBlock === void 0 || releaseBlocks.length !== 1) return null;
67139
+ const hasDisabledMinification = getFinalStaticBoolean(releaseBlock, MINIFY_ASSIGNMENT_PATTERN) === false;
67140
+ const hasDisabledResourceShrinking = getFinalStaticBoolean(releaseBlock, SHRINK_RESOURCES_ASSIGNMENT_PATTERN) === false;
67141
+ if (!hasDisabledMinification && !hasDisabledResourceShrinking) return null;
67142
+ return {
67143
+ filePath,
67144
+ hasDisabledMinification,
67145
+ hasDisabledResourceShrinking
67146
+ };
67147
+ }
67148
+ return null;
67149
+ };
67150
+ const checkReactNativeAndroidReleaseShrinking = (rootDirectory) => {
67151
+ const releaseShrinking = readAndroidReleaseShrinking(rootDirectory);
67152
+ if (releaseShrinking === null) return [];
67153
+ const disabledFeatures = [releaseShrinking.hasDisabledMinification ? "code minification" : null, releaseShrinking.hasDisabledResourceShrinking ? "resource shrinking" : null].filter((feature) => feature !== null);
67154
+ return [buildReactNativeDiagnostic({
67155
+ filePath: releaseShrinking.filePath,
67156
+ rule: "rn-android-release-shrinking-disabled",
67157
+ category: "Performance",
67158
+ message: `The Android release build explicitly disables ${disabledFeatures.join(" and ")}, leaving unreachable code or resources in the shipped app.`,
67159
+ help: "Enable release code minification and resource shrinking, then test the optimized build and add keep rules for libraries that require them."
67160
+ })];
67161
+ };
67162
+ const getTypescriptScriptKind = (fileName) => {
67163
+ if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
67164
+ if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
67165
+ if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
67166
+ return ts.ScriptKind.JS;
67167
+ };
67168
+ const unwrapTypescriptExpression = (expression) => {
67169
+ let currentExpression = expression;
67170
+ while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
67171
+ return currentExpression;
67172
+ };
67173
+ const BABEL_CONFIG_FILE_NAMES$1 = [
67174
+ "babel.config.js",
67175
+ "babel.config.cjs",
67176
+ "babel.config.mjs",
67177
+ "babel.config.ts",
67178
+ "babel.config.cts",
67179
+ "babel.config.json",
67180
+ ".babelrc",
67181
+ ".babelrc.js",
67182
+ ".babelrc.cjs",
67183
+ ".babelrc.mjs",
67184
+ ".babelrc.cts",
67185
+ ".babelrc.json"
67186
+ ];
67187
+ const readUnknownPluginNames = (value) => {
67188
+ if (!Array.isArray(value)) return null;
67189
+ const pluginNames = [];
67190
+ for (const entry of value) {
67191
+ if (typeof entry === "string") {
67192
+ pluginNames.push(entry);
67193
+ continue;
67194
+ }
67195
+ if (Array.isArray(entry) && typeof entry[0] === "string") {
67196
+ pluginNames.push(entry[0]);
67197
+ continue;
67198
+ }
67199
+ return null;
67200
+ }
67201
+ return pluginNames;
67202
+ };
67203
+ const getStaticPropertyName$1 = (propertyName) => {
67204
+ if (ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName)) return propertyName.text;
67205
+ return null;
67206
+ };
67207
+ const getStaticPluginName = (expression) => {
67208
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
67209
+ if (ts.isStringLiteralLike(unwrappedExpression)) return unwrappedExpression.text;
67210
+ if (!ts.isArrayLiteralExpression(unwrappedExpression)) return null;
67211
+ const pluginExpression = unwrappedExpression.elements[0];
67212
+ return pluginExpression && ts.isStringLiteralLike(pluginExpression) ? pluginExpression.text : null;
67213
+ };
67214
+ const getPluginNamesFromObject = (objectExpression) => {
67215
+ if (objectExpression.properties.some((property) => ts.isSpreadAssignment(property))) return null;
67216
+ const pluginProperties = objectExpression.properties.filter((property) => ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === "plugins");
67217
+ if (pluginProperties.length !== 1) return pluginProperties.length === 0 ? [] : null;
67218
+ const pluginListExpression = unwrapTypescriptExpression(pluginProperties[0].initializer);
67219
+ if (!ts.isArrayLiteralExpression(pluginListExpression)) return null;
67220
+ const pluginNames = [];
67221
+ for (const element of pluginListExpression.elements) {
67222
+ if (ts.isSpreadElement(element)) return null;
67223
+ const pluginName = getStaticPluginName(element);
67224
+ if (pluginName === null) return null;
67225
+ pluginNames.push(pluginName);
67226
+ }
67227
+ return pluginNames;
67228
+ };
67229
+ 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";
67230
+ const getDirectExportedObject = (sourceFile) => {
67231
+ const exportedExpressions = [];
67232
+ for (const statement of sourceFile.statements) {
67233
+ if (ts.isExportAssignment(statement)) {
67234
+ exportedExpressions.push(statement.expression);
67235
+ continue;
67236
+ }
67237
+ if (ts.isExpressionStatement(statement) && ts.isBinaryExpression(statement.expression) && statement.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken && isModuleExports(statement.expression.left)) exportedExpressions.push(statement.expression.right);
67238
+ }
67239
+ if (exportedExpressions.length !== 1) return null;
67240
+ const exportedExpression = unwrapTypescriptExpression(exportedExpressions[0]);
67241
+ return ts.isObjectLiteralExpression(exportedExpression) ? exportedExpression : null;
67242
+ };
67243
+ const parseConfigPluginNames = (filePath, contents) => {
67244
+ try {
67245
+ const parsedJson = JSON.parse(contents);
67246
+ return isPlainObject(parsedJson) ? readUnknownPluginNames(parsedJson.plugins) : null;
67247
+ } catch {
67248
+ if (ts.transpileModule(contents, {
67249
+ fileName: filePath,
67250
+ reportDiagnostics: true,
67251
+ compilerOptions: { allowJs: true }
67252
+ }).diagnostics?.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) return null;
67253
+ const exportedObject = getDirectExportedObject(ts.createSourceFile(filePath, contents, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(filePath)));
67254
+ return exportedObject === null ? null : getPluginNamesFromObject(exportedObject);
67255
+ }
67256
+ };
67257
+ const readStaticBabelPluginNames = (rootDirectory) => {
67258
+ for (const fileName of BABEL_CONFIG_FILE_NAMES$1) {
67259
+ const absoluteFilePath = Path.join(rootDirectory, fileName);
67260
+ if (!isFile(absoluteFilePath)) continue;
67261
+ try {
67262
+ return {
67263
+ filePath: fileName,
67264
+ pluginNames: parseConfigPluginNames(fileName, NFS.readFileSync(absoluteFilePath, "utf-8"))
67265
+ };
67266
+ } catch {
67267
+ return {
67268
+ filePath: fileName,
67269
+ pluginNames: null
67270
+ };
67271
+ }
67272
+ }
67273
+ const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
67274
+ if (!isPlainObject(packageJson.babel)) return null;
67275
+ return {
67276
+ filePath: "package.json",
67277
+ pluginNames: readUnknownPluginNames(packageJson.babel.plugins)
67278
+ };
67279
+ };
67280
+ const REACT_COMPILER_PLUGIN_NAMES = new Set(["babel-plugin-react-compiler", "react-compiler"]);
67281
+ const REANIMATED_PLUGIN_NAME = "react-native-reanimated/plugin";
67282
+ const WORKLETS_PLUGIN_NAME = "react-native-worklets/plugin";
67283
+ const checkReactCompilerPluginOrder = (filePath, pluginNames) => {
67284
+ if (pluginNames.findIndex((pluginName) => REACT_COMPILER_PLUGIN_NAMES.has(pluginName)) <= 0) return [];
67285
+ return [buildReactNativeDiagnostic({
67286
+ filePath,
67287
+ rule: "rn-react-compiler-plugin-first",
67288
+ category: "Performance",
67289
+ message: "The React Compiler Babel plugin is not first, so an earlier transform can change component or hook code before the compiler analyzes it.",
67290
+ help: "Move `babel-plugin-react-compiler` to the first entry in the Babel `plugins` array."
67291
+ })];
67292
+ };
67293
+ const checkReanimatedPluginOrder = (project, filePath, pluginNames) => {
67294
+ const reanimatedMajorVersion = project.reanimatedVersion === null || project.reanimatedVersion === void 0 ? null : getLowestDependencyMajor(project.reanimatedVersion);
67295
+ if (reanimatedMajorVersion === null || reanimatedMajorVersion < 4) return [];
67296
+ const diagnostics = [];
67297
+ if (pluginNames.includes(REANIMATED_PLUGIN_NAME)) diagnostics.push(buildReactNativeDiagnostic({
67298
+ filePath,
67299
+ rule: "rn-reanimated-worklets-plugin-last",
67300
+ category: "Performance",
67301
+ message: "This Reanimated 4 project still uses `react-native-reanimated/plugin`, which was renamed to the Worklets Babel plugin.",
67302
+ help: "Replace it with `react-native-worklets/plugin` and keep that plugin last in the Babel `plugins` array."
67303
+ }));
67304
+ const workletsPluginIndex = pluginNames.lastIndexOf(WORKLETS_PLUGIN_NAME);
67305
+ if (workletsPluginIndex !== -1 && workletsPluginIndex !== pluginNames.length - 1) diagnostics.push(buildReactNativeDiagnostic({
67306
+ filePath,
67307
+ rule: "rn-reanimated-worklets-plugin-last",
67308
+ category: "Performance",
67309
+ message: "`react-native-worklets/plugin` is not last in the Babel `plugins` array, so later transforms can prevent worklets from being compiled correctly.",
67310
+ help: "Move `react-native-worklets/plugin` to the final entry in the Babel `plugins` array."
67311
+ }));
67312
+ return diagnostics;
67313
+ };
67314
+ const checkReactNativeBabelPluginOrder = (rootDirectory, project) => {
67315
+ const babelPlugins = readStaticBabelPluginNames(rootDirectory);
67316
+ if (babelPlugins === null || babelPlugins.pluginNames === null) return [];
67317
+ return [...checkReactCompilerPluginOrder(babelPlugins.filePath, babelPlugins.pluginNames), ...checkReanimatedPluginOrder(project, babelPlugins.filePath, babelPlugins.pluginNames)];
67318
+ };
66958
67319
  const BUILDER_BOB_PACKAGE = "react-native-builder-bob";
66959
67320
  const isBuilderBobLibrary = (packageJson) => {
66960
67321
  const bobConfig = packageJson[BUILDER_BOB_PACKAGE];
@@ -67031,7 +67392,12 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
67031
67392
  const isReactNativeProject = (project) => project.framework === "react-native" || project.framework === "expo" || project.hasReactNativeWorkspace || project.expoVersion !== null;
67032
67393
  const checkReactNativeProject = (rootDirectory, project) => {
67033
67394
  if (!isReactNativeProject(project)) return [];
67034
- return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
67395
+ return [
67396
+ ...checkReactNativeMetroBabelPreset(rootDirectory),
67397
+ ...checkReactNativeBabelPluginOrder(rootDirectory, project),
67398
+ ...checkReactNativeAndroidReleaseShrinking(rootDirectory),
67399
+ ...checkReactNativeLibraryDependencies(rootDirectory)
67400
+ ];
67035
67401
  };
67036
67402
  const RULE_KEY = "no-vulnerable-react-server-components";
67037
67403
  const REACT_RSC_ADVISORIES_BY_MINOR = {
@@ -67182,17 +67548,6 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
67182
67548
  }
67183
67549
  return diagnostics;
67184
67550
  };
67185
- const getTypescriptScriptKind = (fileName) => {
67186
- if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
67187
- if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
67188
- if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
67189
- return ts.ScriptKind.JS;
67190
- };
67191
- const unwrapTypescriptExpression = (expression) => {
67192
- let currentExpression = expression;
67193
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
67194
- return currentExpression;
67195
- };
67196
67551
  const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
67197
67552
  isAnimationFunction: false,
67198
67553
  isMotionComponent: false,
@@ -67748,7 +68103,11 @@ const buildCapabilities = (project) => {
67748
68103
  capabilities.add(project.framework);
67749
68104
  if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
67750
68105
  if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
67751
- if (project.expoVersion !== null) capabilities.add("expo");
68106
+ if (project.expoVersion !== null) {
68107
+ capabilities.add("expo");
68108
+ const expoSdkMajorVersion = getLowestDependencyMajor(project.expoVersion);
68109
+ if (expoSdkMajorVersion !== null && expoSdkMajorVersion >= 54) capabilities.add("expo:54");
68110
+ }
67752
68111
  if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
67753
68112
  if (SSR_FRAMEWORKS.has(project.framework) || project.hasSsrDependency) capabilities.add("ssr");
67754
68113
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
@@ -67812,6 +68171,11 @@ const buildCapabilities = (project) => {
67812
68171
  if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
67813
68172
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
67814
68173
  if (project.hasReactCompiler) capabilities.add("react-compiler");
68174
+ if (project.reanimatedVersion !== void 0 && project.reanimatedVersion !== null) {
68175
+ capabilities.add("reanimated");
68176
+ const reanimatedMajorVersion = getLowestDependencyMajor(project.reanimatedVersion);
68177
+ if (reanimatedMajorVersion !== null && reanimatedMajorVersion >= 4) capabilities.add("reanimated:4");
68178
+ }
67815
68179
  if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
67816
68180
  if (project.styledComponentsVersion) {
67817
68181
  capabilities.add("styled-components");
@@ -69709,7 +70073,11 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
69709
70073
  const ROOT_DIRECTORY_PLACEHOLDER = "<root>";
69710
70074
  const normalizeConfigForHash = (config) => {
69711
70075
  const clone = JSON.parse(JSON.stringify(config));
69712
- if (clone?.settings?.["react-doctor"]) clone.settings["react-doctor"].rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
70076
+ if (clone?.settings?.["react-doctor"]) {
70077
+ const reactDoctorSettings = clone.settings["react-doctor"];
70078
+ reactDoctorSettings.rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
70079
+ if (Array.isArray(reactDoctorSettings.unpluginAutoImportRootDirectories)) reactDoctorSettings.unpluginAutoImportRootDirectories = [ROOT_DIRECTORY_PLACEHOLDER];
70080
+ }
69713
70081
  if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
69714
70082
  return clone;
69715
70083
  };
@@ -69868,13 +70236,14 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
69868
70236
  }
69869
70237
  return enabled;
69870
70238
  };
69871
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
70239
+ 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 }) => {
69872
70240
  const hasIncludedTags = includedTags.size > 0;
69873
70241
  const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
69874
70242
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
69875
70243
  const jsPlugins = [];
69876
70244
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
69877
70245
  const capabilities = getCapabilities(project);
70246
+ const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
69878
70247
  const enabledReactDoctorRules = {};
69879
70248
  for (const registryEntry of REACT_DOCTOR_RULES) {
69880
70249
  const rule = reactDoctorPlugin.rules[registryEntry.id];
@@ -69920,8 +70289,16 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
69920
70289
  jsPlugins: [...jsPlugins, pluginPath],
69921
70290
  settings: { "react-doctor": {
69922
70291
  framework: project.framework,
69923
- rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
70292
+ rootDirectory: settingsRootDirectory,
69924
70293
  capabilities: [...capabilities].sort(),
70294
+ ...runtimeGlobals && runtimeGlobals.length > 0 ? { runtimeGlobals: [...runtimeGlobals] } : {},
70295
+ ...unpluginAutoImportGlobalScopes && unpluginAutoImportGlobalScopes.length > 0 ? {
70296
+ unpluginAutoImportRootDirectories: [...new Set([settingsRootDirectory, project.rootDirectory])],
70297
+ unpluginAutoImportGlobalScopes: unpluginAutoImportGlobalScopes.map((scope) => ({
70298
+ directory: scope.directory,
70299
+ names: [...scope.names]
70300
+ }))
70301
+ } : {},
69925
70302
  ...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
69926
70303
  ...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
69927
70304
  } },
@@ -69932,6 +70309,245 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
69932
70309
  }
69933
70310
  };
69934
70311
  };
70312
+ const AUTO_IMPORT_ADAPTER_PATTERN = /^unplugin-auto-import\/(?:astro|esbuild|rollup|rolldown|rspack|vite|webpack)$/;
70313
+ const CONFIG_BASENAMES = [
70314
+ "astro.config",
70315
+ "esbuild.config",
70316
+ "rollup.config",
70317
+ "rolldown.config",
70318
+ "rspack.config",
70319
+ "vite.config",
70320
+ "webpack.config"
70321
+ ];
70322
+ const CONFIG_EXTENSIONS = [
70323
+ ".cjs",
70324
+ ".cts",
70325
+ ".js",
70326
+ ".mjs",
70327
+ ".mts",
70328
+ ".ts"
70329
+ ];
70330
+ const CONFIG_FILENAMES = new Set(CONFIG_BASENAMES.flatMap((basename) => CONFIG_EXTENSIONS.map((extension) => `${basename}${extension}`)));
70331
+ const DEFAULT_ESLINT_GLOBALS_PATH = ".eslintrc-auto-import.json";
70332
+ const SUPPORTED_GLOBAL_VALUES = new Set([
70333
+ true,
70334
+ false,
70335
+ "readable",
70336
+ "readonly",
70337
+ "writable",
70338
+ "writeable"
70339
+ ]);
70340
+ const getStaticProperty = (objectExpression, propertyName) => objectExpression.properties.find((property) => {
70341
+ if (ts.isSpreadAssignment(property)) return false;
70342
+ const name = ts.isComputedPropertyName(property.name) ? unwrapTypescriptExpression(property.name.expression) : property.name;
70343
+ return (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) && name.text === propertyName;
70344
+ }) ?? null;
70345
+ const hasNonLiteralComputedProperty = (objectExpression) => objectExpression.properties.some((property) => !ts.isSpreadAssignment(property) && ts.isComputedPropertyName(property.name) && !ts.isStringLiteralLike(unwrapTypescriptExpression(property.name.expression)));
70346
+ const getStaticPropertyAssignment = (objectExpression, propertyName) => {
70347
+ const property = getStaticProperty(objectExpression, propertyName);
70348
+ return property && ts.isPropertyAssignment(property) ? property : null;
70349
+ };
70350
+ const getRequireModuleSpecifier = (expression) => {
70351
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
70352
+ if (ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === "default") return getRequireModuleSpecifier(unwrappedExpression.expression);
70353
+ if (!ts.isCallExpression(unwrappedExpression) || !ts.isIdentifier(unwrappedExpression.expression) || unwrappedExpression.expression.text !== "require" || unwrappedExpression.arguments.length !== 1) return null;
70354
+ const moduleSpecifier = unwrappedExpression.arguments[0];
70355
+ return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
70356
+ };
70357
+ const getRequiredPropertyModuleSpecifier = (expression, propertyName) => {
70358
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
70359
+ return ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === propertyName ? getRequireModuleSpecifier(unwrappedExpression.expression) : null;
70360
+ };
70361
+ 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");
70362
+ const isTopLevelExpression = (node) => {
70363
+ let ancestor = node.parent;
70364
+ while (ancestor && !ts.isSourceFile(ancestor)) {
70365
+ if (ts.isExpressionStatement(ancestor)) return ts.isSourceFile(ancestor.parent);
70366
+ if (!ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isAwaitExpression(ancestor)) return false;
70367
+ ancestor = ancestor.parent;
70368
+ }
70369
+ return false;
70370
+ };
70371
+ const isInsideActiveConfigProperty = (node, propertyName, sourceFile, esbuildBindings, esbuildNamespaceBindings) => {
70372
+ let ancestor = node.parent;
70373
+ let didFindConfigProperty = false;
70374
+ while (ancestor && !ts.isSourceFile(ancestor)) {
70375
+ 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;
70376
+ if (ts.isPropertyAssignment(ancestor)) {
70377
+ const isConfigProperty = (ts.isIdentifier(ancestor.name) || ts.isStringLiteralLike(ancestor.name)) && ancestor.name.text === propertyName;
70378
+ if (didFindConfigProperty || !isConfigProperty) return false;
70379
+ if (!ts.isObjectLiteralExpression(ancestor.parent) || ancestor.parent.properties.some(ts.isSpreadAssignment)) return false;
70380
+ didFindConfigProperty = true;
70381
+ ancestor = ancestor.parent;
70382
+ continue;
70383
+ }
70384
+ if (didFindConfigProperty) {
70385
+ if (ts.isExportAssignment(ancestor)) return true;
70386
+ if (isCommonJsExportAssignment(ancestor, sourceFile)) return isTopLevelExpression(ancestor);
70387
+ 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);
70388
+ 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;
70389
+ }
70390
+ ancestor = ancestor.parent;
70391
+ }
70392
+ return false;
70393
+ };
70394
+ const getGlobalsPathFromActiveAutoImportCall = (callExpression, packageDirectory) => {
70395
+ const optionsExpression = callExpression.arguments[0];
70396
+ if (!optionsExpression) return null;
70397
+ const unwrappedOptions = unwrapTypescriptExpression(optionsExpression);
70398
+ if (!ts.isObjectLiteralExpression(unwrappedOptions)) return null;
70399
+ if (unwrappedOptions.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(unwrappedOptions)) return null;
70400
+ if (getStaticProperty(unwrappedOptions, "include") || getStaticProperty(unwrappedOptions, "exclude")) return null;
70401
+ const eslintrcProperty = getStaticPropertyAssignment(unwrappedOptions, "eslintrc");
70402
+ if (!eslintrcProperty) return null;
70403
+ const eslintrcExpression = unwrapTypescriptExpression(eslintrcProperty.initializer);
70404
+ if (!ts.isObjectLiteralExpression(eslintrcExpression)) return null;
70405
+ if (eslintrcExpression.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(eslintrcExpression)) return null;
70406
+ const enabledProperty = getStaticPropertyAssignment(eslintrcExpression, "enabled");
70407
+ if (!enabledProperty || unwrapTypescriptExpression(enabledProperty.initializer).kind !== ts.SyntaxKind.TrueKeyword) return null;
70408
+ const filepathProperty = getStaticProperty(eslintrcExpression, "filepath");
70409
+ if (!filepathProperty) return Path.join(packageDirectory, DEFAULT_ESLINT_GLOBALS_PATH);
70410
+ if (!ts.isPropertyAssignment(filepathProperty)) return null;
70411
+ const filepathExpression = unwrapTypescriptExpression(filepathProperty.initializer);
70412
+ return ts.isStringLiteralLike(filepathExpression) ? Path.resolve(packageDirectory, filepathExpression.text) : null;
70413
+ };
70414
+ const collectGlobalsPathsFromConfig = (configPath, packageDirectory) => {
70415
+ let sourceText;
70416
+ try {
70417
+ sourceText = NFS.readFileSync(configPath, "utf8");
70418
+ } catch {
70419
+ return {
70420
+ didFindActiveAutoImport: false,
70421
+ globalsPaths: []
70422
+ };
70423
+ }
70424
+ const sourceFile = ts.createSourceFile(configPath, sourceText, ts.ScriptTarget.Latest, true);
70425
+ const autoImportBindings = /* @__PURE__ */ new Map();
70426
+ const esbuildBindings = /* @__PURE__ */ new Set();
70427
+ const esbuildNamespaceBindings = /* @__PURE__ */ new Set();
70428
+ for (const statement of sourceFile.statements) {
70429
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteralLike(statement.moduleSpecifier)) {
70430
+ const moduleSpecifier = statement.moduleSpecifier.text;
70431
+ if (AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
70432
+ const defaultBinding = statement.importClause?.name;
70433
+ if (defaultBinding) autoImportBindings.set(defaultBinding.text, moduleSpecifier);
70434
+ }
70435
+ if (moduleSpecifier === "esbuild") {
70436
+ const defaultBinding = statement.importClause?.name;
70437
+ if (defaultBinding) esbuildNamespaceBindings.add(defaultBinding.text);
70438
+ const namedBindings = statement.importClause?.namedBindings;
70439
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
70440
+ for (const importSpecifier of namedBindings.elements) if ((importSpecifier.propertyName ?? importSpecifier.name).text === "build") esbuildBindings.add(importSpecifier.name.text);
70441
+ }
70442
+ if (namedBindings && ts.isNamespaceImport(namedBindings)) esbuildNamespaceBindings.add(namedBindings.name.text);
70443
+ }
70444
+ }
70445
+ if (!ts.isVariableStatement(statement)) continue;
70446
+ for (const declaration of statement.declarationList.declarations) {
70447
+ if (!declaration.initializer) continue;
70448
+ const declarationName = ts.isIdentifier(declaration.name) ? declaration.name.text : null;
70449
+ const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
70450
+ if (declarationName && moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) autoImportBindings.set(declarationName, moduleSpecifier);
70451
+ if (moduleSpecifier === "esbuild") {
70452
+ if (declarationName) esbuildNamespaceBindings.add(declarationName);
70453
+ if (ts.isObjectBindingPattern(declaration.name)) for (const bindingElement of declaration.name.elements) {
70454
+ const importedName = bindingElement.propertyName ?? bindingElement.name;
70455
+ if (ts.isIdentifier(importedName) && importedName.text === "build" && ts.isIdentifier(bindingElement.name)) esbuildBindings.add(bindingElement.name.text);
70456
+ }
70457
+ }
70458
+ if (declarationName && getRequiredPropertyModuleSpecifier(declaration.initializer, "build") === "esbuild") esbuildBindings.add(declarationName);
70459
+ }
70460
+ }
70461
+ const globalsPaths = /* @__PURE__ */ new Set();
70462
+ let didFindActiveAutoImport = false;
70463
+ let didFindUnsafeActiveAutoImport = false;
70464
+ const visit = (node) => {
70465
+ if (ts.isCallExpression(node)) {
70466
+ const moduleSpecifier = ts.isIdentifier(node.expression) ? autoImportBindings.get(node.expression.text) : getRequireModuleSpecifier(node.expression);
70467
+ if (moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
70468
+ if (isInsideActiveConfigProperty(node, moduleSpecifier.endsWith("/astro") ? "integrations" : "plugins", sourceFile, esbuildBindings, esbuildNamespaceBindings)) {
70469
+ didFindActiveAutoImport = true;
70470
+ const globalsPath = getGlobalsPathFromActiveAutoImportCall(node, packageDirectory);
70471
+ if (globalsPath) globalsPaths.add(globalsPath);
70472
+ else didFindUnsafeActiveAutoImport = true;
70473
+ }
70474
+ }
70475
+ }
70476
+ ts.forEachChild(node, visit);
70477
+ };
70478
+ visit(sourceFile);
70479
+ return {
70480
+ didFindActiveAutoImport,
70481
+ globalsPaths: didFindUnsafeActiveAutoImport ? [] : [...globalsPaths]
70482
+ };
70483
+ };
70484
+ const collectGeneratedGlobalNames = (globalsPath, rootDirectory) => {
70485
+ const relativePath = Path.relative(rootDirectory, globalsPath);
70486
+ if (relativePath.startsWith("..") || Path.isAbsolute(relativePath)) return [];
70487
+ const parsed = failOpenReadJson(globalsPath, null);
70488
+ if (!isPlainObject(parsed) || !isPlainObject(parsed.globals)) return [];
70489
+ 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();
70490
+ };
70491
+ const findOwningPackageDirectory = (absoluteFilePath, rootDirectory, cache) => {
70492
+ let currentDirectory = Path.dirname(absoluteFilePath);
70493
+ const visitedDirectories = [];
70494
+ while (true) {
70495
+ const cachedDirectory = cache.get(currentDirectory);
70496
+ if (cachedDirectory !== void 0) {
70497
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, cachedDirectory);
70498
+ return cachedDirectory;
70499
+ }
70500
+ const relativeDirectory = Path.relative(rootDirectory, currentDirectory);
70501
+ if (relativeDirectory.startsWith("..") || Path.isAbsolute(relativeDirectory)) {
70502
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
70503
+ return null;
70504
+ }
70505
+ visitedDirectories.push(currentDirectory);
70506
+ if (NFS.existsSync(Path.join(currentDirectory, "package.json"))) {
70507
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, currentDirectory);
70508
+ return currentDirectory;
70509
+ }
70510
+ if (currentDirectory === rootDirectory) {
70511
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
70512
+ return null;
70513
+ }
70514
+ currentDirectory = Path.dirname(currentDirectory);
70515
+ }
70516
+ };
70517
+ const collectPackageGlobalNames = (packageDirectory, rootDirectory) => {
70518
+ let directoryEntries;
70519
+ try {
70520
+ directoryEntries = NFS.readdirSync(packageDirectory, { withFileTypes: true });
70521
+ } catch {
70522
+ return [];
70523
+ }
70524
+ const configuredGlobalsPaths = [];
70525
+ for (const entry of directoryEntries) {
70526
+ if (!entry.isFile() && !entry.isSymbolicLink() || !CONFIG_FILENAMES.has(entry.name)) continue;
70527
+ const configGlobalsPaths = collectGlobalsPathsFromConfig(Path.join(packageDirectory, entry.name), packageDirectory);
70528
+ if (configGlobalsPaths.didFindActiveAutoImport) configuredGlobalsPaths.push(configGlobalsPaths.globalsPaths.toSorted());
70529
+ }
70530
+ if (configuredGlobalsPaths.length === 0) return [];
70531
+ const globalsPaths = configuredGlobalsPaths[0];
70532
+ if (configuredGlobalsPaths.some((candidatePaths) => candidatePaths.length !== globalsPaths.length || candidatePaths.some((candidatePath, index) => candidatePath !== globalsPaths[index]))) return [];
70533
+ const names = /* @__PURE__ */ new Set();
70534
+ for (const globalsPath of globalsPaths) for (const name of collectGeneratedGlobalNames(globalsPath, rootDirectory)) names.add(name);
70535
+ return [...names].sort();
70536
+ };
70537
+ const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }) => {
70538
+ const absoluteRootDirectory = Path.resolve(rootDirectory);
70539
+ const packageDirectoryCache = /* @__PURE__ */ new Map();
70540
+ const packageDirectories = /* @__PURE__ */ new Set();
70541
+ for (const candidateFile of candidateFiles) {
70542
+ const packageDirectory = findOwningPackageDirectory(Path.resolve(absoluteRootDirectory, candidateFile), absoluteRootDirectory, packageDirectoryCache);
70543
+ if (packageDirectory) packageDirectories.add(packageDirectory);
70544
+ }
70545
+ const scopes = [...packageDirectories].map((packageDirectory) => ({
70546
+ directory: Path.relative(absoluteRootDirectory, packageDirectory).replaceAll("\\", "/"),
70547
+ names: collectPackageGlobalNames(packageDirectory, absoluteRootDirectory)
70548
+ })).sort((firstScope, secondScope) => firstScope.directory.localeCompare(secondScope.directory));
70549
+ return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
70550
+ };
69935
70551
  const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
69936
70552
  const decodeFileDiagnostics = (raw) => {
69937
70553
  if (!Array.isArray(raw)) return null;
@@ -70254,6 +70870,12 @@ const appendReanimatedSharedValueHint = (help, rule, project) => {
70254
70870
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
70255
70871
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
70256
70872
  };
70873
+ const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
70874
+ const boundedOffset = Math.min(Math.max(utf8Offset, 0), sourceBuffer.length);
70875
+ let lineStartOffset = boundedOffset;
70876
+ while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
70877
+ return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
70878
+ };
70257
70879
  const REDACTED_PLACEHOLDER = "<redacted>";
70258
70880
  const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
70259
70881
  const KNOWN_SECRET_RULES = [
@@ -70969,7 +71591,7 @@ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORI
70969
71591
  * with empty text still carry a useful jump target, so they're kept
70970
71592
  * with a neutral message.
70971
71593
  */
70972
- const buildRelatedLocations = (labels, filePath) => {
71594
+ const buildRelatedLocations = (labels, filePath, sourceBuffer) => {
70973
71595
  if (labels.length <= 1) return [];
70974
71596
  const related = [];
70975
71597
  for (let labelIndex = 1; labelIndex < labels.length; labelIndex++) {
@@ -70977,8 +71599,8 @@ const buildRelatedLocations = (labels, filePath) => {
70977
71599
  if (!label?.span) continue;
70978
71600
  related.push({
70979
71601
  filePath,
70980
- line: label.span.line ?? 0,
70981
- column: label.span.column ?? 0,
71602
+ line: sourceBuffer === null ? label.span.line ?? 0 : lineOfUtf8Offset(sourceBuffer, label.span.offset),
71603
+ column: sourceBuffer === null ? label.span.column ?? 0 : columnOfUtf8Offset(sourceBuffer, label.span.offset),
70982
71604
  offset: label.span.offset,
70983
71605
  length: label.span.length,
70984
71606
  message: label.label ?? ""
@@ -70998,7 +71620,7 @@ const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnos
70998
71620
  * to the first `{`. Raises `OxlintOutputUnparseable` when the
70999
71621
  * stdout isn't valid JSON or doesn't carry a `diagnostics` array.
71000
71622
  */
71001
- const parseOxlintOutput = (stdout, project, rootDirectory) => {
71623
+ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
71002
71624
  if (!stdout) return [];
71003
71625
  const jsonStart = stdout.indexOf("{");
71004
71626
  const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
@@ -71015,8 +71637,10 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71015
71637
  const sourceBufferCache = /* @__PURE__ */ new Map();
71016
71638
  const sourceLinesCache = /* @__PURE__ */ new Map();
71017
71639
  const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
71640
+ const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
71641
+ const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
71018
71642
  const readSourceBuffer = (filename) => {
71019
- const absolutePath = resolveAbsolutePath(filename);
71643
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71020
71644
  const cached = sourceBufferCache.get(absolutePath);
71021
71645
  if (cached !== void 0) return cached;
71022
71646
  let sourceBuffer;
@@ -71029,7 +71653,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71029
71653
  return sourceBuffer;
71030
71654
  };
71031
71655
  const readSourceLines = (filename) => {
71032
- const absolutePath = resolveAbsolutePath(filename);
71656
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71033
71657
  const cached = sourceLinesCache.get(absolutePath);
71034
71658
  if (cached !== void 0) return cached;
71035
71659
  const sourceBuffer = readSourceBuffer(filename);
@@ -71038,27 +71662,30 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71038
71662
  return sourceLines;
71039
71663
  };
71040
71664
  const isMinifiedDiagnosticFile = (filename) => {
71041
- const absolutePath = resolveAbsolutePath(filename);
71665
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71042
71666
  const cached = minifiedFileCache.get(absolutePath);
71043
71667
  if (cached !== void 0) return cached;
71044
71668
  const minified = isMinifiedSource(absolutePath);
71045
71669
  minifiedFileCache.set(absolutePath, minified);
71046
71670
  return minified;
71047
71671
  };
71048
- 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) => {
71672
+ 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) => {
71049
71673
  const { plugin, rule } = parseRuleCode(diagnostic.code);
71050
71674
  const primaryLabel = diagnostic.labels[0];
71051
71675
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
71052
- const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
71676
+ const mappedSourceFilename = resolveMappedSourceFilename(diagnostic.filename);
71677
+ const normalizedFilePath = (mappedSourceFilename ?? diagnostic.filename).replaceAll("\\", "/");
71053
71678
  const primarySpan = primaryLabel?.span;
71054
71679
  const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
71055
- const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
71680
+ const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath, mappedSourceFilename === void 0 ? null : sourceBuffer);
71056
71681
  const category = resolveDiagnosticCategory(plugin, rule);
71057
71682
  const matchByOccurrence = resolveMatchByOccurrence(rule, category);
71058
71683
  const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
71059
- const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
71684
+ const primaryLineNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.line ?? 0;
71685
+ const primaryColumnNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? columnOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.column ?? 0;
71686
+ const primaryLineIndex = primarySpan ? primaryLineNumber - 1 : -1;
71060
71687
  const primaryLine = sourceLines?.[primaryLineIndex];
71061
- const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
71688
+ const primaryColumnIndex = primarySpan ? primaryColumnNumber - 1 : -1;
71062
71689
  const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
71063
71690
  const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
71064
71691
  const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
@@ -71071,8 +71698,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71071
71698
  message: cleaned.message,
71072
71699
  help: cleaned.help,
71073
71700
  url: diagnostic.url,
71074
- line: primarySpan?.line ?? 0,
71075
- column: primarySpan?.column ?? 0,
71701
+ line: primaryLineNumber,
71702
+ column: primaryColumnNumber,
71076
71703
  ...primarySpan ? {
71077
71704
  offset: primarySpan.offset,
71078
71705
  length: primarySpan.length,
@@ -71260,7 +71887,11 @@ const isParallelismRelatedSpawnError = (error) => {
71260
71887
  * loop with a slimmer config in that case.
71261
71888
  */
71262
71889
  const spawnLintBatches = async (input) => {
71263
- const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
71890
+ const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
71891
+ const resolveSourcePath = (filePath) => {
71892
+ const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
71893
+ return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
71894
+ };
71264
71895
  const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
71265
71896
  let rescueDeadlineEpochMs;
71266
71897
  const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
@@ -71280,7 +71911,7 @@ const spawnLintBatches = async (input) => {
71280
71911
  }
71281
71912
  const batchArgs = [...baseArgs, ...batch];
71282
71913
  try {
71283
- return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
71914
+ return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath);
71284
71915
  } catch (error) {
71285
71916
  if (!isSplittableReactDoctorError(error)) throw error;
71286
71917
  if (isPastDeadline()) {
@@ -71386,10 +72017,12 @@ const spawnLintBatches = async (input) => {
71386
72017
  onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
71387
72018
  };
71388
72019
  const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
71389
- reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
71390
- reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
72020
+ const droppedSourceFiles = [...new Set(droppedFiles.map(resolveSourcePath))];
72021
+ const deadlineSkippedSourceFiles = [...new Set(outcome.deadlineSkippedFiles.map(resolveSourcePath))];
72022
+ reportSkippedFiles(droppedSourceFiles, (fileListPreview) => `${droppedSourceFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
72023
+ reportSkippedFiles(deadlineSkippedSourceFiles, (fileListPreview) => `${deadlineSkippedSourceFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
71391
72024
  const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
71392
- input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
72025
+ input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)).map(resolveSourcePath))].sort());
71393
72026
  return dedupeDiagnostics(diagnostics);
71394
72027
  };
71395
72028
  let didValidate = false;
@@ -71488,6 +72121,266 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
71488
72121
  }
71489
72122
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
71490
72123
  };
72124
+ const THREE_MODULE_IMPORT_PATTERN = /\b(?:from\s*|import\s*(?:\(\s*)?|require\s*\(\s*)["']three(?:\/[^"']*)?["']/;
72125
+ const containsThreeModuleImport = (sourceText) => THREE_MODULE_IMPORT_PATTERN.test(sourceText);
72126
+ const COMMENT_OPEN = "<!--";
72127
+ const COMMENT_CLOSE = "-->";
72128
+ const FRONTMATTER_FENCE = "---";
72129
+ const SCRIPT_TAG_NAME = "script";
72130
+ const SCRIPT_OPEN = `<${SCRIPT_TAG_NAME}`;
72131
+ const SCRIPT_CLOSE = `</${SCRIPT_TAG_NAME}`;
72132
+ const TEMPLATE_TAG_NAME = "template";
72133
+ const TEMPLATE_CLOSE = `</${TEMPLATE_TAG_NAME}`;
72134
+ const JAVASCRIPT_MIME_TYPES = new Set([
72135
+ "application/ecmascript",
72136
+ "application/javascript",
72137
+ "application/x-ecmascript",
72138
+ "application/x-javascript",
72139
+ "text/ecmascript",
72140
+ "text/javascript",
72141
+ "text/javascript1.0",
72142
+ "text/javascript1.1",
72143
+ "text/javascript1.2",
72144
+ "text/javascript1.3",
72145
+ "text/javascript1.4",
72146
+ "text/javascript1.5",
72147
+ "text/jscript",
72148
+ "text/livescript",
72149
+ "text/x-ecmascript",
72150
+ "text/x-javascript"
72151
+ ]);
72152
+ const RAW_TEXT_TAG_NAMES = new Set([
72153
+ "iframe",
72154
+ "noembed",
72155
+ "noframes",
72156
+ "noscript",
72157
+ "style",
72158
+ "textarea",
72159
+ "title",
72160
+ "xmp"
72161
+ ]);
72162
+ const PLAINTEXT_TAG_NAME = "plaintext";
72163
+ const TAG_OPEN_UTF8_BYTE = "<".charCodeAt(0);
72164
+ const TAG_CLOSE_UTF8_BYTE = ">".charCodeAt(0);
72165
+ const SINGLE_QUOTE_UTF8_BYTE = "'".charCodeAt(0);
72166
+ const DOUBLE_QUOTE_UTF8_BYTE = "\"".charCodeAt(0);
72167
+ const ATTRIBUTE_ASSIGNMENT_UTF8_BYTE = "=".charCodeAt(0);
72168
+ const TAG_SELF_CLOSE_UTF8_BYTE = "/".charCodeAt(0);
72169
+ const TAB_UTF8_BYTE = " ".charCodeAt(0);
72170
+ const FORM_FEED_UTF8_BYTE = "\f".charCodeAt(0);
72171
+ const isHtmlWhitespace = (byte) => byte === TAB_UTF8_BYTE || byte === 10 || byte === FORM_FEED_UTF8_BYTE || byte === 13 || byte === 32;
72172
+ const matchesAsciiCaseInsensitive = (sourceBuffer, startByte, expected) => {
72173
+ if (startByte + expected.length > sourceBuffer.length) return false;
72174
+ for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex++) {
72175
+ const sourceByte = sourceBuffer[startByte + expectedIndex];
72176
+ if (sourceByte === void 0 || String.fromCharCode(sourceByte).toLowerCase() !== expected[expectedIndex]) return false;
72177
+ }
72178
+ return true;
72179
+ };
72180
+ const isTagBoundary = (byte) => byte === TAG_CLOSE_UTF8_BYTE || byte === TAG_SELF_CLOSE_UTF8_BYTE || isHtmlWhitespace(byte);
72181
+ const isPotentialTagStart = (byte) => {
72182
+ if (byte === void 0) return false;
72183
+ return /[A-Za-z!/?]/.test(String.fromCharCode(byte));
72184
+ };
72185
+ const findLineEnd = (sourceBuffer, lineStartByte) => {
72186
+ let byteIndex = lineStartByte;
72187
+ while (byteIndex < sourceBuffer.length && sourceBuffer[byteIndex] !== 10 && sourceBuffer[byteIndex] !== 13) byteIndex++;
72188
+ return byteIndex;
72189
+ };
72190
+ const findNextLineStart = (sourceBuffer, lineStartByte) => {
72191
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
72192
+ if (sourceBuffer[lineEndByte] === 13 && sourceBuffer[lineEndByte + 1] === 10) return lineEndByte + 2;
72193
+ return Math.min(lineEndByte + 1, sourceBuffer.length);
72194
+ };
72195
+ const isFrontmatterFenceLine = (sourceBuffer, lineStartByte) => {
72196
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, lineStartByte, FRONTMATTER_FENCE)) return false;
72197
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
72198
+ for (let byteIndex = lineStartByte + 3; byteIndex < lineEndByte; byteIndex++) if (!isHtmlWhitespace(sourceBuffer[byteIndex])) return false;
72199
+ return true;
72200
+ };
72201
+ const findFrontmatterEnd = (sourceBuffer) => {
72202
+ if (!isFrontmatterFenceLine(sourceBuffer, 0)) return 0;
72203
+ const openingFenceEndByte = findLineEnd(sourceBuffer, 0);
72204
+ let lineStartByte = findNextLineStart(sourceBuffer, 0);
72205
+ while (lineStartByte < sourceBuffer.length) {
72206
+ if (isFrontmatterFenceLine(sourceBuffer, lineStartByte)) return findLineEnd(sourceBuffer, lineStartByte);
72207
+ lineStartByte = findNextLineStart(sourceBuffer, lineStartByte);
72208
+ }
72209
+ return openingFenceEndByte;
72210
+ };
72211
+ const maskByteRange = (maskedBuffer, startByte, endByte) => {
72212
+ for (let byteIndex = startByte; byteIndex < endByte; byteIndex++) {
72213
+ const byte = maskedBuffer[byteIndex];
72214
+ if (byte !== 10 && byte !== 13) maskedBuffer[byteIndex] = 32;
72215
+ }
72216
+ };
72217
+ const readStartTagName = (sourceBuffer, tagStartByte) => {
72218
+ const firstNameByte = sourceBuffer[tagStartByte + 1];
72219
+ if (firstNameByte === void 0 || !/[A-Za-z]/.test(String.fromCharCode(firstNameByte))) return null;
72220
+ let nameEndByte = tagStartByte + 2;
72221
+ while (nameEndByte < sourceBuffer.length && /[A-Za-z0-9:-]/.test(String.fromCharCode(sourceBuffer[nameEndByte] ?? 32))) nameEndByte++;
72222
+ return sourceBuffer.subarray(tagStartByte + 1, nameEndByte).toString("ascii").toLowerCase();
72223
+ };
72224
+ const findTagEnd = (sourceBuffer, startByte) => {
72225
+ let quoteByte = null;
72226
+ for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) {
72227
+ const byte = sourceBuffer[byteIndex];
72228
+ if (quoteByte !== null) {
72229
+ if (byte === quoteByte) quoteByte = null;
72230
+ continue;
72231
+ }
72232
+ if (byte === SINGLE_QUOTE_UTF8_BYTE || byte === DOUBLE_QUOTE_UTF8_BYTE) {
72233
+ quoteByte = byte;
72234
+ continue;
72235
+ }
72236
+ if (byte === TAG_CLOSE_UTF8_BYTE) return byteIndex;
72237
+ }
72238
+ return sourceBuffer.length;
72239
+ };
72240
+ const parseScriptAttributes = (sourceBuffer, attributesStartByte, tagEndByte) => {
72241
+ let byteIndex = attributesStartByte;
72242
+ let hasSource = false;
72243
+ let language = null;
72244
+ let scriptType = null;
72245
+ while (byteIndex < tagEndByte) {
72246
+ while (byteIndex < tagEndByte && (isHtmlWhitespace(sourceBuffer[byteIndex]) || sourceBuffer[byteIndex] === TAG_SELF_CLOSE_UTF8_BYTE)) byteIndex++;
72247
+ const attributeNameStartByte = byteIndex;
72248
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== ATTRIBUTE_ASSIGNMENT_UTF8_BYTE && sourceBuffer[byteIndex] !== TAG_SELF_CLOSE_UTF8_BYTE) byteIndex++;
72249
+ const attributeName = sourceBuffer.subarray(attributeNameStartByte, byteIndex).toString("ascii").toLowerCase();
72250
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
72251
+ let attributeValue = "";
72252
+ if (sourceBuffer[byteIndex] === ATTRIBUTE_ASSIGNMENT_UTF8_BYTE) {
72253
+ byteIndex++;
72254
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
72255
+ const quoteByte = sourceBuffer[byteIndex];
72256
+ if (quoteByte === SINGLE_QUOTE_UTF8_BYTE || quoteByte === DOUBLE_QUOTE_UTF8_BYTE) {
72257
+ const valueStartByte = byteIndex + 1;
72258
+ byteIndex = valueStartByte;
72259
+ while (byteIndex < tagEndByte && sourceBuffer[byteIndex] !== quoteByte) byteIndex++;
72260
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
72261
+ if (byteIndex < tagEndByte) byteIndex++;
72262
+ } else {
72263
+ const valueStartByte = byteIndex;
72264
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== TAG_CLOSE_UTF8_BYTE) byteIndex++;
72265
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
72266
+ }
72267
+ }
72268
+ if (attributeName === "src") hasSource = true;
72269
+ else if (attributeName === "type" && scriptType === null) scriptType = attributeValue;
72270
+ else if (attributeName === "language" && language === null) language = attributeValue;
72271
+ }
72272
+ return {
72273
+ hasSource,
72274
+ language,
72275
+ type: scriptType
72276
+ };
72277
+ };
72278
+ const isExecutableScript = (attributes) => {
72279
+ if (attributes.hasSource) return false;
72280
+ const type = attributes.type?.trim().toLowerCase() ?? "";
72281
+ if (type !== "") {
72282
+ const mimeType = type.split(";")[0]?.trim() ?? "";
72283
+ return mimeType === "module" || JAVASCRIPT_MIME_TYPES.has(mimeType);
72284
+ }
72285
+ const language = attributes.language?.trim().toLowerCase() ?? "";
72286
+ return language === "" || JAVASCRIPT_MIME_TYPES.has(`text/${language}`);
72287
+ };
72288
+ const findElementClose = (sourceBuffer, startByte, tagName) => {
72289
+ const closeTagStart = `</${tagName}`;
72290
+ 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;
72291
+ return sourceBuffer.length;
72292
+ };
72293
+ const prepareHtmlScriptSource = (sourceBuffer) => {
72294
+ const frontmatterEndByte = findFrontmatterEnd(sourceBuffer);
72295
+ let maskedBuffer = frontmatterEndByte > 0 ? Buffer.from(sourceBuffer) : null;
72296
+ if (maskedBuffer !== null) maskByteRange(maskedBuffer, 0, frontmatterEndByte);
72297
+ const executableScriptBodies = [];
72298
+ let byteIndex = frontmatterEndByte;
72299
+ let templateDepth = 0;
72300
+ while (byteIndex < sourceBuffer.length) {
72301
+ if (sourceBuffer[byteIndex] !== TAG_OPEN_UTF8_BYTE) {
72302
+ byteIndex++;
72303
+ continue;
72304
+ }
72305
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, COMMENT_OPEN)) {
72306
+ const commentEndByte = sourceBuffer.indexOf(COMMENT_CLOSE, byteIndex + 4);
72307
+ byteIndex = commentEndByte === -1 ? sourceBuffer.length : commentEndByte + 3;
72308
+ continue;
72309
+ }
72310
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, TEMPLATE_CLOSE) && isTagBoundary(sourceBuffer[byteIndex + TEMPLATE_CLOSE.length])) {
72311
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + TEMPLATE_CLOSE.length);
72312
+ if (templateDepth > 0) templateDepth--;
72313
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
72314
+ continue;
72315
+ }
72316
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, SCRIPT_OPEN) || !isTagBoundary(sourceBuffer[byteIndex + SCRIPT_OPEN.length])) {
72317
+ if (!isPotentialTagStart(sourceBuffer[byteIndex + 1])) {
72318
+ byteIndex++;
72319
+ continue;
72320
+ }
72321
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + 1);
72322
+ const tagName = readStartTagName(sourceBuffer, byteIndex);
72323
+ if (tagName === PLAINTEXT_TAG_NAME) break;
72324
+ if (tagName === TEMPLATE_TAG_NAME) templateDepth++;
72325
+ if (tagName !== null && RAW_TEXT_TAG_NAMES.has(tagName)) {
72326
+ const closeTagStartByte = findElementClose(sourceBuffer, tagEndByte + 1, tagName);
72327
+ if (closeTagStartByte === sourceBuffer.length) break;
72328
+ const closeTagEndByte = findTagEnd(sourceBuffer, closeTagStartByte + tagName.length + 2);
72329
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
72330
+ continue;
72331
+ }
72332
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
72333
+ continue;
72334
+ }
72335
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + SCRIPT_OPEN.length);
72336
+ if (tagEndByte === sourceBuffer.length) break;
72337
+ const bodyStartByte = tagEndByte + 1;
72338
+ const bodyEndByte = findElementClose(sourceBuffer, bodyStartByte, SCRIPT_TAG_NAME);
72339
+ const attributes = parseScriptAttributes(sourceBuffer, byteIndex + SCRIPT_OPEN.length, tagEndByte);
72340
+ if (attributes.hasSource || templateDepth > 0) {
72341
+ maskedBuffer ??= Buffer.from(sourceBuffer);
72342
+ maskByteRange(maskedBuffer, bodyStartByte, bodyEndByte);
72343
+ } else if (isExecutableScript(attributes)) executableScriptBodies.push(sourceBuffer.subarray(bodyStartByte, bodyEndByte));
72344
+ if (bodyEndByte === sourceBuffer.length) break;
72345
+ const closeTagEndByte = findTagEnd(sourceBuffer, bodyEndByte + SCRIPT_CLOSE.length);
72346
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
72347
+ }
72348
+ return {
72349
+ executableScriptBodies,
72350
+ lintBuffer: maskedBuffer ?? sourceBuffer
72351
+ };
72352
+ };
72353
+ const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
72354
+ const lintFiles = [];
72355
+ const sourcePathByLintPath = /* @__PURE__ */ new Map();
72356
+ const sizeByLintPath = /* @__PURE__ */ new Map();
72357
+ const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
72358
+ let htmlFileIndex = 0;
72359
+ let hasThreeModuleImport = false;
72360
+ for (const candidateFile of candidateFiles) {
72361
+ if (!HTML_FILE_PATTERN.test(candidateFile)) {
72362
+ lintFiles.push(candidateFile);
72363
+ continue;
72364
+ }
72365
+ const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
72366
+ const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
72367
+ const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
72368
+ if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
72369
+ const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
72370
+ NFS.writeFileSync(lintPath, lintBuffer);
72371
+ lintFiles.push(lintPath);
72372
+ sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
72373
+ sizeByLintPath.set(lintPath, sourceBuffer.length);
72374
+ hasThreeModuleImport ||= executableScriptBodies.some((scriptBody) => containsThreeModuleImport(scriptBody.toString("utf8")));
72375
+ htmlFileIndex++;
72376
+ }
72377
+ return {
72378
+ lintFiles,
72379
+ sourcePathByLintPath,
72380
+ sizeByLintPath,
72381
+ hasThreeModuleImport
72382
+ };
72383
+ };
71491
72384
  /**
71492
72385
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
71493
72386
  * the runner: once for the primary scan, once for the
@@ -71648,6 +72541,8 @@ const reactHooksJsPluginDropNote = (error) => {
71648
72541
  const runOxlint = async (options) => {
71649
72542
  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;
71650
72543
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
72544
+ const runtimeGlobals = Array.isArray(userConfig?.runtimeGlobals) ? userConfig.runtimeGlobals.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
72545
+ let unpluginAutoImportGlobalScopes = [];
71651
72546
  const severityControls = buildRuleSeverityControls(userConfig);
71652
72547
  validateRuleRegistration();
71653
72548
  resetManifestCaches();
@@ -71661,21 +72556,6 @@ const runOxlint = async (options) => {
71661
72556
  const pluginPath = resolvePluginPath();
71662
72557
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
71663
72558
  const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
71664
- const buildConfig = (overrides) => createOxlintConfig({
71665
- pluginPath,
71666
- project,
71667
- customRulesOnly,
71668
- extendsPaths: overrides.extendsPaths,
71669
- ignoredTags,
71670
- includedTags,
71671
- includeTagDefaults,
71672
- serverAuthFunctionNames,
71673
- severityControls,
71674
- userPlugins,
71675
- disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
71676
- ruleSelection: overrides.ruleSelection,
71677
- sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
71678
- });
71679
72559
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
71680
72560
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
71681
72561
  const configPath = Path.join(configDirectory, "oxlintrc.json");
@@ -71711,7 +72591,36 @@ const runOxlint = async (options) => {
71711
72591
  await yieldToEventLoop();
71712
72592
  const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
71713
72593
  const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
72594
+ unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
72595
+ rootDirectory,
72596
+ candidateFiles
72597
+ });
72598
+ const preparedHtmlSources = prepareHtmlLintSources(rootDirectory, configDirectory, candidateFiles);
72599
+ const lintFiles = preparedHtmlSources.lintFiles;
72600
+ const hasHtmlFiles = preparedHtmlSources.sourcePathByLintPath.size > 0;
72601
+ const lintProject = !project.hasThree && preparedHtmlSources.hasThreeModuleImport ? {
72602
+ ...project,
72603
+ hasThree: true
72604
+ } : project;
72605
+ const buildConfig = (overrides) => createOxlintConfig({
72606
+ pluginPath,
72607
+ project: lintProject,
72608
+ customRulesOnly,
72609
+ extendsPaths: overrides.extendsPaths,
72610
+ ignoredTags,
72611
+ includedTags,
72612
+ includeTagDefaults,
72613
+ runtimeGlobals,
72614
+ unpluginAutoImportGlobalScopes,
72615
+ serverAuthFunctionNames,
72616
+ severityControls,
72617
+ userPlugins,
72618
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
72619
+ ruleSelection: overrides.ruleSelection,
72620
+ sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
72621
+ });
71714
72622
  const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
72623
+ if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedHtmlSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
71715
72624
  const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
71716
72625
  baseArgs: passBaseArgs,
71717
72626
  files: passFiles,
@@ -71740,7 +72649,8 @@ const runOxlint = async (options) => {
71740
72649
  fileBatches: passFileBatches,
71741
72650
  rootDirectory,
71742
72651
  nodeBinaryPath,
71743
- project,
72652
+ project: lintProject,
72653
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
71744
72654
  onPartialFailure: reportPartialFailure,
71745
72655
  onAnalyzedFiles: (filePaths) => {
71746
72656
  analyzedFiles = filePaths;
@@ -71775,7 +72685,7 @@ const runOxlint = async (options) => {
71775
72685
  };
71776
72686
  }
71777
72687
  };
71778
- if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
72688
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasHtmlFiles) {
71779
72689
  const rulesetHash = computeRulesetHash({
71780
72690
  config: buildConfig({
71781
72691
  extendsPaths: [],
@@ -71933,14 +72843,15 @@ const runOxlint = async (options) => {
71933
72843
  ]);
71934
72844
  }
71935
72845
  const baseArgs = makeBaseArgs(configPath);
71936
- const fileBatches = buildFileBatches(baseArgs, candidateFiles);
72846
+ const fileBatches = buildFileBatches(baseArgs, lintFiles);
71937
72847
  let analyzedFiles = [];
71938
72848
  const runBatches = () => spawnLintBatches({
71939
72849
  baseArgs,
71940
72850
  fileBatches,
71941
72851
  rootDirectory,
71942
72852
  nodeBinaryPath,
71943
- project,
72853
+ project: lintProject,
72854
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
71944
72855
  onPartialFailure,
71945
72856
  onAnalyzedFiles: (filePaths) => {
71946
72857
  analyzedFiles = filePaths;
@@ -73474,7 +74385,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
73474
74385
  /** Display name used in client-facing messages and progress titles. */
73475
74386
  const SERVER_DISPLAY_NAME = "React Doctor";
73476
74387
  /** Server version reported in `serverInfo`; injected at build, `dev` from source. */
73477
- const SERVER_VERSION = "0.9.0";
74388
+ const SERVER_VERSION = "0.9.1";
73478
74389
  /** `Diagnostic.source` shown next to every published diagnostic. */
73479
74390
  const DIAGNOSTIC_SOURCE = "react-doctor";
73480
74391
  /**
@@ -73516,7 +74427,8 @@ const SCANNABLE_EXTENSIONS = [
73516
74427
  ".js",
73517
74428
  ".jsx",
73518
74429
  ".mts",
73519
- ".mjs"
74430
+ ".mjs",
74431
+ ".html"
73520
74432
  ];
73521
74433
  const SILENT_LOGGER = {
73522
74434
  info: () => {},
@@ -75504,5 +76416,5 @@ const startLanguageServer = () => {
75504
76416
  };
75505
76417
  //#endregion
75506
76418
  export { startLanguageServer };
75507
- !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]="4174ed31-6572-57ab-ac95-6089329d703f")}catch(e){}}();
75508
- //# debugId=4174ed31-6572-57ab-ac95-6089329d703f
76419
+ !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]="6a2a246a-da30-59c5-aa97-af8188206b96")}catch(e){}}();
76420
+ //# debugId=6a2a246a-da30-59c5-aa97-af8188206b96