react-doctor 0.7.1-dev.64452aa → 0.7.1-dev.d353dad

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]="57f4381b-7060-58c6-88a4-95b4c97d3b74")}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]="47338856-c658-5c78-a5e2-e871c2dafaa7")}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";
@@ -36262,6 +36262,23 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
36262
36262
  const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
36263
36263
  const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
36264
36264
  const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
36265
+ /**
36266
+ * The chain of ancestor directories of `startDirectory`, nearest first, up to
36267
+ * and including the filesystem root. With `includeStart`, the chain begins at
36268
+ * `startDirectory` itself; otherwise at its parent. The one place the "walk up
36269
+ * the tree" traversal is expressed, so each caller adds only its own match /
36270
+ * stop policy instead of re-deriving the `path.dirname` loop.
36271
+ */
36272
+ const ancestorDirectories = (startDirectory, { includeStart }) => {
36273
+ const directories = [];
36274
+ let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
36275
+ while (true) {
36276
+ directories.push(currentDirectory);
36277
+ const parentDirectory = Path.dirname(currentDirectory);
36278
+ if (parentDirectory === currentDirectory) return directories;
36279
+ currentDirectory = parentDirectory;
36280
+ }
36281
+ };
36265
36282
  const cachedPackageJsons = /* @__PURE__ */ new Map();
36266
36283
  const readPackageJsonUncached = (packageJsonPath) => {
36267
36284
  try {
@@ -36292,11 +36309,7 @@ const isMonorepoRoot = (directory) => {
36292
36309
  return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);
36293
36310
  };
36294
36311
  const findMonorepoRoot = (startDirectory) => {
36295
- let currentDirectory = Path.dirname(startDirectory);
36296
- while (currentDirectory !== Path.dirname(currentDirectory)) {
36297
- if (isMonorepoRoot(currentDirectory)) return currentDirectory;
36298
- currentDirectory = Path.dirname(currentDirectory);
36299
- }
36312
+ for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) if (isMonorepoRoot(directory)) return directory;
36300
36313
  return null;
36301
36314
  };
36302
36315
  /**
@@ -36942,6 +36955,74 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
36942
36955
  framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceInfo.framework
36943
36956
  };
36944
36957
  };
36958
+ /**
36959
+ * Walk up from `startDirectory` to the nearest ancestor that owns a
36960
+ * `package.json`, stopping at (and including) the enclosing project boundary
36961
+ * — the working tree's git root or a monorepo root. Lets a scan of a package
36962
+ * subfolder that has no `package.json` of its own adopt the nearest enclosing
36963
+ * package as its project root, so it inherits that package's dependency +
36964
+ * framework detection instead of synthesizing an empty (React-blind) project.
36965
+ *
36966
+ * Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
36967
+ * most specific owning package (a leaf workspace, not just the repo root), so
36968
+ * a subfolder of one workspace no longer borrows a sibling's capabilities.
36969
+ *
36970
+ * Returns `null` when no ancestor `package.json` exists inside the project
36971
+ * boundary (a loose tree of files, or a subfolder of a package-less repo).
36972
+ */
36973
+ const findNearestAncestorPackageJson = (startDirectory) => {
36974
+ if (isProjectBoundary(startDirectory)) return null;
36975
+ for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
36976
+ if (isFile(Path.join(directory, "package.json"))) return directory;
36977
+ if (isProjectBoundary(directory)) return null;
36978
+ }
36979
+ return null;
36980
+ };
36981
+ /**
36982
+ * Last-resort React detection: locate React the way Node's `node_modules`
36983
+ * resolution would from `directory` — check each `node_modules/react` up the
36984
+ * tree — but bounded to the enclosing repo so a globally installed React can't
36985
+ * masquerade as the project's version. Stops at (and including) the nearest
36986
+ * project boundary — the git root or a monorepo root — and returns the first
36987
+ * installed `version`.
36988
+ *
36989
+ * Makes "React is installed and importable" ⇒ "React is detected" an invariant
36990
+ * for packages whose only React declaration is a version-less spec
36991
+ * (`workspace:*`, `*`, a dist-tag) or where React lives solely in a hoisted
36992
+ * `node_modules` the declaration walks never reach — the profile of a component
36993
+ * package inside a monorepo. Matching the `node_modules/react` entry rather than
36994
+ * its realpath means a project whose `node_modules` is symlinked elsewhere (a
36995
+ * Docker volume, a shared store) still counts, while a global install outside
36996
+ * the repo does not.
36997
+ *
36998
+ * Returns `null` when React isn't installed within the repo or its package.json
36999
+ * carries no version string. A tree with no boundary marker at all bounds the
37000
+ * search to `directory`, so a dependency hoisted above the scanned package there
37001
+ * is conservatively not adopted.
37002
+ */
37003
+ /**
37004
+ * The nearest enclosing project boundary (git root or monorepo root), or
37005
+ * `directory` itself when the scan target sits outside any repo. Bounds the
37006
+ * node_modules walk so a React hoisted anywhere inside the repo counts, but a
37007
+ * React in an ancestor above the repo — a home-directory or global
37008
+ * `node_modules` — can't leak in.
37009
+ */
37010
+ const findContainmentRoot = (directory) => {
37011
+ for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) if (isProjectBoundary(ancestorDirectory)) return ancestorDirectory;
37012
+ return directory;
37013
+ };
37014
+ const resolveInstalledReactVersion = (directory) => {
37015
+ const containmentRoot = findContainmentRoot(directory);
37016
+ for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) {
37017
+ const reactPackageJsonPath = Path.join(ancestorDirectory, "node_modules", "react", "package.json");
37018
+ if (isFile(reactPackageJsonPath)) {
37019
+ const installedVersion = readPackageJson$1(reactPackageJsonPath).version;
37020
+ return typeof installedVersion === "string" ? installedVersion : null;
37021
+ }
37022
+ if (ancestorDirectory === containmentRoot) return null;
37023
+ }
37024
+ return null;
37025
+ };
36945
37026
  const findInWorkspacePackageJsons = (rootDirectory, rootPackageJson, select) => {
36946
37027
  const rootValue = select(rootPackageJson);
36947
37028
  if (rootValue !== null) return rootValue;
@@ -37278,19 +37359,20 @@ const discoverReactSubprojects = (rootDirectory) => {
37278
37359
  const cachedProjectInfos = /* @__PURE__ */ new Map();
37279
37360
  /**
37280
37361
  * Build a `ProjectInfo` for a directory that has no `package.json` of
37281
- * its own — a monorepo subfolder like `repo/packages`, or any loose tree
37282
- * of TypeScript/JavaScript files. Dependency + framework detection is
37283
- * inherited from the enclosing workspace root when there is one, so
37284
- * scanning a subdirectory of a React monorepo still gets the React
37285
- * capabilities; a standalone non-React directory simply scans with the
37286
- * framework-agnostic rules. Throws only when the directory has nothing
37287
- * to scan (no enclosing project and no source files of its own).
37362
+ * its own — a package subfolder like `repo/packages` or `app/src/features`,
37363
+ * or any loose tree of TypeScript/JavaScript files. Dependency + framework
37364
+ * detection is inherited from the nearest enclosing package (a leaf
37365
+ * workspace, a plain app root, or a monorepo root — whichever is closest,
37366
+ * bounded by the git root), so scanning a subdirectory of a React project
37367
+ * still gets the React capabilities; a standalone non-React directory simply
37368
+ * scans with the framework-agnostic rules. Throws only when the directory has
37369
+ * nothing to scan (no enclosing project and no source files of its own).
37288
37370
  */
37289
37371
  const discoverProjectWithoutPackageJson = (directory) => {
37290
37372
  const sourceFileCount = countSourceFiles(directory);
37291
37373
  const hasOwnTsConfig = NFS.existsSync(Path.join(directory, "tsconfig.json"));
37292
- const monorepoRoot = findMonorepoRoot(directory);
37293
- const enclosingProject = monorepoRoot !== null && isFile(Path.join(monorepoRoot, "package.json")) ? discoverProject(monorepoRoot) : null;
37374
+ const enclosingProjectRoot = findNearestAncestorPackageJson(directory);
37375
+ const enclosingProject = enclosingProjectRoot !== null ? discoverProject(enclosingProjectRoot) : null;
37294
37376
  if (enclosingProject !== null) return {
37295
37377
  ...enclosingProject,
37296
37378
  rootDirectory: directory,
@@ -37394,6 +37476,7 @@ const discoverProject = (directory) => {
37394
37476
  if (!reactVersion && reactDeclaration.version && !isCatalogReference(reactDeclaration.version)) reactVersion = reactDeclaration.version;
37395
37477
  if (!tailwindVersion && tailwindDeclaration.version && !isCatalogReference(tailwindDeclaration.version)) tailwindVersion = tailwindDeclaration.version;
37396
37478
  if (!zodVersion && zodDeclaration.version && !isCatalogReference(zodDeclaration.version)) zodVersion = zodDeclaration.version;
37479
+ if (!reactVersion || parseReactMajor(reactVersion) === null) reactVersion = resolveInstalledReactVersion(directory) ?? reactVersion;
37397
37480
  const projectName = packageJson.name ?? Path.basename(directory);
37398
37481
  const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
37399
37482
  const sourceFileCount = countSourceFiles(directory);
@@ -45924,7 +46007,7 @@ const makeNoopConsole = () => ({
45924
46007
  });
45925
46008
  //#endregion
45926
46009
  //#region src/cli/utils/version.ts
45927
- const VERSION = "0.7.1-dev.64452aa";
46010
+ const VERSION = "0.7.1-dev.d353dad";
45928
46011
  //#endregion
45929
46012
  //#region src/cli/utils/json-mode.ts
45930
46013
  let context = null;
@@ -46293,13 +46376,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
46293
46376
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
46294
46377
  * standard `SENTRY_RELEASE` override.
46295
46378
  */
46296
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.1-dev.64452aa`;
46379
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.1-dev.d353dad`;
46297
46380
  /**
46298
46381
  * Deployment environment shown in Sentry's environment filter. Defaults to
46299
46382
  * `production` for tagged releases and `development` for dev/unbuilt versions,
46300
46383
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
46301
46384
  */
46302
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.1-dev.64452aa") ? "development" : "production");
46385
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.1-dev.d353dad") ? "development" : "production");
46303
46386
  /**
46304
46387
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
46305
46388
  * (set to `0` to disable tracing) and falls back to
@@ -58143,7 +58226,7 @@ const buildRuntimeLayers = (input) => {
58143
58226
  const linterLayer = input.shouldSkipLint ? Linter.layerOf([]) : Linter.layerOxlint;
58144
58227
  const deadCodeLayer = input.shouldRunDeadCode ? DeadCode.layerNode : DeadCode.layerOf([]);
58145
58228
  const scoreLayer = input.shouldComputeScore ? Score.layerHttp : Score.layerOf(null);
58146
- const supplyChainLayer = input.userConfig?.supplyChain?.enabled === false ? SupplyChain.layerOf([]) : SupplyChain.layerNode;
58229
+ const supplyChainLayer = input.shouldRunSupplyChain ? SupplyChain.layerNode : SupplyChain.layerOf([]);
58147
58230
  const projectLayer = input.projectInfoOverride === void 0 ? Project.layerNode : Project.layerOf(input.projectInfoOverride);
58148
58231
  const progressLayer = input.shouldShowProgressSpinners ? Progress.layerOra(buildSpinnerProgressHandle) : Progress.layerNoop;
58149
58232
  const baseLayers = mergeAll$1(projectLayer, input.hasConfigOverride ? Config.layerOf({
@@ -58606,6 +58689,7 @@ const buildScanResultCacheKey = (input) => {
58606
58689
  engineOptions: {
58607
58690
  lint: input.options.lint,
58608
58691
  deadCode: input.options.deadCode,
58692
+ supplyChain: input.options.supplyChain,
58609
58693
  includePaths: [...input.options.includePaths].sort(),
58610
58694
  customRulesOnly: input.options.customRulesOnly,
58611
58695
  respectInlineDisables: input.options.respectInlineDisables,
@@ -58913,6 +58997,7 @@ const buildScanAttributes = (input) => {
58913
58997
  maxDurationMs: input.maxDurationMs,
58914
58998
  lint: input.lint,
58915
58999
  deadCode: input.deadCode,
59000
+ supplyChain: input.supplyChain,
58916
59001
  scoreOnly: input.scoreOnly,
58917
59002
  noScore: input.noScore,
58918
59003
  respectInlineDisables: input.respectInlineDisables,
@@ -60187,6 +60272,7 @@ const buildIgnoredTags = (userConfig) => {
60187
60272
  const mergeInspectOptions = (inputOptions, userConfig) => ({
60188
60273
  lint: inputOptions.lint ?? userConfig?.lint ?? true,
60189
60274
  deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
60275
+ supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
60190
60276
  verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
60191
60277
  outputDirectory: inputOptions.outputDirectory || null,
60192
60278
  scoreOnly: inputOptions.scoreOnly ?? false,
@@ -60226,6 +60312,7 @@ const buildRunEventConfig = (options, userConfig, hasCustomConfig, resolvedWorke
60226
60312
  maxDurationMs: options.maxDurationMs,
60227
60313
  lint: options.lint,
60228
60314
  deadCode: options.deadCode,
60315
+ supplyChain: options.supplyChain,
60229
60316
  scoreOnly: options.scoreOnly,
60230
60317
  noScore: options.noScore,
60231
60318
  respectInlineDisables: options.respectInlineDisables,
@@ -60309,6 +60396,7 @@ const runBaselineComparison = async (params) => {
60309
60396
  projectInfoOverride: params.headProjectInfo,
60310
60397
  shouldSkipLint: !params.options.lint || !params.resolvedNodeBinaryPath,
60311
60398
  shouldRunDeadCode: false,
60399
+ shouldRunSupplyChain: params.options.supplyChain,
60312
60400
  shouldComputeScore: false,
60313
60401
  shouldShowProgressSpinners: false,
60314
60402
  oxlintConcurrency: params.options.concurrency
@@ -60397,6 +60485,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
60397
60485
  configSourceDirectory,
60398
60486
  shouldSkipLint: !options.lint || lintBindingMissing,
60399
60487
  shouldRunDeadCode: options.deadCode,
60488
+ shouldRunSupplyChain: options.supplyChain,
60400
60489
  shouldComputeScore: !options.noScore,
60401
60490
  shouldShowProgressSpinners,
60402
60491
  oxlintConcurrency: options.concurrency
@@ -62682,8 +62771,8 @@ const resolveParallelFlag = (parallel) => parallel === false ? 1 : void 0;
62682
62771
  * accepts. Flag-derived fields only (`scoreOnly`, `noScore`, `silent`,
62683
62772
  * `isCi`): every `userConfig` fallback — including `noScore` — lives in
62684
62773
  * `inspect()`'s merge layer, which sees each project's module-merged
62685
- * config. The plain boolean knobs (`lint`, `deadCode`, `verbose`) pass
62686
- * through unchanged for the same reason. This resolver reads
62774
+ * config. The plain boolean knobs (`lint`, `deadCode`, `supplyChain`,
62775
+ * `verbose`) pass through unchanged for the same reason. This resolver reads
62687
62776
  * `userConfig` only to decide the `--blocking warning` gate.
62688
62777
  */
62689
62778
  const resolveCliInspectOptions = (flags, userConfig) => {
@@ -62691,6 +62780,7 @@ const resolveCliInspectOptions = (flags, userConfig) => {
62691
62780
  return {
62692
62781
  lint: flags.lint,
62693
62782
  deadCode: flags.deadCode,
62783
+ supplyChain: flags.supplyChain,
62694
62784
  verbose: flags.verbose,
62695
62785
  outputDirectory: flags.outputDir,
62696
62786
  respectInlineDisables: flags.respectInlineDisables === false ? false : void 0,
@@ -63241,7 +63331,7 @@ const inspectAction = async (directory, flags) => {
63241
63331
  const scanDirectory = projectScanTarget.resolvedDirectory;
63242
63332
  const projectConfig = projectDirectory === resolvedDirectory ? userConfig : mergeReactDoctorConfigs(userConfig, projectScanTarget.userConfig ?? void 0);
63243
63333
  const projectConfigSourceDirectory = projectScanTarget.userConfig?.plugins === void 0 ? scanTarget.configSourceDirectory : projectScanTarget.configSourceDirectory;
63244
- const supplyChainEnabled = projectConfig?.supplyChain?.enabled !== false;
63334
+ const supplyChainEnabled = flags.supplyChain ?? projectConfig?.supplyChain?.enabled !== false;
63245
63335
  let includePaths;
63246
63336
  let supplyChainManifestChanged = false;
63247
63337
  if (isDiffMode) {
@@ -64161,10 +64251,12 @@ const ROOT_FLAG_SPEC = {
64161
64251
  "--no-parallel",
64162
64252
  "--no-respect-inline-disables",
64163
64253
  "--no-score",
64254
+ "--no-supply-chain",
64164
64255
  "--no-telemetry",
64165
64256
  "--no-warnings",
64166
64257
  "--score",
64167
64258
  "--staged",
64259
+ "--supply-chain",
64168
64260
  "--verbose",
64169
64261
  "--version",
64170
64262
  "--warnings",
@@ -64413,7 +64505,7 @@ ${highlighter.dim("Learn more:")}
64413
64505
  ${highlighter.info(CI_URL)}
64414
64506
  `;
64415
64507
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
64416
- 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("--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 to scan/report: full (default), files, changed (only new issues vs base), or lines (only changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").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);
64508
+ 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 to scan/report: full (default), files, changed (only new issues vs base), or lines (only changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").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);
64417
64509
  program.action(inspectAction);
64418
64510
  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));
64419
64511
  program.command("install").alias("setup").description("Install the react-doctor skill into your coding agents and optional git hook").option("-y, --yes", "skip prompts, install for all detected agents").option("--dry-run", "show what would be installed without writing files").option("--agent-hooks", "install native non-blocking agent hooks for Claude Code and Cursor").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderInstallHelpEpilog).action(installAction);
@@ -64463,4 +64555,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
64463
64555
  export {};
64464
64556
 
64465
64557
  //# sourceMappingURL=cli.js.map
64466
- //# debugId=57f4381b-7060-58c6-88a4-95b4c97d3b74
64558
+ //# debugId=47338856-c658-5c78-a5e2-e871c2dafaa7
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]="f1919957-a013-5ded-b0ed-3d2e8469d0e2")}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]="f00947fe-3794-5d73-a491-232b535dc962")}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";
@@ -33064,6 +33064,23 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
33064
33064
  const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
33065
33065
  const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
33066
33066
  const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
33067
+ /**
33068
+ * The chain of ancestor directories of `startDirectory`, nearest first, up to
33069
+ * and including the filesystem root. With `includeStart`, the chain begins at
33070
+ * `startDirectory` itself; otherwise at its parent. The one place the "walk up
33071
+ * the tree" traversal is expressed, so each caller adds only its own match /
33072
+ * stop policy instead of re-deriving the `path.dirname` loop.
33073
+ */
33074
+ const ancestorDirectories = (startDirectory, { includeStart }) => {
33075
+ const directories = [];
33076
+ let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
33077
+ while (true) {
33078
+ directories.push(currentDirectory);
33079
+ const parentDirectory = Path.dirname(currentDirectory);
33080
+ if (parentDirectory === currentDirectory) return directories;
33081
+ currentDirectory = parentDirectory;
33082
+ }
33083
+ };
33067
33084
  const cachedPackageJsons = /* @__PURE__ */ new Map();
33068
33085
  const clearPackageJsonCache = () => {
33069
33086
  cachedPackageJsons.clear();
@@ -33097,11 +33114,7 @@ const isMonorepoRoot = (directory) => {
33097
33114
  return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);
33098
33115
  };
33099
33116
  const findMonorepoRoot = (startDirectory) => {
33100
- let currentDirectory = Path.dirname(startDirectory);
33101
- while (currentDirectory !== Path.dirname(currentDirectory)) {
33102
- if (isMonorepoRoot(currentDirectory)) return currentDirectory;
33103
- currentDirectory = Path.dirname(currentDirectory);
33104
- }
33117
+ for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) if (isMonorepoRoot(directory)) return directory;
33105
33118
  return null;
33106
33119
  };
33107
33120
  /**
@@ -33747,6 +33760,74 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
33747
33760
  framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceInfo.framework
33748
33761
  };
33749
33762
  };
33763
+ /**
33764
+ * Walk up from `startDirectory` to the nearest ancestor that owns a
33765
+ * `package.json`, stopping at (and including) the enclosing project boundary
33766
+ * — the working tree's git root or a monorepo root. Lets a scan of a package
33767
+ * subfolder that has no `package.json` of its own adopt the nearest enclosing
33768
+ * package as its project root, so it inherits that package's dependency +
33769
+ * framework detection instead of synthesizing an empty (React-blind) project.
33770
+ *
33771
+ * Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
33772
+ * most specific owning package (a leaf workspace, not just the repo root), so
33773
+ * a subfolder of one workspace no longer borrows a sibling's capabilities.
33774
+ *
33775
+ * Returns `null` when no ancestor `package.json` exists inside the project
33776
+ * boundary (a loose tree of files, or a subfolder of a package-less repo).
33777
+ */
33778
+ const findNearestAncestorPackageJson = (startDirectory) => {
33779
+ if (isProjectBoundary(startDirectory)) return null;
33780
+ for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
33781
+ if (isFile(Path.join(directory, "package.json"))) return directory;
33782
+ if (isProjectBoundary(directory)) return null;
33783
+ }
33784
+ return null;
33785
+ };
33786
+ /**
33787
+ * Last-resort React detection: locate React the way Node's `node_modules`
33788
+ * resolution would from `directory` — check each `node_modules/react` up the
33789
+ * tree — but bounded to the enclosing repo so a globally installed React can't
33790
+ * masquerade as the project's version. Stops at (and including) the nearest
33791
+ * project boundary — the git root or a monorepo root — and returns the first
33792
+ * installed `version`.
33793
+ *
33794
+ * Makes "React is installed and importable" ⇒ "React is detected" an invariant
33795
+ * for packages whose only React declaration is a version-less spec
33796
+ * (`workspace:*`, `*`, a dist-tag) or where React lives solely in a hoisted
33797
+ * `node_modules` the declaration walks never reach — the profile of a component
33798
+ * package inside a monorepo. Matching the `node_modules/react` entry rather than
33799
+ * its realpath means a project whose `node_modules` is symlinked elsewhere (a
33800
+ * Docker volume, a shared store) still counts, while a global install outside
33801
+ * the repo does not.
33802
+ *
33803
+ * Returns `null` when React isn't installed within the repo or its package.json
33804
+ * carries no version string. A tree with no boundary marker at all bounds the
33805
+ * search to `directory`, so a dependency hoisted above the scanned package there
33806
+ * is conservatively not adopted.
33807
+ */
33808
+ /**
33809
+ * The nearest enclosing project boundary (git root or monorepo root), or
33810
+ * `directory` itself when the scan target sits outside any repo. Bounds the
33811
+ * node_modules walk so a React hoisted anywhere inside the repo counts, but a
33812
+ * React in an ancestor above the repo — a home-directory or global
33813
+ * `node_modules` — can't leak in.
33814
+ */
33815
+ const findContainmentRoot = (directory) => {
33816
+ for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) if (isProjectBoundary(ancestorDirectory)) return ancestorDirectory;
33817
+ return directory;
33818
+ };
33819
+ const resolveInstalledReactVersion = (directory) => {
33820
+ const containmentRoot = findContainmentRoot(directory);
33821
+ for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) {
33822
+ const reactPackageJsonPath = Path.join(ancestorDirectory, "node_modules", "react", "package.json");
33823
+ if (isFile(reactPackageJsonPath)) {
33824
+ const installedVersion = readPackageJson(reactPackageJsonPath).version;
33825
+ return typeof installedVersion === "string" ? installedVersion : null;
33826
+ }
33827
+ if (ancestorDirectory === containmentRoot) return null;
33828
+ }
33829
+ return null;
33830
+ };
33750
33831
  const findInWorkspacePackageJsons = (rootDirectory, rootPackageJson, select) => {
33751
33832
  const rootValue = select(rootPackageJson);
33752
33833
  if (rootValue !== null) return rootValue;
@@ -34086,19 +34167,20 @@ const clearProjectCache = () => {
34086
34167
  };
34087
34168
  /**
34088
34169
  * Build a `ProjectInfo` for a directory that has no `package.json` of
34089
- * its own — a monorepo subfolder like `repo/packages`, or any loose tree
34090
- * of TypeScript/JavaScript files. Dependency + framework detection is
34091
- * inherited from the enclosing workspace root when there is one, so
34092
- * scanning a subdirectory of a React monorepo still gets the React
34093
- * capabilities; a standalone non-React directory simply scans with the
34094
- * framework-agnostic rules. Throws only when the directory has nothing
34095
- * to scan (no enclosing project and no source files of its own).
34170
+ * its own — a package subfolder like `repo/packages` or `app/src/features`,
34171
+ * or any loose tree of TypeScript/JavaScript files. Dependency + framework
34172
+ * detection is inherited from the nearest enclosing package (a leaf
34173
+ * workspace, a plain app root, or a monorepo root — whichever is closest,
34174
+ * bounded by the git root), so scanning a subdirectory of a React project
34175
+ * still gets the React capabilities; a standalone non-React directory simply
34176
+ * scans with the framework-agnostic rules. Throws only when the directory has
34177
+ * nothing to scan (no enclosing project and no source files of its own).
34096
34178
  */
34097
34179
  const discoverProjectWithoutPackageJson = (directory) => {
34098
34180
  const sourceFileCount = countSourceFiles(directory);
34099
34181
  const hasOwnTsConfig = NFS.existsSync(Path.join(directory, "tsconfig.json"));
34100
- const monorepoRoot = findMonorepoRoot(directory);
34101
- const enclosingProject = monorepoRoot !== null && isFile(Path.join(monorepoRoot, "package.json")) ? discoverProject(monorepoRoot) : null;
34182
+ const enclosingProjectRoot = findNearestAncestorPackageJson(directory);
34183
+ const enclosingProject = enclosingProjectRoot !== null ? discoverProject(enclosingProjectRoot) : null;
34102
34184
  if (enclosingProject !== null) return {
34103
34185
  ...enclosingProject,
34104
34186
  rootDirectory: directory,
@@ -34202,6 +34284,7 @@ const discoverProject = (directory) => {
34202
34284
  if (!reactVersion && reactDeclaration.version && !isCatalogReference(reactDeclaration.version)) reactVersion = reactDeclaration.version;
34203
34285
  if (!tailwindVersion && tailwindDeclaration.version && !isCatalogReference(tailwindDeclaration.version)) tailwindVersion = tailwindDeclaration.version;
34204
34286
  if (!zodVersion && zodDeclaration.version && !isCatalogReference(zodDeclaration.version)) zodVersion = zodDeclaration.version;
34287
+ if (!reactVersion || parseReactMajor(reactVersion) === null) reactVersion = resolveInstalledReactVersion(directory) ?? reactVersion;
34205
34288
  const projectName = packageJson.name ?? Path.basename(directory);
34206
34289
  const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
34207
34290
  const sourceFileCount = countSourceFiles(directory);
@@ -42441,4 +42524,4 @@ const toJsonReport = (result, options) => buildJsonReport({
42441
42524
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
42442
42525
 
42443
42526
  //# sourceMappingURL=index.js.map
42444
- //# debugId=f1919957-a013-5ded-b0ed-3d2e8469d0e2
42527
+ //# debugId=f00947fe-3794-5d73-a491-232b535dc962
package/dist/lsp.js CHANGED
@@ -33123,6 +33123,23 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
33123
33123
  const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
33124
33124
  const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
33125
33125
  const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
33126
+ /**
33127
+ * The chain of ancestor directories of `startDirectory`, nearest first, up to
33128
+ * and including the filesystem root. With `includeStart`, the chain begins at
33129
+ * `startDirectory` itself; otherwise at its parent. The one place the "walk up
33130
+ * the tree" traversal is expressed, so each caller adds only its own match /
33131
+ * stop policy instead of re-deriving the `path.dirname` loop.
33132
+ */
33133
+ const ancestorDirectories = (startDirectory, { includeStart }) => {
33134
+ const directories = [];
33135
+ let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
33136
+ while (true) {
33137
+ directories.push(currentDirectory);
33138
+ const parentDirectory = Path.dirname(currentDirectory);
33139
+ if (parentDirectory === currentDirectory) return directories;
33140
+ currentDirectory = parentDirectory;
33141
+ }
33142
+ };
33126
33143
  const cachedPackageJsons = /* @__PURE__ */ new Map();
33127
33144
  const clearPackageJsonCache = () => {
33128
33145
  cachedPackageJsons.clear();
@@ -33156,11 +33173,7 @@ const isMonorepoRoot = (directory) => {
33156
33173
  return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);
33157
33174
  };
33158
33175
  const findMonorepoRoot = (startDirectory) => {
33159
- let currentDirectory = Path.dirname(startDirectory);
33160
- while (currentDirectory !== Path.dirname(currentDirectory)) {
33161
- if (isMonorepoRoot(currentDirectory)) return currentDirectory;
33162
- currentDirectory = Path.dirname(currentDirectory);
33163
- }
33176
+ for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) if (isMonorepoRoot(directory)) return directory;
33164
33177
  return null;
33165
33178
  };
33166
33179
  /**
@@ -33806,6 +33819,74 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
33806
33819
  framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceInfo.framework
33807
33820
  };
33808
33821
  };
33822
+ /**
33823
+ * Walk up from `startDirectory` to the nearest ancestor that owns a
33824
+ * `package.json`, stopping at (and including) the enclosing project boundary
33825
+ * — the working tree's git root or a monorepo root. Lets a scan of a package
33826
+ * subfolder that has no `package.json` of its own adopt the nearest enclosing
33827
+ * package as its project root, so it inherits that package's dependency +
33828
+ * framework detection instead of synthesizing an empty (React-blind) project.
33829
+ *
33830
+ * Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
33831
+ * most specific owning package (a leaf workspace, not just the repo root), so
33832
+ * a subfolder of one workspace no longer borrows a sibling's capabilities.
33833
+ *
33834
+ * Returns `null` when no ancestor `package.json` exists inside the project
33835
+ * boundary (a loose tree of files, or a subfolder of a package-less repo).
33836
+ */
33837
+ const findNearestAncestorPackageJson = (startDirectory) => {
33838
+ if (isProjectBoundary(startDirectory)) return null;
33839
+ for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
33840
+ if (isFile(Path.join(directory, "package.json"))) return directory;
33841
+ if (isProjectBoundary(directory)) return null;
33842
+ }
33843
+ return null;
33844
+ };
33845
+ /**
33846
+ * Last-resort React detection: locate React the way Node's `node_modules`
33847
+ * resolution would from `directory` — check each `node_modules/react` up the
33848
+ * tree — but bounded to the enclosing repo so a globally installed React can't
33849
+ * masquerade as the project's version. Stops at (and including) the nearest
33850
+ * project boundary — the git root or a monorepo root — and returns the first
33851
+ * installed `version`.
33852
+ *
33853
+ * Makes "React is installed and importable" ⇒ "React is detected" an invariant
33854
+ * for packages whose only React declaration is a version-less spec
33855
+ * (`workspace:*`, `*`, a dist-tag) or where React lives solely in a hoisted
33856
+ * `node_modules` the declaration walks never reach — the profile of a component
33857
+ * package inside a monorepo. Matching the `node_modules/react` entry rather than
33858
+ * its realpath means a project whose `node_modules` is symlinked elsewhere (a
33859
+ * Docker volume, a shared store) still counts, while a global install outside
33860
+ * the repo does not.
33861
+ *
33862
+ * Returns `null` when React isn't installed within the repo or its package.json
33863
+ * carries no version string. A tree with no boundary marker at all bounds the
33864
+ * search to `directory`, so a dependency hoisted above the scanned package there
33865
+ * is conservatively not adopted.
33866
+ */
33867
+ /**
33868
+ * The nearest enclosing project boundary (git root or monorepo root), or
33869
+ * `directory` itself when the scan target sits outside any repo. Bounds the
33870
+ * node_modules walk so a React hoisted anywhere inside the repo counts, but a
33871
+ * React in an ancestor above the repo — a home-directory or global
33872
+ * `node_modules` — can't leak in.
33873
+ */
33874
+ const findContainmentRoot = (directory) => {
33875
+ for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) if (isProjectBoundary(ancestorDirectory)) return ancestorDirectory;
33876
+ return directory;
33877
+ };
33878
+ const resolveInstalledReactVersion = (directory) => {
33879
+ const containmentRoot = findContainmentRoot(directory);
33880
+ for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) {
33881
+ const reactPackageJsonPath = Path.join(ancestorDirectory, "node_modules", "react", "package.json");
33882
+ if (isFile(reactPackageJsonPath)) {
33883
+ const installedVersion = readPackageJson(reactPackageJsonPath).version;
33884
+ return typeof installedVersion === "string" ? installedVersion : null;
33885
+ }
33886
+ if (ancestorDirectory === containmentRoot) return null;
33887
+ }
33888
+ return null;
33889
+ };
33809
33890
  const findInWorkspacePackageJsons = (rootDirectory, rootPackageJson, select) => {
33810
33891
  const rootValue = select(rootPackageJson);
33811
33892
  if (rootValue !== null) return rootValue;
@@ -34145,19 +34226,20 @@ const clearProjectCache = () => {
34145
34226
  };
34146
34227
  /**
34147
34228
  * Build a `ProjectInfo` for a directory that has no `package.json` of
34148
- * its own — a monorepo subfolder like `repo/packages`, or any loose tree
34149
- * of TypeScript/JavaScript files. Dependency + framework detection is
34150
- * inherited from the enclosing workspace root when there is one, so
34151
- * scanning a subdirectory of a React monorepo still gets the React
34152
- * capabilities; a standalone non-React directory simply scans with the
34153
- * framework-agnostic rules. Throws only when the directory has nothing
34154
- * to scan (no enclosing project and no source files of its own).
34229
+ * its own — a package subfolder like `repo/packages` or `app/src/features`,
34230
+ * or any loose tree of TypeScript/JavaScript files. Dependency + framework
34231
+ * detection is inherited from the nearest enclosing package (a leaf
34232
+ * workspace, a plain app root, or a monorepo root — whichever is closest,
34233
+ * bounded by the git root), so scanning a subdirectory of a React project
34234
+ * still gets the React capabilities; a standalone non-React directory simply
34235
+ * scans with the framework-agnostic rules. Throws only when the directory has
34236
+ * nothing to scan (no enclosing project and no source files of its own).
34155
34237
  */
34156
34238
  const discoverProjectWithoutPackageJson = (directory) => {
34157
34239
  const sourceFileCount = countSourceFiles(directory);
34158
34240
  const hasOwnTsConfig = NFS.existsSync(Path.join(directory, "tsconfig.json"));
34159
- const monorepoRoot = findMonorepoRoot(directory);
34160
- const enclosingProject = monorepoRoot !== null && isFile(Path.join(monorepoRoot, "package.json")) ? discoverProject(monorepoRoot) : null;
34241
+ const enclosingProjectRoot = findNearestAncestorPackageJson(directory);
34242
+ const enclosingProject = enclosingProjectRoot !== null ? discoverProject(enclosingProjectRoot) : null;
34161
34243
  if (enclosingProject !== null) return {
34162
34244
  ...enclosingProject,
34163
34245
  rootDirectory: directory,
@@ -34261,6 +34343,7 @@ const discoverProject = (directory) => {
34261
34343
  if (!reactVersion && reactDeclaration.version && !isCatalogReference(reactDeclaration.version)) reactVersion = reactDeclaration.version;
34262
34344
  if (!tailwindVersion && tailwindDeclaration.version && !isCatalogReference(tailwindDeclaration.version)) tailwindVersion = tailwindDeclaration.version;
34263
34345
  if (!zodVersion && zodDeclaration.version && !isCatalogReference(zodDeclaration.version)) zodVersion = zodDeclaration.version;
34346
+ if (!reactVersion || parseReactMajor(reactVersion) === null) reactVersion = resolveInstalledReactVersion(directory) ?? reactVersion;
34264
34347
  const projectName = packageJson.name ?? Path.basename(directory);
34265
34348
  const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
34266
34349
  const sourceFileCount = countSourceFiles(directory);
@@ -44160,5 +44243,5 @@ const startLanguageServer = () => {
44160
44243
  };
44161
44244
  //#endregion
44162
44245
  export { startLanguageServer };
44163
- !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]="0cab34bf-65ac-5994-9a93-41f1b5670387")}catch(e){}}();
44164
- //# debugId=0cab34bf-65ac-5994-9a93-41f1b5670387
44246
+ !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]="8bc40ab2-982a-5d5d-a65c-9733ec980391")}catch(e){}}();
44247
+ //# debugId=8bc40ab2-982a-5d5d-a65c-9733ec980391
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.7.1-dev.64452aa",
3
+ "version": "0.7.1-dev.d353dad",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -66,7 +66,7 @@
66
66
  "vscode-uri": "^3.1.0",
67
67
  "yaml": "^2.9.0",
68
68
  "deslop-js": "0.7.1",
69
- "oxlint-plugin-react-doctor": "0.7.1-dev.64452aa"
69
+ "oxlint-plugin-react-doctor": "0.7.1-dev.d353dad"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/babel__code-frame": "^7.27.0",
@@ -74,8 +74,8 @@
74
74
  "@xterm/headless": "^6.0.0",
75
75
  "commander": "^14.0.3",
76
76
  "ora": "^9.4.0",
77
- "@react-doctor/api": "0.7.1",
78
77
  "@react-doctor/core": "0.7.1",
78
+ "@react-doctor/api": "0.7.1",
79
79
  "@react-doctor/language-server": "0.7.1"
80
80
  },
81
81
  "engines": {