react-doctor 0.6.3-dev.e257a5e → 0.6.3

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]="82500030-a7a7-5da8-b18e-cbdb42102dc3")}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]="328318eb-6af2-5007-b816-51c953a96047")}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";
@@ -36128,7 +36128,6 @@ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
36128
36128
  const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
36129
36129
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
36130
36130
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
36131
- const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
36132
36131
  const SUPPLY_CHAIN_PLUGIN = "socket";
36133
36132
  const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
36134
36133
  const SUPPLY_CHAIN_CATEGORY = "Security";
@@ -38813,25 +38812,6 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
38813
38812
  if (CACHE_DISABLED_VALUES$1.has(noFileCache)) return false;
38814
38813
  return true;
38815
38814
  } }) {};
38816
- /**
38817
- * Whether the whole-project dead-code result cache
38818
- * (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
38819
- * whose inputs (source tree, manifests, configs, analyzer version) are
38820
- * unchanged replays the stored diagnostics instead of re-running the
38821
- * analysis worker. Opt-OUT, two knobs (matching the per-file lint cache):
38822
- *
38823
- * - `REACT_DOCTOR_NO_CACHE` — the global off-switch.
38824
- * - `REACT_DOCTOR_NO_DEAD_CODE_CACHE` — granular: bust only this cache.
38825
- *
38826
- * Tests override via `Layer.succeed(DeadCodeResultCacheEnabled, false)`.
38827
- */
38828
- var DeadCodeResultCacheEnabled = class extends Reference("react-doctor/DeadCodeResultCacheEnabled", { defaultValue: () => {
38829
- const noCache = process.env["REACT_DOCTOR_NO_CACHE"]?.toLowerCase() ?? "";
38830
- const noDeadCodeCache = process.env["REACT_DOCTOR_NO_DEAD_CODE_CACHE"]?.toLowerCase() ?? "";
38831
- if (CACHE_DISABLED_VALUES$1.has(noCache)) return false;
38832
- if (CACHE_DISABLED_VALUES$1.has(noDeadCodeCache)) return false;
38833
- return true;
38834
- } }) {};
38835
38815
  const DIAGNOSTIC_SURFACES = [
38836
38816
  "cli",
38837
38817
  "prComment",
@@ -40564,108 +40544,6 @@ const collectDeadCodeIgnorePatterns = (rootDirectory) => {
40564
40544
  return [...seen].filter((pattern) => pattern.length > 0);
40565
40545
  };
40566
40546
  const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
40567
- const atomicWriteJson = (filePath, value) => {
40568
- try {
40569
- NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
40570
- const temporaryPath = `${filePath}.${process.pid}.tmp`;
40571
- NFS.writeFileSync(temporaryPath, JSON.stringify(value));
40572
- NFS.renameSync(temporaryPath, filePath);
40573
- } catch {
40574
- return;
40575
- }
40576
- };
40577
- const failOpenReadJson = (filePath, fallback) => {
40578
- try {
40579
- return JSON.parse(NFS.readFileSync(filePath, "utf8"));
40580
- } catch {
40581
- return fallback;
40582
- }
40583
- };
40584
- const ANALYZED_FILE_EXTENSIONS = new Set([
40585
- ".ts",
40586
- ".tsx",
40587
- ".js",
40588
- ".jsx",
40589
- ".mts",
40590
- ".mjs",
40591
- ".cts",
40592
- ".cjs",
40593
- ".mdx",
40594
- ".astro",
40595
- ".graphql",
40596
- ".gql",
40597
- ".css",
40598
- ".scss",
40599
- ".vue",
40600
- ".svelte"
40601
- ]);
40602
- const ANALYZED_MANIFEST_NAMES = new Set([
40603
- "package.json",
40604
- "knip.json",
40605
- "app.json",
40606
- "pnpm-workspace.yaml",
40607
- "lerna.json",
40608
- "pnpm-lock.yaml",
40609
- "package-lock.json",
40610
- "yarn.lock",
40611
- "bun.lock",
40612
- "bun.lockb",
40613
- "deno.lock",
40614
- ".gitignore"
40615
- ]);
40616
- const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
40617
- const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
40618
- const collectAnalyzedFileFingerprints = (rootDirectory) => {
40619
- const fingerprints = [];
40620
- for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
40621
- if (!isFingerprintedFile(name)) continue;
40622
- try {
40623
- const fileStat = NFS.statSync(absolutePath);
40624
- const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
40625
- fingerprints.push(`${relativePath}:${fileStat.mtimeMs}:${fileStat.size}`);
40626
- } catch {}
40627
- }
40628
- return fingerprints.sort();
40629
- };
40630
- const bundledRequire$2 = createRequire(import.meta.url);
40631
- const resolveDeslopVersion = () => {
40632
- try {
40633
- const packageJson = JSON.parse(NFS.readFileSync(bundledRequire$2.resolve("deslop-js/package.json"), "utf8"));
40634
- return isRecord$1(packageJson) && typeof packageJson.version === "string" ? packageJson.version : "unknown";
40635
- } catch {
40636
- return "unknown";
40637
- }
40638
- };
40639
- const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
40640
- schemaVersion: 1,
40641
- deslopVersion: resolveDeslopVersion(),
40642
- deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
40643
- entryPatterns: input.entryPatterns,
40644
- ignorePatterns: input.ignorePatterns,
40645
- tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
40646
- files: collectAnalyzedFileFingerprints(input.rootDirectory)
40647
- })).digest("hex");
40648
- const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
40649
- const decodeCachedDiagnostics = (raw) => {
40650
- try {
40651
- for (const entry of raw) validateDiagnostic$1(entry);
40652
- return raw;
40653
- } catch {
40654
- return null;
40655
- }
40656
- };
40657
- const lookupDeadCodeResultCache = (cacheDirectory, cacheKey) => {
40658
- const persisted = failOpenReadJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), null);
40659
- if (persisted === null || !isRecord$1(persisted) || persisted.version !== 1 || persisted.key !== cacheKey || !Array.isArray(persisted.diagnostics)) return null;
40660
- return decodeCachedDiagnostics(persisted.diagnostics);
40661
- };
40662
- const storeDeadCodeResultCache = (cacheDirectory, cacheKey, diagnostics) => {
40663
- atomicWriteJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
40664
- version: 1,
40665
- key: cacheKey,
40666
- diagnostics
40667
- });
40668
- };
40669
40547
  const readSystemFacts = () => ({
40670
40548
  availableCores: os.availableParallelism(),
40671
40549
  totalMemoryBytes: os.totalmem(),
@@ -40734,21 +40612,6 @@ const withDeadCodeWorkerSlot = async (task, abortSignal) => {
40734
40612
  releaseSlot();
40735
40613
  }
40736
40614
  };
40737
- const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
40738
- const resolveReactDoctorCacheDir = (projectDirectory) => {
40739
- const cacheDirOverride = process.env["REACT_DOCTOR_CACHE_DIR"]?.trim();
40740
- if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
40741
- const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
40742
- if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
40743
- return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
40744
- };
40745
- const resolveUserCacheScope = () => {
40746
- try {
40747
- return String(process.getuid?.() ?? os.userInfo().username);
40748
- } catch {
40749
- return "shared";
40750
- }
40751
- };
40752
40615
  /**
40753
40616
  * Resolves a path to its canonical, symlink-free form, falling back to
40754
40617
  * the input when it cannot be realpath'd (broken symlink, permission
@@ -41044,27 +40907,13 @@ const checkDeadCode = async (options) => {
41044
40907
  if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
41045
40908
  const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
41046
40909
  const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
41047
- const tsConfigPath = resolveTsConfigPath(rootDirectory);
41048
- const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
41049
- const cacheKey = options.cacheEnabled ? computeDeadCodeCacheKey({
41050
- rootDirectory,
41051
- entryPatterns,
41052
- ignorePatterns,
41053
- tsConfigPath,
41054
- deslopJsModuleSpecifier
41055
- }) : null;
41056
- if (cacheKey !== null) {
41057
- const cachedDiagnostics = lookupDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey);
41058
- options.onCacheOutcome?.(cachedDiagnostics !== null);
41059
- if (cachedDiagnostics !== null) return [...cachedDiagnostics];
41060
- }
41061
40910
  const spawnAndRun = () => {
41062
40911
  return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
41063
40912
  rootDirectory,
41064
40913
  entryPatterns,
41065
- tsConfigPath,
40914
+ tsConfigPath: resolveTsConfigPath(rootDirectory),
41066
40915
  ignorePatterns,
41067
- deslopJsModuleSpecifier,
40916
+ deslopJsModuleSpecifier: options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js"),
41068
40917
  parseConcurrency: options.parseConcurrency
41069
40918
  }), options.workerTimeoutMs ?? 12e4, options.abortSignal);
41070
40919
  };
@@ -41125,7 +40974,6 @@ const checkDeadCode = async (options) => {
41125
40974
  category: DEAD_CODE_CATEGORY
41126
40975
  });
41127
40976
  }
41128
- if (cacheKey !== null) storeDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey, diagnostics);
41129
40977
  return diagnostics;
41130
40978
  };
41131
40979
  const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
@@ -41228,15 +41076,12 @@ var Config = class Config extends Service()("react-doctor/Config") {
41228
41076
  */
41229
41077
  var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
41230
41078
  static layerNode = succeed$3(DeadCode, DeadCode.of({ run: (input) => unwrap(fn("DeadCode.run")(function* () {
41231
- const cacheEnabled = yield* DeadCodeResultCacheEnabled;
41232
41079
  return yield* tryPromise({
41233
41080
  try: (signal) => checkDeadCode({
41234
41081
  rootDirectory: input.rootDirectory,
41235
41082
  parseConcurrency: input.parseConcurrency,
41236
41083
  workerTimeoutMs: input.workerTimeoutMs,
41237
- abortSignal: signal,
41238
- cacheEnabled,
41239
- onCacheOutcome: input.onCacheOutcome
41084
+ abortSignal: signal
41240
41085
  }),
41241
41086
  catch: (cause) => new ReactDoctorError({ reason: new DeadCodeAnalysisFailed({ cause }) })
41242
41087
  }).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)));
@@ -42162,6 +42007,23 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
42162
42007
  }
42163
42008
  };
42164
42009
  };
42010
+ const atomicWriteJson = (filePath, value) => {
42011
+ try {
42012
+ NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
42013
+ const temporaryPath = `${filePath}.${process.pid}.tmp`;
42014
+ NFS.writeFileSync(temporaryPath, JSON.stringify(value));
42015
+ NFS.renameSync(temporaryPath, filePath);
42016
+ } catch {
42017
+ return;
42018
+ }
42019
+ };
42020
+ const failOpenReadJson = (filePath, fallback) => {
42021
+ try {
42022
+ return JSON.parse(NFS.readFileSync(filePath, "utf8"));
42023
+ } catch {
42024
+ return fallback;
42025
+ }
42026
+ };
42165
42027
  const validateDiagnostic = decodeUnknownSync(Diagnostic);
42166
42028
  const decodeFileDiagnostics = (raw) => {
42167
42029
  if (!Array.isArray(raw)) return null;
@@ -42219,7 +42081,7 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
42219
42081
  }
42220
42082
  };
42221
42083
  };
42222
- const bundledRequire$3 = createRequire(import.meta.url);
42084
+ const bundledRequire$2 = createRequire(import.meta.url);
42223
42085
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
42224
42086
  const resolveChildNodeVersion = (nodeBinaryPath) => {
42225
42087
  if (nodeBinaryPath === process.execPath) return process.version;
@@ -42245,7 +42107,7 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
42245
42107
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
42246
42108
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
42247
42109
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
42248
- const packageJson = bundledRequire$3(specifier);
42110
+ const packageJson = bundledRequire$2(specifier);
42249
42111
  const version = typeof packageJson.version === "string" ? packageJson.version : "unknown";
42250
42112
  versions.push(`${specifier}=${version}`);
42251
42113
  } catch {
@@ -43289,6 +43151,21 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
43289
43151
  }
43290
43152
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
43291
43153
  };
43154
+ const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
43155
+ const resolveReactDoctorCacheDir = (projectDirectory) => {
43156
+ const cacheDirOverride = process.env["REACT_DOCTOR_CACHE_DIR"]?.trim();
43157
+ if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
43158
+ const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
43159
+ if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
43160
+ return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
43161
+ };
43162
+ const resolveUserCacheScope = () => {
43163
+ try {
43164
+ return String(process.getuid?.() ?? os.userInfo().username);
43165
+ } catch {
43166
+ return "shared";
43167
+ }
43168
+ };
43292
43169
  /**
43293
43170
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
43294
43171
  * the runner: once for the primary scan, once for the
@@ -44415,10 +44292,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
44415
44292
  const buildCollectDeadCode = (deadCodeTimeout) => runCollect(applyPerElementPipeline(deadCodeService.run({
44416
44293
  rootDirectory: scanDirectory,
44417
44294
  parseConcurrency: deadCodeParseConcurrency,
44418
- workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
44419
- onCacheOutcome: (didHitCache) => {
44420
- deadCodeCacheHit = didHitCache;
44421
- }
44295
+ workerTimeoutMs: deadCodeTimeout.workerTimeoutMs
44422
44296
  }).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
44423
44297
  yield* set(deadCodeFailure, {
44424
44298
  didFail: true,
@@ -44446,7 +44320,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
44446
44320
  let lastReportedTotalFileCount = 0;
44447
44321
  let lintCacheHitFileCount = null;
44448
44322
  let lintCacheTotalFileCount = null;
44449
- let deadCodeCacheHit = null;
44450
44323
  const baseLintStream = linterService.run({
44451
44324
  rootDirectory: scanDirectory,
44452
44325
  project,
@@ -44576,7 +44449,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
44576
44449
  securityScanFailed,
44577
44450
  lintCacheHitFileCount,
44578
44451
  lintCacheTotalFileCount,
44579
- deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
44580
44452
  suppressedRuleCounts: transform.summarizeSuppressions()
44581
44453
  };
44582
44454
  }).pipe(withSpan("runInspect", { attributes: {
@@ -45358,7 +45230,6 @@ const isNonInteractiveEnvironment = () => NON_INTERACTIVE_ENVIRONMENT_VARIABLES.
45358
45230
  const REACT_DOCTOR_CONFIG_PROJECT_NAME = "react-doctor";
45359
45231
  const STAGED_FILES_TEMP_DIR_PREFIX = "react-doctor-staged-";
45360
45232
  const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
45361
- const RUN_GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
45362
45233
  const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
45363
45234
  const CI_TRUST_COMPANIES = "PayPal, Rippling, and Alibaba";
45364
45235
  const WELCOME_EXPLANATION_HOLD_MS = 1e3;
@@ -45449,7 +45320,7 @@ const makeNoopConsole = () => ({
45449
45320
  });
45450
45321
  //#endregion
45451
45322
  //#region src/cli/utils/version.ts
45452
- const VERSION = "0.6.3-dev.e257a5e";
45323
+ const VERSION = "0.6.3";
45453
45324
  //#endregion
45454
45325
  //#region src/cli/utils/json-mode.ts
45455
45326
  let context = null;
@@ -45818,13 +45689,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
45818
45689
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
45819
45690
  * standard `SENTRY_RELEASE` override.
45820
45691
  */
45821
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.e257a5e`;
45692
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3`;
45822
45693
  /**
45823
45694
  * Deployment environment shown in Sentry's environment filter. Defaults to
45824
45695
  * `production` for tagged releases and `development` for dev/unbuilt versions,
45825
45696
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
45826
45697
  */
45827
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.e257a5e") ? "development" : "production");
45698
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3") ? "development" : "production");
45828
45699
  /**
45829
45700
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
45830
45701
  * (set to `0` to disable tracing) and falls back to
@@ -46025,8 +45896,7 @@ const runGit = (projectRoot, args) => {
46025
45896
  "ignore",
46026
45897
  "pipe",
46027
45898
  "ignore"
46028
- ],
46029
- maxBuffer: RUN_GIT_MAX_BUFFER_BYTES
45899
+ ]
46030
45900
  }).trim();
46031
45901
  } catch {
46032
45902
  return null;
@@ -58052,8 +57922,7 @@ const buildOutcomeAttributes = (input) => {
58052
57922
  }),
58053
57923
  ...withNamespace("deadCode", {
58054
57924
  failed: input.didDeadCodeFail ?? null,
58055
- overlapped: input.deadCodeOverlapped ?? null,
58056
- cacheHit: result.deadCodeCacheHit ?? null
57925
+ overlapped: input.deadCodeOverlapped ?? null
58057
57926
  }),
58058
57927
  ...withNamespace("supplyChain", { overlapTimedOut: input.supplyChainOverlapTimedOut ?? null }),
58059
57928
  ...withNamespace("securityScan", { failed: input.securityScanFailed ?? null }),
@@ -59866,8 +59735,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
59866
59735
  scanMode: baselineDelta ? "baseline" : isDiffMode ? "diff" : "full",
59867
59736
  baselineDegraded,
59868
59737
  lintCacheHitFileCount: output.lintCacheHitFileCount,
59869
- lintCacheTotalFileCount: output.lintCacheTotalFileCount,
59870
- deadCodeCacheHit: output.deadCodeCacheHit
59738
+ lintCacheTotalFileCount: output.lintCacheTotalFileCount
59871
59739
  });
59872
59740
  recordOnboardingCompletion(options);
59873
59741
  return result;
@@ -59902,7 +59770,6 @@ const renderAndRecordScan = async (input) => {
59902
59770
  scanElapsedMilliseconds: input.payload.scanElapsedMilliseconds,
59903
59771
  lintCacheHitFileCount: input.lintCacheHitFileCount ?? null,
59904
59772
  lintCacheTotalFileCount: input.lintCacheTotalFileCount ?? null,
59905
- deadCodeCacheHit: input.deadCodeCacheHit ?? null,
59906
59773
  baselineDelta: input.payload.baselineDelta
59907
59774
  }), input.options.silent));
59908
59775
  const { workerCount: resolvedWorkerCount, parallel } = resolveWorkerTelemetry(input.payload.scanConcurrency, input.options.concurrency);
@@ -59941,7 +59808,7 @@ const renderAndRecordScan = async (input) => {
59941
59808
  return result;
59942
59809
  };
59943
59810
  const finalizeAndRender = (input) => gen(function* () {
59944
- const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, deadCodeCacheHit, baselineDelta } = input;
59811
+ const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, baselineDelta } = input;
59945
59812
  const { skippedChecks, skippedCheckReasons } = buildSkippedChecks({
59946
59813
  didLintFail,
59947
59814
  lintFailureReason,
@@ -59965,7 +59832,6 @@ const finalizeAndRender = (input) => gen(function* () {
59965
59832
  lintCacheHitFileCount,
59966
59833
  lintCacheTotalFileCount
59967
59834
  } : {},
59968
- ...deadCodeCacheHit !== null ? { deadCodeCacheHit } : {},
59969
59835
  ...baselineDelta ? { baselineDelta } : {}
59970
59836
  });
59971
59837
  if (options.suppressRendering) return buildResult();
@@ -63812,4 +63678,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
63812
63678
  export {};
63813
63679
 
63814
63680
  //# sourceMappingURL=cli.js.map
63815
- //# debugId=82500030-a7a7-5da8-b18e-cbdb42102dc3
63681
+ //# debugId=328318eb-6af2-5007-b816-51c953a96047
package/dist/index.d.ts CHANGED
@@ -9743,14 +9743,6 @@ interface InspectResult {
9743
9743
  */
9744
9744
  lintCacheHitFileCount?: number | null;
9745
9745
  lintCacheTotalFileCount?: number | null;
9746
- /**
9747
- * Dead-code result cache outcome: `true` when the pass replayed a cached
9748
- * result (the analysis never ran), `false` on a fresh analysis. Absent when
9749
- * the pass never consulted the cache — dead-code skipped, the cache
9750
- * disabled, or a whole-repo cache replay where no analysis ran. The CLI
9751
- * projects it onto the Sentry wide event as `deadCode.cacheHit`.
9752
- */
9753
- deadCodeCacheHit?: boolean | null;
9754
9746
  /**
9755
9747
  * Present only for a baseline run (`InspectOptions.baseline` set). The
9756
9748
  * `diagnostics` above are then the *introduced* findings only; this
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]="fb390a00-3616-5547-b572-1ce120b0e1a2")}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]="8565c6ea-39f3-51e6-895a-ae9f7c026d0e")}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";
@@ -32927,7 +32927,6 @@ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
32927
32927
  const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
32928
32928
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
32929
32929
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
32930
- const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
32931
32930
  const SUPPLY_CHAIN_PLUGIN = "socket";
32932
32931
  const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
32933
32932
  const SUPPLY_CHAIN_CATEGORY = "Security";
@@ -35614,25 +35613,6 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
35614
35613
  if (CACHE_DISABLED_VALUES.has(noFileCache)) return false;
35615
35614
  return true;
35616
35615
  } }) {};
35617
- /**
35618
- * Whether the whole-project dead-code result cache
35619
- * (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
35620
- * whose inputs (source tree, manifests, configs, analyzer version) are
35621
- * unchanged replays the stored diagnostics instead of re-running the
35622
- * analysis worker. Opt-OUT, two knobs (matching the per-file lint cache):
35623
- *
35624
- * - `REACT_DOCTOR_NO_CACHE` — the global off-switch.
35625
- * - `REACT_DOCTOR_NO_DEAD_CODE_CACHE` — granular: bust only this cache.
35626
- *
35627
- * Tests override via `Layer.succeed(DeadCodeResultCacheEnabled, false)`.
35628
- */
35629
- var DeadCodeResultCacheEnabled = class extends Reference("react-doctor/DeadCodeResultCacheEnabled", { defaultValue: () => {
35630
- const noCache = process.env["REACT_DOCTOR_NO_CACHE"]?.toLowerCase() ?? "";
35631
- const noDeadCodeCache = process.env["REACT_DOCTOR_NO_DEAD_CODE_CACHE"]?.toLowerCase() ?? "";
35632
- if (CACHE_DISABLED_VALUES.has(noCache)) return false;
35633
- if (CACHE_DISABLED_VALUES.has(noDeadCodeCache)) return false;
35634
- return true;
35635
- } }) {};
35636
35616
  const DIAGNOSTIC_SURFACES = [
35637
35617
  "cli",
35638
35618
  "prComment",
@@ -37321,108 +37301,6 @@ const collectDeadCodeIgnorePatterns = (rootDirectory) => {
37321
37301
  return [...seen].filter((pattern) => pattern.length > 0);
37322
37302
  };
37323
37303
  const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
37324
- const atomicWriteJson = (filePath, value) => {
37325
- try {
37326
- NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
37327
- const temporaryPath = `${filePath}.${process.pid}.tmp`;
37328
- NFS.writeFileSync(temporaryPath, JSON.stringify(value));
37329
- NFS.renameSync(temporaryPath, filePath);
37330
- } catch {
37331
- return;
37332
- }
37333
- };
37334
- const failOpenReadJson = (filePath, fallback) => {
37335
- try {
37336
- return JSON.parse(NFS.readFileSync(filePath, "utf8"));
37337
- } catch {
37338
- return fallback;
37339
- }
37340
- };
37341
- const ANALYZED_FILE_EXTENSIONS = new Set([
37342
- ".ts",
37343
- ".tsx",
37344
- ".js",
37345
- ".jsx",
37346
- ".mts",
37347
- ".mjs",
37348
- ".cts",
37349
- ".cjs",
37350
- ".mdx",
37351
- ".astro",
37352
- ".graphql",
37353
- ".gql",
37354
- ".css",
37355
- ".scss",
37356
- ".vue",
37357
- ".svelte"
37358
- ]);
37359
- const ANALYZED_MANIFEST_NAMES = new Set([
37360
- "package.json",
37361
- "knip.json",
37362
- "app.json",
37363
- "pnpm-workspace.yaml",
37364
- "lerna.json",
37365
- "pnpm-lock.yaml",
37366
- "package-lock.json",
37367
- "yarn.lock",
37368
- "bun.lock",
37369
- "bun.lockb",
37370
- "deno.lock",
37371
- ".gitignore"
37372
- ]);
37373
- const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
37374
- const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
37375
- const collectAnalyzedFileFingerprints = (rootDirectory) => {
37376
- const fingerprints = [];
37377
- for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
37378
- if (!isFingerprintedFile(name)) continue;
37379
- try {
37380
- const fileStat = NFS.statSync(absolutePath);
37381
- const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
37382
- fingerprints.push(`${relativePath}:${fileStat.mtimeMs}:${fileStat.size}`);
37383
- } catch {}
37384
- }
37385
- return fingerprints.sort();
37386
- };
37387
- const bundledRequire$2 = createRequire(import.meta.url);
37388
- const resolveDeslopVersion = () => {
37389
- try {
37390
- const packageJson = JSON.parse(NFS.readFileSync(bundledRequire$2.resolve("deslop-js/package.json"), "utf8"));
37391
- return isRecord(packageJson) && typeof packageJson.version === "string" ? packageJson.version : "unknown";
37392
- } catch {
37393
- return "unknown";
37394
- }
37395
- };
37396
- const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
37397
- schemaVersion: 1,
37398
- deslopVersion: resolveDeslopVersion(),
37399
- deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
37400
- entryPatterns: input.entryPatterns,
37401
- ignorePatterns: input.ignorePatterns,
37402
- tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
37403
- files: collectAnalyzedFileFingerprints(input.rootDirectory)
37404
- })).digest("hex");
37405
- const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
37406
- const decodeCachedDiagnostics = (raw) => {
37407
- try {
37408
- for (const entry of raw) validateDiagnostic$1(entry);
37409
- return raw;
37410
- } catch {
37411
- return null;
37412
- }
37413
- };
37414
- const lookupDeadCodeResultCache = (cacheDirectory, cacheKey) => {
37415
- const persisted = failOpenReadJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), null);
37416
- if (persisted === null || !isRecord(persisted) || persisted.version !== 1 || persisted.key !== cacheKey || !Array.isArray(persisted.diagnostics)) return null;
37417
- return decodeCachedDiagnostics(persisted.diagnostics);
37418
- };
37419
- const storeDeadCodeResultCache = (cacheDirectory, cacheKey, diagnostics) => {
37420
- atomicWriteJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
37421
- version: 1,
37422
- key: cacheKey,
37423
- diagnostics
37424
- });
37425
- };
37426
37304
  const readSystemFacts = () => ({
37427
37305
  availableCores: os.availableParallelism(),
37428
37306
  totalMemoryBytes: os.totalmem(),
@@ -37491,21 +37369,6 @@ const withDeadCodeWorkerSlot = async (task, abortSignal) => {
37491
37369
  releaseSlot();
37492
37370
  }
37493
37371
  };
37494
- const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
37495
- const resolveReactDoctorCacheDir = (projectDirectory) => {
37496
- const cacheDirOverride = process.env["REACT_DOCTOR_CACHE_DIR"]?.trim();
37497
- if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
37498
- const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
37499
- if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
37500
- return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
37501
- };
37502
- const resolveUserCacheScope = () => {
37503
- try {
37504
- return String(process.getuid?.() ?? os.userInfo().username);
37505
- } catch {
37506
- return "shared";
37507
- }
37508
- };
37509
37372
  /**
37510
37373
  * Resolves a path to its canonical, symlink-free form, falling back to
37511
37374
  * the input when it cannot be realpath'd (broken symlink, permission
@@ -37801,27 +37664,13 @@ const checkDeadCode = async (options) => {
37801
37664
  if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
37802
37665
  const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
37803
37666
  const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
37804
- const tsConfigPath = resolveTsConfigPath(rootDirectory);
37805
- const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
37806
- const cacheKey = options.cacheEnabled ? computeDeadCodeCacheKey({
37807
- rootDirectory,
37808
- entryPatterns,
37809
- ignorePatterns,
37810
- tsConfigPath,
37811
- deslopJsModuleSpecifier
37812
- }) : null;
37813
- if (cacheKey !== null) {
37814
- const cachedDiagnostics = lookupDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey);
37815
- options.onCacheOutcome?.(cachedDiagnostics !== null);
37816
- if (cachedDiagnostics !== null) return [...cachedDiagnostics];
37817
- }
37818
37667
  const spawnAndRun = () => {
37819
37668
  return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
37820
37669
  rootDirectory,
37821
37670
  entryPatterns,
37822
- tsConfigPath,
37671
+ tsConfigPath: resolveTsConfigPath(rootDirectory),
37823
37672
  ignorePatterns,
37824
- deslopJsModuleSpecifier,
37673
+ deslopJsModuleSpecifier: options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js"),
37825
37674
  parseConcurrency: options.parseConcurrency
37826
37675
  }), options.workerTimeoutMs ?? 12e4, options.abortSignal);
37827
37676
  };
@@ -37882,7 +37731,6 @@ const checkDeadCode = async (options) => {
37882
37731
  category: DEAD_CODE_CATEGORY
37883
37732
  });
37884
37733
  }
37885
- if (cacheKey !== null) storeDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey, diagnostics);
37886
37734
  return diagnostics;
37887
37735
  };
37888
37736
  const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
@@ -37985,15 +37833,12 @@ var Config = class Config extends Service()("react-doctor/Config") {
37985
37833
  */
37986
37834
  var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
37987
37835
  static layerNode = succeed$3(DeadCode, DeadCode.of({ run: (input) => unwrap(fn("DeadCode.run")(function* () {
37988
- const cacheEnabled = yield* DeadCodeResultCacheEnabled;
37989
37836
  return yield* tryPromise({
37990
37837
  try: (signal) => checkDeadCode({
37991
37838
  rootDirectory: input.rootDirectory,
37992
37839
  parseConcurrency: input.parseConcurrency,
37993
37840
  workerTimeoutMs: input.workerTimeoutMs,
37994
- abortSignal: signal,
37995
- cacheEnabled,
37996
- onCacheOutcome: input.onCacheOutcome
37841
+ abortSignal: signal
37997
37842
  }),
37998
37843
  catch: (cause) => new ReactDoctorError({ reason: new DeadCodeAnalysisFailed({ cause }) })
37999
37844
  }).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)));
@@ -38919,6 +38764,23 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
38919
38764
  }
38920
38765
  };
38921
38766
  };
38767
+ const atomicWriteJson = (filePath, value) => {
38768
+ try {
38769
+ NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
38770
+ const temporaryPath = `${filePath}.${process.pid}.tmp`;
38771
+ NFS.writeFileSync(temporaryPath, JSON.stringify(value));
38772
+ NFS.renameSync(temporaryPath, filePath);
38773
+ } catch {
38774
+ return;
38775
+ }
38776
+ };
38777
+ const failOpenReadJson = (filePath, fallback) => {
38778
+ try {
38779
+ return JSON.parse(NFS.readFileSync(filePath, "utf8"));
38780
+ } catch {
38781
+ return fallback;
38782
+ }
38783
+ };
38922
38784
  const validateDiagnostic = decodeUnknownSync(Diagnostic);
38923
38785
  const decodeFileDiagnostics = (raw) => {
38924
38786
  if (!Array.isArray(raw)) return null;
@@ -40046,6 +39908,21 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
40046
39908
  }
40047
39909
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
40048
39910
  };
39911
+ const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
39912
+ const resolveReactDoctorCacheDir = (projectDirectory) => {
39913
+ const cacheDirOverride = process.env["REACT_DOCTOR_CACHE_DIR"]?.trim();
39914
+ if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
39915
+ const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
39916
+ if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
39917
+ return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
39918
+ };
39919
+ const resolveUserCacheScope = () => {
39920
+ try {
39921
+ return String(process.getuid?.() ?? os.userInfo().username);
39922
+ } catch {
39923
+ return "shared";
39924
+ }
39925
+ };
40049
39926
  /**
40050
39927
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
40051
39928
  * the runner: once for the primary scan, once for the
@@ -41172,10 +41049,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41172
41049
  const buildCollectDeadCode = (deadCodeTimeout) => runCollect(applyPerElementPipeline(deadCodeService.run({
41173
41050
  rootDirectory: scanDirectory,
41174
41051
  parseConcurrency: deadCodeParseConcurrency,
41175
- workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
41176
- onCacheOutcome: (didHitCache) => {
41177
- deadCodeCacheHit = didHitCache;
41178
- }
41052
+ workerTimeoutMs: deadCodeTimeout.workerTimeoutMs
41179
41053
  }).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
41180
41054
  yield* set(deadCodeFailure, {
41181
41055
  didFail: true,
@@ -41203,7 +41077,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41203
41077
  let lastReportedTotalFileCount = 0;
41204
41078
  let lintCacheHitFileCount = null;
41205
41079
  let lintCacheTotalFileCount = null;
41206
- let deadCodeCacheHit = null;
41207
41080
  const baseLintStream = linterService.run({
41208
41081
  rootDirectory: scanDirectory,
41209
41082
  project,
@@ -41333,7 +41206,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41333
41206
  securityScanFailed,
41334
41207
  lintCacheHitFileCount,
41335
41208
  lintCacheTotalFileCount,
41336
- deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
41337
41209
  suppressedRuleCounts: transform.summarizeSuppressions()
41338
41210
  };
41339
41211
  }).pipe(withSpan("runInspect", { attributes: {
@@ -41974,4 +41846,4 @@ const toJsonReport = (result, options) => buildJsonReport({
41974
41846
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
41975
41847
 
41976
41848
  //# sourceMappingURL=index.js.map
41977
- //# debugId=fb390a00-3616-5547-b572-1ce120b0e1a2
41849
+ //# debugId=8565c6ea-39f3-51e6-895a-ae9f7c026d0e
package/dist/lsp.js CHANGED
@@ -32986,7 +32986,6 @@ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
32986
32986
  const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
32987
32987
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
32988
32988
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
32989
- const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
32990
32989
  const SUPPLY_CHAIN_PLUGIN = "socket";
32991
32990
  const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
32992
32991
  const SUPPLY_CHAIN_CATEGORY = "Security";
@@ -35647,25 +35646,6 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
35647
35646
  if (CACHE_DISABLED_VALUES.has(noFileCache)) return false;
35648
35647
  return true;
35649
35648
  } }) {};
35650
- /**
35651
- * Whether the whole-project dead-code result cache
35652
- * (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
35653
- * whose inputs (source tree, manifests, configs, analyzer version) are
35654
- * unchanged replays the stored diagnostics instead of re-running the
35655
- * analysis worker. Opt-OUT, two knobs (matching the per-file lint cache):
35656
- *
35657
- * - `REACT_DOCTOR_NO_CACHE` — the global off-switch.
35658
- * - `REACT_DOCTOR_NO_DEAD_CODE_CACHE` — granular: bust only this cache.
35659
- *
35660
- * Tests override via `Layer.succeed(DeadCodeResultCacheEnabled, false)`.
35661
- */
35662
- var DeadCodeResultCacheEnabled = class extends Reference("react-doctor/DeadCodeResultCacheEnabled", { defaultValue: () => {
35663
- const noCache = process.env["REACT_DOCTOR_NO_CACHE"]?.toLowerCase() ?? "";
35664
- const noDeadCodeCache = process.env["REACT_DOCTOR_NO_DEAD_CODE_CACHE"]?.toLowerCase() ?? "";
35665
- if (CACHE_DISABLED_VALUES.has(noCache)) return false;
35666
- if (CACHE_DISABLED_VALUES.has(noDeadCodeCache)) return false;
35667
- return true;
35668
- } }) {};
35669
35649
  const DIAGNOSTIC_SURFACES = [
35670
35650
  "cli",
35671
35651
  "prComment",
@@ -37306,108 +37286,6 @@ const collectDeadCodeIgnorePatterns = (rootDirectory) => {
37306
37286
  return [...seen].filter((pattern) => pattern.length > 0);
37307
37287
  };
37308
37288
  const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
37309
- const atomicWriteJson = (filePath, value) => {
37310
- try {
37311
- NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
37312
- const temporaryPath = `${filePath}.${process.pid}.tmp`;
37313
- NFS.writeFileSync(temporaryPath, JSON.stringify(value));
37314
- NFS.renameSync(temporaryPath, filePath);
37315
- } catch {
37316
- return;
37317
- }
37318
- };
37319
- const failOpenReadJson = (filePath, fallback) => {
37320
- try {
37321
- return JSON.parse(NFS.readFileSync(filePath, "utf8"));
37322
- } catch {
37323
- return fallback;
37324
- }
37325
- };
37326
- const ANALYZED_FILE_EXTENSIONS = new Set([
37327
- ".ts",
37328
- ".tsx",
37329
- ".js",
37330
- ".jsx",
37331
- ".mts",
37332
- ".mjs",
37333
- ".cts",
37334
- ".cjs",
37335
- ".mdx",
37336
- ".astro",
37337
- ".graphql",
37338
- ".gql",
37339
- ".css",
37340
- ".scss",
37341
- ".vue",
37342
- ".svelte"
37343
- ]);
37344
- const ANALYZED_MANIFEST_NAMES = new Set([
37345
- "package.json",
37346
- "knip.json",
37347
- "app.json",
37348
- "pnpm-workspace.yaml",
37349
- "lerna.json",
37350
- "pnpm-lock.yaml",
37351
- "package-lock.json",
37352
- "yarn.lock",
37353
- "bun.lock",
37354
- "bun.lockb",
37355
- "deno.lock",
37356
- ".gitignore"
37357
- ]);
37358
- const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
37359
- const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
37360
- const collectAnalyzedFileFingerprints = (rootDirectory) => {
37361
- const fingerprints = [];
37362
- for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
37363
- if (!isFingerprintedFile(name)) continue;
37364
- try {
37365
- const fileStat = NFS.statSync(absolutePath);
37366
- const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
37367
- fingerprints.push(`${relativePath}:${fileStat.mtimeMs}:${fileStat.size}`);
37368
- } catch {}
37369
- }
37370
- return fingerprints.sort();
37371
- };
37372
- const bundledRequire$2 = createRequire(import.meta.url);
37373
- const resolveDeslopVersion = () => {
37374
- try {
37375
- const packageJson = JSON.parse(NFS.readFileSync(bundledRequire$2.resolve("deslop-js/package.json"), "utf8"));
37376
- return isRecord(packageJson) && typeof packageJson.version === "string" ? packageJson.version : "unknown";
37377
- } catch {
37378
- return "unknown";
37379
- }
37380
- };
37381
- const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
37382
- schemaVersion: 1,
37383
- deslopVersion: resolveDeslopVersion(),
37384
- deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
37385
- entryPatterns: input.entryPatterns,
37386
- ignorePatterns: input.ignorePatterns,
37387
- tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
37388
- files: collectAnalyzedFileFingerprints(input.rootDirectory)
37389
- })).digest("hex");
37390
- const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
37391
- const decodeCachedDiagnostics = (raw) => {
37392
- try {
37393
- for (const entry of raw) validateDiagnostic$1(entry);
37394
- return raw;
37395
- } catch {
37396
- return null;
37397
- }
37398
- };
37399
- const lookupDeadCodeResultCache = (cacheDirectory, cacheKey) => {
37400
- const persisted = failOpenReadJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), null);
37401
- if (persisted === null || !isRecord(persisted) || persisted.version !== 1 || persisted.key !== cacheKey || !Array.isArray(persisted.diagnostics)) return null;
37402
- return decodeCachedDiagnostics(persisted.diagnostics);
37403
- };
37404
- const storeDeadCodeResultCache = (cacheDirectory, cacheKey, diagnostics) => {
37405
- atomicWriteJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
37406
- version: 1,
37407
- key: cacheKey,
37408
- diagnostics
37409
- });
37410
- };
37411
37289
  const readSystemFacts = () => ({
37412
37290
  availableCores: os.availableParallelism(),
37413
37291
  totalMemoryBytes: os.totalmem(),
@@ -37476,21 +37354,6 @@ const withDeadCodeWorkerSlot = async (task, abortSignal) => {
37476
37354
  releaseSlot();
37477
37355
  }
37478
37356
  };
37479
- const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
37480
- const resolveReactDoctorCacheDir = (projectDirectory) => {
37481
- const cacheDirOverride = process.env["REACT_DOCTOR_CACHE_DIR"]?.trim();
37482
- if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
37483
- const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
37484
- if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
37485
- return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
37486
- };
37487
- const resolveUserCacheScope = () => {
37488
- try {
37489
- return String(process.getuid?.() ?? os.userInfo().username);
37490
- } catch {
37491
- return "shared";
37492
- }
37493
- };
37494
37357
  /**
37495
37358
  * Resolves a path to its canonical, symlink-free form, falling back to
37496
37359
  * the input when it cannot be realpath'd (broken symlink, permission
@@ -37786,27 +37649,13 @@ const checkDeadCode = async (options) => {
37786
37649
  if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
37787
37650
  const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
37788
37651
  const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
37789
- const tsConfigPath = resolveTsConfigPath(rootDirectory);
37790
- const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
37791
- const cacheKey = options.cacheEnabled ? computeDeadCodeCacheKey({
37792
- rootDirectory,
37793
- entryPatterns,
37794
- ignorePatterns,
37795
- tsConfigPath,
37796
- deslopJsModuleSpecifier
37797
- }) : null;
37798
- if (cacheKey !== null) {
37799
- const cachedDiagnostics = lookupDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey);
37800
- options.onCacheOutcome?.(cachedDiagnostics !== null);
37801
- if (cachedDiagnostics !== null) return [...cachedDiagnostics];
37802
- }
37803
37652
  const spawnAndRun = () => {
37804
37653
  return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
37805
37654
  rootDirectory,
37806
37655
  entryPatterns,
37807
- tsConfigPath,
37656
+ tsConfigPath: resolveTsConfigPath(rootDirectory),
37808
37657
  ignorePatterns,
37809
- deslopJsModuleSpecifier,
37658
+ deslopJsModuleSpecifier: options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js"),
37810
37659
  parseConcurrency: options.parseConcurrency
37811
37660
  }), options.workerTimeoutMs ?? 12e4, options.abortSignal);
37812
37661
  };
@@ -37867,7 +37716,6 @@ const checkDeadCode = async (options) => {
37867
37716
  category: DEAD_CODE_CATEGORY
37868
37717
  });
37869
37718
  }
37870
- if (cacheKey !== null) storeDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey, diagnostics);
37871
37719
  return diagnostics;
37872
37720
  };
37873
37721
  const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
@@ -37970,15 +37818,12 @@ var Config = class Config extends Service()("react-doctor/Config") {
37970
37818
  */
37971
37819
  var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
37972
37820
  static layerNode = succeed$3(DeadCode, DeadCode.of({ run: (input) => unwrap(fn("DeadCode.run")(function* () {
37973
- const cacheEnabled = yield* DeadCodeResultCacheEnabled;
37974
37821
  return yield* tryPromise({
37975
37822
  try: (signal) => checkDeadCode({
37976
37823
  rootDirectory: input.rootDirectory,
37977
37824
  parseConcurrency: input.parseConcurrency,
37978
37825
  workerTimeoutMs: input.workerTimeoutMs,
37979
- abortSignal: signal,
37980
- cacheEnabled,
37981
- onCacheOutcome: input.onCacheOutcome
37826
+ abortSignal: signal
37982
37827
  }),
37983
37828
  catch: (cause) => new ReactDoctorError({ reason: new DeadCodeAnalysisFailed({ cause }) })
37984
37829
  }).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)));
@@ -38904,6 +38749,23 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
38904
38749
  }
38905
38750
  };
38906
38751
  };
38752
+ const atomicWriteJson = (filePath, value) => {
38753
+ try {
38754
+ NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
38755
+ const temporaryPath = `${filePath}.${process.pid}.tmp`;
38756
+ NFS.writeFileSync(temporaryPath, JSON.stringify(value));
38757
+ NFS.renameSync(temporaryPath, filePath);
38758
+ } catch {
38759
+ return;
38760
+ }
38761
+ };
38762
+ const failOpenReadJson = (filePath, fallback) => {
38763
+ try {
38764
+ return JSON.parse(NFS.readFileSync(filePath, "utf8"));
38765
+ } catch {
38766
+ return fallback;
38767
+ }
38768
+ };
38907
38769
  const validateDiagnostic = decodeUnknownSync(Diagnostic);
38908
38770
  const decodeFileDiagnostics = (raw) => {
38909
38771
  if (!Array.isArray(raw)) return null;
@@ -40031,6 +39893,21 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
40031
39893
  }
40032
39894
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
40033
39895
  };
39896
+ const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
39897
+ const resolveReactDoctorCacheDir = (projectDirectory) => {
39898
+ const cacheDirOverride = process.env["REACT_DOCTOR_CACHE_DIR"]?.trim();
39899
+ if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
39900
+ const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
39901
+ if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
39902
+ return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
39903
+ };
39904
+ const resolveUserCacheScope = () => {
39905
+ try {
39906
+ return String(process.getuid?.() ?? os.userInfo().username);
39907
+ } catch {
39908
+ return "shared";
39909
+ }
39910
+ };
40034
39911
  /**
40035
39912
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
40036
39913
  * the runner: once for the primary scan, once for the
@@ -41157,10 +41034,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41157
41034
  const buildCollectDeadCode = (deadCodeTimeout) => runCollect(applyPerElementPipeline(deadCodeService.run({
41158
41035
  rootDirectory: scanDirectory,
41159
41036
  parseConcurrency: deadCodeParseConcurrency,
41160
- workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
41161
- onCacheOutcome: (didHitCache) => {
41162
- deadCodeCacheHit = didHitCache;
41163
- }
41037
+ workerTimeoutMs: deadCodeTimeout.workerTimeoutMs
41164
41038
  }).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
41165
41039
  yield* set(deadCodeFailure, {
41166
41040
  didFail: true,
@@ -41188,7 +41062,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41188
41062
  let lastReportedTotalFileCount = 0;
41189
41063
  let lintCacheHitFileCount = null;
41190
41064
  let lintCacheTotalFileCount = null;
41191
- let deadCodeCacheHit = null;
41192
41065
  const baseLintStream = linterService.run({
41193
41066
  rootDirectory: scanDirectory,
41194
41067
  project,
@@ -41318,7 +41191,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41318
41191
  securityScanFailed,
41319
41192
  lintCacheHitFileCount,
41320
41193
  lintCacheTotalFileCount,
41321
- deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
41322
41194
  suppressedRuleCounts: transform.summarizeSuppressions()
41323
41195
  };
41324
41196
  }).pipe(withSpan("runInspect", { attributes: {
@@ -43698,5 +43570,5 @@ const startLanguageServer = () => {
43698
43570
  };
43699
43571
  //#endregion
43700
43572
  export { startLanguageServer };
43701
- !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]="46e851cc-7b86-5c73-afb0-e09296beab28")}catch(e){}}();
43702
- //# debugId=46e851cc-7b86-5c73-afb0-e09296beab28
43573
+ !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]="94a57ec3-d5a9-52ea-a743-e91d996065b8")}catch(e){}}();
43574
+ //# debugId=94a57ec3-d5a9-52ea-a743-e91d996065b8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.6.3-dev.e257a5e",
3
+ "version": "0.6.3",
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.6.3-dev.e257a5e",
69
- "deslop-js": "0.6.3"
68
+ "deslop-js": "0.6.3",
69
+ "oxlint-plugin-react-doctor": "0.6.3"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/babel__code-frame": "^7.27.0",
@@ -75,8 +75,8 @@
75
75
  "commander": "^14.0.3",
76
76
  "ora": "^9.4.0",
77
77
  "@react-doctor/api": "0.6.3",
78
- "@react-doctor/core": "0.6.3",
79
- "@react-doctor/language-server": "0.6.3"
78
+ "@react-doctor/language-server": "0.6.3",
79
+ "@react-doctor/core": "0.6.3"
80
80
  },
81
81
  "engines": {
82
82
  "node": "^20.19.0 || >=22.13.0"