react-doctor 0.2.10 → 0.2.11-dev.f036b0f

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
  import { i as __toESM, n as __exportAll, r as __require, t as __commonJSMin } from "./rolldown-runtime-uZX_iqCz.js";
2
- import { A as isReactDoctorError, C as filterSourceFiles, D as groupBy, E as getDiffInfo, F as runInspect, I as toRelativePath, M as listWorkspacePackages, N as resolveScanTarget, O as highlighter, P as restoreLegacyThrow, S as filterDiagnosticsForSurface, T as formatReactDoctorError, _ as Score, a as DeadCode, b as buildJsonReportError, c as LintPartialFailures, d as OXLINT_NODE_REQUIREMENT, f as Progress, g as SKILL_NAME, h as SHARE_BASE_URL, i as Config, j as layerOtlp, k as isMonorepoRoot, l as Linter, m as Reporter, o as Files, p as Project, r as CANONICAL_GITHUB_URL, s as Git, t as cliLogger, u as NodeResolver, v as StagedFiles, w as formatErrorChain, x as discoverReactSubprojects, y as buildJsonReport } from "./cli-logger-BRBUS1pE.js";
2
+ import { A as isReactDoctorError, C as filterSourceFiles, D as groupBy, E as getDiffInfo, F as runInspect, I as toRelativePath, M as listWorkspacePackages, N as resolveScanTarget, O as highlighter, P as restoreLegacyThrow, S as filterDiagnosticsForSurface, T as formatReactDoctorError, _ as Score, a as DeadCode, b as buildJsonReportError, c as LintPartialFailures, d as OXLINT_NODE_REQUIREMENT, f as Progress, g as SKILL_NAME, h as SHARE_BASE_URL, i as Config, j as layerOtlp, k as isMonorepoRoot, l as Linter, m as Reporter, o as Files, p as Project, r as CANONICAL_GITHUB_URL, s as Git, t as cliLogger, u as NodeResolver, v as StagedFiles, w as formatErrorChain, x as discoverReactSubprojects, y as buildJsonReport } from "./cli-logger-Df45H6Lw.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { execFileSync, execSync } from "node:child_process";
5
5
  import path, { join } from "node:path";
@@ -6666,7 +6666,7 @@ const resolveOxlintNodeEffect = (isLintEnabled, isQuiet) => Effect.gen(function*
6666
6666
  const resolveOxlintNode = (isLintEnabled, isQuiet) => Effect.runPromise(resolveOxlintNodeEffect(isLintEnabled, isQuiet).pipe(Effect.provide(NodeResolver.layerNode)));
6667
6667
  //#endregion
6668
6668
  //#region src/cli/utils/version.ts
6669
- const VERSION = "0.2.10";
6669
+ const VERSION = "0.2.11-dev.f036b0f";
6670
6670
  //#endregion
6671
6671
  //#region src/inspect.ts
6672
6672
  const silentConsole = makeNoopConsole();
@@ -6764,9 +6764,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
6764
6764
  const output = await Effect.runPromise(restoreLegacyThrow(programWithLayers));
6765
6765
  const didLintFail = lintBindingMissing || output.didLintFail;
6766
6766
  const lintFailureReason = lintBindingMissing ? `oxlint native binding not found for Node ${process.version}; expected one matching ${OXLINT_NODE_REQUIREMENT}` : output.lintFailureReason;
6767
- const lintFailureReasonTag = output.lintFailureReasonTag;
6768
- const isNativeBindingFailure = lintFailureReasonTag === "OxlintUnavailable" || lintFailureReasonTag === "OxlintSpawnFailed";
6769
- if (!options.scoreOnly && !lintBindingMissing && output.didLintFail && lintFailureReason !== null) if (isNativeBindingFailure && /native binding/.test(lintFailureReason)) runConsole(Console.log(highlighter.gray(` Upgrade to Node ${OXLINT_NODE_REQUIREMENT} or run: npx -p oxlint@latest react-doctor@latest`)));
6767
+ if (!options.scoreOnly && !lintBindingMissing && output.didLintFail && lintFailureReason !== null) if (output.lintFailureReasonKind === "native-binding-missing") runConsole(Console.log(highlighter.gray(` Upgrade to Node ${OXLINT_NODE_REQUIREMENT} or run: npx -p oxlint@latest react-doctor@latest`)));
6770
6768
  else runConsole(Console.error(highlighter.error(lintFailureReason)));
6771
6769
  const inspectDiagnostics = output.diagnostics;
6772
6770
  const score = didLintFail ? null : output.score;
@@ -7463,7 +7461,7 @@ const warnSetupPromptFailure = async (options, error) => {
7463
7461
  return;
7464
7462
  }
7465
7463
  try {
7466
- const { cliLogger } = await import("./cli-logger-BRBUS1pE.js").then((n) => n.n);
7464
+ const { cliLogger } = await import("./cli-logger-Df45H6Lw.js").then((n) => n.n);
7467
7465
  cliLogger.warn(message);
7468
7466
  } catch {}
7469
7467
  };
@@ -7566,12 +7564,14 @@ const resolveDiffMode = async (diffInfo, effectiveDiff, shouldSkipPrompts, isQui
7566
7564
  message: "Choose what to scan",
7567
7565
  choices: [{
7568
7566
  title: "Full codebase",
7567
+ description: "Scan every source file",
7569
7568
  value: "full"
7570
7569
  }, {
7571
- title: `Changed files (${changedSourceFiles.length})`,
7570
+ title: diffInfo.isCurrentChanges ? `Uncommitted changes (${changedSourceFiles.length})` : `Changed files on ${diffInfo.currentBranch ?? "this branch"} (${changedSourceFiles.length})`,
7571
+ description: diffInfo.isCurrentChanges ? "Compare working tree changes against HEAD" : `Compare against ${diffInfo.baseBranch} from the branch merge-base`,
7572
7572
  value: "branch"
7573
7573
  }],
7574
- initial: 0
7574
+ initial: diffInfo.isCurrentChanges ? 0 : 1
7575
7575
  });
7576
7576
  return scanScope === "branch";
7577
7577
  };
@@ -7601,13 +7601,13 @@ const VALID_FAIL_ON_LEVELS = new Set([
7601
7601
  "warning",
7602
7602
  "none"
7603
7603
  ]);
7604
- const DEFAULT_FAIL_ON_LEVEL = "error";
7604
+ const DEFAULT_FAIL_ON_LEVEL = "none";
7605
7605
  const isValidFailOnLevel = (level) => VALID_FAIL_ON_LEVELS.has(level);
7606
7606
  const resolveFailOnLevel = (flags, userConfig) => {
7607
7607
  const sourceValue = flags.failOn ?? userConfig?.failOn ?? DEFAULT_FAIL_ON_LEVEL;
7608
7608
  if (isValidFailOnLevel(sourceValue)) return sourceValue;
7609
- cliLogger.warn(`Invalid failOn level "${sourceValue}". Expected one of: error, warning, none. Falling back to "none".`);
7610
- return "none";
7609
+ cliLogger.warn(`Invalid failOn level "${sourceValue}". Expected one of: error, warning, none. Falling back to "${DEFAULT_FAIL_ON_LEVEL}".`);
7610
+ return DEFAULT_FAIL_ON_LEVEL;
7611
7611
  };
7612
7612
  //#endregion
7613
7613
  //#region src/cli/utils/resolve-project-diff-include-paths.ts
@@ -7892,7 +7892,14 @@ const inspectAction = async (directory, flags) => {
7892
7892
  cliLogger.log(`Scanning ${highlighter.info(`${stagedFiles.length}`)} staged files...`);
7893
7893
  cliLogger.break();
7894
7894
  }
7895
- const snapshot = await materializeStagedFiles(resolvedDirectory, stagedFiles, mkdtempSync(path.join(tmpdir(), STAGED_FILES_TEMP_DIR_PREFIX)));
7895
+ const tempDirectory = mkdtempSync(path.join(tmpdir(), STAGED_FILES_TEMP_DIR_PREFIX));
7896
+ const snapshot = await materializeStagedFiles(resolvedDirectory, stagedFiles, tempDirectory).catch((error) => {
7897
+ rmSync(tempDirectory, {
7898
+ recursive: true,
7899
+ force: true
7900
+ });
7901
+ throw error;
7902
+ });
7896
7903
  try {
7897
7904
  const scanResult = await inspect(snapshot.tempDirectory, {
7898
7905
  ...scanOptions,
@@ -7901,7 +7908,7 @@ const inspectAction = async (directory, flags) => {
7901
7908
  });
7902
7909
  const remappedDiagnostics = scanResult.diagnostics.map((diagnostic) => ({
7903
7910
  ...diagnostic,
7904
- filePath: path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(snapshot.tempDirectory, resolvedDirectory) : diagnostic.filePath
7911
+ filePath: path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(snapshot.tempDirectory, () => resolvedDirectory) : diagnostic.filePath
7905
7912
  }));
7906
7913
  finalizeScans({
7907
7914
  diagnostics: remappedDiagnostics,
@@ -9139,7 +9146,7 @@ const stripUnknownCliFlags = (argv) => {
9139
9146
  //#region src/cli/index.ts
9140
9147
  process.on("SIGINT", exitGracefully);
9141
9148
  process.on("SIGTERM", exitGracefully);
9142
- 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("--verbose", "show every rule and per-file details (default shows top 3 rules)").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("-y, --yes", "skip prompts, scan all workspace projects").option("--full", "force a full scan (overrides any `diff` value in config or `--diff`)").option("--project <name>", "select workspace project (comma-separated for multiple)").option("--diff [base]", "scan only files changed vs base branch (pass `false` to disable; overridden by --full)").option("--no-score", "skip the score API and the share URL").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--fail-on <level>", "exit with error code on diagnostics: error, warning, none (default: error)").option("--annotations", "output diagnostics as GitHub Actions annotations").option("--pr-comment", "tune CLI output for sticky PR comments (drops weak-signal rule families like `design` from the printed list and the fail-on gate; configure via config.surfaces)").option("--explain <file:line>", "diagnose why a rule fired or why a suppression didn't apply at a specific location").option("--why <file:line>", "alias for --explain").option("--respect-inline-disables", "respect inline `// eslint-disable*` / `// oxlint-disable*` comments (default)").option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").addHelpText("after", `
9149
+ 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("--verbose", "show every rule and per-file details (default shows top 3 rules)").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("-y, --yes", "skip prompts, scan all workspace projects").option("--full", "force a full scan (overrides any `diff` value in config or `--diff`)").option("--project <name>", "select workspace project (comma-separated for multiple)").option("--diff [base]", "scan only files changed vs base branch (pass `false` to disable; overridden by --full)").option("--no-score", "skip the score API and the share URL").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--fail-on <level>", "exit with error code on diagnostics: error, warning, none (default: none)").option("--annotations", "output diagnostics as GitHub Actions annotations").option("--pr-comment", "tune CLI output for sticky PR comments (drops weak-signal rule families like `design` from the printed list and the fail-on gate; configure via config.surfaces)").option("--explain <file:line>", "diagnose why a rule fired or why a suppression didn't apply at a specific location").option("--why <file:line>", "alias for --explain").option("--respect-inline-disables", "respect inline `// eslint-disable*` / `// oxlint-disable*` comments (default)").option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").addHelpText("after", `
9143
9150
  ${highlighter.dim("Configuration:")}
9144
9151
  Place a ${highlighter.info("react-doctor.config.json")} (or ${highlighter.info("\"reactDoctor\"")} key in your package.json) in the project root.
9145
9152
  CLI flags always override config values. See the README for the full schema.
package/dist/index.d.ts CHANGED
@@ -310,15 +310,17 @@ interface ProjectInfo {
310
310
  hasReactCompiler: boolean;
311
311
  hasTanStackQuery: boolean;
312
312
  /**
313
- * `true` when `preact` is declared anywhere in the project's
314
- * dependency manifest. Drives the `preact` capability in
315
- * `buildCapabilities`, which gates every `preact-*` rule. Modeled
316
- * on `hasTanStackQuery` rather than the `framework` field because
317
- * the dominant Preact setup today is Preact-on-Vite — those
318
- * projects classify as `framework: "vite"` for build-tool reasons
319
- * but still need Preact-specific rules to fire.
313
+ * The declared `preact` version spec, or `null` when Preact isn't a
314
+ * dependency. Parallels `reactVersion` so a React-compatible runtime is
315
+ * modeled the same way React is. Drives the `preact` capability in
316
+ * `buildCapabilities` (which gates every `preact-*` rule) — keyed off
317
+ * this rather than `framework` because the dominant Preact setup
318
+ * (Preact-on-Vite) classifies as `framework: "vite"` but still needs
319
+ * Preact rules to fire.
320
320
  */
321
- hasPreact: boolean;
321
+ preactVersion: string | null;
322
+ /** Parsed major from `preactVersion`, or `null` when absent/unparseable. Mirrors `reactMajorVersion`. */
323
+ preactMajorVersion: number | null;
322
324
  /**
323
325
  * `true` when the project (or any of its workspace packages) declares
324
326
  * React Native or Expo as a dependency. Enables the `react-native`
@@ -333,6 +335,13 @@ interface ProjectInfo {
333
335
  * — no `rn-*` rules load for the project at all.
334
336
  */
335
337
  hasReactNativeWorkspace: boolean;
338
+ /**
339
+ * `true` when the project (or any of its workspace packages) declares
340
+ * `react-native-reanimated`. Lets diagnostics surface reanimated's
341
+ * Compiler-compatible `.get()` / `.set()` accessors only where they
342
+ * apply, instead of on every React Native project.
343
+ */
344
+ hasReanimated: boolean;
336
345
  sourceFileCount: number;
337
346
  }
338
347
  //#endregion