react-doctor 0.5.6-dev.5b742fa → 0.5.6-dev.5d1347e

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.
Files changed (4) hide show
  1. package/dist/cli.js +399 -250
  2. package/dist/index.js +95 -76
  3. package/dist/lsp.js +114 -98
  4. package/package.json +2 -2
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]="b4f6f7e7-99db-553a-aa15-14b646162f39")}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]="ff319d21-ecce-5f79-a822-8cb00c30fea1")}catch(e){}}();
3
3
  import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import * as NFS from "node:fs";
@@ -32724,6 +32724,7 @@ const isLargeMinifiedFile = (absolutePath) => {
32724
32724
  if (sizeBytes < 2e4) return false;
32725
32725
  return isMinifiedSource(absolutePath);
32726
32726
  };
32727
+ const isErrnoException = (error) => error instanceof Error && "code" in error;
32727
32728
  const IGNORABLE_READDIR_ERROR_CODES = new Set([
32728
32729
  "EACCES",
32729
32730
  "EPERM",
@@ -32733,11 +32734,7 @@ const IGNORABLE_READDIR_ERROR_CODES = new Set([
32733
32734
  "ELOOP",
32734
32735
  "ENAMETOOLONG"
32735
32736
  ]);
32736
- const isIgnorableReaddirError = (error) => {
32737
- if (typeof error !== "object" || error === null) return false;
32738
- const errorCode = error.code;
32739
- return typeof errorCode === "string" && IGNORABLE_READDIR_ERROR_CODES.has(errorCode);
32740
- };
32737
+ const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
32741
32738
  const readDirectoryEntries = (directoryPath) => {
32742
32739
  try {
32743
32740
  return NFS.readdirSync(directoryPath, { withFileTypes: true });
@@ -32787,7 +32784,7 @@ const readPackageJsonUncached = (packageJsonPath) => {
32787
32784
  return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
32788
32785
  } catch (error) {
32789
32786
  if (error instanceof SyntaxError) return {};
32790
- if (error instanceof Error && "code" in error) {
32787
+ if (isErrnoException(error)) {
32791
32788
  const { code } = error;
32792
32789
  if (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "ENOENT") return {};
32793
32790
  }
@@ -33512,17 +33509,13 @@ const isPackageJsonReactNativeAware = (packageJson) => {
33512
33509
  return false;
33513
33510
  };
33514
33511
  const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
33515
- const getExpoDependencySpec = (packageJson) => {
33516
- const spec = packageJson.dependencies?.expo ?? packageJson.devDependencies?.expo ?? packageJson.peerDependencies?.expo ?? packageJson.optionalDependencies?.expo;
33512
+ const getDependencySpec = (packageJson, packageName) => {
33513
+ const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
33517
33514
  return typeof spec === "string" ? spec : null;
33518
33515
  };
33519
- const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getExpoDependencySpec);
33516
+ const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
33520
33517
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
33521
- const getShopifyFlashListDependencySpec = (packageJson) => {
33522
- const spec = packageJson.dependencies?.["@shopify/flash-list"] ?? packageJson.devDependencies?.["@shopify/flash-list"] ?? packageJson.peerDependencies?.["@shopify/flash-list"] ?? packageJson.optionalDependencies?.["@shopify/flash-list"];
33523
- return typeof spec === "string" ? spec : null;
33524
- };
33525
- const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getShopifyFlashListDependencySpec);
33518
+ const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
33526
33519
  const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
33527
33520
  if (version === null || !isCatalogReference(version)) return version;
33528
33521
  const catalogName = extractCatalogName(version);
@@ -33534,11 +33527,7 @@ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson,
33534
33527
  if (!isFile(monorepoPackageJsonPath)) return version;
33535
33528
  return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
33536
33529
  };
33537
- const getNextjsDependencySpec = (packageJson) => {
33538
- const spec = packageJson.dependencies?.next ?? packageJson.devDependencies?.next ?? packageJson.peerDependencies?.next ?? packageJson.optionalDependencies?.next;
33539
- return typeof spec === "string" ? spec : null;
33540
- };
33541
- const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getNextjsDependencySpec);
33530
+ const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
33542
33531
  const getPreactVersion = (packageJson) => {
33543
33532
  return {
33544
33533
  ...packageJson.peerDependencies,
@@ -33620,6 +33609,11 @@ const ES_TARGET_YEAR_BY_NAME = {
33620
33609
  esnext: 9999
33621
33610
  };
33622
33611
  /**
33612
+ * tsconfig filenames probed when resolving a project's TypeScript
33613
+ * compiler options — the root config first, then a monorepo base config.
33614
+ */
33615
+ const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
33616
+ /**
33623
33617
  * Project-config files that `StagedFiles.materialize` copies into
33624
33618
  * the temp directory alongside staged sources so oxlint resolves
33625
33619
  * `tsconfig` / `package.json` / lint configs the same way it would
@@ -34118,6 +34112,7 @@ const isTailwindAtLeast = (detected, required) => {
34118
34112
  if (detected.major !== required.major) return detected.major > required.major;
34119
34113
  return detected.minor >= required.minor;
34120
34114
  };
34115
+ const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
34121
34116
  var InvalidGlobPatternError = class extends Error {
34122
34117
  pattern;
34123
34118
  reason;
@@ -34146,7 +34141,7 @@ const compileGlobPattern = (rawPattern) => {
34146
34141
  try {
34147
34142
  return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
34148
34143
  } catch (caughtError) {
34149
- throw new InvalidGlobPatternError(rawPattern, caughtError instanceof Error ? caughtError.message : String(caughtError));
34144
+ throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
34150
34145
  }
34151
34146
  };
34152
34147
  const compileGlobPatternsLenient = (patterns, onInvalid) => {
@@ -35328,7 +35323,6 @@ const PACKAGE_JSON_FILENAME = "package.json";
35328
35323
  const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
35329
35324
  const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
35330
35325
  const jiti = createJiti(import.meta.url);
35331
- const formatError = (error) => error instanceof Error ? error.message : String(error);
35332
35326
  const importDefaultExport = async (jitiInstance, filePath) => {
35333
35327
  const imported = await jitiInstance.import(filePath);
35334
35328
  return imported?.default ?? imported;
@@ -35360,7 +35354,7 @@ const loadModuleConfig = async (filePath) => {
35360
35354
  try {
35361
35355
  return await importDefaultExport(aliasJiti, filePath);
35362
35356
  } catch (retryError) {
35363
- throw new Error(`${formatError(error)} (retry with ${SELF_PACKAGE_IMPORT_SPECIFIER} aliased to the running react-doctor package also failed: ${formatError(retryError)})`, { cause: retryError });
35357
+ throw new Error(`${messageFromUnknown(error)} (retry with ${SELF_PACKAGE_IMPORT_SPECIFIER} aliased to the running react-doctor package also failed: ${messageFromUnknown(retryError)})`, { cause: retryError });
35364
35358
  }
35365
35359
  }
35366
35360
  };
@@ -35409,7 +35403,7 @@ const loadLegacyConfig = (directory) => {
35409
35403
  }
35410
35404
  warn(`${LEGACY_CONFIG_FILENAME} must contain an object, ignoring.`);
35411
35405
  } catch (error) {
35412
- warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${formatError(error)}`);
35406
+ warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${messageFromUnknown(error)}`);
35413
35407
  }
35414
35408
  return {
35415
35409
  status: "invalid",
@@ -35436,7 +35430,7 @@ const loadConfigFromDirectory = async (directory) => {
35436
35430
  warn(`${CONFIG_BASENAME}.${extension} must export an object, ignoring.`);
35437
35431
  sawBrokenConfigFile = true;
35438
35432
  } catch (error) {
35439
- warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${formatError(error)}`);
35433
+ warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${messageFromUnknown(error)}`);
35440
35434
  sawBrokenConfigFile = true;
35441
35435
  }
35442
35436
  }
@@ -36472,15 +36466,10 @@ const buildCapabilities = (project) => {
36472
36466
  }
36473
36467
  if (project.tailwindVersion !== null) {
36474
36468
  capabilities.add("tailwind");
36475
- const tailwind = parseTailwindMajorMinor(project.tailwindVersion);
36476
- if (isTailwindAtLeast(tailwind, {
36469
+ if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
36477
36470
  major: 3,
36478
36471
  minor: 4
36479
36472
  })) capabilities.add("tailwind:3.4");
36480
- if (tailwind !== null && isTailwindAtLeast(tailwind, {
36481
- major: 4,
36482
- minor: 0
36483
- })) capabilities.add("tailwind:4");
36484
36473
  }
36485
36474
  if (project.zodVersion !== null) {
36486
36475
  capabilities.add("zod");
@@ -36669,7 +36658,7 @@ const readIgnoreFile = (filePath) => {
36669
36658
  try {
36670
36659
  content = NFS.readFileSync(filePath, "utf-8");
36671
36660
  } catch (error) {
36672
- const errnoCode = error?.code;
36661
+ const errnoCode = isErrnoException(error) ? error.code : void 0;
36673
36662
  if (errnoCode && errnoCode !== "ENOENT") runSync(warn$1(`Could not read ignore file ${filePath}: ${errnoCode}`));
36674
36663
  return [];
36675
36664
  }
@@ -36710,8 +36699,8 @@ const collectIgnorePatterns = (rootDirectory) => {
36710
36699
  cachedPatternsByRoot.set(rootDirectory, patterns);
36711
36700
  return patterns;
36712
36701
  };
36702
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36713
36703
  const KNIP_JSON_FILENAME = "knip.json";
36714
- const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36715
36704
  const readJsonFileSafe = (filePath) => {
36716
36705
  let rawContents;
36717
36706
  try {
@@ -36727,10 +36716,10 @@ const readJsonFileSafe = (filePath) => {
36727
36716
  };
36728
36717
  const readKnipConfig = (rootDirectory) => {
36729
36718
  const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
36730
- if (isRecord$1(knipJson)) return knipJson;
36719
+ if (isRecord(knipJson)) return knipJson;
36731
36720
  const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
36732
- const packageKnipConfig = isRecord$1(packageJson) ? packageJson.knip : null;
36733
- return isRecord$1(packageKnipConfig) ? packageKnipConfig : null;
36721
+ const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
36722
+ return isRecord(packageKnipConfig) ? packageKnipConfig : null;
36734
36723
  };
36735
36724
  const normalizePatternList = (value) => {
36736
36725
  if (typeof value === "string" && value.length > 0) return [value];
@@ -36742,10 +36731,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
36742
36731
  return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
36743
36732
  };
36744
36733
  const collectKnipWorkspacePatterns = (workspaces, settingName) => {
36745
- if (!isRecord$1(workspaces)) return [];
36734
+ if (!isRecord(workspaces)) return [];
36746
36735
  const patterns = [];
36747
36736
  for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
36748
- if (!isRecord$1(workspaceConfig)) continue;
36737
+ if (!isRecord(workspaceConfig)) continue;
36749
36738
  patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
36750
36739
  }
36751
36740
  return patterns;
@@ -36790,8 +36779,6 @@ const toCanonicalPath = (filePath) => {
36790
36779
  };
36791
36780
  const DEAD_CODE_PLUGIN = "deslop";
36792
36781
  const DEAD_CODE_CATEGORY = "Maintainability";
36793
- const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
36794
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36795
36782
  const DEAD_CODE_WORKER_SCRIPT = `
36796
36783
  const inputChunks = [];
36797
36784
  process.stdin.on("data", (chunk) => inputChunks.push(chunk));
@@ -36849,7 +36836,7 @@ process.stdin.on("end", () => {
36849
36836
  });
36850
36837
  `;
36851
36838
  const resolveTsConfigPath = (rootDirectory) => {
36852
- for (const filename of TSCONFIG_FILENAMES$1) {
36839
+ for (const filename of TSCONFIG_FILENAMES) {
36853
36840
  const candidate = Path.join(rootDirectory, filename);
36854
36841
  if (NFS.existsSync(candidate)) return candidate;
36855
36842
  }
@@ -37230,15 +37217,13 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
37230
37217
  })()) }));
37231
37218
  static layerOf = (diagnostics) => succeed$3(DeadCode, DeadCode.of({ run: () => fromIterable$1(diagnostics) }));
37232
37219
  };
37233
- const createNodeReadFileLinesSync = (rootDirectory) => {
37234
- return (filePath) => {
37235
- const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.join(rootDirectory, filePath);
37236
- try {
37237
- return NFS.readFileSync(absolutePath, "utf-8").split("\n");
37238
- } catch {
37239
- return null;
37240
- }
37241
- };
37220
+ const createNodeReadFileLinesSync = (rootDirectory) => (filePath) => {
37221
+ const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.join(rootDirectory, filePath);
37222
+ try {
37223
+ return NFS.readFileSync(absolutePath, "utf-8").split("\n");
37224
+ } catch {
37225
+ return null;
37226
+ }
37242
37227
  };
37243
37228
  var Files = class Files extends Service()("react-doctor/Files") {
37244
37229
  static layerNode = succeed$3(Files, Files.of({
@@ -37449,7 +37434,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
37449
37434
  directory: input.directory,
37450
37435
  cause
37451
37436
  }) });
37452
- }));
37437
+ }), withSpan("git.exec", { attributes: {
37438
+ "git.command": input.command,
37439
+ "git.subcommand": input.args[0] ?? ""
37440
+ } }));
37453
37441
  const runGit = (directory, args) => runCommand({
37454
37442
  command: "git",
37455
37443
  args,
@@ -37477,7 +37465,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37477
37465
  ]);
37478
37466
  if (candidates.status !== 0) return null;
37479
37467
  return trimOrNull(candidates.stdout.split("\n")[0] ?? "");
37480
- });
37468
+ }).pipe(withSpan("Git.defaultBranch"));
37481
37469
  const branchExists = (directory, branch) => runGit(directory, [
37482
37470
  "rev-parse",
37483
37471
  "--verify",
@@ -37524,7 +37512,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37524
37512
  const result = resultOption.value;
37525
37513
  if (result.status !== 0) return null;
37526
37514
  return parseGithubViewerPermission(result.stdout);
37527
- }).pipe(catch_$1(() => succeed$2(null)));
37515
+ }).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.githubViewerPermission"));
37528
37516
  /**
37529
37517
  * Resolves a `--diff A..B` / `A...B` commit range into a changed-file
37530
37518
  * selection. Each endpoint is validated with `isSafeGitRevision`
@@ -37638,7 +37626,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37638
37626
  changedFiles: splitNullSeparated(diff.stdout),
37639
37627
  isCurrentChanges: false
37640
37628
  };
37641
- }),
37629
+ }).pipe(withSpan("Git.diffSelection")),
37642
37630
  stagedFilePaths: (directory) => runGit(directory, [
37643
37631
  "diff",
37644
37632
  "--cached",
@@ -37680,7 +37668,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37680
37668
  status: result.status,
37681
37669
  stdout: result.stdout
37682
37670
  };
37683
- }),
37671
+ }).pipe(withSpan("Git.grep")),
37684
37672
  changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
37685
37673
  if (files.length === 0) return [];
37686
37674
  if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
@@ -37696,7 +37684,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37696
37684
  ]);
37697
37685
  if (result.status !== 0) return null;
37698
37686
  return parseChangedLineRanges(result.stdout);
37699
- })
37687
+ }).pipe(withSpan("Git.changedLineRanges"))
37700
37688
  });
37701
37689
  })).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
37702
37690
  /**
@@ -37911,7 +37899,7 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
37911
37899
  for (const [absolutePath, originalContent] of originalContents) try {
37912
37900
  NFS.writeFileSync(absolutePath, originalContent);
37913
37901
  } catch (error) {
37914
- process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${error instanceof Error ? error.message : String(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
37902
+ process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
37915
37903
  }
37916
37904
  };
37917
37905
  const onExit = () => restore();
@@ -38017,7 +38005,7 @@ const resolveUserPlugin = (spec, configSourceDirectory) => {
38017
38005
  try {
38018
38006
  resolvedSpecifier = isRelative ? Path.resolve(configSourceDirectory, spec) : candidateRequire.resolve(spec);
38019
38007
  } catch (error) {
38020
- warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${error instanceof Error ? error.message : String(error)}`);
38008
+ warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${messageFromUnknown(error)}`);
38021
38009
  return null;
38022
38010
  }
38023
38011
  const { name, ruleNames } = readPluginShape(resolvedSpecifier, (target) => candidateRequire(target));
@@ -38089,8 +38077,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
38089
38077
  }
38090
38078
  return enabled;
38091
38079
  };
38092
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
38093
- const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
38080
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
38081
+ const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
38094
38082
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
38095
38083
  const jsPlugins = [];
38096
38084
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -38150,7 +38138,6 @@ const resolveOxlintBinary = () => {
38150
38138
  return Path.join(oxlintPackageDirectory, "bin", "oxlint");
38151
38139
  };
38152
38140
  const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
38153
- const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
38154
38141
  const resolveTsConfigRelativePath = (rootDirectory) => {
38155
38142
  for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
38156
38143
  return null;
@@ -38522,7 +38509,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
38522
38509
  const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
38523
38510
  let currentNode = identifier.parent;
38524
38511
  while (currentNode) {
38525
- if (isScopeNode(currentNode)) {
38512
+ if (isScopeBoundary(currentNode)) {
38526
38513
  if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
38527
38514
  }
38528
38515
  if (currentNode === sourceFile) return false;
@@ -38613,11 +38600,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
38613
38600
  });
38614
38601
  return resolution;
38615
38602
  };
38616
- const isScopeNode = isScopeBoundary;
38617
38603
  const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
38618
38604
  let currentNode = identifier.parent;
38619
38605
  while (currentNode) {
38620
- if (isScopeNode(currentNode)) {
38606
+ if (isScopeBoundary(currentNode)) {
38621
38607
  const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
38622
38608
  if (resolution) return resolution;
38623
38609
  }
@@ -38787,9 +38773,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
38787
38773
  try {
38788
38774
  parsed = JSON.parse(sanitizedStdout);
38789
38775
  } catch {
38790
- throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
38776
+ throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
38791
38777
  }
38792
- if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
38778
+ if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
38793
38779
  const minifiedFileCache = /* @__PURE__ */ new Map();
38794
38780
  const isMinifiedDiagnosticFile = (filename) => {
38795
38781
  const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
@@ -38865,7 +38851,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
38865
38851
  child.kill("SIGKILL");
38866
38852
  reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
38867
38853
  kind: "timeout",
38868
- detail: `${spawnTimeoutMs / 1e3}s budget exceeded`
38854
+ detail: `${spawnTimeoutMs / MILLISECONDS_PER_SECOND}s budget exceeded`
38869
38855
  }) }));
38870
38856
  }, spawnTimeoutMs);
38871
38857
  timeoutHandle.unref?.();
@@ -39080,6 +39066,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
39080
39066
  NFS.closeSync(fileHandle);
39081
39067
  }
39082
39068
  };
39069
+ const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
39070
+ /**
39071
+ * Detects an oxlint config-load crash caused by the optional
39072
+ * `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
39073
+ * builds the partial-failure note for it; returns `null` when the failure
39074
+ * was anything else.
39075
+ *
39076
+ * oxlint prints a framed error to stdout (not stderr) and exits non-zero
39077
+ * when a `jsPlugins` entry can't be imported; that non-JSON stdout
39078
+ * surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
39079
+ * config load on it, leaving the plugin in would drop every curated
39080
+ * react-doctor diagnostic too — so the caller retries with the plugin
39081
+ * stripped (issue #833). Both markers sit at the start of oxlint's
39082
+ * message, so they survive the `preview` slice even for deep pnpm paths.
39083
+ */
39084
+ const reactHooksJsPluginDropNote = (error) => {
39085
+ if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
39086
+ const { preview } = error.reason;
39087
+ if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
39088
+ const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
39089
+ return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
39090
+ };
39083
39091
  /**
39084
39092
  * The oxlint runner. Composed of three pieces in `runners/oxlint/`:
39085
39093
  *
@@ -39107,15 +39115,16 @@ const runOxlint = async (options) => {
39107
39115
  const pluginPath = resolvePluginPath();
39108
39116
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
39109
39117
  const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
39110
- const buildConfig = (extendsForThisAttempt) => createOxlintConfig({
39118
+ const buildConfig = (overrides) => createOxlintConfig({
39111
39119
  pluginPath,
39112
39120
  project,
39113
39121
  customRulesOnly,
39114
- extendsPaths: extendsForThisAttempt,
39122
+ extendsPaths: overrides.extendsPaths,
39115
39123
  ignoredTags,
39116
39124
  serverAuthFunctionNames,
39117
39125
  severityControls,
39118
- userPlugins
39126
+ userPlugins,
39127
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
39119
39128
  });
39120
39129
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
39121
39130
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
@@ -39151,12 +39160,22 @@ const runOxlint = async (options) => {
39151
39160
  outputMaxBytes,
39152
39161
  concurrency: options.concurrency
39153
39162
  });
39154
- writeOxlintConfig(configPath, buildConfig(extendsPaths));
39163
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
39155
39164
  try {
39156
39165
  return await runBatches();
39157
39166
  } catch (error) {
39167
+ const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
39168
+ if (reactHooksJsDropNote !== null) {
39169
+ writeOxlintConfig(configPath, buildConfig({
39170
+ extendsPaths,
39171
+ disableReactHooksJsPlugin: true
39172
+ }));
39173
+ const diagnostics = await runBatches();
39174
+ onPartialFailure?.(reactHooksJsDropNote);
39175
+ return diagnostics;
39176
+ }
39158
39177
  if (extendsPaths.length === 0) throw error;
39159
- writeOxlintConfig(configPath, buildConfig([]));
39178
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
39160
39179
  return await runBatches();
39161
39180
  }
39162
39181
  } finally {
@@ -39954,7 +39973,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
39954
39973
  }))))))));
39955
39974
  const deadCodeFailureState = yield* get$2(deadCodeFailure);
39956
39975
  const scanElapsedMilliseconds = Date.now() - scanStartTime;
39957
- const scanElapsedSeconds = (scanElapsedMilliseconds / 1e3).toFixed(1);
39976
+ const scanElapsedSeconds = (scanElapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1);
39958
39977
  if (!lintFailureState.didFail) if (deadCodeFailureState.didFail) yield* scanProgress.fail(DEAD_CODE_FAIL_TEXT);
39959
39978
  else if (input.suppressScanSummary) yield* scanProgress.stop();
39960
39979
  else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
@@ -40168,7 +40187,7 @@ const materializeSourceTree = (input) => gen(function* () {
40168
40187
  static layerNode = effect(StagedFiles, gen(function* () {
40169
40188
  const git = yield* Git;
40170
40189
  return StagedFiles.of({
40171
- discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile))),
40190
+ discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
40172
40191
  materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
40173
40192
  directory,
40174
40193
  files: stagedFiles,
@@ -40178,7 +40197,7 @@ const materializeSourceTree = (input) => gen(function* () {
40178
40197
  tempDirectory: tree.tempDirectory,
40179
40198
  stagedFiles: tree.materializedFiles,
40180
40199
  cleanup: tree.cleanup
40181
- })))
40200
+ })), withSpan("StagedFiles.materialize"))
40182
40201
  });
40183
40202
  }));
40184
40203
  /**
@@ -40576,4 +40595,4 @@ const toJsonReport = (result, options) => buildJsonReport({
40576
40595
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
40577
40596
 
40578
40597
  //# sourceMappingURL=index.js.map
40579
- //# debugId=b4f6f7e7-99db-553a-aa15-14b646162f39
40598
+ //# debugId=ff319d21-ecce-5f79-a822-8cb00c30fea1