react-doctor 0.9.1-dev.5d2f66d → 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/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ea274003-c9c6-5b5c-b839-b1545ccc48fa")}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]="7f26fa62-fe0c-5ae0-bc9c-97a0deb50b43")}catch(e){}}();
3
3
  import { createRequire } from "node:module";
4
4
  import * as NodeChildProcess from "node:child_process";
5
5
  import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
@@ -64616,7 +64616,8 @@ var AmbiguousProjectError = class extends Error {
64616
64616
  }
64617
64617
  };
64618
64618
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
64619
- const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
64619
+ const HTML_FILE_PATTERN = /\.html$/i;
64620
+ const SOURCE_FILE_PATTERN = /\.(?:tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
64620
64621
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
64621
64622
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
64622
64623
  const MINIFIED_SNIFF_BYTES = 65536;
@@ -65485,7 +65486,7 @@ const parseConfigSourceFile = (filePath, content) => filePath.endsWith(".json")
65485
65486
  const getStaticPropertyName$2 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
65486
65487
  const isCommonJsConfigExportAssignment = (node, sourceFile) => ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && (node.left.getText(sourceFile) === "module.exports" || node.left.getText(sourceFile) === "exports.default");
65487
65488
  const hasExportModifier = (node) => ts.canHaveModifiers(node) && Boolean(ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
65488
- const getRequireModuleSpecifier = (expression) => {
65489
+ const getRequireModuleSpecifier$1 = (expression) => {
65489
65490
  if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "require" || expression.arguments.length !== 1) return null;
65490
65491
  const moduleSpecifier = expression.arguments[0];
65491
65492
  return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
@@ -65498,7 +65499,7 @@ const hasTopLevelValueBinding = (sourceFile, bindingName) => sourceFile.statemen
65498
65499
  const namedBindings = importClause?.namedBindings;
65499
65500
  return namedBindings ? ts.isNamespaceImport(namedBindings) ? namedBindings.name.text === bindingName : namedBindings.elements.some((element) => element.name.text === bindingName) : false;
65500
65501
  }
65501
- if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === bindingName);
65502
+ if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContainsIdentifier(declaration.name, bindingName));
65502
65503
  return (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name?.text === bindingName;
65503
65504
  });
65504
65505
  const getImportBinding = (sourceFile, bindingName) => {
@@ -65529,21 +65530,21 @@ const getImportBinding = (sourceFile, bindingName) => {
65529
65530
  for (const declaration of statement.declarationList.declarations) {
65530
65531
  if (!declaration.initializer) continue;
65531
65532
  if (ts.isIdentifier(declaration.name) && declaration.name.text === bindingName) {
65532
- const directModuleSpecifier = getRequireModuleSpecifier(declaration.initializer);
65533
+ const directModuleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
65533
65534
  if (directModuleSpecifier) return {
65534
65535
  moduleSpecifier: directModuleSpecifier,
65535
65536
  exportName: "default",
65536
65537
  isNamespace: true
65537
65538
  };
65538
- if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier(declaration.initializer.expression) !== null) return {
65539
- moduleSpecifier: getRequireModuleSpecifier(declaration.initializer.expression) ?? "",
65539
+ if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier$1(declaration.initializer.expression) !== null) return {
65540
+ moduleSpecifier: getRequireModuleSpecifier$1(declaration.initializer.expression) ?? "",
65540
65541
  exportName: declaration.initializer.name.text,
65541
65542
  isNamespace: false
65542
65543
  };
65543
65544
  }
65544
65545
  if (!ts.isObjectBindingPattern(declaration.name)) continue;
65545
65546
  const bindingElement = declaration.name.elements.find((element) => ts.isIdentifier(element.name) && element.name.text === bindingName);
65546
- const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
65547
+ const moduleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
65547
65548
  if (bindingElement && moduleSpecifier) return {
65548
65549
  moduleSpecifier,
65549
65550
  exportName: bindingElement.propertyName ? getStaticPropertyName$2(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
@@ -65599,6 +65600,48 @@ const getScopedConfigBinding = (identifier) => {
65599
65600
  };
65600
65601
  };
65601
65602
  const isCompilerTransformModule = (moduleSpecifier, exportName) => moduleSpecifier === "babel-plugin-react-compiler" && exportName === "default" || moduleSpecifier === "@vitejs/plugin-react" && exportName === "reactCompilerPreset";
65603
+ const NODE_MODULE_SPECIFIERS = new Set(["module", "node:module"]);
65604
+ const isConstantVariableInitializer = (node) => ts.isExpression(node) && ts.isVariableDeclaration(node.parent) && ts.isVariableDeclarationList(node.parent.parent) && Boolean(node.parent.parent.flags & ts.NodeFlags.Const);
65605
+ const isNodeCreateRequireCall = (node, analysis) => {
65606
+ if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertionExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isAwaitExpression(node)) return isNodeCreateRequireCall(node.expression, analysis);
65607
+ if (!ts.isCallExpression(node)) return false;
65608
+ const target = node.expression;
65609
+ if (ts.isIdentifier(target)) {
65610
+ if (analysis.localBindings.has(target.text) || getScopedConfigBinding(target).wasFound) return false;
65611
+ const importBinding = getImportBinding(analysis.sourceFile, target.text);
65612
+ return Boolean(importBinding && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier) && importBinding.exportName === "createRequire");
65613
+ }
65614
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return false;
65615
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "createRequire") return false;
65616
+ const createRequireReceiver = target.expression;
65617
+ if (ts.isCallExpression(createRequireReceiver)) {
65618
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(createRequireReceiver);
65619
+ if (requiredModuleSpecifier === null || !NODE_MODULE_SPECIFIERS.has(requiredModuleSpecifier) || !ts.isIdentifier(createRequireReceiver.expression)) return false;
65620
+ const requireIdentifier = createRequireReceiver.expression;
65621
+ return !analysis.localBindings.has(requireIdentifier.text) && !getScopedConfigBinding(requireIdentifier).wasFound && !hasTopLevelValueBinding(analysis.sourceFile, requireIdentifier.text);
65622
+ }
65623
+ if (!ts.isIdentifier(createRequireReceiver)) return false;
65624
+ if (analysis.localBindings.has(createRequireReceiver.text) || getScopedConfigBinding(createRequireReceiver).wasFound) return false;
65625
+ const importBinding = getImportBinding(analysis.sourceFile, createRequireReceiver.text);
65626
+ return Boolean(importBinding?.isNamespace && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier));
65627
+ };
65628
+ const getNodeRequireResolveModuleSpecifier = (callExpression, analysis) => {
65629
+ const [moduleSpecifierNode] = callExpression.arguments;
65630
+ if (!moduleSpecifierNode || !ts.isStringLiteralLike(moduleSpecifierNode)) return null;
65631
+ const target = callExpression.expression;
65632
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
65633
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "resolve") return null;
65634
+ if (isNodeCreateRequireCall(target.expression, analysis)) return moduleSpecifierNode.text;
65635
+ if (!ts.isIdentifier(target.expression)) return null;
65636
+ const resolverIdentifier = target.expression;
65637
+ if (analysis.localBindings.has(resolverIdentifier.text)) return null;
65638
+ const scopedBinding = getScopedConfigBinding(resolverIdentifier);
65639
+ const topLevelBinding = scopedBinding.wasFound ? null : getTopLevelBinding(analysis.sourceFile, resolverIdentifier.text);
65640
+ const resolverInitializer = scopedBinding.wasFound ? scopedBinding.initializer : topLevelBinding;
65641
+ if (resolverInitializer === null && !scopedBinding.wasFound && resolverIdentifier.text === "require" && !hasTopLevelValueBinding(analysis.sourceFile, resolverIdentifier.text) && getImportBinding(analysis.sourceFile, resolverIdentifier.text) === null) return moduleSpecifierNode.text;
65642
+ if (!resolverInitializer || !isConstantVariableInitializer(resolverInitializer) || !isNodeCreateRequireCall(resolverInitializer, analysis)) return null;
65643
+ return moduleSpecifierNode.text;
65644
+ };
65602
65645
  const getAssignedPropertyInitializer = (identifier, propertyName) => {
65603
65646
  let bindingScope = null;
65604
65647
  let currentNode = identifier;
@@ -65914,7 +65957,7 @@ const analyzeConfigCallTarget = (callExpression, analysis, allowCompilerTransfor
65914
65957
  if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
65915
65958
  const propertyName = ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null;
65916
65959
  if (propertyName === null) return null;
65917
- const requiredModuleSpecifier = getRequireModuleSpecifier(target.expression);
65960
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(target.expression);
65918
65961
  if (requiredModuleSpecifier !== null) {
65919
65962
  if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
65920
65963
  if (!requiredModuleSpecifier.startsWith(".")) return null;
@@ -65974,9 +66017,11 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
65974
66017
  });
65975
66018
  }
65976
66019
  if (ts.isCallExpression(node)) {
66020
+ const resolvedModuleSpecifier = getNodeRequireResolveModuleSpecifier(node, analysis);
66021
+ if (resolvedModuleSpecifier !== null) return allowCompilerTransform && isCompilerTransformModule(resolvedModuleSpecifier, "default");
65977
66022
  const callTargetResult = analyzeConfigCallTarget(node, analysis, allowCompilerTransform);
65978
66023
  if (callTargetResult !== null) return callTargetResult;
65979
- const directModuleSpecifier = getRequireModuleSpecifier(node);
66024
+ const directModuleSpecifier = getRequireModuleSpecifier$1(node);
65980
66025
  const isRequireShadowed = analysis.localBindings.has("require") || ts.isIdentifier(node.expression) && getScopedConfigBinding(node.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require");
65981
66026
  if (directModuleSpecifier && isRequireShadowed) return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
65982
66027
  if (directModuleSpecifier && !isRequireShadowed) {
@@ -65998,7 +66043,7 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
65998
66043
  return analyzeConfigNode(node.expression, analysis, allowCompilerTransform) || node.arguments.some((argument) => analyzeConfigNode(argument, analysis, false));
65999
66044
  }
66000
66045
  if (ts.isPropertyAccessExpression(node)) {
66001
- const requiredModuleSpecifier = getRequireModuleSpecifier(node.expression);
66046
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(node.expression);
66002
66047
  if (requiredModuleSpecifier) {
66003
66048
  if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
66004
66049
  if (requiredModuleSpecifier.startsWith(".")) {
@@ -69335,7 +69380,7 @@ const warn = (message) => {
69335
69380
  runSync(warn$1(message));
69336
69381
  };
69337
69382
  const CONFIG_BASENAME = "doctor.config";
69338
- const CONFIG_EXTENSIONS = [
69383
+ const CONFIG_EXTENSIONS$1 = [
69339
69384
  "ts",
69340
69385
  "mts",
69341
69386
  "cts",
@@ -69439,7 +69484,7 @@ const loadLegacyConfig = (directory) => {
69439
69484
  };
69440
69485
  const loadConfigFromDirectory = async (directory) => {
69441
69486
  let sawBrokenConfigFile = false;
69442
- for (const extension of CONFIG_EXTENSIONS) {
69487
+ for (const extension of CONFIG_EXTENSIONS$1) {
69443
69488
  const filePath = Path.join(directory, `${CONFIG_BASENAME}.${extension}`);
69444
69489
  if (!isFile(filePath)) continue;
69445
69490
  const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
@@ -69498,7 +69543,7 @@ const loadConfigWithSource = (rootDirectory) => {
69498
69543
  return loadPromise;
69499
69544
  };
69500
69545
  const directoryHasCurrentConfig = (directory) => {
69501
- for (const extension of CONFIG_EXTENSIONS) if (isFile(Path.join(directory, `${CONFIG_BASENAME}.${extension}`))) return true;
69546
+ for (const extension of CONFIG_EXTENSIONS$1) if (isFile(Path.join(directory, `${CONFIG_BASENAME}.${extension}`))) return true;
69502
69547
  return readEmbeddedPackageJsonConfig(directory) !== null;
69503
69548
  };
69504
69549
  /**
@@ -73290,7 +73335,11 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
73290
73335
  const ROOT_DIRECTORY_PLACEHOLDER = "<root>";
73291
73336
  const normalizeConfigForHash = (config) => {
73292
73337
  const clone = JSON.parse(JSON.stringify(config));
73293
- if (clone?.settings?.["react-doctor"]) clone.settings["react-doctor"].rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
73338
+ if (clone?.settings?.["react-doctor"]) {
73339
+ const reactDoctorSettings = clone.settings["react-doctor"];
73340
+ reactDoctorSettings.rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
73341
+ if (Array.isArray(reactDoctorSettings.unpluginAutoImportRootDirectories)) reactDoctorSettings.unpluginAutoImportRootDirectories = [ROOT_DIRECTORY_PLACEHOLDER];
73342
+ }
73294
73343
  if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
73295
73344
  return clone;
73296
73345
  };
@@ -73449,13 +73498,14 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
73449
73498
  }
73450
73499
  return enabled;
73451
73500
  };
73452
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
73501
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, runtimeGlobals, unpluginAutoImportGlobalScopes, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
73453
73502
  const hasIncludedTags = includedTags.size > 0;
73454
73503
  const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
73455
73504
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
73456
73505
  const jsPlugins = [];
73457
73506
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
73458
73507
  const capabilities = getCapabilities(project);
73508
+ const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
73459
73509
  const enabledReactDoctorRules = {};
73460
73510
  for (const registryEntry of REACT_DOCTOR_RULES) {
73461
73511
  const rule = reactDoctorPlugin.rules[registryEntry.id];
@@ -73501,8 +73551,16 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
73501
73551
  jsPlugins: [...jsPlugins, pluginPath],
73502
73552
  settings: { "react-doctor": {
73503
73553
  framework: project.framework,
73504
- rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
73554
+ rootDirectory: settingsRootDirectory,
73505
73555
  capabilities: [...capabilities].sort(),
73556
+ ...runtimeGlobals && runtimeGlobals.length > 0 ? { runtimeGlobals: [...runtimeGlobals] } : {},
73557
+ ...unpluginAutoImportGlobalScopes && unpluginAutoImportGlobalScopes.length > 0 ? {
73558
+ unpluginAutoImportRootDirectories: [...new Set([settingsRootDirectory, project.rootDirectory])],
73559
+ unpluginAutoImportGlobalScopes: unpluginAutoImportGlobalScopes.map((scope) => ({
73560
+ directory: scope.directory,
73561
+ names: [...scope.names]
73562
+ }))
73563
+ } : {},
73506
73564
  ...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
73507
73565
  ...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
73508
73566
  } },
@@ -73513,6 +73571,245 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
73513
73571
  }
73514
73572
  };
73515
73573
  };
73574
+ const AUTO_IMPORT_ADAPTER_PATTERN = /^unplugin-auto-import\/(?:astro|esbuild|rollup|rolldown|rspack|vite|webpack)$/;
73575
+ const CONFIG_BASENAMES = [
73576
+ "astro.config",
73577
+ "esbuild.config",
73578
+ "rollup.config",
73579
+ "rolldown.config",
73580
+ "rspack.config",
73581
+ "vite.config",
73582
+ "webpack.config"
73583
+ ];
73584
+ const CONFIG_EXTENSIONS = [
73585
+ ".cjs",
73586
+ ".cts",
73587
+ ".js",
73588
+ ".mjs",
73589
+ ".mts",
73590
+ ".ts"
73591
+ ];
73592
+ const CONFIG_FILENAMES = new Set(CONFIG_BASENAMES.flatMap((basename) => CONFIG_EXTENSIONS.map((extension) => `${basename}${extension}`)));
73593
+ const DEFAULT_ESLINT_GLOBALS_PATH = ".eslintrc-auto-import.json";
73594
+ const SUPPORTED_GLOBAL_VALUES = new Set([
73595
+ true,
73596
+ false,
73597
+ "readable",
73598
+ "readonly",
73599
+ "writable",
73600
+ "writeable"
73601
+ ]);
73602
+ const getStaticProperty = (objectExpression, propertyName) => objectExpression.properties.find((property) => {
73603
+ if (ts.isSpreadAssignment(property)) return false;
73604
+ const name = ts.isComputedPropertyName(property.name) ? unwrapTypescriptExpression(property.name.expression) : property.name;
73605
+ return (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) && name.text === propertyName;
73606
+ }) ?? null;
73607
+ const hasNonLiteralComputedProperty = (objectExpression) => objectExpression.properties.some((property) => !ts.isSpreadAssignment(property) && ts.isComputedPropertyName(property.name) && !ts.isStringLiteralLike(unwrapTypescriptExpression(property.name.expression)));
73608
+ const getStaticPropertyAssignment = (objectExpression, propertyName) => {
73609
+ const property = getStaticProperty(objectExpression, propertyName);
73610
+ return property && ts.isPropertyAssignment(property) ? property : null;
73611
+ };
73612
+ const getRequireModuleSpecifier = (expression) => {
73613
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
73614
+ if (ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === "default") return getRequireModuleSpecifier(unwrappedExpression.expression);
73615
+ if (!ts.isCallExpression(unwrappedExpression) || !ts.isIdentifier(unwrappedExpression.expression) || unwrappedExpression.expression.text !== "require" || unwrappedExpression.arguments.length !== 1) return null;
73616
+ const moduleSpecifier = unwrappedExpression.arguments[0];
73617
+ return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
73618
+ };
73619
+ const getRequiredPropertyModuleSpecifier = (expression, propertyName) => {
73620
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
73621
+ return ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === propertyName ? getRequireModuleSpecifier(unwrappedExpression.expression) : null;
73622
+ };
73623
+ const isCommonJsExportAssignment = (node, sourceFile) => ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && (node.left.getText(sourceFile) === "module.exports" || node.left.getText(sourceFile) === "exports.default");
73624
+ const isTopLevelExpression = (node) => {
73625
+ let ancestor = node.parent;
73626
+ while (ancestor && !ts.isSourceFile(ancestor)) {
73627
+ if (ts.isExpressionStatement(ancestor)) return ts.isSourceFile(ancestor.parent);
73628
+ if (!ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isAwaitExpression(ancestor)) return false;
73629
+ ancestor = ancestor.parent;
73630
+ }
73631
+ return false;
73632
+ };
73633
+ const isInsideActiveConfigProperty = (node, propertyName, sourceFile, esbuildBindings, esbuildNamespaceBindings) => {
73634
+ let ancestor = node.parent;
73635
+ let didFindConfigProperty = false;
73636
+ while (ancestor && !ts.isSourceFile(ancestor)) {
73637
+ if (!didFindConfigProperty && !ts.isArrayLiteralExpression(ancestor) && !ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isPropertyAssignment(ancestor)) return false;
73638
+ if (ts.isPropertyAssignment(ancestor)) {
73639
+ const isConfigProperty = (ts.isIdentifier(ancestor.name) || ts.isStringLiteralLike(ancestor.name)) && ancestor.name.text === propertyName;
73640
+ if (didFindConfigProperty || !isConfigProperty) return false;
73641
+ if (!ts.isObjectLiteralExpression(ancestor.parent) || ancestor.parent.properties.some(ts.isSpreadAssignment)) return false;
73642
+ didFindConfigProperty = true;
73643
+ ancestor = ancestor.parent;
73644
+ continue;
73645
+ }
73646
+ if (didFindConfigProperty) {
73647
+ if (ts.isExportAssignment(ancestor)) return true;
73648
+ if (isCommonJsExportAssignment(ancestor, sourceFile)) return isTopLevelExpression(ancestor);
73649
+ if (propertyName === "plugins" && ts.isCallExpression(ancestor) && (ts.isIdentifier(ancestor.expression) ? esbuildBindings.has(ancestor.expression.text) : ts.isPropertyAccessExpression(ancestor.expression) && ancestor.expression.name.text === "build" && (ts.isIdentifier(ancestor.expression.expression) && esbuildNamespaceBindings.has(ancestor.expression.expression.text) || getRequireModuleSpecifier(ancestor.expression.expression) === "esbuild"))) return isTopLevelExpression(ancestor);
73650
+ if (!(ts.isObjectLiteralExpression(ancestor) || ts.isParenthesizedExpression(ancestor) || ts.isAsExpression(ancestor) || ts.isSatisfiesExpression(ancestor) || ts.isNonNullExpression(ancestor) || ts.isTypeAssertionExpression(ancestor) || ts.isCallExpression(ancestor) && ts.isIdentifier(ancestor.expression) && ancestor.expression.text === "defineConfig")) return false;
73651
+ }
73652
+ ancestor = ancestor.parent;
73653
+ }
73654
+ return false;
73655
+ };
73656
+ const getGlobalsPathFromActiveAutoImportCall = (callExpression, packageDirectory) => {
73657
+ const optionsExpression = callExpression.arguments[0];
73658
+ if (!optionsExpression) return null;
73659
+ const unwrappedOptions = unwrapTypescriptExpression(optionsExpression);
73660
+ if (!ts.isObjectLiteralExpression(unwrappedOptions)) return null;
73661
+ if (unwrappedOptions.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(unwrappedOptions)) return null;
73662
+ if (getStaticProperty(unwrappedOptions, "include") || getStaticProperty(unwrappedOptions, "exclude")) return null;
73663
+ const eslintrcProperty = getStaticPropertyAssignment(unwrappedOptions, "eslintrc");
73664
+ if (!eslintrcProperty) return null;
73665
+ const eslintrcExpression = unwrapTypescriptExpression(eslintrcProperty.initializer);
73666
+ if (!ts.isObjectLiteralExpression(eslintrcExpression)) return null;
73667
+ if (eslintrcExpression.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(eslintrcExpression)) return null;
73668
+ const enabledProperty = getStaticPropertyAssignment(eslintrcExpression, "enabled");
73669
+ if (!enabledProperty || unwrapTypescriptExpression(enabledProperty.initializer).kind !== ts.SyntaxKind.TrueKeyword) return null;
73670
+ const filepathProperty = getStaticProperty(eslintrcExpression, "filepath");
73671
+ if (!filepathProperty) return Path.join(packageDirectory, DEFAULT_ESLINT_GLOBALS_PATH);
73672
+ if (!ts.isPropertyAssignment(filepathProperty)) return null;
73673
+ const filepathExpression = unwrapTypescriptExpression(filepathProperty.initializer);
73674
+ return ts.isStringLiteralLike(filepathExpression) ? Path.resolve(packageDirectory, filepathExpression.text) : null;
73675
+ };
73676
+ const collectGlobalsPathsFromConfig = (configPath, packageDirectory) => {
73677
+ let sourceText;
73678
+ try {
73679
+ sourceText = NFS.readFileSync(configPath, "utf8");
73680
+ } catch {
73681
+ return {
73682
+ didFindActiveAutoImport: false,
73683
+ globalsPaths: []
73684
+ };
73685
+ }
73686
+ const sourceFile = ts.createSourceFile(configPath, sourceText, ts.ScriptTarget.Latest, true);
73687
+ const autoImportBindings = /* @__PURE__ */ new Map();
73688
+ const esbuildBindings = /* @__PURE__ */ new Set();
73689
+ const esbuildNamespaceBindings = /* @__PURE__ */ new Set();
73690
+ for (const statement of sourceFile.statements) {
73691
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteralLike(statement.moduleSpecifier)) {
73692
+ const moduleSpecifier = statement.moduleSpecifier.text;
73693
+ if (AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
73694
+ const defaultBinding = statement.importClause?.name;
73695
+ if (defaultBinding) autoImportBindings.set(defaultBinding.text, moduleSpecifier);
73696
+ }
73697
+ if (moduleSpecifier === "esbuild") {
73698
+ const defaultBinding = statement.importClause?.name;
73699
+ if (defaultBinding) esbuildNamespaceBindings.add(defaultBinding.text);
73700
+ const namedBindings = statement.importClause?.namedBindings;
73701
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
73702
+ for (const importSpecifier of namedBindings.elements) if ((importSpecifier.propertyName ?? importSpecifier.name).text === "build") esbuildBindings.add(importSpecifier.name.text);
73703
+ }
73704
+ if (namedBindings && ts.isNamespaceImport(namedBindings)) esbuildNamespaceBindings.add(namedBindings.name.text);
73705
+ }
73706
+ }
73707
+ if (!ts.isVariableStatement(statement)) continue;
73708
+ for (const declaration of statement.declarationList.declarations) {
73709
+ if (!declaration.initializer) continue;
73710
+ const declarationName = ts.isIdentifier(declaration.name) ? declaration.name.text : null;
73711
+ const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
73712
+ if (declarationName && moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) autoImportBindings.set(declarationName, moduleSpecifier);
73713
+ if (moduleSpecifier === "esbuild") {
73714
+ if (declarationName) esbuildNamespaceBindings.add(declarationName);
73715
+ if (ts.isObjectBindingPattern(declaration.name)) for (const bindingElement of declaration.name.elements) {
73716
+ const importedName = bindingElement.propertyName ?? bindingElement.name;
73717
+ if (ts.isIdentifier(importedName) && importedName.text === "build" && ts.isIdentifier(bindingElement.name)) esbuildBindings.add(bindingElement.name.text);
73718
+ }
73719
+ }
73720
+ if (declarationName && getRequiredPropertyModuleSpecifier(declaration.initializer, "build") === "esbuild") esbuildBindings.add(declarationName);
73721
+ }
73722
+ }
73723
+ const globalsPaths = /* @__PURE__ */ new Set();
73724
+ let didFindActiveAutoImport = false;
73725
+ let didFindUnsafeActiveAutoImport = false;
73726
+ const visit = (node) => {
73727
+ if (ts.isCallExpression(node)) {
73728
+ const moduleSpecifier = ts.isIdentifier(node.expression) ? autoImportBindings.get(node.expression.text) : getRequireModuleSpecifier(node.expression);
73729
+ if (moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
73730
+ if (isInsideActiveConfigProperty(node, moduleSpecifier.endsWith("/astro") ? "integrations" : "plugins", sourceFile, esbuildBindings, esbuildNamespaceBindings)) {
73731
+ didFindActiveAutoImport = true;
73732
+ const globalsPath = getGlobalsPathFromActiveAutoImportCall(node, packageDirectory);
73733
+ if (globalsPath) globalsPaths.add(globalsPath);
73734
+ else didFindUnsafeActiveAutoImport = true;
73735
+ }
73736
+ }
73737
+ }
73738
+ ts.forEachChild(node, visit);
73739
+ };
73740
+ visit(sourceFile);
73741
+ return {
73742
+ didFindActiveAutoImport,
73743
+ globalsPaths: didFindUnsafeActiveAutoImport ? [] : [...globalsPaths]
73744
+ };
73745
+ };
73746
+ const collectGeneratedGlobalNames = (globalsPath, rootDirectory) => {
73747
+ const relativePath = Path.relative(rootDirectory, globalsPath);
73748
+ if (relativePath.startsWith("..") || Path.isAbsolute(relativePath)) return [];
73749
+ const parsed = failOpenReadJson(globalsPath, null);
73750
+ if (!isPlainObject(parsed) || !isPlainObject(parsed.globals)) return [];
73751
+ return Object.entries(parsed.globals).filter((entry) => entry[0].length > 0 && (typeof entry[1] === "boolean" || typeof entry[1] === "string") && SUPPORTED_GLOBAL_VALUES.has(entry[1])).map(([name]) => name).sort();
73752
+ };
73753
+ const findOwningPackageDirectory = (absoluteFilePath, rootDirectory, cache) => {
73754
+ let currentDirectory = Path.dirname(absoluteFilePath);
73755
+ const visitedDirectories = [];
73756
+ while (true) {
73757
+ const cachedDirectory = cache.get(currentDirectory);
73758
+ if (cachedDirectory !== void 0) {
73759
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, cachedDirectory);
73760
+ return cachedDirectory;
73761
+ }
73762
+ const relativeDirectory = Path.relative(rootDirectory, currentDirectory);
73763
+ if (relativeDirectory.startsWith("..") || Path.isAbsolute(relativeDirectory)) {
73764
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
73765
+ return null;
73766
+ }
73767
+ visitedDirectories.push(currentDirectory);
73768
+ if (NFS.existsSync(Path.join(currentDirectory, "package.json"))) {
73769
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, currentDirectory);
73770
+ return currentDirectory;
73771
+ }
73772
+ if (currentDirectory === rootDirectory) {
73773
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
73774
+ return null;
73775
+ }
73776
+ currentDirectory = Path.dirname(currentDirectory);
73777
+ }
73778
+ };
73779
+ const collectPackageGlobalNames = (packageDirectory, rootDirectory) => {
73780
+ let directoryEntries;
73781
+ try {
73782
+ directoryEntries = NFS.readdirSync(packageDirectory, { withFileTypes: true });
73783
+ } catch {
73784
+ return [];
73785
+ }
73786
+ const configuredGlobalsPaths = [];
73787
+ for (const entry of directoryEntries) {
73788
+ if (!entry.isFile() && !entry.isSymbolicLink() || !CONFIG_FILENAMES.has(entry.name)) continue;
73789
+ const configGlobalsPaths = collectGlobalsPathsFromConfig(Path.join(packageDirectory, entry.name), packageDirectory);
73790
+ if (configGlobalsPaths.didFindActiveAutoImport) configuredGlobalsPaths.push(configGlobalsPaths.globalsPaths.toSorted());
73791
+ }
73792
+ if (configuredGlobalsPaths.length === 0) return [];
73793
+ const globalsPaths = configuredGlobalsPaths[0];
73794
+ if (configuredGlobalsPaths.some((candidatePaths) => candidatePaths.length !== globalsPaths.length || candidatePaths.some((candidatePath, index) => candidatePath !== globalsPaths[index]))) return [];
73795
+ const names = /* @__PURE__ */ new Set();
73796
+ for (const globalsPath of globalsPaths) for (const name of collectGeneratedGlobalNames(globalsPath, rootDirectory)) names.add(name);
73797
+ return [...names].sort();
73798
+ };
73799
+ const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }) => {
73800
+ const absoluteRootDirectory = Path.resolve(rootDirectory);
73801
+ const packageDirectoryCache = /* @__PURE__ */ new Map();
73802
+ const packageDirectories = /* @__PURE__ */ new Set();
73803
+ for (const candidateFile of candidateFiles) {
73804
+ const packageDirectory = findOwningPackageDirectory(Path.resolve(absoluteRootDirectory, candidateFile), absoluteRootDirectory, packageDirectoryCache);
73805
+ if (packageDirectory) packageDirectories.add(packageDirectory);
73806
+ }
73807
+ const scopes = [...packageDirectories].map((packageDirectory) => ({
73808
+ directory: Path.relative(absoluteRootDirectory, packageDirectory).replaceAll("\\", "/"),
73809
+ names: collectPackageGlobalNames(packageDirectory, absoluteRootDirectory)
73810
+ })).sort((firstScope, secondScope) => firstScope.directory.localeCompare(secondScope.directory));
73811
+ return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
73812
+ };
73516
73813
  const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
73517
73814
  const decodeFileDiagnostics = (raw) => {
73518
73815
  if (!Array.isArray(raw)) return null;
@@ -73835,6 +74132,12 @@ const appendReanimatedSharedValueHint = (help, rule, project) => {
73835
74132
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
73836
74133
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
73837
74134
  };
74135
+ const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
74136
+ const boundedOffset = Math.min(Math.max(utf8Offset, 0), sourceBuffer.length);
74137
+ let lineStartOffset = boundedOffset;
74138
+ while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
74139
+ return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
74140
+ };
73838
74141
  const REDACTED_PLACEHOLDER = "<redacted>";
73839
74142
  const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
73840
74143
  const KNOWN_SECRET_RULES = [
@@ -74550,7 +74853,7 @@ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORI
74550
74853
  * with empty text still carry a useful jump target, so they're kept
74551
74854
  * with a neutral message.
74552
74855
  */
74553
- const buildRelatedLocations = (labels, filePath) => {
74856
+ const buildRelatedLocations = (labels, filePath, sourceBuffer) => {
74554
74857
  if (labels.length <= 1) return [];
74555
74858
  const related = [];
74556
74859
  for (let labelIndex = 1; labelIndex < labels.length; labelIndex++) {
@@ -74558,8 +74861,8 @@ const buildRelatedLocations = (labels, filePath) => {
74558
74861
  if (!label?.span) continue;
74559
74862
  related.push({
74560
74863
  filePath,
74561
- line: label.span.line ?? 0,
74562
- column: label.span.column ?? 0,
74864
+ line: sourceBuffer === null ? label.span.line ?? 0 : lineOfUtf8Offset(sourceBuffer, label.span.offset),
74865
+ column: sourceBuffer === null ? label.span.column ?? 0 : columnOfUtf8Offset(sourceBuffer, label.span.offset),
74563
74866
  offset: label.span.offset,
74564
74867
  length: label.span.length,
74565
74868
  message: label.label ?? ""
@@ -74579,7 +74882,7 @@ const isOxlintOutput = (value) => isRecord$1(value) && Array.isArray(value.diagn
74579
74882
  * to the first `{`. Raises `OxlintOutputUnparseable` when the
74580
74883
  * stdout isn't valid JSON or doesn't carry a `diagnostics` array.
74581
74884
  */
74582
- const parseOxlintOutput = (stdout, project, rootDirectory) => {
74885
+ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
74583
74886
  if (!stdout) return [];
74584
74887
  const jsonStart = stdout.indexOf("{");
74585
74888
  const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
@@ -74596,8 +74899,10 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74596
74899
  const sourceBufferCache = /* @__PURE__ */ new Map();
74597
74900
  const sourceLinesCache = /* @__PURE__ */ new Map();
74598
74901
  const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
74902
+ const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
74903
+ const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
74599
74904
  const readSourceBuffer = (filename) => {
74600
- const absolutePath = resolveAbsolutePath(filename);
74905
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
74601
74906
  const cached = sourceBufferCache.get(absolutePath);
74602
74907
  if (cached !== void 0) return cached;
74603
74908
  let sourceBuffer;
@@ -74610,7 +74915,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74610
74915
  return sourceBuffer;
74611
74916
  };
74612
74917
  const readSourceLines = (filename) => {
74613
- const absolutePath = resolveAbsolutePath(filename);
74918
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
74614
74919
  const cached = sourceLinesCache.get(absolutePath);
74615
74920
  if (cached !== void 0) return cached;
74616
74921
  const sourceBuffer = readSourceBuffer(filename);
@@ -74619,27 +74924,30 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74619
74924
  return sourceLines;
74620
74925
  };
74621
74926
  const isMinifiedDiagnosticFile = (filename) => {
74622
- const absolutePath = resolveAbsolutePath(filename);
74927
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
74623
74928
  const cached = minifiedFileCache.get(absolutePath);
74624
74929
  if (cached !== void 0) return cached;
74625
74930
  const minified = isMinifiedSource(absolutePath);
74626
74931
  minifiedFileCache.set(absolutePath, minified);
74627
74932
  return minified;
74628
74933
  };
74629
- return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
74934
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(resolveSourceFilename(diagnostic.filename)) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
74630
74935
  const { plugin, rule } = parseRuleCode(diagnostic.code);
74631
74936
  const primaryLabel = diagnostic.labels[0];
74632
74937
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
74633
- const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
74938
+ const mappedSourceFilename = resolveMappedSourceFilename(diagnostic.filename);
74939
+ const normalizedFilePath = (mappedSourceFilename ?? diagnostic.filename).replaceAll("\\", "/");
74634
74940
  const primarySpan = primaryLabel?.span;
74635
74941
  const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
74636
- const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
74942
+ const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath, mappedSourceFilename === void 0 ? null : sourceBuffer);
74637
74943
  const category = resolveDiagnosticCategory(plugin, rule);
74638
74944
  const matchByOccurrence = resolveMatchByOccurrence(rule, category);
74639
74945
  const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
74640
- const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
74946
+ const primaryLineNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.line ?? 0;
74947
+ const primaryColumnNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? columnOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.column ?? 0;
74948
+ const primaryLineIndex = primarySpan ? primaryLineNumber - 1 : -1;
74641
74949
  const primaryLine = sourceLines?.[primaryLineIndex];
74642
- const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
74950
+ const primaryColumnIndex = primarySpan ? primaryColumnNumber - 1 : -1;
74643
74951
  const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
74644
74952
  const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
74645
74953
  const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
@@ -74652,8 +74960,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74652
74960
  message: cleaned.message,
74653
74961
  help: cleaned.help,
74654
74962
  url: diagnostic.url,
74655
- line: primarySpan?.line ?? 0,
74656
- column: primarySpan?.column ?? 0,
74963
+ line: primaryLineNumber,
74964
+ column: primaryColumnNumber,
74657
74965
  ...primarySpan ? {
74658
74966
  offset: primarySpan.offset,
74659
74967
  length: primarySpan.length,
@@ -74841,7 +75149,11 @@ const isParallelismRelatedSpawnError = (error) => {
74841
75149
  * loop with a slimmer config in that case.
74842
75150
  */
74843
75151
  const spawnLintBatches = async (input) => {
74844
- const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
75152
+ const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
75153
+ const resolveSourcePath = (filePath) => {
75154
+ const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
75155
+ return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
75156
+ };
74845
75157
  const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
74846
75158
  let rescueDeadlineEpochMs;
74847
75159
  const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
@@ -74861,7 +75173,7 @@ const spawnLintBatches = async (input) => {
74861
75173
  }
74862
75174
  const batchArgs = [...baseArgs, ...batch];
74863
75175
  try {
74864
- return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
75176
+ return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath);
74865
75177
  } catch (error) {
74866
75178
  if (!isSplittableReactDoctorError(error)) throw error;
74867
75179
  if (isPastDeadline()) {
@@ -74967,10 +75279,12 @@ const spawnLintBatches = async (input) => {
74967
75279
  onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
74968
75280
  };
74969
75281
  const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
74970
- reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
74971
- reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
75282
+ const droppedSourceFiles = [...new Set(droppedFiles.map(resolveSourcePath))];
75283
+ const deadlineSkippedSourceFiles = [...new Set(outcome.deadlineSkippedFiles.map(resolveSourcePath))];
75284
+ reportSkippedFiles(droppedSourceFiles, (fileListPreview) => `${droppedSourceFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
75285
+ reportSkippedFiles(deadlineSkippedSourceFiles, (fileListPreview) => `${deadlineSkippedSourceFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
74972
75286
  const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
74973
- input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
75287
+ input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)).map(resolveSourcePath))].sort());
74974
75288
  return dedupeDiagnostics(diagnostics);
74975
75289
  };
74976
75290
  let didValidate = false;
@@ -75069,6 +75383,266 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
75069
75383
  }
75070
75384
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
75071
75385
  };
75386
+ const THREE_MODULE_IMPORT_PATTERN = /\b(?:from\s*|import\s*(?:\(\s*)?|require\s*\(\s*)["']three(?:\/[^"']*)?["']/;
75387
+ const containsThreeModuleImport = (sourceText) => THREE_MODULE_IMPORT_PATTERN.test(sourceText);
75388
+ const COMMENT_OPEN = "<!--";
75389
+ const COMMENT_CLOSE = "-->";
75390
+ const FRONTMATTER_FENCE = "---";
75391
+ const SCRIPT_TAG_NAME = "script";
75392
+ const SCRIPT_OPEN = `<${SCRIPT_TAG_NAME}`;
75393
+ const SCRIPT_CLOSE = `</${SCRIPT_TAG_NAME}`;
75394
+ const TEMPLATE_TAG_NAME = "template";
75395
+ const TEMPLATE_CLOSE = `</${TEMPLATE_TAG_NAME}`;
75396
+ const JAVASCRIPT_MIME_TYPES = new Set([
75397
+ "application/ecmascript",
75398
+ "application/javascript",
75399
+ "application/x-ecmascript",
75400
+ "application/x-javascript",
75401
+ "text/ecmascript",
75402
+ "text/javascript",
75403
+ "text/javascript1.0",
75404
+ "text/javascript1.1",
75405
+ "text/javascript1.2",
75406
+ "text/javascript1.3",
75407
+ "text/javascript1.4",
75408
+ "text/javascript1.5",
75409
+ "text/jscript",
75410
+ "text/livescript",
75411
+ "text/x-ecmascript",
75412
+ "text/x-javascript"
75413
+ ]);
75414
+ const RAW_TEXT_TAG_NAMES = new Set([
75415
+ "iframe",
75416
+ "noembed",
75417
+ "noframes",
75418
+ "noscript",
75419
+ "style",
75420
+ "textarea",
75421
+ "title",
75422
+ "xmp"
75423
+ ]);
75424
+ const PLAINTEXT_TAG_NAME = "plaintext";
75425
+ const TAG_OPEN_UTF8_BYTE = "<".charCodeAt(0);
75426
+ const TAG_CLOSE_UTF8_BYTE = ">".charCodeAt(0);
75427
+ const SINGLE_QUOTE_UTF8_BYTE = "'".charCodeAt(0);
75428
+ const DOUBLE_QUOTE_UTF8_BYTE = "\"".charCodeAt(0);
75429
+ const ATTRIBUTE_ASSIGNMENT_UTF8_BYTE = "=".charCodeAt(0);
75430
+ const TAG_SELF_CLOSE_UTF8_BYTE = "/".charCodeAt(0);
75431
+ const TAB_UTF8_BYTE = " ".charCodeAt(0);
75432
+ const FORM_FEED_UTF8_BYTE = "\f".charCodeAt(0);
75433
+ const isHtmlWhitespace = (byte) => byte === TAB_UTF8_BYTE || byte === 10 || byte === FORM_FEED_UTF8_BYTE || byte === 13 || byte === 32;
75434
+ const matchesAsciiCaseInsensitive = (sourceBuffer, startByte, expected) => {
75435
+ if (startByte + expected.length > sourceBuffer.length) return false;
75436
+ for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex++) {
75437
+ const sourceByte = sourceBuffer[startByte + expectedIndex];
75438
+ if (sourceByte === void 0 || String.fromCharCode(sourceByte).toLowerCase() !== expected[expectedIndex]) return false;
75439
+ }
75440
+ return true;
75441
+ };
75442
+ const isTagBoundary = (byte) => byte === TAG_CLOSE_UTF8_BYTE || byte === TAG_SELF_CLOSE_UTF8_BYTE || isHtmlWhitespace(byte);
75443
+ const isPotentialTagStart = (byte) => {
75444
+ if (byte === void 0) return false;
75445
+ return /[A-Za-z!/?]/.test(String.fromCharCode(byte));
75446
+ };
75447
+ const findLineEnd = (sourceBuffer, lineStartByte) => {
75448
+ let byteIndex = lineStartByte;
75449
+ while (byteIndex < sourceBuffer.length && sourceBuffer[byteIndex] !== 10 && sourceBuffer[byteIndex] !== 13) byteIndex++;
75450
+ return byteIndex;
75451
+ };
75452
+ const findNextLineStart = (sourceBuffer, lineStartByte) => {
75453
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
75454
+ if (sourceBuffer[lineEndByte] === 13 && sourceBuffer[lineEndByte + 1] === 10) return lineEndByte + 2;
75455
+ return Math.min(lineEndByte + 1, sourceBuffer.length);
75456
+ };
75457
+ const isFrontmatterFenceLine = (sourceBuffer, lineStartByte) => {
75458
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, lineStartByte, FRONTMATTER_FENCE)) return false;
75459
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
75460
+ for (let byteIndex = lineStartByte + 3; byteIndex < lineEndByte; byteIndex++) if (!isHtmlWhitespace(sourceBuffer[byteIndex])) return false;
75461
+ return true;
75462
+ };
75463
+ const findFrontmatterEnd = (sourceBuffer) => {
75464
+ if (!isFrontmatterFenceLine(sourceBuffer, 0)) return 0;
75465
+ const openingFenceEndByte = findLineEnd(sourceBuffer, 0);
75466
+ let lineStartByte = findNextLineStart(sourceBuffer, 0);
75467
+ while (lineStartByte < sourceBuffer.length) {
75468
+ if (isFrontmatterFenceLine(sourceBuffer, lineStartByte)) return findLineEnd(sourceBuffer, lineStartByte);
75469
+ lineStartByte = findNextLineStart(sourceBuffer, lineStartByte);
75470
+ }
75471
+ return openingFenceEndByte;
75472
+ };
75473
+ const maskByteRange = (maskedBuffer, startByte, endByte) => {
75474
+ for (let byteIndex = startByte; byteIndex < endByte; byteIndex++) {
75475
+ const byte = maskedBuffer[byteIndex];
75476
+ if (byte !== 10 && byte !== 13) maskedBuffer[byteIndex] = 32;
75477
+ }
75478
+ };
75479
+ const readStartTagName = (sourceBuffer, tagStartByte) => {
75480
+ const firstNameByte = sourceBuffer[tagStartByte + 1];
75481
+ if (firstNameByte === void 0 || !/[A-Za-z]/.test(String.fromCharCode(firstNameByte))) return null;
75482
+ let nameEndByte = tagStartByte + 2;
75483
+ while (nameEndByte < sourceBuffer.length && /[A-Za-z0-9:-]/.test(String.fromCharCode(sourceBuffer[nameEndByte] ?? 32))) nameEndByte++;
75484
+ return sourceBuffer.subarray(tagStartByte + 1, nameEndByte).toString("ascii").toLowerCase();
75485
+ };
75486
+ const findTagEnd = (sourceBuffer, startByte) => {
75487
+ let quoteByte = null;
75488
+ for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) {
75489
+ const byte = sourceBuffer[byteIndex];
75490
+ if (quoteByte !== null) {
75491
+ if (byte === quoteByte) quoteByte = null;
75492
+ continue;
75493
+ }
75494
+ if (byte === SINGLE_QUOTE_UTF8_BYTE || byte === DOUBLE_QUOTE_UTF8_BYTE) {
75495
+ quoteByte = byte;
75496
+ continue;
75497
+ }
75498
+ if (byte === TAG_CLOSE_UTF8_BYTE) return byteIndex;
75499
+ }
75500
+ return sourceBuffer.length;
75501
+ };
75502
+ const parseScriptAttributes = (sourceBuffer, attributesStartByte, tagEndByte) => {
75503
+ let byteIndex = attributesStartByte;
75504
+ let hasSource = false;
75505
+ let language = null;
75506
+ let scriptType = null;
75507
+ while (byteIndex < tagEndByte) {
75508
+ while (byteIndex < tagEndByte && (isHtmlWhitespace(sourceBuffer[byteIndex]) || sourceBuffer[byteIndex] === TAG_SELF_CLOSE_UTF8_BYTE)) byteIndex++;
75509
+ const attributeNameStartByte = byteIndex;
75510
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== ATTRIBUTE_ASSIGNMENT_UTF8_BYTE && sourceBuffer[byteIndex] !== TAG_SELF_CLOSE_UTF8_BYTE) byteIndex++;
75511
+ const attributeName = sourceBuffer.subarray(attributeNameStartByte, byteIndex).toString("ascii").toLowerCase();
75512
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
75513
+ let attributeValue = "";
75514
+ if (sourceBuffer[byteIndex] === ATTRIBUTE_ASSIGNMENT_UTF8_BYTE) {
75515
+ byteIndex++;
75516
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
75517
+ const quoteByte = sourceBuffer[byteIndex];
75518
+ if (quoteByte === SINGLE_QUOTE_UTF8_BYTE || quoteByte === DOUBLE_QUOTE_UTF8_BYTE) {
75519
+ const valueStartByte = byteIndex + 1;
75520
+ byteIndex = valueStartByte;
75521
+ while (byteIndex < tagEndByte && sourceBuffer[byteIndex] !== quoteByte) byteIndex++;
75522
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
75523
+ if (byteIndex < tagEndByte) byteIndex++;
75524
+ } else {
75525
+ const valueStartByte = byteIndex;
75526
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== TAG_CLOSE_UTF8_BYTE) byteIndex++;
75527
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
75528
+ }
75529
+ }
75530
+ if (attributeName === "src") hasSource = true;
75531
+ else if (attributeName === "type" && scriptType === null) scriptType = attributeValue;
75532
+ else if (attributeName === "language" && language === null) language = attributeValue;
75533
+ }
75534
+ return {
75535
+ hasSource,
75536
+ language,
75537
+ type: scriptType
75538
+ };
75539
+ };
75540
+ const isExecutableScript = (attributes) => {
75541
+ if (attributes.hasSource) return false;
75542
+ const type = attributes.type?.trim().toLowerCase() ?? "";
75543
+ if (type !== "") {
75544
+ const mimeType = type.split(";")[0]?.trim() ?? "";
75545
+ return mimeType === "module" || JAVASCRIPT_MIME_TYPES.has(mimeType);
75546
+ }
75547
+ const language = attributes.language?.trim().toLowerCase() ?? "";
75548
+ return language === "" || JAVASCRIPT_MIME_TYPES.has(`text/${language}`);
75549
+ };
75550
+ const findElementClose = (sourceBuffer, startByte, tagName) => {
75551
+ const closeTagStart = `</${tagName}`;
75552
+ for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) if (sourceBuffer[byteIndex] === TAG_OPEN_UTF8_BYTE && matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, closeTagStart) && isTagBoundary(sourceBuffer[byteIndex + closeTagStart.length])) return byteIndex;
75553
+ return sourceBuffer.length;
75554
+ };
75555
+ const prepareHtmlScriptSource = (sourceBuffer) => {
75556
+ const frontmatterEndByte = findFrontmatterEnd(sourceBuffer);
75557
+ let maskedBuffer = frontmatterEndByte > 0 ? Buffer.from(sourceBuffer) : null;
75558
+ if (maskedBuffer !== null) maskByteRange(maskedBuffer, 0, frontmatterEndByte);
75559
+ const executableScriptBodies = [];
75560
+ let byteIndex = frontmatterEndByte;
75561
+ let templateDepth = 0;
75562
+ while (byteIndex < sourceBuffer.length) {
75563
+ if (sourceBuffer[byteIndex] !== TAG_OPEN_UTF8_BYTE) {
75564
+ byteIndex++;
75565
+ continue;
75566
+ }
75567
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, COMMENT_OPEN)) {
75568
+ const commentEndByte = sourceBuffer.indexOf(COMMENT_CLOSE, byteIndex + 4);
75569
+ byteIndex = commentEndByte === -1 ? sourceBuffer.length : commentEndByte + 3;
75570
+ continue;
75571
+ }
75572
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, TEMPLATE_CLOSE) && isTagBoundary(sourceBuffer[byteIndex + TEMPLATE_CLOSE.length])) {
75573
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + TEMPLATE_CLOSE.length);
75574
+ if (templateDepth > 0) templateDepth--;
75575
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
75576
+ continue;
75577
+ }
75578
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, SCRIPT_OPEN) || !isTagBoundary(sourceBuffer[byteIndex + SCRIPT_OPEN.length])) {
75579
+ if (!isPotentialTagStart(sourceBuffer[byteIndex + 1])) {
75580
+ byteIndex++;
75581
+ continue;
75582
+ }
75583
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + 1);
75584
+ const tagName = readStartTagName(sourceBuffer, byteIndex);
75585
+ if (tagName === PLAINTEXT_TAG_NAME) break;
75586
+ if (tagName === TEMPLATE_TAG_NAME) templateDepth++;
75587
+ if (tagName !== null && RAW_TEXT_TAG_NAMES.has(tagName)) {
75588
+ const closeTagStartByte = findElementClose(sourceBuffer, tagEndByte + 1, tagName);
75589
+ if (closeTagStartByte === sourceBuffer.length) break;
75590
+ const closeTagEndByte = findTagEnd(sourceBuffer, closeTagStartByte + tagName.length + 2);
75591
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
75592
+ continue;
75593
+ }
75594
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
75595
+ continue;
75596
+ }
75597
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + SCRIPT_OPEN.length);
75598
+ if (tagEndByte === sourceBuffer.length) break;
75599
+ const bodyStartByte = tagEndByte + 1;
75600
+ const bodyEndByte = findElementClose(sourceBuffer, bodyStartByte, SCRIPT_TAG_NAME);
75601
+ const attributes = parseScriptAttributes(sourceBuffer, byteIndex + SCRIPT_OPEN.length, tagEndByte);
75602
+ if (attributes.hasSource || templateDepth > 0) {
75603
+ maskedBuffer ??= Buffer.from(sourceBuffer);
75604
+ maskByteRange(maskedBuffer, bodyStartByte, bodyEndByte);
75605
+ } else if (isExecutableScript(attributes)) executableScriptBodies.push(sourceBuffer.subarray(bodyStartByte, bodyEndByte));
75606
+ if (bodyEndByte === sourceBuffer.length) break;
75607
+ const closeTagEndByte = findTagEnd(sourceBuffer, bodyEndByte + SCRIPT_CLOSE.length);
75608
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
75609
+ }
75610
+ return {
75611
+ executableScriptBodies,
75612
+ lintBuffer: maskedBuffer ?? sourceBuffer
75613
+ };
75614
+ };
75615
+ const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
75616
+ const lintFiles = [];
75617
+ const sourcePathByLintPath = /* @__PURE__ */ new Map();
75618
+ const sizeByLintPath = /* @__PURE__ */ new Map();
75619
+ const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
75620
+ let htmlFileIndex = 0;
75621
+ let hasThreeModuleImport = false;
75622
+ for (const candidateFile of candidateFiles) {
75623
+ if (!HTML_FILE_PATTERN.test(candidateFile)) {
75624
+ lintFiles.push(candidateFile);
75625
+ continue;
75626
+ }
75627
+ const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
75628
+ const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
75629
+ const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
75630
+ if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
75631
+ const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
75632
+ NFS.writeFileSync(lintPath, lintBuffer);
75633
+ lintFiles.push(lintPath);
75634
+ sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
75635
+ sizeByLintPath.set(lintPath, sourceBuffer.length);
75636
+ hasThreeModuleImport ||= executableScriptBodies.some((scriptBody) => containsThreeModuleImport(scriptBody.toString("utf8")));
75637
+ htmlFileIndex++;
75638
+ }
75639
+ return {
75640
+ lintFiles,
75641
+ sourcePathByLintPath,
75642
+ sizeByLintPath,
75643
+ hasThreeModuleImport
75644
+ };
75645
+ };
75072
75646
  /**
75073
75647
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
75074
75648
  * the runner: once for the primary scan, once for the
@@ -75229,6 +75803,8 @@ const reactHooksJsPluginDropNote = (error) => {
75229
75803
  const runOxlint = async (options) => {
75230
75804
  const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
75231
75805
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
75806
+ const runtimeGlobals = Array.isArray(userConfig?.runtimeGlobals) ? userConfig.runtimeGlobals.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
75807
+ let unpluginAutoImportGlobalScopes = [];
75232
75808
  const severityControls = buildRuleSeverityControls(userConfig);
75233
75809
  validateRuleRegistration();
75234
75810
  resetManifestCaches();
@@ -75242,21 +75818,6 @@ const runOxlint = async (options) => {
75242
75818
  const pluginPath = resolvePluginPath();
75243
75819
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
75244
75820
  const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
75245
- const buildConfig = (overrides) => createOxlintConfig({
75246
- pluginPath,
75247
- project,
75248
- customRulesOnly,
75249
- extendsPaths: overrides.extendsPaths,
75250
- ignoredTags,
75251
- includedTags,
75252
- includeTagDefaults,
75253
- serverAuthFunctionNames,
75254
- severityControls,
75255
- userPlugins,
75256
- disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
75257
- ruleSelection: overrides.ruleSelection,
75258
- sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
75259
- });
75260
75821
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
75261
75822
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
75262
75823
  const configPath = Path.join(configDirectory, "oxlintrc.json");
@@ -75292,7 +75853,36 @@ const runOxlint = async (options) => {
75292
75853
  await yieldToEventLoop();
75293
75854
  const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
75294
75855
  const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
75856
+ unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
75857
+ rootDirectory,
75858
+ candidateFiles
75859
+ });
75860
+ const preparedHtmlSources = prepareHtmlLintSources(rootDirectory, configDirectory, candidateFiles);
75861
+ const lintFiles = preparedHtmlSources.lintFiles;
75862
+ const hasHtmlFiles = preparedHtmlSources.sourcePathByLintPath.size > 0;
75863
+ const lintProject = !project.hasThree && preparedHtmlSources.hasThreeModuleImport ? {
75864
+ ...project,
75865
+ hasThree: true
75866
+ } : project;
75867
+ const buildConfig = (overrides) => createOxlintConfig({
75868
+ pluginPath,
75869
+ project: lintProject,
75870
+ customRulesOnly,
75871
+ extendsPaths: overrides.extendsPaths,
75872
+ ignoredTags,
75873
+ includedTags,
75874
+ includeTagDefaults,
75875
+ runtimeGlobals,
75876
+ unpluginAutoImportGlobalScopes,
75877
+ serverAuthFunctionNames,
75878
+ severityControls,
75879
+ userPlugins,
75880
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
75881
+ ruleSelection: overrides.ruleSelection,
75882
+ sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
75883
+ });
75295
75884
  const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
75885
+ if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedHtmlSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
75296
75886
  const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
75297
75887
  baseArgs: passBaseArgs,
75298
75888
  files: passFiles,
@@ -75321,7 +75911,8 @@ const runOxlint = async (options) => {
75321
75911
  fileBatches: passFileBatches,
75322
75912
  rootDirectory,
75323
75913
  nodeBinaryPath,
75324
- project,
75914
+ project: lintProject,
75915
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
75325
75916
  onPartialFailure: reportPartialFailure,
75326
75917
  onAnalyzedFiles: (filePaths) => {
75327
75918
  analyzedFiles = filePaths;
@@ -75356,7 +75947,7 @@ const runOxlint = async (options) => {
75356
75947
  };
75357
75948
  }
75358
75949
  };
75359
- if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
75950
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasHtmlFiles) {
75360
75951
  const rulesetHash = computeRulesetHash({
75361
75952
  config: buildConfig({
75362
75953
  extendsPaths: [],
@@ -75514,14 +76105,15 @@ const runOxlint = async (options) => {
75514
76105
  ]);
75515
76106
  }
75516
76107
  const baseArgs = makeBaseArgs(configPath);
75517
- const fileBatches = buildFileBatches(baseArgs, candidateFiles);
76108
+ const fileBatches = buildFileBatches(baseArgs, lintFiles);
75518
76109
  let analyzedFiles = [];
75519
76110
  const runBatches = () => spawnLintBatches({
75520
76111
  baseArgs,
75521
76112
  fileBatches,
75522
76113
  rootDirectory,
75523
76114
  nodeBinaryPath,
75524
- project,
76115
+ project: lintProject,
76116
+ sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
75525
76117
  onPartialFailure,
75526
76118
  onAnalyzedFiles: (filePaths) => {
75527
76119
  analyzedFiles = filePaths;
@@ -77728,7 +78320,7 @@ const makeNoopConsole = () => ({
77728
78320
  });
77729
78321
  //#endregion
77730
78322
  //#region src/cli/utils/version.ts
77731
- const VERSION = "0.9.1-dev.5d2f66d";
78323
+ const VERSION = "0.9.1-dev.7ee59d3";
77732
78324
  //#endregion
77733
78325
  //#region src/cli/utils/json-mode.ts
77734
78326
  let context = null;
@@ -78086,13 +78678,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
78086
78678
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
78087
78679
  * standard `SENTRY_RELEASE` override.
78088
78680
  */
78089
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.1-dev.5d2f66d`;
78681
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.1-dev.7ee59d3`;
78090
78682
  /**
78091
78683
  * Deployment environment shown in Sentry's environment filter. Defaults to
78092
78684
  * `production` for tagged releases and `development` for dev/unbuilt versions,
78093
78685
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
78094
78686
  */
78095
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.1-dev.5d2f66d") ? "development" : "production");
78687
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.1-dev.7ee59d3") ? "development" : "production");
78096
78688
  /**
78097
78689
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
78098
78690
  * (set to `0` to disable tracing) and falls back to
@@ -90757,6 +91349,7 @@ const buildScanAttributes = (input) => {
90757
91349
  rulesDisabled: ruleKeys.filter((key) => ruleOverrides[key] === "off").length,
90758
91350
  fileCount: input.result?.scannedFileCount ?? null,
90759
91351
  nonJsxFileCount: input.result?.analyzedFiles?.filter((filePath) => !JSX_FILE_PATTERN.test(filePath)).length ?? null,
91352
+ htmlFileCount: input.result?.analyzedFiles?.filter((filePath) => HTML_FILE_PATTERN.test(filePath)).length ?? null,
90760
91353
  multilineDiagnosticCount: input.result?.diagnostics.filter((diagnostic) => (diagnostic.endLine ?? diagnostic.line) > diagnostic.line).length ?? null
90761
91354
  });
90762
91355
  };
@@ -96810,7 +97403,7 @@ ${highlighter.dim("Learn more:")}
96810
97403
  ${highlighter.info(CI_URL)}
96811
97404
  `;
96812
97405
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
96813
- const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
97406
+ const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS and inline HTML script source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
96814
97407
  program.action(inspectAction);
96815
97408
  program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
96816
97409
  program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
@@ -96890,4 +97483,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
96890
97483
  export { toForwardSlashes as A, highlighter as B, buildRulePriorityMap as C, resolveBlockingLevel as D, formatLearnMoreLine as E, isCiEnvironment as F, sync as G, mergeReactDoctorConfigs as H, DIAGNOSTIC_CATEGORY_BUCKETS as I, void_ as K, Progress as L, isUnicodeSupported as M, METRIC as N, isReactDoctorWorkflowInstalled as O, TUI_REPORT_DETAIL_WIDTH_FRACTION as P, Reporter as R, hasLintHardFailure as S, formatFixRecipeLine as T, resolveScanTarget as U, mapWithConcurrency as V, runPromise as W, canAnimateOnboarding as _, resolveCliInspectOptions as a, buildCodeFrame as b, detectLaunchableAgents as c, launchCliAgent as d, isShareOptedOut as f, doctorFace as g, easeOutCubic as h, selectProjects as i, findNearestPackageDirectory as j, recordCount as k, CLI_AGENT_BINARIES as l, printFooter as m, shouldFailScanGate as n, countUniqueScannedFiles as o, inspect as p, succeed$3 as q, discoverWorkspacePackages as r, setUpGitHubActions as s, exitGracefully as t, copyToClipboard as u, computeProjectedScore as v, buildSortedRuleGroups as w, buildNoScoreMessage as x, formatElapsedTime as y, getCategoryImpact as z };
96891
97484
 
96892
97485
  //# sourceMappingURL=cli.js.map
96893
- //# debugId=ea274003-c9c6-5b5c-b839-b1545ccc48fa
97486
+ //# debugId=7f26fa62-fe0c-5ae0-bc9c-97a0deb50b43