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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="eb93b210-c190-581c-8fe2-f1e1c70e0bab")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5ad39650-1163-5117-aad5-472963ee3867")}catch(e){}}();
3
3
  import { i as __toESM$1, r as __require, t as __commonJSMin$1 } from "./chunk-ChKA3wi6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
@@ -61448,7 +61448,8 @@ var AmbiguousProjectError = class extends Error {
61448
61448
  }
61449
61449
  };
61450
61450
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
61451
- const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
61451
+ const HTML_FILE_PATTERN = /\.html$/i;
61452
+ const SOURCE_FILE_PATTERN = /\.(?:tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
61452
61453
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
61453
61454
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
61454
61455
  const MINIFIED_SNIFF_BYTES = 65536;
@@ -62285,10 +62286,10 @@ const resolveImportedConfigFile = (fromFilePath, moduleSpecifier) => {
62285
62286
  ]).find(isFile) ?? null;
62286
62287
  };
62287
62288
  const parseConfigSourceFile = (filePath, content) => filePath.endsWith(".json") || Path.basename(filePath) === ".babelrc" ? ts.parseJsonText(filePath, content) : ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
62288
- const getStaticPropertyName$1 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
62289
+ const getStaticPropertyName$2 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
62289
62290
  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");
62290
62291
  const hasExportModifier = (node) => ts.canHaveModifiers(node) && Boolean(ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
62291
- const getRequireModuleSpecifier = (expression) => {
62292
+ const getRequireModuleSpecifier$1 = (expression) => {
62292
62293
  if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "require" || expression.arguments.length !== 1) return null;
62293
62294
  const moduleSpecifier = expression.arguments[0];
62294
62295
  return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
@@ -62301,7 +62302,7 @@ const hasTopLevelValueBinding = (sourceFile, bindingName) => sourceFile.statemen
62301
62302
  const namedBindings = importClause?.namedBindings;
62302
62303
  return namedBindings ? ts.isNamespaceImport(namedBindings) ? namedBindings.name.text === bindingName : namedBindings.elements.some((element) => element.name.text === bindingName) : false;
62303
62304
  }
62304
- if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === bindingName);
62305
+ if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContainsIdentifier(declaration.name, bindingName));
62305
62306
  return (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name?.text === bindingName;
62306
62307
  });
62307
62308
  const getImportBinding = (sourceFile, bindingName) => {
@@ -62332,24 +62333,24 @@ const getImportBinding = (sourceFile, bindingName) => {
62332
62333
  for (const declaration of statement.declarationList.declarations) {
62333
62334
  if (!declaration.initializer) continue;
62334
62335
  if (ts.isIdentifier(declaration.name) && declaration.name.text === bindingName) {
62335
- const directModuleSpecifier = getRequireModuleSpecifier(declaration.initializer);
62336
+ const directModuleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
62336
62337
  if (directModuleSpecifier) return {
62337
62338
  moduleSpecifier: directModuleSpecifier,
62338
62339
  exportName: "default",
62339
62340
  isNamespace: true
62340
62341
  };
62341
- if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier(declaration.initializer.expression) !== null) return {
62342
- moduleSpecifier: getRequireModuleSpecifier(declaration.initializer.expression) ?? "",
62342
+ if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier$1(declaration.initializer.expression) !== null) return {
62343
+ moduleSpecifier: getRequireModuleSpecifier$1(declaration.initializer.expression) ?? "",
62343
62344
  exportName: declaration.initializer.name.text,
62344
62345
  isNamespace: false
62345
62346
  };
62346
62347
  }
62347
62348
  if (!ts.isObjectBindingPattern(declaration.name)) continue;
62348
62349
  const bindingElement = declaration.name.elements.find((element) => ts.isIdentifier(element.name) && element.name.text === bindingName);
62349
- const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
62350
+ const moduleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
62350
62351
  if (bindingElement && moduleSpecifier) return {
62351
62352
  moduleSpecifier,
62352
- exportName: bindingElement.propertyName ? getStaticPropertyName$1(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
62353
+ exportName: bindingElement.propertyName ? getStaticPropertyName$2(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
62353
62354
  isNamespace: false
62354
62355
  };
62355
62356
  }
@@ -62402,6 +62403,48 @@ const getScopedConfigBinding = (identifier) => {
62402
62403
  };
62403
62404
  };
62404
62405
  const isCompilerTransformModule = (moduleSpecifier, exportName) => moduleSpecifier === "babel-plugin-react-compiler" && exportName === "default" || moduleSpecifier === "@vitejs/plugin-react" && exportName === "reactCompilerPreset";
62406
+ const NODE_MODULE_SPECIFIERS = new Set(["module", "node:module"]);
62407
+ const isConstantVariableInitializer = (node) => ts.isExpression(node) && ts.isVariableDeclaration(node.parent) && ts.isVariableDeclarationList(node.parent.parent) && Boolean(node.parent.parent.flags & ts.NodeFlags.Const);
62408
+ const isNodeCreateRequireCall = (node, analysis) => {
62409
+ if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertionExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isAwaitExpression(node)) return isNodeCreateRequireCall(node.expression, analysis);
62410
+ if (!ts.isCallExpression(node)) return false;
62411
+ const target = node.expression;
62412
+ if (ts.isIdentifier(target)) {
62413
+ if (analysis.localBindings.has(target.text) || getScopedConfigBinding(target).wasFound) return false;
62414
+ const importBinding = getImportBinding(analysis.sourceFile, target.text);
62415
+ return Boolean(importBinding && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier) && importBinding.exportName === "createRequire");
62416
+ }
62417
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return false;
62418
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "createRequire") return false;
62419
+ const createRequireReceiver = target.expression;
62420
+ if (ts.isCallExpression(createRequireReceiver)) {
62421
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(createRequireReceiver);
62422
+ if (requiredModuleSpecifier === null || !NODE_MODULE_SPECIFIERS.has(requiredModuleSpecifier) || !ts.isIdentifier(createRequireReceiver.expression)) return false;
62423
+ const requireIdentifier = createRequireReceiver.expression;
62424
+ return !analysis.localBindings.has(requireIdentifier.text) && !getScopedConfigBinding(requireIdentifier).wasFound && !hasTopLevelValueBinding(analysis.sourceFile, requireIdentifier.text);
62425
+ }
62426
+ if (!ts.isIdentifier(createRequireReceiver)) return false;
62427
+ if (analysis.localBindings.has(createRequireReceiver.text) || getScopedConfigBinding(createRequireReceiver).wasFound) return false;
62428
+ const importBinding = getImportBinding(analysis.sourceFile, createRequireReceiver.text);
62429
+ return Boolean(importBinding?.isNamespace && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier));
62430
+ };
62431
+ const getNodeRequireResolveModuleSpecifier = (callExpression, analysis) => {
62432
+ const [moduleSpecifierNode] = callExpression.arguments;
62433
+ if (!moduleSpecifierNode || !ts.isStringLiteralLike(moduleSpecifierNode)) return null;
62434
+ const target = callExpression.expression;
62435
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
62436
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "resolve") return null;
62437
+ if (isNodeCreateRequireCall(target.expression, analysis)) return moduleSpecifierNode.text;
62438
+ if (!ts.isIdentifier(target.expression)) return null;
62439
+ const resolverIdentifier = target.expression;
62440
+ if (analysis.localBindings.has(resolverIdentifier.text)) return null;
62441
+ const scopedBinding = getScopedConfigBinding(resolverIdentifier);
62442
+ const topLevelBinding = scopedBinding.wasFound ? null : getTopLevelBinding(analysis.sourceFile, resolverIdentifier.text);
62443
+ const resolverInitializer = scopedBinding.wasFound ? scopedBinding.initializer : topLevelBinding;
62444
+ if (resolverInitializer === null && !scopedBinding.wasFound && resolverIdentifier.text === "require" && !hasTopLevelValueBinding(analysis.sourceFile, resolverIdentifier.text) && getImportBinding(analysis.sourceFile, resolverIdentifier.text) === null) return moduleSpecifierNode.text;
62445
+ if (!resolverInitializer || !isConstantVariableInitializer(resolverInitializer) || !isNodeCreateRequireCall(resolverInitializer, analysis)) return null;
62446
+ return moduleSpecifierNode.text;
62447
+ };
62405
62448
  const getAssignedPropertyInitializer = (identifier, propertyName) => {
62406
62449
  let bindingScope = null;
62407
62450
  let currentNode = identifier;
@@ -62510,7 +62553,7 @@ const getReactCompilerFlagState = (expression, analysis) => {
62510
62553
  }
62511
62554
  if (!ts.isObjectLiteralExpression(unwrappedExpression)) return null;
62512
62555
  for (const property of [...unwrappedExpression.properties].reverse()) {
62513
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
62556
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
62514
62557
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.name, analysis) };
62515
62558
  if (ts.isSpreadAssignment(property)) {
62516
62559
  const spreadState = getReactCompilerFlagState(property.expression, analysis);
@@ -62536,8 +62579,8 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
62536
62579
  }
62537
62580
  if (!ts.isObjectLiteralExpression(resolvedExpression)) return null;
62538
62581
  for (const property of [...resolvedExpression.properties].reverse()) {
62539
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === propertyName) return property.initializer;
62540
- if (ts.isMethodDeclaration(property) && getStaticPropertyName$1(property.name) === propertyName) return property;
62582
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === propertyName) return property.initializer;
62583
+ if (ts.isMethodDeclaration(property) && getStaticPropertyName$2(property.name) === propertyName) return property;
62541
62584
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property.name;
62542
62585
  if (ts.isSpreadAssignment(property)) {
62543
62586
  const spreadProperty = getSelectedObjectProperty(property.expression, propertyName, analysis, visitedExpressions);
@@ -62568,7 +62611,7 @@ const configExpressionMayDefineProperty = (expression, propertyName, analysis) =
62568
62611
  return resolvedExpression.properties.some((property) => {
62569
62612
  if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
62570
62613
  if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
62571
- const staticPropertyName = getStaticPropertyName$1(property.name);
62614
+ const staticPropertyName = getStaticPropertyName$2(property.name);
62572
62615
  return staticPropertyName === null || staticPropertyName === propertyName;
62573
62616
  }
62574
62617
  return false;
@@ -62587,7 +62630,7 @@ const getExportedConfigNodes = (sourceFile, exportName) => {
62587
62630
  continue;
62588
62631
  }
62589
62632
  if (ts.isExpressionStatement(statement) && isCommonJsConfigExportAssignment(statement.expression, sourceFile) && exportName !== "default" && ts.isObjectLiteralExpression(statement.expression.right)) for (const property of [...statement.expression.right.properties].reverse()) {
62590
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === exportName) {
62633
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === exportName) {
62591
62634
  exportedNodes.push(property.initializer);
62592
62635
  break;
62593
62636
  }
@@ -62717,7 +62760,7 @@ const analyzeConfigCallTarget = (callExpression, analysis, allowCompilerTransfor
62717
62760
  if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
62718
62761
  const propertyName = ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null;
62719
62762
  if (propertyName === null) return null;
62720
- const requiredModuleSpecifier = getRequireModuleSpecifier(target.expression);
62763
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(target.expression);
62721
62764
  if (requiredModuleSpecifier !== null) {
62722
62765
  if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62723
62766
  if (!requiredModuleSpecifier.startsWith(".")) return null;
@@ -62746,10 +62789,10 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62746
62789
  const reactCompilerFlagState = excludedPropertyNames?.has("reactCompiler") ? null : getReactCompilerFlagState(node, analysis);
62747
62790
  if (reactCompilerFlagState?.isEnabled) return true;
62748
62791
  for (const [propertyIndex, property] of node.properties.entries()) if (ts.isPropertyAssignment(property)) {
62749
- const propertyName = getStaticPropertyName$1(property.name);
62792
+ const propertyName = getStaticPropertyName$2(property.name);
62750
62793
  if (propertyName && excludedPropertyNames?.has(propertyName)) continue;
62751
62794
  if (propertyName === "reactCompiler") continue;
62752
- 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;
62795
+ 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;
62753
62796
  const propertyAllowsCompilerTransform = propertyName === "plugins" || propertyName === "presets";
62754
62797
  if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer) && property.initializer.text.startsWith(".")) {
62755
62798
  const extendedFilePath = resolveImportedConfigFile(analysis.filePath, property.initializer.text);
@@ -62759,12 +62802,12 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62759
62802
  } else if (ts.isShorthandPropertyAssignment(property)) {
62760
62803
  if (excludedPropertyNames?.has(property.name.text)) continue;
62761
62804
  if (property.name.text === "reactCompiler") continue;
62762
- 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;
62805
+ 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;
62763
62806
  const propertyAllowsCompilerTransform = property.name.text === "plugins" || property.name.text === "presets";
62764
62807
  if (analyzeConfigNode(property.name, analysis, propertyAllowsCompilerTransform, propertyAllowsCompilerTransform)) return true;
62765
62808
  } else if (ts.isSpreadAssignment(property)) {
62766
62809
  if (reactCompilerFlagState && getReactCompilerFlagState(property.expression, analysis) !== null) continue;
62767
- 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;
62810
+ 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;
62768
62811
  if (analyzeConfigNode(property.expression, analysis, allowCompilerTransform, false, excludedPropertyNames)) return true;
62769
62812
  }
62770
62813
  return false;
@@ -62777,9 +62820,11 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62777
62820
  });
62778
62821
  }
62779
62822
  if (ts.isCallExpression(node)) {
62823
+ const resolvedModuleSpecifier = getNodeRequireResolveModuleSpecifier(node, analysis);
62824
+ if (resolvedModuleSpecifier !== null) return allowCompilerTransform && isCompilerTransformModule(resolvedModuleSpecifier, "default");
62780
62825
  const callTargetResult = analyzeConfigCallTarget(node, analysis, allowCompilerTransform);
62781
62826
  if (callTargetResult !== null) return callTargetResult;
62782
- const directModuleSpecifier = getRequireModuleSpecifier(node);
62827
+ const directModuleSpecifier = getRequireModuleSpecifier$1(node);
62783
62828
  const isRequireShadowed = analysis.localBindings.has("require") || ts.isIdentifier(node.expression) && getScopedConfigBinding(node.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require");
62784
62829
  if (directModuleSpecifier && isRequireShadowed) return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
62785
62830
  if (directModuleSpecifier && !isRequireShadowed) {
@@ -62801,7 +62846,7 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62801
62846
  return analyzeConfigNode(node.expression, analysis, allowCompilerTransform) || node.arguments.some((argument) => analyzeConfigNode(argument, analysis, false));
62802
62847
  }
62803
62848
  if (ts.isPropertyAccessExpression(node)) {
62804
- const requiredModuleSpecifier = getRequireModuleSpecifier(node.expression);
62849
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(node.expression);
62805
62850
  if (requiredModuleSpecifier) {
62806
62851
  if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62807
62852
  if (requiredModuleSpecifier.startsWith(".")) {
@@ -66138,7 +66183,7 @@ const warn = (message) => {
66138
66183
  runSync(warn$1(message));
66139
66184
  };
66140
66185
  const CONFIG_BASENAME = "doctor.config";
66141
- const CONFIG_EXTENSIONS = [
66186
+ const CONFIG_EXTENSIONS$1 = [
66142
66187
  "ts",
66143
66188
  "mts",
66144
66189
  "cts",
@@ -66242,7 +66287,7 @@ const loadLegacyConfig = (directory) => {
66242
66287
  };
66243
66288
  const loadConfigFromDirectory = async (directory) => {
66244
66289
  let sawBrokenConfigFile = false;
66245
- for (const extension of CONFIG_EXTENSIONS) {
66290
+ for (const extension of CONFIG_EXTENSIONS$1) {
66246
66291
  const filePath = Path.join(directory, `${CONFIG_BASENAME}.${extension}`);
66247
66292
  if (!isFile(filePath)) continue;
66248
66293
  const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
@@ -66977,6 +67022,321 @@ const buildReactNativeDiagnostic = (input) => ({
66977
67022
  column: input.column ?? 0,
66978
67023
  category: input.category ?? "Correctness"
66979
67024
  });
67025
+ const ANDROID_APP_BUILD_FILE_NAMES = ["build.gradle", "build.gradle.kts"];
67026
+ const BUILD_TYPES_BLOCK_PATTERN = /\bbuildTypes\s*\{/g;
67027
+ const RELEASE_STRING_MARKER = "__RD_RELEASE__";
67028
+ const RELEASE_BLOCK_PATTERNS = [/\brelease\s*\{/g, /\b(?:getByName|named)\s*\(\s*(?:["']release["']|__RD_RELEASE__)\s*\)\s*\{/g];
67029
+ const MINIFY_ASSIGNMENT_PATTERN = /\b(?:isMinifyEnabled|minifyEnabled)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
67030
+ const SHRINK_RESOURCES_ASSIGNMENT_PATTERN = /\b(?:isShrinkResources|shrinkResources)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
67031
+ const stripGradleComments = (contents) => {
67032
+ let result = "";
67033
+ let index = 0;
67034
+ let quote = null;
67035
+ while (index < contents.length) {
67036
+ const character = contents[index];
67037
+ const nextCharacter = contents[index + 1];
67038
+ if (quote !== null) {
67039
+ result += character;
67040
+ if (character === "\\") {
67041
+ result += nextCharacter ?? "";
67042
+ index += 2;
67043
+ continue;
67044
+ }
67045
+ if (character === quote) quote = null;
67046
+ index += 1;
67047
+ continue;
67048
+ }
67049
+ if (character === "\"" || character === "'") {
67050
+ quote = character;
67051
+ result += character;
67052
+ index += 1;
67053
+ continue;
67054
+ }
67055
+ if (character === "/" && nextCharacter === "/") {
67056
+ while (index < contents.length && contents[index] !== "\n") {
67057
+ result += " ";
67058
+ index += 1;
67059
+ }
67060
+ continue;
67061
+ }
67062
+ if (character === "/" && nextCharacter === "*") {
67063
+ result += " ";
67064
+ index += 2;
67065
+ while (index < contents.length && !(contents[index] === "*" && contents[index + 1] === "/")) {
67066
+ result += contents[index] === "\n" ? "\n" : " ";
67067
+ index += 1;
67068
+ }
67069
+ if (index < contents.length) {
67070
+ result += " ";
67071
+ index += 2;
67072
+ }
67073
+ continue;
67074
+ }
67075
+ result += character;
67076
+ index += 1;
67077
+ }
67078
+ return result;
67079
+ };
67080
+ const maskGradleStrings = (contents) => {
67081
+ let result = "";
67082
+ let index = 0;
67083
+ let quote = null;
67084
+ while (index < contents.length) {
67085
+ const character = contents[index];
67086
+ if (quote === null) {
67087
+ if (character === "\"" || character === "'") {
67088
+ quote = character;
67089
+ result += " ";
67090
+ } else result += character;
67091
+ index += 1;
67092
+ continue;
67093
+ }
67094
+ if (character === "\\") {
67095
+ result += " ";
67096
+ index += 2;
67097
+ continue;
67098
+ }
67099
+ if (character === quote) quote = null;
67100
+ result += character === "\n" ? "\n" : " ";
67101
+ index += 1;
67102
+ }
67103
+ return result;
67104
+ };
67105
+ const findBlockContents = (contents, pattern) => {
67106
+ const blocks = [];
67107
+ pattern.lastIndex = 0;
67108
+ let match = pattern.exec(contents);
67109
+ while (match !== null) {
67110
+ const openingBraceIndex = pattern.lastIndex - 1;
67111
+ let depth = 1;
67112
+ let index = openingBraceIndex + 1;
67113
+ let quote = null;
67114
+ while (index < contents.length && depth > 0) {
67115
+ const character = contents[index];
67116
+ if (quote !== null) {
67117
+ if (character === "\\") {
67118
+ index += 2;
67119
+ continue;
67120
+ }
67121
+ if (character === quote) quote = null;
67122
+ } else if (character === "\"" || character === "'") quote = character;
67123
+ else if (character === "{") depth += 1;
67124
+ else if (character === "}") depth -= 1;
67125
+ index += 1;
67126
+ }
67127
+ if (depth === 0) blocks.push(contents.slice(openingBraceIndex + 1, index - 1));
67128
+ match = pattern.exec(contents);
67129
+ }
67130
+ return blocks;
67131
+ };
67132
+ const getFinalStaticBoolean = (contents, pattern) => {
67133
+ pattern.lastIndex = 0;
67134
+ let finalValue = null;
67135
+ let match = pattern.exec(contents);
67136
+ while (match !== null) {
67137
+ const staticValue = match[1]?.trim().replace(/\)$/, "").trim();
67138
+ if (staticValue === "true") finalValue = true;
67139
+ else if (staticValue === "false") finalValue = false;
67140
+ else finalValue = null;
67141
+ match = pattern.exec(contents);
67142
+ }
67143
+ return finalValue;
67144
+ };
67145
+ const getReleaseBlocks = (contents) => findBlockContents(contents, BUILD_TYPES_BLOCK_PATTERN).flatMap((buildTypesBlock) => RELEASE_BLOCK_PATTERNS.flatMap((pattern) => findBlockContents(buildTypesBlock, pattern)));
67146
+ const readAndroidReleaseShrinking = (rootDirectory) => {
67147
+ for (const buildFileName of ANDROID_APP_BUILD_FILE_NAMES) {
67148
+ const filePath = Path.posix.join("android", "app", buildFileName);
67149
+ const absoluteFilePath = Path.join(rootDirectory, filePath);
67150
+ if (!isFile(absoluteFilePath)) continue;
67151
+ let contents;
67152
+ try {
67153
+ contents = stripGradleComments(NFS.readFileSync(absoluteFilePath, "utf-8"));
67154
+ } catch {
67155
+ return null;
67156
+ }
67157
+ const releaseBlocks = getReleaseBlocks(maskGradleStrings(contents.replace(/(["'])release\1/g, RELEASE_STRING_MARKER)));
67158
+ const [releaseBlock] = releaseBlocks;
67159
+ if (releaseBlock === void 0 || releaseBlocks.length !== 1) return null;
67160
+ const hasDisabledMinification = getFinalStaticBoolean(releaseBlock, MINIFY_ASSIGNMENT_PATTERN) === false;
67161
+ const hasDisabledResourceShrinking = getFinalStaticBoolean(releaseBlock, SHRINK_RESOURCES_ASSIGNMENT_PATTERN) === false;
67162
+ if (!hasDisabledMinification && !hasDisabledResourceShrinking) return null;
67163
+ return {
67164
+ filePath,
67165
+ hasDisabledMinification,
67166
+ hasDisabledResourceShrinking
67167
+ };
67168
+ }
67169
+ return null;
67170
+ };
67171
+ const checkReactNativeAndroidReleaseShrinking = (rootDirectory) => {
67172
+ const releaseShrinking = readAndroidReleaseShrinking(rootDirectory);
67173
+ if (releaseShrinking === null) return [];
67174
+ const disabledFeatures = [releaseShrinking.hasDisabledMinification ? "code minification" : null, releaseShrinking.hasDisabledResourceShrinking ? "resource shrinking" : null].filter((feature) => feature !== null);
67175
+ return [buildReactNativeDiagnostic({
67176
+ filePath: releaseShrinking.filePath,
67177
+ rule: "rn-android-release-shrinking-disabled",
67178
+ category: "Performance",
67179
+ message: `The Android release build explicitly disables ${disabledFeatures.join(" and ")}, leaving unreachable code or resources in the shipped app.`,
67180
+ help: "Enable release code minification and resource shrinking, then test the optimized build and add keep rules for libraries that require them."
67181
+ })];
67182
+ };
67183
+ const getTypescriptScriptKind = (fileName) => {
67184
+ if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
67185
+ if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
67186
+ if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
67187
+ return ts.ScriptKind.JS;
67188
+ };
67189
+ const unwrapTypescriptExpression = (expression) => {
67190
+ let currentExpression = expression;
67191
+ while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
67192
+ return currentExpression;
67193
+ };
67194
+ const BABEL_CONFIG_FILE_NAMES$1 = [
67195
+ "babel.config.js",
67196
+ "babel.config.cjs",
67197
+ "babel.config.mjs",
67198
+ "babel.config.ts",
67199
+ "babel.config.cts",
67200
+ "babel.config.json",
67201
+ ".babelrc",
67202
+ ".babelrc.js",
67203
+ ".babelrc.cjs",
67204
+ ".babelrc.mjs",
67205
+ ".babelrc.cts",
67206
+ ".babelrc.json"
67207
+ ];
67208
+ const readUnknownPluginNames = (value) => {
67209
+ if (!Array.isArray(value)) return null;
67210
+ const pluginNames = [];
67211
+ for (const entry of value) {
67212
+ if (typeof entry === "string") {
67213
+ pluginNames.push(entry);
67214
+ continue;
67215
+ }
67216
+ if (Array.isArray(entry) && typeof entry[0] === "string") {
67217
+ pluginNames.push(entry[0]);
67218
+ continue;
67219
+ }
67220
+ return null;
67221
+ }
67222
+ return pluginNames;
67223
+ };
67224
+ const getStaticPropertyName$1 = (propertyName) => {
67225
+ if (ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName)) return propertyName.text;
67226
+ return null;
67227
+ };
67228
+ const getStaticPluginName = (expression) => {
67229
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
67230
+ if (ts.isStringLiteralLike(unwrappedExpression)) return unwrappedExpression.text;
67231
+ if (!ts.isArrayLiteralExpression(unwrappedExpression)) return null;
67232
+ const pluginExpression = unwrappedExpression.elements[0];
67233
+ return pluginExpression && ts.isStringLiteralLike(pluginExpression) ? pluginExpression.text : null;
67234
+ };
67235
+ const getPluginNamesFromObject = (objectExpression) => {
67236
+ if (objectExpression.properties.some((property) => ts.isSpreadAssignment(property))) return null;
67237
+ const pluginProperties = objectExpression.properties.filter((property) => ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === "plugins");
67238
+ if (pluginProperties.length !== 1) return pluginProperties.length === 0 ? [] : null;
67239
+ const pluginListExpression = unwrapTypescriptExpression(pluginProperties[0].initializer);
67240
+ if (!ts.isArrayLiteralExpression(pluginListExpression)) return null;
67241
+ const pluginNames = [];
67242
+ for (const element of pluginListExpression.elements) {
67243
+ if (ts.isSpreadElement(element)) return null;
67244
+ const pluginName = getStaticPluginName(element);
67245
+ if (pluginName === null) return null;
67246
+ pluginNames.push(pluginName);
67247
+ }
67248
+ return pluginNames;
67249
+ };
67250
+ 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";
67251
+ const getDirectExportedObject = (sourceFile) => {
67252
+ const exportedExpressions = [];
67253
+ for (const statement of sourceFile.statements) {
67254
+ if (ts.isExportAssignment(statement)) {
67255
+ exportedExpressions.push(statement.expression);
67256
+ continue;
67257
+ }
67258
+ if (ts.isExpressionStatement(statement) && ts.isBinaryExpression(statement.expression) && statement.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken && isModuleExports(statement.expression.left)) exportedExpressions.push(statement.expression.right);
67259
+ }
67260
+ if (exportedExpressions.length !== 1) return null;
67261
+ const exportedExpression = unwrapTypescriptExpression(exportedExpressions[0]);
67262
+ return ts.isObjectLiteralExpression(exportedExpression) ? exportedExpression : null;
67263
+ };
67264
+ const parseConfigPluginNames = (filePath, contents) => {
67265
+ try {
67266
+ const parsedJson = JSON.parse(contents);
67267
+ return isPlainObject(parsedJson) ? readUnknownPluginNames(parsedJson.plugins) : null;
67268
+ } catch {
67269
+ if (ts.transpileModule(contents, {
67270
+ fileName: filePath,
67271
+ reportDiagnostics: true,
67272
+ compilerOptions: { allowJs: true }
67273
+ }).diagnostics?.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) return null;
67274
+ const exportedObject = getDirectExportedObject(ts.createSourceFile(filePath, contents, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(filePath)));
67275
+ return exportedObject === null ? null : getPluginNamesFromObject(exportedObject);
67276
+ }
67277
+ };
67278
+ const readStaticBabelPluginNames = (rootDirectory) => {
67279
+ for (const fileName of BABEL_CONFIG_FILE_NAMES$1) {
67280
+ const absoluteFilePath = Path.join(rootDirectory, fileName);
67281
+ if (!isFile(absoluteFilePath)) continue;
67282
+ try {
67283
+ return {
67284
+ filePath: fileName,
67285
+ pluginNames: parseConfigPluginNames(fileName, NFS.readFileSync(absoluteFilePath, "utf-8"))
67286
+ };
67287
+ } catch {
67288
+ return {
67289
+ filePath: fileName,
67290
+ pluginNames: null
67291
+ };
67292
+ }
67293
+ }
67294
+ const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
67295
+ if (!isPlainObject(packageJson.babel)) return null;
67296
+ return {
67297
+ filePath: "package.json",
67298
+ pluginNames: readUnknownPluginNames(packageJson.babel.plugins)
67299
+ };
67300
+ };
67301
+ const REACT_COMPILER_PLUGIN_NAMES = new Set(["babel-plugin-react-compiler", "react-compiler"]);
67302
+ const REANIMATED_PLUGIN_NAME = "react-native-reanimated/plugin";
67303
+ const WORKLETS_PLUGIN_NAME = "react-native-worklets/plugin";
67304
+ const checkReactCompilerPluginOrder = (filePath, pluginNames) => {
67305
+ if (pluginNames.findIndex((pluginName) => REACT_COMPILER_PLUGIN_NAMES.has(pluginName)) <= 0) return [];
67306
+ return [buildReactNativeDiagnostic({
67307
+ filePath,
67308
+ rule: "rn-react-compiler-plugin-first",
67309
+ category: "Performance",
67310
+ message: "The React Compiler Babel plugin is not first, so an earlier transform can change component or hook code before the compiler analyzes it.",
67311
+ help: "Move `babel-plugin-react-compiler` to the first entry in the Babel `plugins` array."
67312
+ })];
67313
+ };
67314
+ const checkReanimatedPluginOrder = (project, filePath, pluginNames) => {
67315
+ const reanimatedMajorVersion = project.reanimatedVersion === null || project.reanimatedVersion === void 0 ? null : getLowestDependencyMajor(project.reanimatedVersion);
67316
+ if (reanimatedMajorVersion === null || reanimatedMajorVersion < 4) return [];
67317
+ const diagnostics = [];
67318
+ if (pluginNames.includes(REANIMATED_PLUGIN_NAME)) diagnostics.push(buildReactNativeDiagnostic({
67319
+ filePath,
67320
+ rule: "rn-reanimated-worklets-plugin-last",
67321
+ category: "Performance",
67322
+ message: "This Reanimated 4 project still uses `react-native-reanimated/plugin`, which was renamed to the Worklets Babel plugin.",
67323
+ help: "Replace it with `react-native-worklets/plugin` and keep that plugin last in the Babel `plugins` array."
67324
+ }));
67325
+ const workletsPluginIndex = pluginNames.lastIndexOf(WORKLETS_PLUGIN_NAME);
67326
+ if (workletsPluginIndex !== -1 && workletsPluginIndex !== pluginNames.length - 1) diagnostics.push(buildReactNativeDiagnostic({
67327
+ filePath,
67328
+ rule: "rn-reanimated-worklets-plugin-last",
67329
+ category: "Performance",
67330
+ message: "`react-native-worklets/plugin` is not last in the Babel `plugins` array, so later transforms can prevent worklets from being compiled correctly.",
67331
+ help: "Move `react-native-worklets/plugin` to the final entry in the Babel `plugins` array."
67332
+ }));
67333
+ return diagnostics;
67334
+ };
67335
+ const checkReactNativeBabelPluginOrder = (rootDirectory, project) => {
67336
+ const babelPlugins = readStaticBabelPluginNames(rootDirectory);
67337
+ if (babelPlugins === null || babelPlugins.pluginNames === null) return [];
67338
+ return [...checkReactCompilerPluginOrder(babelPlugins.filePath, babelPlugins.pluginNames), ...checkReanimatedPluginOrder(project, babelPlugins.filePath, babelPlugins.pluginNames)];
67339
+ };
66980
67340
  const BUILDER_BOB_PACKAGE = "react-native-builder-bob";
66981
67341
  const isBuilderBobLibrary = (packageJson) => {
66982
67342
  const bobConfig = packageJson[BUILDER_BOB_PACKAGE];
@@ -67053,7 +67413,12 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
67053
67413
  const isReactNativeProject = (project) => project.framework === "react-native" || project.framework === "expo" || project.hasReactNativeWorkspace || project.expoVersion !== null;
67054
67414
  const checkReactNativeProject = (rootDirectory, project) => {
67055
67415
  if (!isReactNativeProject(project)) return [];
67056
- return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
67416
+ return [
67417
+ ...checkReactNativeMetroBabelPreset(rootDirectory),
67418
+ ...checkReactNativeBabelPluginOrder(rootDirectory, project),
67419
+ ...checkReactNativeAndroidReleaseShrinking(rootDirectory),
67420
+ ...checkReactNativeLibraryDependencies(rootDirectory)
67421
+ ];
67057
67422
  };
67058
67423
  const RULE_KEY = "no-vulnerable-react-server-components";
67059
67424
  const REACT_RSC_ADVISORIES_BY_MINOR = {
@@ -67204,17 +67569,6 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
67204
67569
  }
67205
67570
  return diagnostics;
67206
67571
  };
67207
- const getTypescriptScriptKind = (fileName) => {
67208
- if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
67209
- if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
67210
- if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
67211
- return ts.ScriptKind.JS;
67212
- };
67213
- const unwrapTypescriptExpression = (expression) => {
67214
- let currentExpression = expression;
67215
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
67216
- return currentExpression;
67217
- };
67218
67572
  const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
67219
67573
  isAnimationFunction: false,
67220
67574
  isMotionComponent: false,
@@ -67770,7 +68124,11 @@ const buildCapabilities = (project) => {
67770
68124
  capabilities.add(project.framework);
67771
68125
  if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
67772
68126
  if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
67773
- if (project.expoVersion !== null) capabilities.add("expo");
68127
+ if (project.expoVersion !== null) {
68128
+ capabilities.add("expo");
68129
+ const expoSdkMajorVersion = getLowestDependencyMajor(project.expoVersion);
68130
+ if (expoSdkMajorVersion !== null && expoSdkMajorVersion >= 54) capabilities.add("expo:54");
68131
+ }
67774
68132
  if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
67775
68133
  if (SSR_FRAMEWORKS.has(project.framework) || project.hasSsrDependency) capabilities.add("ssr");
67776
68134
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
@@ -67834,6 +68192,11 @@ const buildCapabilities = (project) => {
67834
68192
  if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
67835
68193
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
67836
68194
  if (project.hasReactCompiler) capabilities.add("react-compiler");
68195
+ if (project.reanimatedVersion !== void 0 && project.reanimatedVersion !== null) {
68196
+ capabilities.add("reanimated");
68197
+ const reanimatedMajorVersion = getLowestDependencyMajor(project.reanimatedVersion);
68198
+ if (reanimatedMajorVersion !== null && reanimatedMajorVersion >= 4) capabilities.add("reanimated:4");
68199
+ }
67837
68200
  if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
67838
68201
  if (project.styledComponentsVersion) {
67839
68202
  capabilities.add("styled-components");
@@ -69731,7 +70094,11 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
69731
70094
  const ROOT_DIRECTORY_PLACEHOLDER = "<root>";
69732
70095
  const normalizeConfigForHash = (config) => {
69733
70096
  const clone = JSON.parse(JSON.stringify(config));
69734
- if (clone?.settings?.["react-doctor"]) clone.settings["react-doctor"].rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
70097
+ if (clone?.settings?.["react-doctor"]) {
70098
+ const reactDoctorSettings = clone.settings["react-doctor"];
70099
+ reactDoctorSettings.rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
70100
+ if (Array.isArray(reactDoctorSettings.unpluginAutoImportRootDirectories)) reactDoctorSettings.unpluginAutoImportRootDirectories = [ROOT_DIRECTORY_PLACEHOLDER];
70101
+ }
69735
70102
  if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
69736
70103
  return clone;
69737
70104
  };
@@ -69890,13 +70257,14 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
69890
70257
  }
69891
70258
  return enabled;
69892
70259
  };
69893
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
70260
+ 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 }) => {
69894
70261
  const hasIncludedTags = includedTags.size > 0;
69895
70262
  const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
69896
70263
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
69897
70264
  const jsPlugins = [];
69898
70265
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
69899
70266
  const capabilities = getCapabilities(project);
70267
+ const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
69900
70268
  const enabledReactDoctorRules = {};
69901
70269
  for (const registryEntry of REACT_DOCTOR_RULES) {
69902
70270
  const rule = reactDoctorPlugin.rules[registryEntry.id];
@@ -69942,8 +70310,16 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
69942
70310
  jsPlugins: [...jsPlugins, pluginPath],
69943
70311
  settings: { "react-doctor": {
69944
70312
  framework: project.framework,
69945
- rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
70313
+ rootDirectory: settingsRootDirectory,
69946
70314
  capabilities: [...capabilities].sort(),
70315
+ ...runtimeGlobals && runtimeGlobals.length > 0 ? { runtimeGlobals: [...runtimeGlobals] } : {},
70316
+ ...unpluginAutoImportGlobalScopes && unpluginAutoImportGlobalScopes.length > 0 ? {
70317
+ unpluginAutoImportRootDirectories: [...new Set([settingsRootDirectory, project.rootDirectory])],
70318
+ unpluginAutoImportGlobalScopes: unpluginAutoImportGlobalScopes.map((scope) => ({
70319
+ directory: scope.directory,
70320
+ names: [...scope.names]
70321
+ }))
70322
+ } : {},
69947
70323
  ...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
69948
70324
  ...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
69949
70325
  } },
@@ -69954,6 +70330,245 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
69954
70330
  }
69955
70331
  };
69956
70332
  };
70333
+ const AUTO_IMPORT_ADAPTER_PATTERN = /^unplugin-auto-import\/(?:astro|esbuild|rollup|rolldown|rspack|vite|webpack)$/;
70334
+ const CONFIG_BASENAMES = [
70335
+ "astro.config",
70336
+ "esbuild.config",
70337
+ "rollup.config",
70338
+ "rolldown.config",
70339
+ "rspack.config",
70340
+ "vite.config",
70341
+ "webpack.config"
70342
+ ];
70343
+ const CONFIG_EXTENSIONS = [
70344
+ ".cjs",
70345
+ ".cts",
70346
+ ".js",
70347
+ ".mjs",
70348
+ ".mts",
70349
+ ".ts"
70350
+ ];
70351
+ const CONFIG_FILENAMES = new Set(CONFIG_BASENAMES.flatMap((basename) => CONFIG_EXTENSIONS.map((extension) => `${basename}${extension}`)));
70352
+ const DEFAULT_ESLINT_GLOBALS_PATH = ".eslintrc-auto-import.json";
70353
+ const SUPPORTED_GLOBAL_VALUES = new Set([
70354
+ true,
70355
+ false,
70356
+ "readable",
70357
+ "readonly",
70358
+ "writable",
70359
+ "writeable"
70360
+ ]);
70361
+ const getStaticProperty = (objectExpression, propertyName) => objectExpression.properties.find((property) => {
70362
+ if (ts.isSpreadAssignment(property)) return false;
70363
+ const name = ts.isComputedPropertyName(property.name) ? unwrapTypescriptExpression(property.name.expression) : property.name;
70364
+ return (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) && name.text === propertyName;
70365
+ }) ?? null;
70366
+ const hasNonLiteralComputedProperty = (objectExpression) => objectExpression.properties.some((property) => !ts.isSpreadAssignment(property) && ts.isComputedPropertyName(property.name) && !ts.isStringLiteralLike(unwrapTypescriptExpression(property.name.expression)));
70367
+ const getStaticPropertyAssignment = (objectExpression, propertyName) => {
70368
+ const property = getStaticProperty(objectExpression, propertyName);
70369
+ return property && ts.isPropertyAssignment(property) ? property : null;
70370
+ };
70371
+ const getRequireModuleSpecifier = (expression) => {
70372
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
70373
+ if (ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === "default") return getRequireModuleSpecifier(unwrappedExpression.expression);
70374
+ if (!ts.isCallExpression(unwrappedExpression) || !ts.isIdentifier(unwrappedExpression.expression) || unwrappedExpression.expression.text !== "require" || unwrappedExpression.arguments.length !== 1) return null;
70375
+ const moduleSpecifier = unwrappedExpression.arguments[0];
70376
+ return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
70377
+ };
70378
+ const getRequiredPropertyModuleSpecifier = (expression, propertyName) => {
70379
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
70380
+ return ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === propertyName ? getRequireModuleSpecifier(unwrappedExpression.expression) : null;
70381
+ };
70382
+ 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");
70383
+ const isTopLevelExpression = (node) => {
70384
+ let ancestor = node.parent;
70385
+ while (ancestor && !ts.isSourceFile(ancestor)) {
70386
+ if (ts.isExpressionStatement(ancestor)) return ts.isSourceFile(ancestor.parent);
70387
+ if (!ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isAwaitExpression(ancestor)) return false;
70388
+ ancestor = ancestor.parent;
70389
+ }
70390
+ return false;
70391
+ };
70392
+ const isInsideActiveConfigProperty = (node, propertyName, sourceFile, esbuildBindings, esbuildNamespaceBindings) => {
70393
+ let ancestor = node.parent;
70394
+ let didFindConfigProperty = false;
70395
+ while (ancestor && !ts.isSourceFile(ancestor)) {
70396
+ 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;
70397
+ if (ts.isPropertyAssignment(ancestor)) {
70398
+ const isConfigProperty = (ts.isIdentifier(ancestor.name) || ts.isStringLiteralLike(ancestor.name)) && ancestor.name.text === propertyName;
70399
+ if (didFindConfigProperty || !isConfigProperty) return false;
70400
+ if (!ts.isObjectLiteralExpression(ancestor.parent) || ancestor.parent.properties.some(ts.isSpreadAssignment)) return false;
70401
+ didFindConfigProperty = true;
70402
+ ancestor = ancestor.parent;
70403
+ continue;
70404
+ }
70405
+ if (didFindConfigProperty) {
70406
+ if (ts.isExportAssignment(ancestor)) return true;
70407
+ if (isCommonJsExportAssignment(ancestor, sourceFile)) return isTopLevelExpression(ancestor);
70408
+ 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);
70409
+ 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;
70410
+ }
70411
+ ancestor = ancestor.parent;
70412
+ }
70413
+ return false;
70414
+ };
70415
+ const getGlobalsPathFromActiveAutoImportCall = (callExpression, packageDirectory) => {
70416
+ const optionsExpression = callExpression.arguments[0];
70417
+ if (!optionsExpression) return null;
70418
+ const unwrappedOptions = unwrapTypescriptExpression(optionsExpression);
70419
+ if (!ts.isObjectLiteralExpression(unwrappedOptions)) return null;
70420
+ if (unwrappedOptions.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(unwrappedOptions)) return null;
70421
+ if (getStaticProperty(unwrappedOptions, "include") || getStaticProperty(unwrappedOptions, "exclude")) return null;
70422
+ const eslintrcProperty = getStaticPropertyAssignment(unwrappedOptions, "eslintrc");
70423
+ if (!eslintrcProperty) return null;
70424
+ const eslintrcExpression = unwrapTypescriptExpression(eslintrcProperty.initializer);
70425
+ if (!ts.isObjectLiteralExpression(eslintrcExpression)) return null;
70426
+ if (eslintrcExpression.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(eslintrcExpression)) return null;
70427
+ const enabledProperty = getStaticPropertyAssignment(eslintrcExpression, "enabled");
70428
+ if (!enabledProperty || unwrapTypescriptExpression(enabledProperty.initializer).kind !== ts.SyntaxKind.TrueKeyword) return null;
70429
+ const filepathProperty = getStaticProperty(eslintrcExpression, "filepath");
70430
+ if (!filepathProperty) return Path.join(packageDirectory, DEFAULT_ESLINT_GLOBALS_PATH);
70431
+ if (!ts.isPropertyAssignment(filepathProperty)) return null;
70432
+ const filepathExpression = unwrapTypescriptExpression(filepathProperty.initializer);
70433
+ return ts.isStringLiteralLike(filepathExpression) ? Path.resolve(packageDirectory, filepathExpression.text) : null;
70434
+ };
70435
+ const collectGlobalsPathsFromConfig = (configPath, packageDirectory) => {
70436
+ let sourceText;
70437
+ try {
70438
+ sourceText = NFS.readFileSync(configPath, "utf8");
70439
+ } catch {
70440
+ return {
70441
+ didFindActiveAutoImport: false,
70442
+ globalsPaths: []
70443
+ };
70444
+ }
70445
+ const sourceFile = ts.createSourceFile(configPath, sourceText, ts.ScriptTarget.Latest, true);
70446
+ const autoImportBindings = /* @__PURE__ */ new Map();
70447
+ const esbuildBindings = /* @__PURE__ */ new Set();
70448
+ const esbuildNamespaceBindings = /* @__PURE__ */ new Set();
70449
+ for (const statement of sourceFile.statements) {
70450
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteralLike(statement.moduleSpecifier)) {
70451
+ const moduleSpecifier = statement.moduleSpecifier.text;
70452
+ if (AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
70453
+ const defaultBinding = statement.importClause?.name;
70454
+ if (defaultBinding) autoImportBindings.set(defaultBinding.text, moduleSpecifier);
70455
+ }
70456
+ if (moduleSpecifier === "esbuild") {
70457
+ const defaultBinding = statement.importClause?.name;
70458
+ if (defaultBinding) esbuildNamespaceBindings.add(defaultBinding.text);
70459
+ const namedBindings = statement.importClause?.namedBindings;
70460
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
70461
+ for (const importSpecifier of namedBindings.elements) if ((importSpecifier.propertyName ?? importSpecifier.name).text === "build") esbuildBindings.add(importSpecifier.name.text);
70462
+ }
70463
+ if (namedBindings && ts.isNamespaceImport(namedBindings)) esbuildNamespaceBindings.add(namedBindings.name.text);
70464
+ }
70465
+ }
70466
+ if (!ts.isVariableStatement(statement)) continue;
70467
+ for (const declaration of statement.declarationList.declarations) {
70468
+ if (!declaration.initializer) continue;
70469
+ const declarationName = ts.isIdentifier(declaration.name) ? declaration.name.text : null;
70470
+ const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
70471
+ if (declarationName && moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) autoImportBindings.set(declarationName, moduleSpecifier);
70472
+ if (moduleSpecifier === "esbuild") {
70473
+ if (declarationName) esbuildNamespaceBindings.add(declarationName);
70474
+ if (ts.isObjectBindingPattern(declaration.name)) for (const bindingElement of declaration.name.elements) {
70475
+ const importedName = bindingElement.propertyName ?? bindingElement.name;
70476
+ if (ts.isIdentifier(importedName) && importedName.text === "build" && ts.isIdentifier(bindingElement.name)) esbuildBindings.add(bindingElement.name.text);
70477
+ }
70478
+ }
70479
+ if (declarationName && getRequiredPropertyModuleSpecifier(declaration.initializer, "build") === "esbuild") esbuildBindings.add(declarationName);
70480
+ }
70481
+ }
70482
+ const globalsPaths = /* @__PURE__ */ new Set();
70483
+ let didFindActiveAutoImport = false;
70484
+ let didFindUnsafeActiveAutoImport = false;
70485
+ const visit = (node) => {
70486
+ if (ts.isCallExpression(node)) {
70487
+ const moduleSpecifier = ts.isIdentifier(node.expression) ? autoImportBindings.get(node.expression.text) : getRequireModuleSpecifier(node.expression);
70488
+ if (moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
70489
+ if (isInsideActiveConfigProperty(node, moduleSpecifier.endsWith("/astro") ? "integrations" : "plugins", sourceFile, esbuildBindings, esbuildNamespaceBindings)) {
70490
+ didFindActiveAutoImport = true;
70491
+ const globalsPath = getGlobalsPathFromActiveAutoImportCall(node, packageDirectory);
70492
+ if (globalsPath) globalsPaths.add(globalsPath);
70493
+ else didFindUnsafeActiveAutoImport = true;
70494
+ }
70495
+ }
70496
+ }
70497
+ ts.forEachChild(node, visit);
70498
+ };
70499
+ visit(sourceFile);
70500
+ return {
70501
+ didFindActiveAutoImport,
70502
+ globalsPaths: didFindUnsafeActiveAutoImport ? [] : [...globalsPaths]
70503
+ };
70504
+ };
70505
+ const collectGeneratedGlobalNames = (globalsPath, rootDirectory) => {
70506
+ const relativePath = Path.relative(rootDirectory, globalsPath);
70507
+ if (relativePath.startsWith("..") || Path.isAbsolute(relativePath)) return [];
70508
+ const parsed = failOpenReadJson(globalsPath, null);
70509
+ if (!isPlainObject(parsed) || !isPlainObject(parsed.globals)) return [];
70510
+ 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();
70511
+ };
70512
+ const findOwningPackageDirectory = (absoluteFilePath, rootDirectory, cache) => {
70513
+ let currentDirectory = Path.dirname(absoluteFilePath);
70514
+ const visitedDirectories = [];
70515
+ while (true) {
70516
+ const cachedDirectory = cache.get(currentDirectory);
70517
+ if (cachedDirectory !== void 0) {
70518
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, cachedDirectory);
70519
+ return cachedDirectory;
70520
+ }
70521
+ const relativeDirectory = Path.relative(rootDirectory, currentDirectory);
70522
+ if (relativeDirectory.startsWith("..") || Path.isAbsolute(relativeDirectory)) {
70523
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
70524
+ return null;
70525
+ }
70526
+ visitedDirectories.push(currentDirectory);
70527
+ if (NFS.existsSync(Path.join(currentDirectory, "package.json"))) {
70528
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, currentDirectory);
70529
+ return currentDirectory;
70530
+ }
70531
+ if (currentDirectory === rootDirectory) {
70532
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
70533
+ return null;
70534
+ }
70535
+ currentDirectory = Path.dirname(currentDirectory);
70536
+ }
70537
+ };
70538
+ const collectPackageGlobalNames = (packageDirectory, rootDirectory) => {
70539
+ let directoryEntries;
70540
+ try {
70541
+ directoryEntries = NFS.readdirSync(packageDirectory, { withFileTypes: true });
70542
+ } catch {
70543
+ return [];
70544
+ }
70545
+ const configuredGlobalsPaths = [];
70546
+ for (const entry of directoryEntries) {
70547
+ if (!entry.isFile() && !entry.isSymbolicLink() || !CONFIG_FILENAMES.has(entry.name)) continue;
70548
+ const configGlobalsPaths = collectGlobalsPathsFromConfig(Path.join(packageDirectory, entry.name), packageDirectory);
70549
+ if (configGlobalsPaths.didFindActiveAutoImport) configuredGlobalsPaths.push(configGlobalsPaths.globalsPaths.toSorted());
70550
+ }
70551
+ if (configuredGlobalsPaths.length === 0) return [];
70552
+ const globalsPaths = configuredGlobalsPaths[0];
70553
+ if (configuredGlobalsPaths.some((candidatePaths) => candidatePaths.length !== globalsPaths.length || candidatePaths.some((candidatePath, index) => candidatePath !== globalsPaths[index]))) return [];
70554
+ const names = /* @__PURE__ */ new Set();
70555
+ for (const globalsPath of globalsPaths) for (const name of collectGeneratedGlobalNames(globalsPath, rootDirectory)) names.add(name);
70556
+ return [...names].sort();
70557
+ };
70558
+ const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }) => {
70559
+ const absoluteRootDirectory = Path.resolve(rootDirectory);
70560
+ const packageDirectoryCache = /* @__PURE__ */ new Map();
70561
+ const packageDirectories = /* @__PURE__ */ new Set();
70562
+ for (const candidateFile of candidateFiles) {
70563
+ const packageDirectory = findOwningPackageDirectory(Path.resolve(absoluteRootDirectory, candidateFile), absoluteRootDirectory, packageDirectoryCache);
70564
+ if (packageDirectory) packageDirectories.add(packageDirectory);
70565
+ }
70566
+ const scopes = [...packageDirectories].map((packageDirectory) => ({
70567
+ directory: Path.relative(absoluteRootDirectory, packageDirectory).replaceAll("\\", "/"),
70568
+ names: collectPackageGlobalNames(packageDirectory, absoluteRootDirectory)
70569
+ })).sort((firstScope, secondScope) => firstScope.directory.localeCompare(secondScope.directory));
70570
+ return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
70571
+ };
69957
70572
  const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
69958
70573
  const decodeFileDiagnostics = (raw) => {
69959
70574
  if (!Array.isArray(raw)) return null;
@@ -70276,6 +70891,12 @@ const appendReanimatedSharedValueHint = (help, rule, project) => {
70276
70891
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
70277
70892
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
70278
70893
  };
70894
+ const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
70895
+ const boundedOffset = Math.min(Math.max(utf8Offset, 0), sourceBuffer.length);
70896
+ let lineStartOffset = boundedOffset;
70897
+ while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
70898
+ return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
70899
+ };
70279
70900
  const REDACTED_PLACEHOLDER = "<redacted>";
70280
70901
  const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
70281
70902
  const KNOWN_SECRET_RULES = [
@@ -70991,7 +71612,7 @@ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORI
70991
71612
  * with empty text still carry a useful jump target, so they're kept
70992
71613
  * with a neutral message.
70993
71614
  */
70994
- const buildRelatedLocations = (labels, filePath) => {
71615
+ const buildRelatedLocations = (labels, filePath, sourceBuffer) => {
70995
71616
  if (labels.length <= 1) return [];
70996
71617
  const related = [];
70997
71618
  for (let labelIndex = 1; labelIndex < labels.length; labelIndex++) {
@@ -70999,8 +71620,8 @@ const buildRelatedLocations = (labels, filePath) => {
70999
71620
  if (!label?.span) continue;
71000
71621
  related.push({
71001
71622
  filePath,
71002
- line: label.span.line ?? 0,
71003
- column: label.span.column ?? 0,
71623
+ line: sourceBuffer === null ? label.span.line ?? 0 : lineOfUtf8Offset(sourceBuffer, label.span.offset),
71624
+ column: sourceBuffer === null ? label.span.column ?? 0 : columnOfUtf8Offset(sourceBuffer, label.span.offset),
71004
71625
  offset: label.span.offset,
71005
71626
  length: label.span.length,
71006
71627
  message: label.label ?? ""
@@ -71020,7 +71641,7 @@ const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnos
71020
71641
  * to the first `{`. Raises `OxlintOutputUnparseable` when the
71021
71642
  * stdout isn't valid JSON or doesn't carry a `diagnostics` array.
71022
71643
  */
71023
- const parseOxlintOutput = (stdout, project, rootDirectory) => {
71644
+ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
71024
71645
  if (!stdout) return [];
71025
71646
  const jsonStart = stdout.indexOf("{");
71026
71647
  const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
@@ -71037,8 +71658,10 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71037
71658
  const sourceBufferCache = /* @__PURE__ */ new Map();
71038
71659
  const sourceLinesCache = /* @__PURE__ */ new Map();
71039
71660
  const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
71661
+ const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
71662
+ const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
71040
71663
  const readSourceBuffer = (filename) => {
71041
- const absolutePath = resolveAbsolutePath(filename);
71664
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71042
71665
  const cached = sourceBufferCache.get(absolutePath);
71043
71666
  if (cached !== void 0) return cached;
71044
71667
  let sourceBuffer;
@@ -71051,7 +71674,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71051
71674
  return sourceBuffer;
71052
71675
  };
71053
71676
  const readSourceLines = (filename) => {
71054
- const absolutePath = resolveAbsolutePath(filename);
71677
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71055
71678
  const cached = sourceLinesCache.get(absolutePath);
71056
71679
  if (cached !== void 0) return cached;
71057
71680
  const sourceBuffer = readSourceBuffer(filename);
@@ -71060,27 +71683,30 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71060
71683
  return sourceLines;
71061
71684
  };
71062
71685
  const isMinifiedDiagnosticFile = (filename) => {
71063
- const absolutePath = resolveAbsolutePath(filename);
71686
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
71064
71687
  const cached = minifiedFileCache.get(absolutePath);
71065
71688
  if (cached !== void 0) return cached;
71066
71689
  const minified = isMinifiedSource(absolutePath);
71067
71690
  minifiedFileCache.set(absolutePath, minified);
71068
71691
  return minified;
71069
71692
  };
71070
- 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) => {
71693
+ 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) => {
71071
71694
  const { plugin, rule } = parseRuleCode(diagnostic.code);
71072
71695
  const primaryLabel = diagnostic.labels[0];
71073
71696
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
71074
- const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
71697
+ const mappedSourceFilename = resolveMappedSourceFilename(diagnostic.filename);
71698
+ const normalizedFilePath = (mappedSourceFilename ?? diagnostic.filename).replaceAll("\\", "/");
71075
71699
  const primarySpan = primaryLabel?.span;
71076
71700
  const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
71077
- const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
71701
+ const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath, mappedSourceFilename === void 0 ? null : sourceBuffer);
71078
71702
  const category = resolveDiagnosticCategory(plugin, rule);
71079
71703
  const matchByOccurrence = resolveMatchByOccurrence(rule, category);
71080
71704
  const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
71081
- const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
71705
+ const primaryLineNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.line ?? 0;
71706
+ const primaryColumnNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? columnOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.column ?? 0;
71707
+ const primaryLineIndex = primarySpan ? primaryLineNumber - 1 : -1;
71082
71708
  const primaryLine = sourceLines?.[primaryLineIndex];
71083
- const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
71709
+ const primaryColumnIndex = primarySpan ? primaryColumnNumber - 1 : -1;
71084
71710
  const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
71085
71711
  const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
71086
71712
  const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
@@ -71093,8 +71719,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
71093
71719
  message: cleaned.message,
71094
71720
  help: cleaned.help,
71095
71721
  url: diagnostic.url,
71096
- line: primarySpan?.line ?? 0,
71097
- column: primarySpan?.column ?? 0,
71722
+ line: primaryLineNumber,
71723
+ column: primaryColumnNumber,
71098
71724
  ...primarySpan ? {
71099
71725
  offset: primarySpan.offset,
71100
71726
  length: primarySpan.length,
@@ -71282,7 +71908,11 @@ const isParallelismRelatedSpawnError = (error) => {
71282
71908
  * loop with a slimmer config in that case.
71283
71909
  */
71284
71910
  const spawnLintBatches = async (input) => {
71285
- const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
71911
+ const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
71912
+ const resolveSourcePath = (filePath) => {
71913
+ const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
71914
+ return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
71915
+ };
71286
71916
  const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
71287
71917
  let rescueDeadlineEpochMs;
71288
71918
  const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
@@ -71302,7 +71932,7 @@ const spawnLintBatches = async (input) => {
71302
71932
  }
71303
71933
  const batchArgs = [...baseArgs, ...batch];
71304
71934
  try {
71305
- return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
71935
+ return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath);
71306
71936
  } catch (error) {
71307
71937
  if (!isSplittableReactDoctorError(error)) throw error;
71308
71938
  if (isPastDeadline()) {
@@ -71408,10 +72038,12 @@ const spawnLintBatches = async (input) => {
71408
72038
  onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
71409
72039
  };
71410
72040
  const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
71411
- reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
71412
- reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
72041
+ const droppedSourceFiles = [...new Set(droppedFiles.map(resolveSourcePath))];
72042
+ const deadlineSkippedSourceFiles = [...new Set(outcome.deadlineSkippedFiles.map(resolveSourcePath))];
72043
+ reportSkippedFiles(droppedSourceFiles, (fileListPreview) => `${droppedSourceFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
72044
+ reportSkippedFiles(deadlineSkippedSourceFiles, (fileListPreview) => `${deadlineSkippedSourceFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
71413
72045
  const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
71414
- input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
72046
+ input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)).map(resolveSourcePath))].sort());
71415
72047
  return dedupeDiagnostics(diagnostics);
71416
72048
  };
71417
72049
  let didValidate = false;
@@ -71510,6 +72142,266 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
71510
72142
  }
71511
72143
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
71512
72144
  };
72145
+ const THREE_MODULE_IMPORT_PATTERN = /\b(?:from\s*|import\s*(?:\(\s*)?|require\s*\(\s*)["']three(?:\/[^"']*)?["']/;
72146
+ const containsThreeModuleImport = (sourceText) => THREE_MODULE_IMPORT_PATTERN.test(sourceText);
72147
+ const COMMENT_OPEN = "<!--";
72148
+ const COMMENT_CLOSE = "-->";
72149
+ const FRONTMATTER_FENCE = "---";
72150
+ const SCRIPT_TAG_NAME = "script";
72151
+ const SCRIPT_OPEN = `<${SCRIPT_TAG_NAME}`;
72152
+ const SCRIPT_CLOSE = `</${SCRIPT_TAG_NAME}`;
72153
+ const TEMPLATE_TAG_NAME = "template";
72154
+ const TEMPLATE_CLOSE = `</${TEMPLATE_TAG_NAME}`;
72155
+ const JAVASCRIPT_MIME_TYPES = new Set([
72156
+ "application/ecmascript",
72157
+ "application/javascript",
72158
+ "application/x-ecmascript",
72159
+ "application/x-javascript",
72160
+ "text/ecmascript",
72161
+ "text/javascript",
72162
+ "text/javascript1.0",
72163
+ "text/javascript1.1",
72164
+ "text/javascript1.2",
72165
+ "text/javascript1.3",
72166
+ "text/javascript1.4",
72167
+ "text/javascript1.5",
72168
+ "text/jscript",
72169
+ "text/livescript",
72170
+ "text/x-ecmascript",
72171
+ "text/x-javascript"
72172
+ ]);
72173
+ const RAW_TEXT_TAG_NAMES = new Set([
72174
+ "iframe",
72175
+ "noembed",
72176
+ "noframes",
72177
+ "noscript",
72178
+ "style",
72179
+ "textarea",
72180
+ "title",
72181
+ "xmp"
72182
+ ]);
72183
+ const PLAINTEXT_TAG_NAME = "plaintext";
72184
+ const TAG_OPEN_UTF8_BYTE = "<".charCodeAt(0);
72185
+ const TAG_CLOSE_UTF8_BYTE = ">".charCodeAt(0);
72186
+ const SINGLE_QUOTE_UTF8_BYTE = "'".charCodeAt(0);
72187
+ const DOUBLE_QUOTE_UTF8_BYTE = "\"".charCodeAt(0);
72188
+ const ATTRIBUTE_ASSIGNMENT_UTF8_BYTE = "=".charCodeAt(0);
72189
+ const TAG_SELF_CLOSE_UTF8_BYTE = "/".charCodeAt(0);
72190
+ const TAB_UTF8_BYTE = " ".charCodeAt(0);
72191
+ const FORM_FEED_UTF8_BYTE = "\f".charCodeAt(0);
72192
+ const isHtmlWhitespace = (byte) => byte === TAB_UTF8_BYTE || byte === 10 || byte === FORM_FEED_UTF8_BYTE || byte === 13 || byte === 32;
72193
+ const matchesAsciiCaseInsensitive = (sourceBuffer, startByte, expected) => {
72194
+ if (startByte + expected.length > sourceBuffer.length) return false;
72195
+ for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex++) {
72196
+ const sourceByte = sourceBuffer[startByte + expectedIndex];
72197
+ if (sourceByte === void 0 || String.fromCharCode(sourceByte).toLowerCase() !== expected[expectedIndex]) return false;
72198
+ }
72199
+ return true;
72200
+ };
72201
+ const isTagBoundary = (byte) => byte === TAG_CLOSE_UTF8_BYTE || byte === TAG_SELF_CLOSE_UTF8_BYTE || isHtmlWhitespace(byte);
72202
+ const isPotentialTagStart = (byte) => {
72203
+ if (byte === void 0) return false;
72204
+ return /[A-Za-z!/?]/.test(String.fromCharCode(byte));
72205
+ };
72206
+ const findLineEnd = (sourceBuffer, lineStartByte) => {
72207
+ let byteIndex = lineStartByte;
72208
+ while (byteIndex < sourceBuffer.length && sourceBuffer[byteIndex] !== 10 && sourceBuffer[byteIndex] !== 13) byteIndex++;
72209
+ return byteIndex;
72210
+ };
72211
+ const findNextLineStart = (sourceBuffer, lineStartByte) => {
72212
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
72213
+ if (sourceBuffer[lineEndByte] === 13 && sourceBuffer[lineEndByte + 1] === 10) return lineEndByte + 2;
72214
+ return Math.min(lineEndByte + 1, sourceBuffer.length);
72215
+ };
72216
+ const isFrontmatterFenceLine = (sourceBuffer, lineStartByte) => {
72217
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, lineStartByte, FRONTMATTER_FENCE)) return false;
72218
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
72219
+ for (let byteIndex = lineStartByte + 3; byteIndex < lineEndByte; byteIndex++) if (!isHtmlWhitespace(sourceBuffer[byteIndex])) return false;
72220
+ return true;
72221
+ };
72222
+ const findFrontmatterEnd = (sourceBuffer) => {
72223
+ if (!isFrontmatterFenceLine(sourceBuffer, 0)) return 0;
72224
+ const openingFenceEndByte = findLineEnd(sourceBuffer, 0);
72225
+ let lineStartByte = findNextLineStart(sourceBuffer, 0);
72226
+ while (lineStartByte < sourceBuffer.length) {
72227
+ if (isFrontmatterFenceLine(sourceBuffer, lineStartByte)) return findLineEnd(sourceBuffer, lineStartByte);
72228
+ lineStartByte = findNextLineStart(sourceBuffer, lineStartByte);
72229
+ }
72230
+ return openingFenceEndByte;
72231
+ };
72232
+ const maskByteRange = (maskedBuffer, startByte, endByte) => {
72233
+ for (let byteIndex = startByte; byteIndex < endByte; byteIndex++) {
72234
+ const byte = maskedBuffer[byteIndex];
72235
+ if (byte !== 10 && byte !== 13) maskedBuffer[byteIndex] = 32;
72236
+ }
72237
+ };
72238
+ const readStartTagName = (sourceBuffer, tagStartByte) => {
72239
+ const firstNameByte = sourceBuffer[tagStartByte + 1];
72240
+ if (firstNameByte === void 0 || !/[A-Za-z]/.test(String.fromCharCode(firstNameByte))) return null;
72241
+ let nameEndByte = tagStartByte + 2;
72242
+ while (nameEndByte < sourceBuffer.length && /[A-Za-z0-9:-]/.test(String.fromCharCode(sourceBuffer[nameEndByte] ?? 32))) nameEndByte++;
72243
+ return sourceBuffer.subarray(tagStartByte + 1, nameEndByte).toString("ascii").toLowerCase();
72244
+ };
72245
+ const findTagEnd = (sourceBuffer, startByte) => {
72246
+ let quoteByte = null;
72247
+ for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) {
72248
+ const byte = sourceBuffer[byteIndex];
72249
+ if (quoteByte !== null) {
72250
+ if (byte === quoteByte) quoteByte = null;
72251
+ continue;
72252
+ }
72253
+ if (byte === SINGLE_QUOTE_UTF8_BYTE || byte === DOUBLE_QUOTE_UTF8_BYTE) {
72254
+ quoteByte = byte;
72255
+ continue;
72256
+ }
72257
+ if (byte === TAG_CLOSE_UTF8_BYTE) return byteIndex;
72258
+ }
72259
+ return sourceBuffer.length;
72260
+ };
72261
+ const parseScriptAttributes = (sourceBuffer, attributesStartByte, tagEndByte) => {
72262
+ let byteIndex = attributesStartByte;
72263
+ let hasSource = false;
72264
+ let language = null;
72265
+ let scriptType = null;
72266
+ while (byteIndex < tagEndByte) {
72267
+ while (byteIndex < tagEndByte && (isHtmlWhitespace(sourceBuffer[byteIndex]) || sourceBuffer[byteIndex] === TAG_SELF_CLOSE_UTF8_BYTE)) byteIndex++;
72268
+ const attributeNameStartByte = byteIndex;
72269
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== ATTRIBUTE_ASSIGNMENT_UTF8_BYTE && sourceBuffer[byteIndex] !== TAG_SELF_CLOSE_UTF8_BYTE) byteIndex++;
72270
+ const attributeName = sourceBuffer.subarray(attributeNameStartByte, byteIndex).toString("ascii").toLowerCase();
72271
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
72272
+ let attributeValue = "";
72273
+ if (sourceBuffer[byteIndex] === ATTRIBUTE_ASSIGNMENT_UTF8_BYTE) {
72274
+ byteIndex++;
72275
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
72276
+ const quoteByte = sourceBuffer[byteIndex];
72277
+ if (quoteByte === SINGLE_QUOTE_UTF8_BYTE || quoteByte === DOUBLE_QUOTE_UTF8_BYTE) {
72278
+ const valueStartByte = byteIndex + 1;
72279
+ byteIndex = valueStartByte;
72280
+ while (byteIndex < tagEndByte && sourceBuffer[byteIndex] !== quoteByte) byteIndex++;
72281
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
72282
+ if (byteIndex < tagEndByte) byteIndex++;
72283
+ } else {
72284
+ const valueStartByte = byteIndex;
72285
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== TAG_CLOSE_UTF8_BYTE) byteIndex++;
72286
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
72287
+ }
72288
+ }
72289
+ if (attributeName === "src") hasSource = true;
72290
+ else if (attributeName === "type" && scriptType === null) scriptType = attributeValue;
72291
+ else if (attributeName === "language" && language === null) language = attributeValue;
72292
+ }
72293
+ return {
72294
+ hasSource,
72295
+ language,
72296
+ type: scriptType
72297
+ };
72298
+ };
72299
+ const isExecutableScript = (attributes) => {
72300
+ if (attributes.hasSource) return false;
72301
+ const type = attributes.type?.trim().toLowerCase() ?? "";
72302
+ if (type !== "") {
72303
+ const mimeType = type.split(";")[0]?.trim() ?? "";
72304
+ return mimeType === "module" || JAVASCRIPT_MIME_TYPES.has(mimeType);
72305
+ }
72306
+ const language = attributes.language?.trim().toLowerCase() ?? "";
72307
+ return language === "" || JAVASCRIPT_MIME_TYPES.has(`text/${language}`);
72308
+ };
72309
+ const findElementClose = (sourceBuffer, startByte, tagName) => {
72310
+ const closeTagStart = `</${tagName}`;
72311
+ 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;
72312
+ return sourceBuffer.length;
72313
+ };
72314
+ const prepareHtmlScriptSource = (sourceBuffer) => {
72315
+ const frontmatterEndByte = findFrontmatterEnd(sourceBuffer);
72316
+ let maskedBuffer = frontmatterEndByte > 0 ? Buffer.from(sourceBuffer) : null;
72317
+ if (maskedBuffer !== null) maskByteRange(maskedBuffer, 0, frontmatterEndByte);
72318
+ const executableScriptBodies = [];
72319
+ let byteIndex = frontmatterEndByte;
72320
+ let templateDepth = 0;
72321
+ while (byteIndex < sourceBuffer.length) {
72322
+ if (sourceBuffer[byteIndex] !== TAG_OPEN_UTF8_BYTE) {
72323
+ byteIndex++;
72324
+ continue;
72325
+ }
72326
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, COMMENT_OPEN)) {
72327
+ const commentEndByte = sourceBuffer.indexOf(COMMENT_CLOSE, byteIndex + 4);
72328
+ byteIndex = commentEndByte === -1 ? sourceBuffer.length : commentEndByte + 3;
72329
+ continue;
72330
+ }
72331
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, TEMPLATE_CLOSE) && isTagBoundary(sourceBuffer[byteIndex + TEMPLATE_CLOSE.length])) {
72332
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + TEMPLATE_CLOSE.length);
72333
+ if (templateDepth > 0) templateDepth--;
72334
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
72335
+ continue;
72336
+ }
72337
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, SCRIPT_OPEN) || !isTagBoundary(sourceBuffer[byteIndex + SCRIPT_OPEN.length])) {
72338
+ if (!isPotentialTagStart(sourceBuffer[byteIndex + 1])) {
72339
+ byteIndex++;
72340
+ continue;
72341
+ }
72342
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + 1);
72343
+ const tagName = readStartTagName(sourceBuffer, byteIndex);
72344
+ if (tagName === PLAINTEXT_TAG_NAME) break;
72345
+ if (tagName === TEMPLATE_TAG_NAME) templateDepth++;
72346
+ if (tagName !== null && RAW_TEXT_TAG_NAMES.has(tagName)) {
72347
+ const closeTagStartByte = findElementClose(sourceBuffer, tagEndByte + 1, tagName);
72348
+ if (closeTagStartByte === sourceBuffer.length) break;
72349
+ const closeTagEndByte = findTagEnd(sourceBuffer, closeTagStartByte + tagName.length + 2);
72350
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
72351
+ continue;
72352
+ }
72353
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
72354
+ continue;
72355
+ }
72356
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + SCRIPT_OPEN.length);
72357
+ if (tagEndByte === sourceBuffer.length) break;
72358
+ const bodyStartByte = tagEndByte + 1;
72359
+ const bodyEndByte = findElementClose(sourceBuffer, bodyStartByte, SCRIPT_TAG_NAME);
72360
+ const attributes = parseScriptAttributes(sourceBuffer, byteIndex + SCRIPT_OPEN.length, tagEndByte);
72361
+ if (attributes.hasSource || templateDepth > 0) {
72362
+ maskedBuffer ??= Buffer.from(sourceBuffer);
72363
+ maskByteRange(maskedBuffer, bodyStartByte, bodyEndByte);
72364
+ } else if (isExecutableScript(attributes)) executableScriptBodies.push(sourceBuffer.subarray(bodyStartByte, bodyEndByte));
72365
+ if (bodyEndByte === sourceBuffer.length) break;
72366
+ const closeTagEndByte = findTagEnd(sourceBuffer, bodyEndByte + SCRIPT_CLOSE.length);
72367
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
72368
+ }
72369
+ return {
72370
+ executableScriptBodies,
72371
+ lintBuffer: maskedBuffer ?? sourceBuffer
72372
+ };
72373
+ };
72374
+ const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
72375
+ const lintFiles = [];
72376
+ const sourcePathByLintPath = /* @__PURE__ */ new Map();
72377
+ const sizeByLintPath = /* @__PURE__ */ new Map();
72378
+ const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
72379
+ let htmlFileIndex = 0;
72380
+ let hasThreeModuleImport = false;
72381
+ for (const candidateFile of candidateFiles) {
72382
+ if (!HTML_FILE_PATTERN.test(candidateFile)) {
72383
+ lintFiles.push(candidateFile);
72384
+ continue;
72385
+ }
72386
+ const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
72387
+ const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
72388
+ const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
72389
+ if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
72390
+ const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
72391
+ NFS.writeFileSync(lintPath, lintBuffer);
72392
+ lintFiles.push(lintPath);
72393
+ sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
72394
+ sizeByLintPath.set(lintPath, sourceBuffer.length);
72395
+ hasThreeModuleImport ||= executableScriptBodies.some((scriptBody) => containsThreeModuleImport(scriptBody.toString("utf8")));
72396
+ htmlFileIndex++;
72397
+ }
72398
+ return {
72399
+ lintFiles,
72400
+ sourcePathByLintPath,
72401
+ sizeByLintPath,
72402
+ hasThreeModuleImport
72403
+ };
72404
+ };
71513
72405
  /**
71514
72406
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
71515
72407
  * the runner: once for the primary scan, once for the
@@ -71670,6 +72562,8 @@ const reactHooksJsPluginDropNote = (error) => {
71670
72562
  const runOxlint = async (options) => {
71671
72563
  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;
71672
72564
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
72565
+ const runtimeGlobals = Array.isArray(userConfig?.runtimeGlobals) ? userConfig.runtimeGlobals.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
72566
+ let unpluginAutoImportGlobalScopes = [];
71673
72567
  const severityControls = buildRuleSeverityControls(userConfig);
71674
72568
  validateRuleRegistration();
71675
72569
  resetManifestCaches();
@@ -71683,21 +72577,6 @@ const runOxlint = async (options) => {
71683
72577
  const pluginPath = resolvePluginPath();
71684
72578
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
71685
72579
  const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
71686
- const buildConfig = (overrides) => createOxlintConfig({
71687
- pluginPath,
71688
- project,
71689
- customRulesOnly,
71690
- extendsPaths: overrides.extendsPaths,
71691
- ignoredTags,
71692
- includedTags,
71693
- includeTagDefaults,
71694
- serverAuthFunctionNames,
71695
- severityControls,
71696
- userPlugins,
71697
- disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
71698
- ruleSelection: overrides.ruleSelection,
71699
- sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
71700
- });
71701
72580
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
71702
72581
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
71703
72582
  const configPath = Path.join(configDirectory, "oxlintrc.json");
@@ -71733,7 +72612,36 @@ const runOxlint = async (options) => {
71733
72612
  await yieldToEventLoop();
71734
72613
  const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
71735
72614
  const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
72615
+ unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
72616
+ rootDirectory,
72617
+ candidateFiles
72618
+ });
72619
+ const preparedHtmlSources = prepareHtmlLintSources(rootDirectory, configDirectory, candidateFiles);
72620
+ const lintFiles = preparedHtmlSources.lintFiles;
72621
+ const hasHtmlFiles = preparedHtmlSources.sourcePathByLintPath.size > 0;
72622
+ const lintProject = !project.hasThree && preparedHtmlSources.hasThreeModuleImport ? {
72623
+ ...project,
72624
+ hasThree: true
72625
+ } : project;
72626
+ const buildConfig = (overrides) => createOxlintConfig({
72627
+ pluginPath,
72628
+ project: lintProject,
72629
+ customRulesOnly,
72630
+ extendsPaths: overrides.extendsPaths,
72631
+ ignoredTags,
72632
+ includedTags,
72633
+ includeTagDefaults,
72634
+ runtimeGlobals,
72635
+ unpluginAutoImportGlobalScopes,
72636
+ serverAuthFunctionNames,
72637
+ severityControls,
72638
+ userPlugins,
72639
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
72640
+ ruleSelection: overrides.ruleSelection,
72641
+ sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
72642
+ });
71736
72643
  const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
72644
+ if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedHtmlSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
71737
72645
  const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
71738
72646
  baseArgs: passBaseArgs,
71739
72647
  files: passFiles,
@@ -71762,7 +72670,8 @@ const runOxlint = async (options) => {
71762
72670
  fileBatches: passFileBatches,
71763
72671
  rootDirectory,
71764
72672
  nodeBinaryPath,
71765
- project,
72673
+ project: lintProject,
72674
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
71766
72675
  onPartialFailure: reportPartialFailure,
71767
72676
  onAnalyzedFiles: (filePaths) => {
71768
72677
  analyzedFiles = filePaths;
@@ -71797,7 +72706,7 @@ const runOxlint = async (options) => {
71797
72706
  };
71798
72707
  }
71799
72708
  };
71800
- if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
72709
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasHtmlFiles) {
71801
72710
  const rulesetHash = computeRulesetHash({
71802
72711
  config: buildConfig({
71803
72712
  extendsPaths: [],
@@ -71955,14 +72864,15 @@ const runOxlint = async (options) => {
71955
72864
  ]);
71956
72865
  }
71957
72866
  const baseArgs = makeBaseArgs(configPath);
71958
- const fileBatches = buildFileBatches(baseArgs, candidateFiles);
72867
+ const fileBatches = buildFileBatches(baseArgs, lintFiles);
71959
72868
  let analyzedFiles = [];
71960
72869
  const runBatches = () => spawnLintBatches({
71961
72870
  baseArgs,
71962
72871
  fileBatches,
71963
72872
  rootDirectory,
71964
72873
  nodeBinaryPath,
71965
- project,
72874
+ project: lintProject,
72875
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
71966
72876
  onPartialFailure,
71967
72877
  onAnalyzedFiles: (filePaths) => {
71968
72878
  analyzedFiles = filePaths;
@@ -73884,4 +74794,4 @@ const toJsonReport = (result, options) => buildJsonReport({
73884
74794
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
73885
74795
 
73886
74796
  //# sourceMappingURL=index.js.map
73887
- //# debugId=eb93b210-c190-581c-8fe2-f1e1c70e0bab
74797
+ //# debugId=5ad39650-1163-5117-aad5-472963ee3867