react-doctor 0.9.1-dev.54ba416 → 0.9.1-dev.7ee59d3

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;
@@ -62338,10 +62339,10 @@ const resolveImportedConfigFile = (fromFilePath, moduleSpecifier) => {
62338
62339
  ]).find(isFile) ?? null;
62339
62340
  };
62340
62341
  const parseConfigSourceFile = (filePath, content) => filePath.endsWith(".json") || Path.basename(filePath) === ".babelrc" ? ts.parseJsonText(filePath, content) : ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
62341
- 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;
62342
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");
62343
62344
  const hasExportModifier = (node) => ts.canHaveModifiers(node) && Boolean(ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
62344
- const getRequireModuleSpecifier = (expression) => {
62345
+ const getRequireModuleSpecifier$1 = (expression) => {
62345
62346
  if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "require" || expression.arguments.length !== 1) return null;
62346
62347
  const moduleSpecifier = expression.arguments[0];
62347
62348
  return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
@@ -62354,7 +62355,7 @@ const hasTopLevelValueBinding = (sourceFile, bindingName) => sourceFile.statemen
62354
62355
  const namedBindings = importClause?.namedBindings;
62355
62356
  return namedBindings ? ts.isNamespaceImport(namedBindings) ? namedBindings.name.text === bindingName : namedBindings.elements.some((element) => element.name.text === bindingName) : false;
62356
62357
  }
62357
- 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));
62358
62359
  return (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name?.text === bindingName;
62359
62360
  });
62360
62361
  const getImportBinding = (sourceFile, bindingName) => {
@@ -62385,24 +62386,24 @@ const getImportBinding = (sourceFile, bindingName) => {
62385
62386
  for (const declaration of statement.declarationList.declarations) {
62386
62387
  if (!declaration.initializer) continue;
62387
62388
  if (ts.isIdentifier(declaration.name) && declaration.name.text === bindingName) {
62388
- const directModuleSpecifier = getRequireModuleSpecifier(declaration.initializer);
62389
+ const directModuleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
62389
62390
  if (directModuleSpecifier) return {
62390
62391
  moduleSpecifier: directModuleSpecifier,
62391
62392
  exportName: "default",
62392
62393
  isNamespace: true
62393
62394
  };
62394
- if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier(declaration.initializer.expression) !== null) return {
62395
- 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) ?? "",
62396
62397
  exportName: declaration.initializer.name.text,
62397
62398
  isNamespace: false
62398
62399
  };
62399
62400
  }
62400
62401
  if (!ts.isObjectBindingPattern(declaration.name)) continue;
62401
62402
  const bindingElement = declaration.name.elements.find((element) => ts.isIdentifier(element.name) && element.name.text === bindingName);
62402
- const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
62403
+ const moduleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
62403
62404
  if (bindingElement && moduleSpecifier) return {
62404
62405
  moduleSpecifier,
62405
- 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),
62406
62407
  isNamespace: false
62407
62408
  };
62408
62409
  }
@@ -62455,6 +62456,48 @@ const getScopedConfigBinding = (identifier) => {
62455
62456
  };
62456
62457
  };
62457
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
+ };
62458
62501
  const getAssignedPropertyInitializer = (identifier, propertyName) => {
62459
62502
  let bindingScope = null;
62460
62503
  let currentNode = identifier;
@@ -62563,7 +62606,7 @@ const getReactCompilerFlagState = (expression, analysis) => {
62563
62606
  }
62564
62607
  if (!ts.isObjectLiteralExpression(unwrappedExpression)) return null;
62565
62608
  for (const property of [...unwrappedExpression.properties].reverse()) {
62566
- 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) };
62567
62610
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.name, analysis) };
62568
62611
  if (ts.isSpreadAssignment(property)) {
62569
62612
  const spreadState = getReactCompilerFlagState(property.expression, analysis);
@@ -62589,8 +62632,8 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
62589
62632
  }
62590
62633
  if (!ts.isObjectLiteralExpression(resolvedExpression)) return null;
62591
62634
  for (const property of [...resolvedExpression.properties].reverse()) {
62592
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === propertyName) return property.initializer;
62593
- 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;
62594
62637
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property.name;
62595
62638
  if (ts.isSpreadAssignment(property)) {
62596
62639
  const spreadProperty = getSelectedObjectProperty(property.expression, propertyName, analysis, visitedExpressions);
@@ -62621,7 +62664,7 @@ const configExpressionMayDefineProperty = (expression, propertyName, analysis) =
62621
62664
  return resolvedExpression.properties.some((property) => {
62622
62665
  if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
62623
62666
  if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
62624
- const staticPropertyName = getStaticPropertyName$1(property.name);
62667
+ const staticPropertyName = getStaticPropertyName$2(property.name);
62625
62668
  return staticPropertyName === null || staticPropertyName === propertyName;
62626
62669
  }
62627
62670
  return false;
@@ -62640,7 +62683,7 @@ const getExportedConfigNodes = (sourceFile, exportName) => {
62640
62683
  continue;
62641
62684
  }
62642
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()) {
62643
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === exportName) {
62686
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === exportName) {
62644
62687
  exportedNodes.push(property.initializer);
62645
62688
  break;
62646
62689
  }
@@ -62770,7 +62813,7 @@ const analyzeConfigCallTarget = (callExpression, analysis, allowCompilerTransfor
62770
62813
  if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
62771
62814
  const propertyName = ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null;
62772
62815
  if (propertyName === null) return null;
62773
- const requiredModuleSpecifier = getRequireModuleSpecifier(target.expression);
62816
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(target.expression);
62774
62817
  if (requiredModuleSpecifier !== null) {
62775
62818
  if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62776
62819
  if (!requiredModuleSpecifier.startsWith(".")) return null;
@@ -62799,10 +62842,10 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62799
62842
  const reactCompilerFlagState = excludedPropertyNames?.has("reactCompiler") ? null : getReactCompilerFlagState(node, analysis);
62800
62843
  if (reactCompilerFlagState?.isEnabled) return true;
62801
62844
  for (const [propertyIndex, property] of node.properties.entries()) if (ts.isPropertyAssignment(property)) {
62802
- const propertyName = getStaticPropertyName$1(property.name);
62845
+ const propertyName = getStaticPropertyName$2(property.name);
62803
62846
  if (propertyName && excludedPropertyNames?.has(propertyName)) continue;
62804
62847
  if (propertyName === "reactCompiler") continue;
62805
- 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;
62806
62849
  const propertyAllowsCompilerTransform = propertyName === "plugins" || propertyName === "presets";
62807
62850
  if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer) && property.initializer.text.startsWith(".")) {
62808
62851
  const extendedFilePath = resolveImportedConfigFile(analysis.filePath, property.initializer.text);
@@ -62812,12 +62855,12 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62812
62855
  } else if (ts.isShorthandPropertyAssignment(property)) {
62813
62856
  if (excludedPropertyNames?.has(property.name.text)) continue;
62814
62857
  if (property.name.text === "reactCompiler") continue;
62815
- 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;
62816
62859
  const propertyAllowsCompilerTransform = property.name.text === "plugins" || property.name.text === "presets";
62817
62860
  if (analyzeConfigNode(property.name, analysis, propertyAllowsCompilerTransform, propertyAllowsCompilerTransform)) return true;
62818
62861
  } else if (ts.isSpreadAssignment(property)) {
62819
62862
  if (reactCompilerFlagState && getReactCompilerFlagState(property.expression, analysis) !== null) continue;
62820
- 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;
62821
62864
  if (analyzeConfigNode(property.expression, analysis, allowCompilerTransform, false, excludedPropertyNames)) return true;
62822
62865
  }
62823
62866
  return false;
@@ -62830,9 +62873,11 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62830
62873
  });
62831
62874
  }
62832
62875
  if (ts.isCallExpression(node)) {
62876
+ const resolvedModuleSpecifier = getNodeRequireResolveModuleSpecifier(node, analysis);
62877
+ if (resolvedModuleSpecifier !== null) return allowCompilerTransform && isCompilerTransformModule(resolvedModuleSpecifier, "default");
62833
62878
  const callTargetResult = analyzeConfigCallTarget(node, analysis, allowCompilerTransform);
62834
62879
  if (callTargetResult !== null) return callTargetResult;
62835
- const directModuleSpecifier = getRequireModuleSpecifier(node);
62880
+ const directModuleSpecifier = getRequireModuleSpecifier$1(node);
62836
62881
  const isRequireShadowed = analysis.localBindings.has("require") || ts.isIdentifier(node.expression) && getScopedConfigBinding(node.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require");
62837
62882
  if (directModuleSpecifier && isRequireShadowed) return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
62838
62883
  if (directModuleSpecifier && !isRequireShadowed) {
@@ -62854,7 +62899,7 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62854
62899
  return analyzeConfigNode(node.expression, analysis, allowCompilerTransform) || node.arguments.some((argument) => analyzeConfigNode(argument, analysis, false));
62855
62900
  }
62856
62901
  if (ts.isPropertyAccessExpression(node)) {
62857
- const requiredModuleSpecifier = getRequireModuleSpecifier(node.expression);
62902
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(node.expression);
62858
62903
  if (requiredModuleSpecifier) {
62859
62904
  if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62860
62905
  if (requiredModuleSpecifier.startsWith(".")) {
@@ -66165,7 +66210,7 @@ const warn = (message) => {
66165
66210
  runSync(warn$1(message));
66166
66211
  };
66167
66212
  const CONFIG_BASENAME = "doctor.config";
66168
- const CONFIG_EXTENSIONS = [
66213
+ const CONFIG_EXTENSIONS$1 = [
66169
66214
  "ts",
66170
66215
  "mts",
66171
66216
  "cts",
@@ -66269,7 +66314,7 @@ const loadLegacyConfig = (directory) => {
66269
66314
  };
66270
66315
  const loadConfigFromDirectory = async (directory) => {
66271
66316
  let sawBrokenConfigFile = false;
66272
- for (const extension of CONFIG_EXTENSIONS) {
66317
+ for (const extension of CONFIG_EXTENSIONS$1) {
66273
66318
  const filePath = Path.join(directory, `${CONFIG_BASENAME}.${extension}`);
66274
66319
  if (!isFile(filePath)) continue;
66275
66320
  const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
@@ -66956,6 +67001,321 @@ const buildReactNativeDiagnostic = (input) => ({
66956
67001
  column: input.column ?? 0,
66957
67002
  category: input.category ?? "Correctness"
66958
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
+ };
66959
67319
  const BUILDER_BOB_PACKAGE = "react-native-builder-bob";
66960
67320
  const isBuilderBobLibrary = (packageJson) => {
66961
67321
  const bobConfig = packageJson[BUILDER_BOB_PACKAGE];
@@ -67032,7 +67392,12 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
67032
67392
  const isReactNativeProject = (project) => project.framework === "react-native" || project.framework === "expo" || project.hasReactNativeWorkspace || project.expoVersion !== null;
67033
67393
  const checkReactNativeProject = (rootDirectory, project) => {
67034
67394
  if (!isReactNativeProject(project)) return [];
67035
- return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
67395
+ return [
67396
+ ...checkReactNativeMetroBabelPreset(rootDirectory),
67397
+ ...checkReactNativeBabelPluginOrder(rootDirectory, project),
67398
+ ...checkReactNativeAndroidReleaseShrinking(rootDirectory),
67399
+ ...checkReactNativeLibraryDependencies(rootDirectory)
67400
+ ];
67036
67401
  };
67037
67402
  const RULE_KEY = "no-vulnerable-react-server-components";
67038
67403
  const REACT_RSC_ADVISORIES_BY_MINOR = {
@@ -67183,17 +67548,6 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
67183
67548
  }
67184
67549
  return diagnostics;
67185
67550
  };
67186
- const getTypescriptScriptKind = (fileName) => {
67187
- if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
67188
- if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
67189
- if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
67190
- return ts.ScriptKind.JS;
67191
- };
67192
- const unwrapTypescriptExpression = (expression) => {
67193
- let currentExpression = expression;
67194
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
67195
- return currentExpression;
67196
- };
67197
67551
  const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
67198
67552
  isAnimationFunction: false,
67199
67553
  isMotionComponent: false,
@@ -67749,7 +68103,11 @@ const buildCapabilities = (project) => {
67749
68103
  capabilities.add(project.framework);
67750
68104
  if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
67751
68105
  if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
67752
- 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
+ }
67753
68111
  if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
67754
68112
  if (SSR_FRAMEWORKS.has(project.framework) || project.hasSsrDependency) capabilities.add("ssr");
67755
68113
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
@@ -67813,6 +68171,11 @@ const buildCapabilities = (project) => {
67813
68171
  if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
67814
68172
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
67815
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
+ }
67816
68179
  if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
67817
68180
  if (project.styledComponentsVersion) {
67818
68181
  capabilities.add("styled-components");
@@ -69710,7 +70073,11 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
69710
70073
  const ROOT_DIRECTORY_PLACEHOLDER = "<root>";
69711
70074
  const normalizeConfigForHash = (config) => {
69712
70075
  const clone = JSON.parse(JSON.stringify(config));
69713
- 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
+ }
69714
70081
  if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
69715
70082
  return clone;
69716
70083
  };
@@ -69869,13 +70236,14 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
69869
70236
  }
69870
70237
  return enabled;
69871
70238
  };
69872
- 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 }) => {
69873
70240
  const hasIncludedTags = includedTags.size > 0;
69874
70241
  const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
69875
70242
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
69876
70243
  const jsPlugins = [];
69877
70244
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
69878
70245
  const capabilities = getCapabilities(project);
70246
+ const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
69879
70247
  const enabledReactDoctorRules = {};
69880
70248
  for (const registryEntry of REACT_DOCTOR_RULES) {
69881
70249
  const rule = reactDoctorPlugin.rules[registryEntry.id];
@@ -69921,8 +70289,16 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
69921
70289
  jsPlugins: [...jsPlugins, pluginPath],
69922
70290
  settings: { "react-doctor": {
69923
70291
  framework: project.framework,
69924
- rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
70292
+ rootDirectory: settingsRootDirectory,
69925
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
+ } : {},
69926
70302
  ...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
69927
70303
  ...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
69928
70304
  } },
@@ -69933,6 +70309,245 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
69933
70309
  }
69934
70310
  };
69935
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
+ };
69936
70551
  const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
69937
70552
  const decodeFileDiagnostics = (raw) => {
69938
70553
  if (!Array.isArray(raw)) return null;
@@ -70255,6 +70870,12 @@ const appendReanimatedSharedValueHint = (help, rule, project) => {
70255
70870
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
70256
70871
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
70257
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
+ };
70258
70879
  const REDACTED_PLACEHOLDER = "<redacted>";
70259
70880
  const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
70260
70881
  const KNOWN_SECRET_RULES = [
@@ -70970,7 +71591,7 @@ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORI
70970
71591
  * with empty text still carry a useful jump target, so they're kept
70971
71592
  * with a neutral message.
70972
71593
  */
70973
- const buildRelatedLocations = (labels, filePath) => {
71594
+ const buildRelatedLocations = (labels, filePath, sourceBuffer) => {
70974
71595
  if (labels.length <= 1) return [];
70975
71596
  const related = [];
70976
71597
  for (let labelIndex = 1; labelIndex < labels.length; labelIndex++) {
@@ -70978,8 +71599,8 @@ const buildRelatedLocations = (labels, filePath) => {
70978
71599
  if (!label?.span) continue;
70979
71600
  related.push({
70980
71601
  filePath,
70981
- line: label.span.line ?? 0,
70982
- 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),
70983
71604
  offset: label.span.offset,
70984
71605
  length: label.span.length,
70985
71606
  message: label.label ?? ""
@@ -70999,7 +71620,7 @@ const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnos
70999
71620
  * to the first `{`. Raises `OxlintOutputUnparseable` when the
71000
71621
  * stdout isn't valid JSON or doesn't carry a `diagnostics` array.
71001
71622
  */
71002
- const parseOxlintOutput = (stdout, project, rootDirectory) => {
71623
+ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
71003
71624
  if (!stdout) return [];
71004
71625
  const jsonStart = stdout.indexOf("{");
71005
71626
  const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
@@ -71016,8 +71637,10 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71016
71637
  const sourceBufferCache = /* @__PURE__ */ new Map();
71017
71638
  const sourceLinesCache = /* @__PURE__ */ new Map();
71018
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;
71019
71642
  const readSourceBuffer = (filename) => {
71020
- const absolutePath = resolveAbsolutePath(filename);
71643
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71021
71644
  const cached = sourceBufferCache.get(absolutePath);
71022
71645
  if (cached !== void 0) return cached;
71023
71646
  let sourceBuffer;
@@ -71030,7 +71653,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71030
71653
  return sourceBuffer;
71031
71654
  };
71032
71655
  const readSourceLines = (filename) => {
71033
- const absolutePath = resolveAbsolutePath(filename);
71656
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71034
71657
  const cached = sourceLinesCache.get(absolutePath);
71035
71658
  if (cached !== void 0) return cached;
71036
71659
  const sourceBuffer = readSourceBuffer(filename);
@@ -71039,27 +71662,30 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71039
71662
  return sourceLines;
71040
71663
  };
71041
71664
  const isMinifiedDiagnosticFile = (filename) => {
71042
- const absolutePath = resolveAbsolutePath(filename);
71665
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71043
71666
  const cached = minifiedFileCache.get(absolutePath);
71044
71667
  if (cached !== void 0) return cached;
71045
71668
  const minified = isMinifiedSource(absolutePath);
71046
71669
  minifiedFileCache.set(absolutePath, minified);
71047
71670
  return minified;
71048
71671
  };
71049
- 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) => {
71050
71673
  const { plugin, rule } = parseRuleCode(diagnostic.code);
71051
71674
  const primaryLabel = diagnostic.labels[0];
71052
71675
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
71053
- const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
71676
+ const mappedSourceFilename = resolveMappedSourceFilename(diagnostic.filename);
71677
+ const normalizedFilePath = (mappedSourceFilename ?? diagnostic.filename).replaceAll("\\", "/");
71054
71678
  const primarySpan = primaryLabel?.span;
71055
71679
  const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
71056
- const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
71680
+ const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath, mappedSourceFilename === void 0 ? null : sourceBuffer);
71057
71681
  const category = resolveDiagnosticCategory(plugin, rule);
71058
71682
  const matchByOccurrence = resolveMatchByOccurrence(rule, category);
71059
71683
  const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
71060
- 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;
71061
71687
  const primaryLine = sourceLines?.[primaryLineIndex];
71062
- const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
71688
+ const primaryColumnIndex = primarySpan ? primaryColumnNumber - 1 : -1;
71063
71689
  const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
71064
71690
  const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
71065
71691
  const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
@@ -71072,8 +71698,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71072
71698
  message: cleaned.message,
71073
71699
  help: cleaned.help,
71074
71700
  url: diagnostic.url,
71075
- line: primarySpan?.line ?? 0,
71076
- column: primarySpan?.column ?? 0,
71701
+ line: primaryLineNumber,
71702
+ column: primaryColumnNumber,
71077
71703
  ...primarySpan ? {
71078
71704
  offset: primarySpan.offset,
71079
71705
  length: primarySpan.length,
@@ -71261,7 +71887,11 @@ const isParallelismRelatedSpawnError = (error) => {
71261
71887
  * loop with a slimmer config in that case.
71262
71888
  */
71263
71889
  const spawnLintBatches = async (input) => {
71264
- 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
+ };
71265
71895
  const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
71266
71896
  let rescueDeadlineEpochMs;
71267
71897
  const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
@@ -71281,7 +71911,7 @@ const spawnLintBatches = async (input) => {
71281
71911
  }
71282
71912
  const batchArgs = [...baseArgs, ...batch];
71283
71913
  try {
71284
- 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);
71285
71915
  } catch (error) {
71286
71916
  if (!isSplittableReactDoctorError(error)) throw error;
71287
71917
  if (isPastDeadline()) {
@@ -71387,10 +72017,12 @@ const spawnLintBatches = async (input) => {
71387
72017
  onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
71388
72018
  };
71389
72019
  const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
71390
- reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
71391
- 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})`);
71392
72024
  const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
71393
- 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());
71394
72026
  return dedupeDiagnostics(diagnostics);
71395
72027
  };
71396
72028
  let didValidate = false;
@@ -71489,6 +72121,266 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
71489
72121
  }
71490
72122
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
71491
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
+ };
71492
72384
  /**
71493
72385
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
71494
72386
  * the runner: once for the primary scan, once for the
@@ -71649,6 +72541,8 @@ const reactHooksJsPluginDropNote = (error) => {
71649
72541
  const runOxlint = async (options) => {
71650
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;
71651
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 = [];
71652
72546
  const severityControls = buildRuleSeverityControls(userConfig);
71653
72547
  validateRuleRegistration();
71654
72548
  resetManifestCaches();
@@ -71662,21 +72556,6 @@ const runOxlint = async (options) => {
71662
72556
  const pluginPath = resolvePluginPath();
71663
72557
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
71664
72558
  const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
71665
- const buildConfig = (overrides) => createOxlintConfig({
71666
- pluginPath,
71667
- project,
71668
- customRulesOnly,
71669
- extendsPaths: overrides.extendsPaths,
71670
- ignoredTags,
71671
- includedTags,
71672
- includeTagDefaults,
71673
- serverAuthFunctionNames,
71674
- severityControls,
71675
- userPlugins,
71676
- disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
71677
- ruleSelection: overrides.ruleSelection,
71678
- sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
71679
- });
71680
72559
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
71681
72560
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
71682
72561
  const configPath = Path.join(configDirectory, "oxlintrc.json");
@@ -71712,7 +72591,36 @@ const runOxlint = async (options) => {
71712
72591
  await yieldToEventLoop();
71713
72592
  const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
71714
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
+ });
71715
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);
71716
72624
  const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
71717
72625
  baseArgs: passBaseArgs,
71718
72626
  files: passFiles,
@@ -71741,7 +72649,8 @@ const runOxlint = async (options) => {
71741
72649
  fileBatches: passFileBatches,
71742
72650
  rootDirectory,
71743
72651
  nodeBinaryPath,
71744
- project,
72652
+ project: lintProject,
72653
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
71745
72654
  onPartialFailure: reportPartialFailure,
71746
72655
  onAnalyzedFiles: (filePaths) => {
71747
72656
  analyzedFiles = filePaths;
@@ -71776,7 +72685,7 @@ const runOxlint = async (options) => {
71776
72685
  };
71777
72686
  }
71778
72687
  };
71779
- 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) {
71780
72689
  const rulesetHash = computeRulesetHash({
71781
72690
  config: buildConfig({
71782
72691
  extendsPaths: [],
@@ -71934,14 +72843,15 @@ const runOxlint = async (options) => {
71934
72843
  ]);
71935
72844
  }
71936
72845
  const baseArgs = makeBaseArgs(configPath);
71937
- const fileBatches = buildFileBatches(baseArgs, candidateFiles);
72846
+ const fileBatches = buildFileBatches(baseArgs, lintFiles);
71938
72847
  let analyzedFiles = [];
71939
72848
  const runBatches = () => spawnLintBatches({
71940
72849
  baseArgs,
71941
72850
  fileBatches,
71942
72851
  rootDirectory,
71943
72852
  nodeBinaryPath,
71944
- project,
72853
+ project: lintProject,
72854
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
71945
72855
  onPartialFailure,
71946
72856
  onAnalyzedFiles: (filePaths) => {
71947
72857
  analyzedFiles = filePaths;
@@ -73517,7 +74427,8 @@ const SCANNABLE_EXTENSIONS = [
73517
74427
  ".js",
73518
74428
  ".jsx",
73519
74429
  ".mts",
73520
- ".mjs"
74430
+ ".mjs",
74431
+ ".html"
73521
74432
  ];
73522
74433
  const SILENT_LOGGER = {
73523
74434
  info: () => {},
@@ -75505,5 +76416,5 @@ const startLanguageServer = () => {
75505
76416
  };
75506
76417
  //#endregion
75507
76418
  export { startLanguageServer };
75508
- !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]="aeb8bc8c-7094-5b26-bb18-e269e2d4318a")}catch(e){}}();
75509
- //# debugId=aeb8bc8c-7094-5b26-bb18-e269e2d4318a
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