react-doctor 0.7.6-dev.e026a23 → 0.7.6-dev.e877ca7

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]="bc56f5c4-5b95-5727-8e86-d43a534abbbc")}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]="63b8a227-543e-5501-a998-58c03a1fb10e")}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";
@@ -40762,7 +40762,9 @@ const setColorEnabled = (enabled) => {
40762
40762
  highlighter.gray = colors.gray;
40763
40763
  highlighter.bold = colors.bold;
40764
40764
  };
40765
- const computeExplicitLintIncludePaths = (includePaths) => includePaths.length > 0 ? includePaths.filter(isLintableSourceFile) : void 0;
40765
+ const NEXT_ENTRY_FILE_PATTERN = /^(?:\.\/)?(?:src\/)?(?:middleware|proxy)\.(?:tsx?|jsx?|mts|mjs)$/;
40766
+ const shouldIncludeExplicitLintPath = (filePath, project) => JSX_FILE_PATTERN.test(filePath) || project?.framework === "nextjs" && NEXT_ENTRY_FILE_PATTERN.test(filePath);
40767
+ const computeExplicitLintIncludePaths = (includePaths, project) => includePaths.length > 0 ? includePaths.filter((filePath) => shouldIncludeExplicitLintPath(filePath, project)) : void 0;
40766
40768
  const LINGUIST_ATTRIBUTE_PATTERN = /^linguist-(?:vendored|generated)(?:=([a-zA-Z0-9]+))?$/i;
40767
40769
  const FALSY_VALUES = new Set([
40768
40770
  "false",
@@ -41601,11 +41603,11 @@ const resolveDeadCodeTimeout = (input) => {
41601
41603
  phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
41602
41604
  };
41603
41605
  };
41604
- const resolveLintIncludePaths = (rootDirectory, userConfig) => {
41606
+ const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
41605
41607
  if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
41606
41608
  const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
41607
41609
  return listSourceFiles(rootDirectory).filter((filePath) => {
41608
- if (!isLintableSourceFile(filePath)) return false;
41610
+ if (!shouldIncludeExplicitLintPath(filePath, project)) return false;
41609
41611
  return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
41610
41612
  });
41611
41613
  };
@@ -45487,7 +45489,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
45487
45489
  directory: scanDirectory,
45488
45490
  repo
45489
45491
  }).pipe(orElseSucceed(() => null)) : succeed$2(null));
45490
- const lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config);
45492
+ const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
45491
45493
  const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
45492
45494
  const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
45493
45495
  const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
@@ -46665,7 +46667,7 @@ const makeNoopConsole = () => ({
46665
46667
  });
46666
46668
  //#endregion
46667
46669
  //#region src/cli/utils/version.ts
46668
- const VERSION = "0.7.6-dev.e026a23";
46670
+ const VERSION = "0.7.6-dev.e877ca7";
46669
46671
  //#endregion
46670
46672
  //#region src/cli/utils/json-mode.ts
46671
46673
  let context = null;
@@ -47034,13 +47036,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47034
47036
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47035
47037
  * standard `SENTRY_RELEASE` override.
47036
47038
  */
47037
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.6-dev.e026a23`;
47039
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.6-dev.e877ca7`;
47038
47040
  /**
47039
47041
  * Deployment environment shown in Sentry's environment filter. Defaults to
47040
47042
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47041
47043
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47042
47044
  */
47043
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.6-dev.e026a23") ? "development" : "production");
47045
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.6-dev.e877ca7") ? "development" : "production");
47044
47046
  /**
47045
47047
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47046
47048
  * (set to `0` to disable tracing) and falls back to
@@ -59200,7 +59202,7 @@ const buildDirtyPathContentFingerprint = (absolutePath, statusCode) => {
59200
59202
  return null;
59201
59203
  }
59202
59204
  if (!stats.isFile()) return null;
59203
- if (stats.size > 10485760) return null;
59205
+ if (stats.size > 10485760) return `stat:${stats.mtimeMs}:${stats.size}`;
59204
59206
  return hashFileContents(absolutePath);
59205
59207
  };
59206
59208
  const buildWorktreeFingerprint = (projectDirectory) => {
@@ -59674,8 +59676,7 @@ const buildScanAttributes = (input) => {
59674
59676
  hasCustomConfig: input.hasCustomConfig,
59675
59677
  rulesConfigured: ruleKeys.length,
59676
59678
  rulesDisabled: ruleKeys.filter((key) => ruleOverrides[key] === "off").length,
59677
- fileCount: input.result?.scannedFileCount ?? null,
59678
- nonJsxFileCount: input.result?.analyzedFiles?.filter((filePath) => !JSX_FILE_PATTERN.test(filePath)).length ?? null
59679
+ fileCount: input.result?.scannedFileCount ?? null
59679
59680
  });
59680
59681
  };
59681
59682
  /**
@@ -65180,7 +65181,7 @@ ${highlighter.dim("Learn more:")}
65180
65181
  ${highlighter.info(CI_URL)}
65181
65182
  `;
65182
65183
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
65183
- const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (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);
65184
+ 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);
65184
65185
  program.action(inspectAction);
65185
65186
  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));
65186
65187
  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);
@@ -65230,4 +65231,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
65230
65231
  export {};
65231
65232
 
65232
65233
  //# sourceMappingURL=cli.js.map
65233
- //# debugId=bc56f5c4-5b95-5727-8e86-d43a534abbbc
65234
+ //# debugId=63b8a227-543e-5501-a998-58c03a1fb10e
package/dist/index.d.ts CHANGED
@@ -9654,7 +9654,6 @@ interface DiagnoseOptions {
9654
9654
  /** See `ReactDoctorConfig.deadCode`. Ignored in diff mode. */
9655
9655
  deadCode?: boolean;
9656
9656
  verbose?: boolean;
9657
- /** Restrict linting to these supported JS/TS source files. */
9658
9657
  includePaths?: string[];
9659
9658
  /**
9660
9659
  * Per-call override for `ReactDoctorConfig.respectInlineDisables`.
@@ -9916,9 +9915,9 @@ interface JsonReportProjectEntry {
9916
9915
  skippedCheckReasons?: Record<string, string>;
9917
9916
  /**
9918
9917
  * Number of source files this scan's linter examined. In diff / changed
9919
- * mode it's the count of changed supported JS/TS source files; in a full
9920
- * scan it's the whole source tree. `0` in a diff scan means the changed
9921
- * files held nothing React Doctor lints —
9918
+ * mode it's the count of changed React-eligible files (`.tsx`/`.jsx` plus
9919
+ * framework entry files); in a full scan it's the whole source tree. `0`
9920
+ * in a diff scan means the changed files held nothing React Doctor lints —
9922
9921
  * the GitHub Action reads that as "nothing to report" (skips the PR comment;
9923
9922
  * the commit status says "skipped"). Optional: absent on reports from
9924
9923
  * constructors that don't track it (e.g. `toJsonReport`).
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]="3e7262c1-34a6-5fd7-a4a2-5e7a15ca735d")}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]="7a10d23c-04fd-53e1-a623-a3dc5d6d0830")}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 reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
@@ -32930,6 +32930,7 @@ const IGNORED_DIRECTORIES = new Set([
32930
32930
  "out",
32931
32931
  "storybook-static"
32932
32932
  ]);
32933
+ const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
32933
32934
  const MILLISECONDS_PER_SECOND = 1e3;
32934
32935
  const SCORE_API_URL = "https://www.react.doctor/api/score";
32935
32936
  const FETCH_TIMEOUT_MS = 1e4;
@@ -37515,7 +37516,9 @@ const highlighter = {
37515
37516
  gray: import_picocolors.default.gray,
37516
37517
  bold: import_picocolors.default.bold
37517
37518
  };
37518
- const computeExplicitLintIncludePaths = (includePaths) => includePaths.length > 0 ? includePaths.filter(isLintableSourceFile) : void 0;
37519
+ const NEXT_ENTRY_FILE_PATTERN = /^(?:\.\/)?(?:src\/)?(?:middleware|proxy)\.(?:tsx?|jsx?|mts|mjs)$/;
37520
+ const shouldIncludeExplicitLintPath = (filePath, project) => JSX_FILE_PATTERN.test(filePath) || project?.framework === "nextjs" && NEXT_ENTRY_FILE_PATTERN.test(filePath);
37521
+ const computeExplicitLintIncludePaths = (includePaths, project) => includePaths.length > 0 ? includePaths.filter((filePath) => shouldIncludeExplicitLintPath(filePath, project)) : void 0;
37519
37522
  const LINGUIST_ATTRIBUTE_PATTERN = /^linguist-(?:vendored|generated)(?:=([a-zA-Z0-9]+))?$/i;
37520
37523
  const FALSY_VALUES = new Set([
37521
37524
  "false",
@@ -38357,11 +38360,11 @@ const resolveDeadCodeTimeout = (input) => {
38357
38360
  phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
38358
38361
  };
38359
38362
  };
38360
- const resolveLintIncludePaths = (rootDirectory, userConfig) => {
38363
+ const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
38361
38364
  if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
38362
38365
  const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
38363
38366
  return listSourceFiles(rootDirectory).filter((filePath) => {
38364
- if (!isLintableSourceFile(filePath)) return false;
38367
+ if (!shouldIncludeExplicitLintPath(filePath, project)) return false;
38365
38368
  return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
38366
38369
  });
38367
38370
  };
@@ -42243,7 +42246,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
42243
42246
  directory: scanDirectory,
42244
42247
  repo
42245
42248
  }).pipe(orElseSucceed(() => null)) : succeed$2(null));
42246
- const lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config);
42249
+ const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
42247
42250
  const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
42248
42251
  const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
42249
42252
  const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
@@ -43207,4 +43210,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43207
43210
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43208
43211
 
43209
43212
  //# sourceMappingURL=index.js.map
43210
- //# debugId=3e7262c1-34a6-5fd7-a4a2-5e7a15ca735d
43213
+ //# debugId=7a10d23c-04fd-53e1-a623-a3dc5d6d0830
package/dist/lsp.js CHANGED
@@ -32959,6 +32959,7 @@ const IGNORED_DIRECTORIES = new Set([
32959
32959
  "out",
32960
32960
  "storybook-static"
32961
32961
  ]);
32962
+ const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
32962
32963
  const MILLISECONDS_PER_SECOND = 1e3;
32963
32964
  const SCORE_API_URL = "https://www.react.doctor/api/score";
32964
32965
  const FETCH_TIMEOUT_MS = 1e4;
@@ -37493,7 +37494,9 @@ const highlighter = {
37493
37494
  gray: import_picocolors.default.gray,
37494
37495
  bold: import_picocolors.default.bold
37495
37496
  };
37496
- const computeExplicitLintIncludePaths = (includePaths) => includePaths.length > 0 ? includePaths.filter(isLintableSourceFile) : void 0;
37497
+ const NEXT_ENTRY_FILE_PATTERN = /^(?:\.\/)?(?:src\/)?(?:middleware|proxy)\.(?:tsx?|jsx?|mts|mjs)$/;
37498
+ const shouldIncludeExplicitLintPath = (filePath, project) => JSX_FILE_PATTERN.test(filePath) || project?.framework === "nextjs" && NEXT_ENTRY_FILE_PATTERN.test(filePath);
37499
+ const computeExplicitLintIncludePaths = (includePaths, project) => includePaths.length > 0 ? includePaths.filter((filePath) => shouldIncludeExplicitLintPath(filePath, project)) : void 0;
37497
37500
  const LINGUIST_ATTRIBUTE_PATTERN = /^linguist-(?:vendored|generated)(?:=([a-zA-Z0-9]+))?$/i;
37498
37501
  const FALSY_VALUES = new Set([
37499
37502
  "false",
@@ -38335,11 +38338,11 @@ const resolveDeadCodeTimeout = (input) => {
38335
38338
  phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
38336
38339
  };
38337
38340
  };
38338
- const resolveLintIncludePaths = (rootDirectory, userConfig) => {
38341
+ const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
38339
38342
  if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
38340
38343
  const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
38341
38344
  return listSourceFiles(rootDirectory).filter((filePath) => {
38342
- if (!isLintableSourceFile(filePath)) return false;
38345
+ if (!shouldIncludeExplicitLintPath(filePath, project)) return false;
38343
38346
  return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
38344
38347
  });
38345
38348
  };
@@ -42221,7 +42224,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
42221
42224
  directory: scanDirectory,
42222
42225
  repo
42223
42226
  }).pipe(orElseSucceed(() => null)) : succeed$2(null));
42224
- const lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config);
42227
+ const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
42225
42228
  const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
42226
42229
  const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
42227
42230
  const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
@@ -42716,7 +42719,7 @@ const runEditorScan = async (input) => {
42716
42719
  warnings,
42717
42720
  isCi: false,
42718
42721
  resolveLocalGithubViewerPermission: false,
42719
- skipExplicitIncludePathFilter: true
42722
+ skipJsxIncludeFilter: true
42720
42723
  }).pipe(withSpan("runEditorScan", { attributes: {
42721
42724
  "editor.lint": lint,
42722
42725
  "editor.runDeadCode": runDeadCode
@@ -43479,7 +43482,7 @@ const createLintCache = (input) => {
43479
43482
  let persistTimer = null;
43480
43483
  try {
43481
43484
  const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
43482
- if (parsed.version === 2 && parsed.fingerprint === input.fingerprint) for (const [fsPath, entry] of Object.entries(parsed.entries)) entries.set(fsPath, entry);
43485
+ if (parsed.version === 1 && parsed.fingerprint === input.fingerprint) for (const [fsPath, entry] of Object.entries(parsed.entries)) entries.set(fsPath, entry);
43483
43486
  } catch {}
43484
43487
  const persist = () => {
43485
43488
  if (persistTimer) {
@@ -43490,7 +43493,7 @@ const createLintCache = (input) => {
43490
43493
  dirty = false;
43491
43494
  try {
43492
43495
  const payload = {
43493
- version: 2,
43496
+ version: 1,
43494
43497
  fingerprint: input.fingerprint,
43495
43498
  entries: Object.fromEntries(entries)
43496
43499
  };
@@ -43503,14 +43506,14 @@ const createLintCache = (input) => {
43503
43506
  }
43504
43507
  };
43505
43508
  return {
43506
- lookup: (fsPath, identity) => {
43509
+ lookup: (fsPath, stat) => {
43507
43510
  const entry = entries.get(fsPath);
43508
- if (entry !== void 0 && entry.contentHash === identity.contentHash) return entry.diagnostics;
43511
+ if (entry !== void 0 && entry.mtimeMs === stat.mtimeMs && entry.size === stat.size) return entry.diagnostics;
43509
43512
  return null;
43510
43513
  },
43511
- store: (fsPath, identity, diagnostics) => {
43514
+ store: (fsPath, stat, diagnostics) => {
43512
43515
  entries.set(fsPath, {
43513
- ...identity,
43516
+ ...stat,
43514
43517
  diagnostics
43515
43518
  });
43516
43519
  dirty = true;
@@ -43599,9 +43602,16 @@ const resolveDiagnosticFsPath = (rawFilePath, scanDirectory, projectDirectory, o
43599
43602
  }
43600
43603
  return normalizeFsPath(absolute);
43601
43604
  };
43602
- const readFileIdentity = (fsPath) => {
43603
- const contentHash = hashFileContents(fsPath);
43604
- return contentHash === null ? null : { contentHash };
43605
+ const statSafe = (fsPath) => {
43606
+ try {
43607
+ const stat = fs.statSync(fsPath);
43608
+ return {
43609
+ mtimeMs: stat.mtimeMs,
43610
+ size: stat.size
43611
+ };
43612
+ } catch {
43613
+ return null;
43614
+ }
43605
43615
  };
43606
43616
  /**
43607
43617
  * Outcome for a per-file request served without running oxlint (every
@@ -43627,7 +43637,7 @@ const outcomeWithoutScan = (request, byFile, requestedPaths) => ({
43627
43637
  * overlay tree (unsaved buffers) or disk, groups diagnostics by canonical
43628
43638
  * absolute path, and reports stale-detection metadata.
43629
43639
  *
43630
- * A persistent per-file lint cache (keyed by content, namespaced by a
43640
+ * A persistent per-file lint cache (keyed by mtime + size, namespaced by a
43631
43641
  * config fingerprint) short-circuits unchanged files so a re-opened editor
43632
43642
  * or repeated workspace scan skips the oxlint subprocess for everything it
43633
43643
  * hasn't edited. The cache applies only to disk-based, lint-only, per-file
@@ -43657,15 +43667,15 @@ const createScanRunner = (options) => {
43657
43667
  const requestedPaths = request.priority === "background" && !request.useOverlay && options.isOpen ? allRequested.filter((fsPath) => !options.isOpen?.(fsPath)) : allRequested;
43658
43668
  const cache = cacheEnabled && !isWholeProject && !request.useOverlay && !request.runDeadCode ? getCache(projectDirectory) : null;
43659
43669
  const byFile = /* @__PURE__ */ new Map();
43660
- const identityByPath = /* @__PURE__ */ new Map();
43670
+ const statByPath = /* @__PURE__ */ new Map();
43661
43671
  let filesToScan = requestedPaths;
43662
43672
  if (cache) {
43663
43673
  const uncached = [];
43664
43674
  for (const fsPath of requestedPaths) {
43665
- const identity = readFileIdentity(fsPath);
43666
- if (identity) {
43667
- identityByPath.set(fsPath, identity);
43668
- const hit = cache.lookup(fsPath, identity);
43675
+ const stat = statSafe(fsPath);
43676
+ if (stat) {
43677
+ statByPath.set(fsPath, stat);
43678
+ const hit = cache.lookup(fsPath, stat);
43669
43679
  if (hit !== null) {
43670
43680
  if (hit.length > 0) byFile.set(fsPath, hit);
43671
43681
  continue;
@@ -43708,9 +43718,9 @@ const createScanRunner = (options) => {
43708
43718
  }
43709
43719
  if (cache && result.ok && !result.skipped && !result.didLintFail && result.lintPartialFailures.length === 0) {
43710
43720
  for (const fsPath of filesToScan) {
43711
- const identity = identityByPath.get(fsPath);
43712
- if (!identity) continue;
43713
- cache.store(fsPath, identity, byFile.get(fsPath) ?? []);
43721
+ const stat = statByPath.get(fsPath);
43722
+ if (!stat) continue;
43723
+ cache.store(fsPath, stat, byFile.get(fsPath) ?? []);
43714
43724
  }
43715
43725
  cache.schedulePersist();
43716
43726
  }
@@ -44844,5 +44854,5 @@ const startLanguageServer = () => {
44844
44854
  };
44845
44855
  //#endregion
44846
44856
  export { startLanguageServer };
44847
- !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]="a3135dfe-cc85-5d34-adea-93f5c29d9bcb")}catch(e){}}();
44848
- //# debugId=a3135dfe-cc85-5d34-adea-93f5c29d9bcb
44857
+ !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]="b77898db-d8e8-531a-a32b-9de2d1a63635")}catch(e){}}();
44858
+ //# debugId=b77898db-d8e8-531a-a32b-9de2d1a63635
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.7.6-dev.e026a23",
3
+ "version": "0.7.6-dev.e877ca7",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -65,8 +65,8 @@
65
65
  "vscode-languageserver-textdocument": "^1.0.12",
66
66
  "vscode-uri": "^3.1.0",
67
67
  "yaml": "^2.9.0",
68
- "oxlint-plugin-react-doctor": "0.7.6-dev.e026a23",
69
- "deslop-js": "0.7.6"
68
+ "deslop-js": "0.7.6",
69
+ "oxlint-plugin-react-doctor": "0.7.6-dev.e877ca7"
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/core": "0.7.6",
78
77
  "@react-doctor/api": "0.7.6",
78
+ "@react-doctor/core": "0.7.6",
79
79
  "@react-doctor/language-server": "0.7.6"
80
80
  },
81
81
  "engines": {