react-doctor 0.6.3-dev.bdf8074 → 0.6.3-dev.ce49250

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/index.d.ts CHANGED
@@ -9743,14 +9743,6 @@ interface InspectResult {
9743
9743
  */
9744
9744
  lintCacheHitFileCount?: number | null;
9745
9745
  lintCacheTotalFileCount?: number | null;
9746
- /**
9747
- * Sidecar lint cache outcome: cache-hit files whose cross-file diagnostics
9748
- * replayed from the sidecar store, and the hits considered. Both absent
9749
- * when the sidecar cache was off or bypassed. The CLI projects these onto
9750
- * the Sentry wide event as `lint.sidecarReplayRatio`.
9751
- */
9752
- lintSidecarReplayedFileCount?: number | null;
9753
- lintSidecarTotalFileCount?: number | null;
9754
9746
  /**
9755
9747
  * Dead-code result cache outcome: `true` when the pass replayed a cached
9756
9748
  * result (the analysis never ran), `false` on a fresh analysis. Absent when
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]="b55ef8b2-8e9d-512b-81de-a01f6ce3e60e")}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]="f615f76d-a949-5fb6-ace8-145f3e137af4")}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";
@@ -9,7 +9,7 @@ import path from "node:path";
9
9
  import * as NodeChildProcess from "node:child_process";
10
10
  import { execFileSync, spawn, spawnSync } from "node:child_process";
11
11
  import * as ts from "typescript";
12
- import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
12
+ import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
13
13
  import * as OS from "node:os";
14
14
  import os from "node:os";
15
15
  import { parseJSON5 } from "confbox";
@@ -32928,7 +32928,6 @@ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
32928
32928
  const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
32929
32929
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
32930
32930
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
32931
- const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
32932
32931
  const CORE_PACKAGE_VERSION = "0.6.3";
32933
32932
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
32934
32933
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
@@ -35619,29 +35618,6 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
35619
35618
  return true;
35620
35619
  } }) {};
35621
35620
  /**
35622
- * Whether the sidecar lint cache (`runners/oxlint/sidecar-lint-cache.ts`) is
35623
- * active. Defaults ON — warm rescans replay the cross-file rules' cached
35624
- * diagnostics for every file whose dependency fingerprint (the probe set the
35625
- * plugin's collectors recorded) still matches the tree, and re-lint only the
35626
- * rest. Only reachable when the per-file lint cache itself is on (the
35627
- * sidecar covers its cache hits), so `REACT_DOCTOR_NO_CACHE` /
35628
- * `REACT_DOCTOR_NO_FILE_CACHE` implicitly disable it too. Opt-OUT knobs:
35629
- *
35630
- * - `REACT_DOCTOR_NO_CACHE` — the global off-switch.
35631
- * - `REACT_DOCTOR_NO_SIDECAR_CACHE` — granular rollback hatch: keep the
35632
- * per-file cache but run the always-fresh sidecar over every hit
35633
- * (the pre-cache behavior).
35634
- *
35635
- * Tests override via `Layer.succeed(SidecarLintCacheEnabled, false)`.
35636
- */
35637
- var SidecarLintCacheEnabled = class extends Reference("react-doctor/SidecarLintCacheEnabled", { defaultValue: () => {
35638
- const noCache = process.env["REACT_DOCTOR_NO_CACHE"]?.toLowerCase() ?? "";
35639
- const noSidecarCache = process.env["REACT_DOCTOR_NO_SIDECAR_CACHE"]?.toLowerCase() ?? "";
35640
- if (CACHE_DISABLED_VALUES.has(noCache)) return false;
35641
- if (CACHE_DISABLED_VALUES.has(noSidecarCache)) return false;
35642
- return true;
35643
- } }) {};
35644
- /**
35645
35621
  * Whether the whole-project dead-code result cache
35646
35622
  * (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
35647
35623
  * whose inputs (source tree, manifests, configs, analyzer version) are
@@ -37401,10 +37377,10 @@ const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON
37401
37377
  tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
37402
37378
  files: collectAnalyzedFileFingerprints(input.rootDirectory)
37403
37379
  })).digest("hex");
37404
- const validateDiagnostic$2 = decodeUnknownSync(Diagnostic);
37380
+ const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
37405
37381
  const decodeCachedDiagnostics = (raw) => {
37406
37382
  try {
37407
- for (const entry of raw) validateDiagnostic$2(entry);
37383
+ for (const entry of raw) validateDiagnostic$1(entry);
37408
37384
  return raw;
37409
37385
  } catch {
37410
37386
  return null;
@@ -38894,7 +38870,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
38894
38870
  }
38895
38871
  return enabled;
38896
38872
  };
38897
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
38873
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection }) => {
38898
38874
  const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
38899
38875
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
38900
38876
  const jsPlugins = [];
@@ -38906,7 +38882,6 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
38906
38882
  if (!rule) continue;
38907
38883
  if (ruleSelection === "cacheable" && CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
38908
38884
  if (ruleSelection === "sidecar" && !CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
38909
- if (ruleSelection === "sidecar" && sidecarRuleIdFilter !== void 0 && !sidecarRuleIdFilter.has(registryEntry.id)) continue;
38910
38885
  if (rule.scan !== void 0) continue;
38911
38886
  if (customRulesOnly && registryEntry.originallyExternal) continue;
38912
38887
  if (rule.framework !== "global" && !rule.requires) continue;
@@ -38951,23 +38926,23 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
38951
38926
  }
38952
38927
  };
38953
38928
  };
38954
- const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
38929
+ const validateDiagnostic = decodeUnknownSync(Diagnostic);
38955
38930
  const decodeFileDiagnostics = (raw) => {
38956
38931
  if (!Array.isArray(raw)) return null;
38957
38932
  try {
38958
- for (const entry of raw) validateDiagnostic$1(entry);
38933
+ for (const entry of raw) validateDiagnostic(entry);
38959
38934
  return raw;
38960
38935
  } catch {
38961
38936
  return null;
38962
38937
  }
38963
38938
  };
38964
- const emptyCache$1 = () => ({
38939
+ const emptyCache = () => ({
38965
38940
  version: 1,
38966
38941
  rulesets: {}
38967
38942
  });
38968
- const loadRulesetEntries$1 = (cacheFilePath, rulesetHash) => {
38943
+ const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
38969
38944
  const entries = /* @__PURE__ */ new Map();
38970
- const persisted = failOpenReadJson(cacheFilePath, emptyCache$1());
38945
+ const persisted = failOpenReadJson(cacheFilePath, emptyCache());
38971
38946
  if (persisted.version !== 1 || !isRecord(persisted.rulesets)) return entries;
38972
38947
  const bucket = persisted.rulesets[rulesetHash];
38973
38948
  if (!isRecord(bucket) || !isRecord(bucket.files)) return entries;
@@ -38979,156 +38954,20 @@ const loadRulesetEntries$1 = (cacheFilePath, rulesetHash) => {
38979
38954
  };
38980
38955
  const createFileLintCache = (cacheDirectory, rulesetHash) => {
38981
38956
  const cacheFilePath = Path.join(cacheDirectory, FILE_LINT_CACHE_FILENAME);
38982
- const entries = loadRulesetEntries$1(cacheFilePath, rulesetHash);
38957
+ const entries = loadRulesetEntries(cacheFilePath, rulesetHash);
38983
38958
  return {
38984
38959
  lookup: (fileKey) => entries.get(fileKey) ?? null,
38985
38960
  store: (fileKey, diagnostics) => {
38986
38961
  entries.delete(fileKey);
38987
38962
  entries.set(fileKey, diagnostics);
38988
38963
  },
38989
- persist: () => {
38990
- const onDisk = failOpenReadJson(cacheFilePath, emptyCache$1());
38991
- const rulesets = onDisk.version === 1 && isRecord(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
38992
- const existingBucket = rulesets[rulesetHash];
38993
- const existingFiles = isRecord(existingBucket) && isRecord(existingBucket.files) ? existingBucket.files : {};
38994
- const ourFiles = {};
38995
- for (const [fileKey, diagnostics] of entries) ourFiles[fileKey] = diagnostics;
38996
- const cappedEntries = Object.entries({
38997
- ...existingFiles,
38998
- ...ourFiles
38999
- }).slice(-FILE_LINT_CACHE_MAX_FILE_COUNT);
39000
- rulesets[rulesetHash] = {
39001
- updatedAtMs: Date.now(),
39002
- files: Object.fromEntries(cappedEntries)
39003
- };
39004
- atomicWriteJson(cacheFilePath, {
39005
- version: 1,
39006
- rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
39007
- });
39008
- }
39009
- };
39010
- };
39011
- const hashFileContents = (filePath) => {
39012
- try {
39013
- return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
39014
- } catch {
39015
- return null;
39016
- }
39017
- };
39018
- const ABSENT_CONTENT_ANSWER = "absent";
39019
- /**
39020
- * Answers dependency probes for the sidecar lint cache — used both when
39021
- * STORING an entry (turn the collector's probe paths into answers) and when
39022
- * VERIFYING one (re-answer each stored probe against the current tree).
39023
- * Store and verify must agree exactly, so both go through this one resolver.
39024
- *
39025
- * - `content` — SHA-1 of the file's bytes, `"absent"` when unreadable
39026
- * (missing, a directory, permission failure). Source files reuse the
39027
- * hashes the cache-partition loop already computed
39028
- * (`contentHashByRelativePath`); everything else (package.json,
39029
- * tsconfig, ignored files) is hashed on demand.
39030
- * - `exists` — the existence class a module-resolution candidate probe
39031
- * sees: `"file"`, `"dir"`, or `"none"` (missing or an exotic entry —
39032
- * `statSync` follows symlinks, matching the resolvers).
39033
- *
39034
- * Answers are memoized per scan: the filesystem is frozen for the run, and
39035
- * hot dependency paths (a barrel imported by hundreds of files, the shared
39036
- * tsconfig chain) repeat across many files' probe sets.
39037
- */
39038
- const createSidecarProbeAnswerResolver = (input) => {
39039
- const contentAnswerByPath = /* @__PURE__ */ new Map();
39040
- const existsAnswerByPath = /* @__PURE__ */ new Map();
39041
- const toRelativePath = (absolutePath) => Path.relative(input.rootDirectory, absolutePath).replaceAll("\\", "/");
39042
- const contentAnswer = (relativePath) => {
39043
- const memoized = contentAnswerByPath.get(relativePath);
39044
- if (memoized !== void 0) return memoized;
39045
- const answer = input.contentHashByRelativePath.get(relativePath) ?? hashFileContents(Path.resolve(input.rootDirectory, relativePath)) ?? ABSENT_CONTENT_ANSWER;
39046
- contentAnswerByPath.set(relativePath, answer);
39047
- return answer;
39048
- };
39049
- const existsAnswer = (relativePath) => {
39050
- const memoized = existsAnswerByPath.get(relativePath);
39051
- if (memoized !== void 0) return memoized;
39052
- let answer;
39053
- try {
39054
- const stat = NFS.statSync(Path.resolve(input.rootDirectory, relativePath));
39055
- answer = stat.isFile() ? "file" : stat.isDirectory() ? "dir" : "none";
39056
- } catch {
39057
- answer = "none";
39058
- }
39059
- existsAnswerByPath.set(relativePath, answer);
39060
- return answer;
39061
- };
39062
- return {
39063
- answerFor: (kind, relativePath) => kind === "content" ? contentAnswer(relativePath) : existsAnswer(relativePath),
39064
- toRelativePath
39065
- };
39066
- };
39067
- const validateDiagnostic = decodeUnknownSync(Diagnostic);
39068
- const isProbeKind = (value) => value === "content" || value === "exists";
39069
- const decodeSidecarFileEntry = (raw) => {
39070
- if (!isRecord(raw) || !Array.isArray(raw.probes) || !Array.isArray(raw.diagnostics)) return null;
39071
- const probes = [];
39072
- for (const rawProbe of raw.probes) {
39073
- if (!Array.isArray(rawProbe) || rawProbe.length !== 3) return null;
39074
- const [kind, probePath, answer] = rawProbe;
39075
- if (!isProbeKind(kind) || typeof probePath !== "string" || typeof answer !== "string") return null;
39076
- probes.push({
39077
- kind,
39078
- path: probePath,
39079
- answer
39080
- });
39081
- }
39082
- try {
39083
- for (const entry of raw.diagnostics) validateDiagnostic(entry);
39084
- } catch {
39085
- return null;
39086
- }
39087
- return {
39088
- probes,
39089
- diagnostics: raw.diagnostics
39090
- };
39091
- };
39092
- const encodeSidecarFileEntry = (entry) => ({
39093
- probes: entry.probes.map((probe) => [
39094
- probe.kind,
39095
- probe.path,
39096
- probe.answer
39097
- ]),
39098
- diagnostics: entry.diagnostics
39099
- });
39100
- const emptyCache = () => ({
39101
- version: 1,
39102
- rulesets: {}
39103
- });
39104
- const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
39105
- const entries = /* @__PURE__ */ new Map();
39106
- const persisted = failOpenReadJson(cacheFilePath, emptyCache());
39107
- if (persisted.version !== 1 || !isRecord(persisted.rulesets)) return entries;
39108
- const bucket = persisted.rulesets[rulesetHash];
39109
- if (!isRecord(bucket) || !isRecord(bucket.files)) return entries;
39110
- for (const [fileKey, rawEntry] of Object.entries(bucket.files)) {
39111
- const decoded = decodeSidecarFileEntry(rawEntry);
39112
- if (decoded !== null) entries.set(fileKey, decoded);
39113
- }
39114
- return entries;
39115
- };
39116
- const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
39117
- const cacheFilePath = Path.join(cacheDirectory, SIDECAR_LINT_CACHE_FILENAME);
39118
- const entries = loadRulesetEntries(cacheFilePath, rulesetHash);
39119
- return {
39120
- lookup: (fileKey) => entries.get(fileKey) ?? null,
39121
- store: (fileKey, entry) => {
39122
- entries.delete(fileKey);
39123
- entries.set(fileKey, entry);
39124
- },
39125
38964
  persist: () => {
39126
38965
  const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
39127
38966
  const rulesets = onDisk.version === 1 && isRecord(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
39128
38967
  const existingBucket = rulesets[rulesetHash];
39129
38968
  const existingFiles = isRecord(existingBucket) && isRecord(existingBucket.files) ? existingBucket.files : {};
39130
38969
  const ourFiles = {};
39131
- for (const [fileKey, entry] of entries) ourFiles[fileKey] = encodeSidecarFileEntry(entry);
38970
+ for (const [fileKey, diagnostics] of entries) ourFiles[fileKey] = diagnostics;
39132
38971
  const cappedEntries = Object.entries({
39133
38972
  ...existingFiles,
39134
38973
  ...ourFiles
@@ -40143,6 +39982,13 @@ const validateRuleRegistration = () => {
40143
39982
  ].filter((entry) => entry !== null).join("; ");
40144
39983
  console.warn(`[react-doctor] rule-registration drift: ${detail}`);
40145
39984
  };
39985
+ const hashFileContents = (filePath) => {
39986
+ try {
39987
+ return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
39988
+ } catch {
39989
+ return null;
39990
+ }
39991
+ };
40146
39992
  /**
40147
39993
  * Balanced LPT (longest-processing-time-first) lint batch planner. Where
40148
39994
  * `batchIncludePaths` greedily fills 100-file batches and leaves a small
@@ -40224,106 +40070,6 @@ const writeOxlintConfig = (configPath, configToWrite) => {
40224
40070
  NFS.closeSync(fileHandle);
40225
40071
  }
40226
40072
  };
40227
- /**
40228
- * Attributes diagnostics back to the file that produced them by the
40229
- * normalized path oxlint echoes. Returns `null` when ANY diagnostic can't be
40230
- * attributed — the path forms don't align, so the caller must skip its cache
40231
- * store rather than risk caching a wrong empty result for a file that
40232
- * actually had diagnostics.
40233
- */
40234
- const attributeDiagnosticsToFiles = (diagnostics, files) => {
40235
- const fileByNormalizedPath = /* @__PURE__ */ new Map();
40236
- for (const file of files) fileByNormalizedPath.set(file.replaceAll("\\", "/"), file);
40237
- const diagnosticsByFile = /* @__PURE__ */ new Map();
40238
- for (const diagnostic of diagnostics) {
40239
- const file = fileByNormalizedPath.get(diagnostic.filePath);
40240
- if (file === void 0) return null;
40241
- const fileDiagnostics = diagnosticsByFile.get(file) ?? [];
40242
- fileDiagnostics.push(diagnostic);
40243
- diagnosticsByFile.set(file, fileDiagnostics);
40244
- }
40245
- return diagnosticsByFile;
40246
- };
40247
- /**
40248
- * Collects each file's cross-file dependency probes (via the plugin's
40249
- * collectors) with their current answers. Fail-open per file: an unreadable /
40250
- * unparseable / collector-failing file maps to `null` (no entry stored — it
40251
- * re-lints next scan). The filesystem is frozen for the scan, so this can run
40252
- * CONCURRENTLY with an oxlint child-process await — the caller starts it
40253
- * unawaited before a lint pass and awaits it at store time, hiding the
40254
- * in-process parse + resolution cost under the subprocess wait. The loop
40255
- * yields on the cooperative time budget so the child's stdout handling (and
40256
- * sibling fibers) keep flowing; each per-file collection is synchronous, so
40257
- * the module-level probe recorder never sees interleaved use. Never rejects.
40258
- */
40259
- const collectSidecarProbesForFiles = async (input) => {
40260
- const buildProbes = (file) => {
40261
- const absoluteFilePath = Path.resolve(input.rootDirectory, file);
40262
- let trace;
40263
- try {
40264
- trace = collectCrossFileDependencyProbes({
40265
- absoluteFilePath,
40266
- sourceText: NFS.readFileSync(absoluteFilePath, "utf8"),
40267
- ruleIds: input.boundedSidecarRuleIds
40268
- });
40269
- } catch {
40270
- return null;
40271
- }
40272
- if (trace === null) return null;
40273
- const probes = [];
40274
- for (const contentPath of trace.contentPaths) {
40275
- const relativePath = input.probeAnswers.toRelativePath(contentPath);
40276
- probes.push({
40277
- kind: "content",
40278
- path: relativePath,
40279
- answer: input.probeAnswers.answerFor("content", relativePath)
40280
- });
40281
- }
40282
- for (const existencePath of trace.existencePaths) {
40283
- const relativePath = input.probeAnswers.toRelativePath(existencePath);
40284
- probes.push({
40285
- kind: "exists",
40286
- path: relativePath,
40287
- answer: input.probeAnswers.answerFor("exists", relativePath)
40288
- });
40289
- }
40290
- return probes;
40291
- };
40292
- const probesByFile = /* @__PURE__ */ new Map();
40293
- let collectSliceStartedAt = performance.now();
40294
- for (const file of input.files) {
40295
- probesByFile.set(file, buildProbes(file));
40296
- if (performance.now() - collectSliceStartedAt >= 12) {
40297
- await yieldToEventLoop();
40298
- collectSliceStartedAt = performance.now();
40299
- }
40300
- }
40301
- return probesByFile;
40302
- };
40303
- /**
40304
- * Stores each freshly-linted file's probe set + cross-file diagnostics so
40305
- * the next scan can replay instead of re-linting.
40306
- */
40307
- const storeSidecarEntries = (input) => {
40308
- let didStoreAnyEntry = false;
40309
- for (const pass of input.storablePasses) {
40310
- if (!pass.isTrusted) continue;
40311
- const diagnosticsByFile = attributeDiagnosticsToFiles(pass.diagnostics, pass.files);
40312
- if (diagnosticsByFile === null) continue;
40313
- for (const file of pass.files) {
40314
- const cacheKey = input.cacheKeyByFile.get(file);
40315
- if (cacheKey === void 0) continue;
40316
- const probes = pass.probesByFile.get(file);
40317
- if (probes === void 0 || probes === null) continue;
40318
- input.sidecarCache.store(cacheKey, {
40319
- probes,
40320
- diagnostics: diagnosticsByFile.get(file) ?? []
40321
- });
40322
- didStoreAnyEntry = true;
40323
- }
40324
- }
40325
- if (didStoreAnyEntry) input.sidecarCache.persist();
40326
- };
40327
40073
  const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
40328
40074
  /**
40329
40075
  * Detects an oxlint config-load crash caused by the optional
@@ -40365,7 +40111,7 @@ const reactHooksJsPluginDropNote = (error) => {
40365
40111
  * 6. always restore disable directives + clean up the temp dir
40366
40112
  */
40367
40113
  const runOxlint = async (options) => {
40368
- const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
40114
+ const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, perFileLintCacheEnabled = false, onCacheStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
40369
40115
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
40370
40116
  const severityControls = buildRuleSeverityControls(userConfig);
40371
40117
  validateRuleRegistration();
@@ -40383,8 +40129,7 @@ const runOxlint = async (options) => {
40383
40129
  severityControls,
40384
40130
  userPlugins,
40385
40131
  disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
40386
- ruleSelection: overrides.ruleSelection,
40387
- sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
40132
+ ruleSelection: overrides.ruleSelection
40388
40133
  });
40389
40134
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
40390
40135
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
@@ -40487,18 +40232,15 @@ const runOxlint = async (options) => {
40487
40232
  });
40488
40233
  const cache = createFileLintCache(resolveReactDoctorCacheDir(rootDirectory), rulesetHash);
40489
40234
  const cacheKeyByFile = /* @__PURE__ */ new Map();
40490
- const contentHashByRelativePath = /* @__PURE__ */ new Map();
40491
40235
  const missFiles = [];
40492
40236
  const replayedDiagnostics = [];
40493
40237
  let hashSliceStartedAt = performance.now();
40494
40238
  for (const candidateFile of candidateFiles) {
40495
- const absoluteCandidatePath = Path.resolve(rootDirectory, candidateFile);
40496
- const contentHash = hashFileContents(absoluteCandidatePath);
40239
+ const contentHash = hashFileContents(Path.resolve(rootDirectory, candidateFile));
40497
40240
  if (contentHash === null) {
40498
40241
  missFiles.push(candidateFile);
40499
40242
  continue;
40500
40243
  }
40501
- contentHashByRelativePath.set(Path.relative(rootDirectory, absoluteCandidatePath).replaceAll("\\", "/"), contentHash);
40502
40244
  const cacheKey = `${candidateFile.replaceAll("\\", "/")}\u0000${contentHash}`;
40503
40245
  cacheKeyByFile.set(candidateFile, cacheKey);
40504
40246
  const cachedDiagnostics = cache.lookup(cacheKey);
@@ -40510,111 +40252,43 @@ const runOxlint = async (options) => {
40510
40252
  }
40511
40253
  }
40512
40254
  const cacheHitFileCount = candidateFiles.length - missFiles.length;
40513
- const enabledSidecarRuleIds = Object.keys(buildConfig({
40514
- extendsPaths: [],
40515
- ruleSelection: "sidecar"
40516
- }).rules).map((ruleKey) => ruleKey.slice(ruleKey.lastIndexOf("/") + 1)).filter((ruleId) => CROSS_FILE_RULE_IDS.has(ruleId));
40517
- const boundedSidecarRuleIds = enabledSidecarRuleIds.filter((ruleId) => CROSS_FILE_DEPENDENCY_COLLECTORS.has(ruleId));
40518
- const boundedSidecarRuleIdSet = new Set(boundedSidecarRuleIds);
40519
- const unboundedSidecarRuleIds = enabledSidecarRuleIds.filter((ruleId) => !CROSS_FILE_DEPENDENCY_COLLECTORS.has(ruleId));
40520
- const useSidecarCache = sidecarLintCacheEnabled && boundedSidecarRuleIds.length > 0;
40521
- const sidecarCache = useSidecarCache ? createSidecarLintCache(resolveReactDoctorCacheDir(rootDirectory), computeRulesetHash({
40522
- config: buildConfig({
40523
- extendsPaths: [],
40524
- ruleSelection: "sidecar",
40525
- sidecarRuleIdFilter: boundedSidecarRuleIdSet
40526
- }),
40527
- toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
40528
- ignorePatterns: combinedPatterns,
40529
- tsconfigContent
40530
- })) : null;
40531
- const probeAnswers = createSidecarProbeAnswerResolver({
40532
- rootDirectory,
40533
- contentHashByRelativePath
40534
- });
40535
- const missProbesTask = sidecarCache === null ? null : collectSidecarProbesForFiles({
40536
- files: missFiles,
40537
- rootDirectory,
40538
- boundedSidecarRuleIds,
40539
- probeAnswers
40540
- });
40541
40255
  const fullResult = await runConfigOverFiles((overrides) => buildConfig({
40542
40256
  extendsPaths: [],
40543
40257
  disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
40544
40258
  }), "oxlintrc.full.json", missFiles, options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(scannedFileCount, candidateFiles.length)));
40545
40259
  const missFileSet = new Set(missFiles);
40546
- const hitFiles = candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile));
40547
- const sidecarReplayedDiagnostics = [];
40548
- const sidecarLintFiles = [];
40549
- if (sidecarCache === null) sidecarLintFiles.push(...hitFiles);
40550
- else {
40551
- let verifySliceStartedAt = performance.now();
40552
- for (const hitFile of hitFiles) {
40553
- const cacheKey = cacheKeyByFile.get(hitFile);
40554
- const entry = cacheKey === void 0 ? null : sidecarCache.lookup(cacheKey);
40555
- if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer)) sidecarReplayedDiagnostics.push(...entry.diagnostics);
40556
- else sidecarLintFiles.push(hitFile);
40557
- if (performance.now() - verifySliceStartedAt >= 12) {
40558
- await yieldToEventLoop();
40559
- verifySliceStartedAt = performance.now();
40560
- }
40561
- }
40562
- }
40563
- const sidecarProbesTask = sidecarCache === null ? null : collectSidecarProbesForFiles({
40564
- files: sidecarLintFiles,
40565
- rootDirectory,
40566
- boundedSidecarRuleIds,
40567
- probeAnswers
40568
- });
40569
- const sidecarReplayedFileCount = hitFiles.length - sidecarLintFiles.length;
40570
- if (sidecarReplayedFileCount > 0) options.onFileProgress?.(missFiles.length + sidecarReplayedFileCount, candidateFiles.length);
40571
- const boundedSidecarResult = await runConfigOverFiles(() => buildConfig({
40572
- extendsPaths: [],
40573
- ruleSelection: "sidecar",
40574
- ...useSidecarCache ? { sidecarRuleIdFilter: boundedSidecarRuleIdSet } : {}
40575
- }), "oxlintrc.sidecar.json", sidecarLintFiles, options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(missFiles.length + sidecarReplayedFileCount + scannedFileCount, candidateFiles.length)));
40576
- const unboundedSidecarResult = useSidecarCache && unboundedSidecarRuleIds.length > 0 ? await runConfigOverFiles(() => buildConfig({
40260
+ const sidecarResult = await runConfigOverFiles(() => buildConfig({
40577
40261
  extendsPaths: [],
40578
- ruleSelection: "sidecar",
40579
- sidecarRuleIdFilter: new Set(unboundedSidecarRuleIds)
40580
- }), "oxlintrc.sidecar-unbounded.json", hitFiles, void 0) : {
40581
- diagnostics: [],
40582
- didDropReactHooksJsPlugin: false,
40583
- hadPartialFailure: false
40584
- };
40262
+ ruleSelection: "sidecar"
40263
+ }), "oxlintrc.sidecar.json", candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile)), options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(missFiles.length + scannedFileCount, candidateFiles.length)));
40585
40264
  const freshCacheableDiagnostics = [];
40586
40265
  for (const diagnostic of fullResult.diagnostics) if (!CROSS_FILE_RULE_IDS.has(diagnostic.rule)) freshCacheableDiagnostics.push(diagnostic);
40587
40266
  onCacheStats?.(cacheHitFileCount, candidateFiles.length);
40588
- if (sidecarCache !== null) onSidecarStats?.(hitFiles.length - sidecarLintFiles.length, hitFiles.length);
40589
- const freshDiagnosticsByFile = attributeDiagnosticsToFiles(freshCacheableDiagnostics, missFiles);
40590
- if (!fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure && freshDiagnosticsByFile !== null) {
40267
+ const missFileByNormalizedPath = /* @__PURE__ */ new Map();
40268
+ for (const missFile of missFiles) missFileByNormalizedPath.set(missFile.replaceAll("\\", "/"), missFile);
40269
+ const freshDiagnosticsByFile = /* @__PURE__ */ new Map();
40270
+ let isAttributionSound = true;
40271
+ for (const diagnostic of freshCacheableDiagnostics) {
40272
+ const missFile = missFileByNormalizedPath.get(diagnostic.filePath);
40273
+ if (missFile === void 0) {
40274
+ isAttributionSound = false;
40275
+ break;
40276
+ }
40277
+ const fileDiagnostics = freshDiagnosticsByFile.get(missFile) ?? [];
40278
+ fileDiagnostics.push(diagnostic);
40279
+ freshDiagnosticsByFile.set(missFile, fileDiagnostics);
40280
+ }
40281
+ if (!fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure && isAttributionSound) {
40591
40282
  for (const missFile of missFiles) {
40592
40283
  const cacheKey = cacheKeyByFile.get(missFile);
40593
40284
  if (cacheKey !== void 0) cache.store(cacheKey, freshDiagnosticsByFile.get(missFile) ?? []);
40594
40285
  }
40595
40286
  cache.persist();
40596
40287
  }
40597
- if (sidecarCache !== null && missProbesTask !== null && sidecarProbesTask !== null) storeSidecarEntries({
40598
- sidecarCache,
40599
- cacheKeyByFile,
40600
- storablePasses: [{
40601
- files: sidecarLintFiles,
40602
- diagnostics: boundedSidecarResult.diagnostics,
40603
- isTrusted: !boundedSidecarResult.hadPartialFailure,
40604
- probesByFile: await sidecarProbesTask
40605
- }, {
40606
- files: missFiles,
40607
- diagnostics: fullResult.diagnostics.filter((diagnostic) => boundedSidecarRuleIdSet.has(diagnostic.rule)),
40608
- isTrusted: !fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure,
40609
- probesByFile: await missProbesTask
40610
- }]
40611
- });
40612
40288
  return dedupeDiagnostics([
40613
40289
  ...replayedDiagnostics,
40614
40290
  ...fullResult.diagnostics,
40615
- ...sidecarReplayedDiagnostics,
40616
- ...boundedSidecarResult.diagnostics,
40617
- ...unboundedSidecarResult.diagnostics
40291
+ ...sidecarResult.diagnostics
40618
40292
  ]);
40619
40293
  }
40620
40294
  const baseArgs = makeBaseArgs(configPath);
@@ -40712,7 +40386,6 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
40712
40386
  const concurrency = yield* OxlintConcurrency;
40713
40387
  const lintBatchOrdering = yield* LintBatchOrdering;
40714
40388
  const perFileLintCacheEnabled = yield* PerFileLintCacheEnabled;
40715
- const sidecarLintCacheEnabled = yield* SidecarLintCacheEnabled;
40716
40389
  const collectedFailures = [];
40717
40390
  const diagnostics = yield* tryPromise({
40718
40391
  try: (signal) => runOxlint({
@@ -40731,9 +40404,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
40731
40404
  },
40732
40405
  onFileProgress: input.onFileProgress,
40733
40406
  perFileLintCacheEnabled,
40734
- sidecarLintCacheEnabled,
40735
40407
  onCacheStats: input.onCacheStats,
40736
- onSidecarStats: input.onSidecarStats,
40737
40408
  spawnTimeoutMs,
40738
40409
  outputMaxBytes,
40739
40410
  concurrency,
@@ -41543,8 +41214,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41543
41214
  let lastReportedTotalFileCount = 0;
41544
41215
  let lintCacheHitFileCount = null;
41545
41216
  let lintCacheTotalFileCount = null;
41546
- let lintSidecarReplayedFileCount = null;
41547
- let lintSidecarTotalFileCount = null;
41548
41217
  let deadCodeCacheHit = null;
41549
41218
  let deadCodeSummaryCacheHits = null;
41550
41219
  let deadCodeSummaryCacheMisses = null;
@@ -41567,10 +41236,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41567
41236
  lintCacheHitFileCount = cacheHitFileCount;
41568
41237
  lintCacheTotalFileCount = totalConsideredFileCount;
41569
41238
  },
41570
- onSidecarStats: (sidecarReplayedFileCount, sidecarConsideredFileCount) => {
41571
- lintSidecarReplayedFileCount = sidecarReplayedFileCount;
41572
- lintSidecarTotalFileCount = sidecarConsideredFileCount;
41573
- },
41574
41239
  deadlineEpochMs: input.deadlineEpochMs
41575
41240
  }).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
41576
41241
  yield* set(lintFailure, {
@@ -41681,8 +41346,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41681
41346
  securityScanFailed,
41682
41347
  lintCacheHitFileCount,
41683
41348
  lintCacheTotalFileCount,
41684
- lintSidecarReplayedFileCount,
41685
- lintSidecarTotalFileCount,
41686
41349
  deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
41687
41350
  deadCodeSummaryCacheHits: lintFailureState.didFail ? null : deadCodeSummaryCacheHits,
41688
41351
  deadCodeSummaryCacheMisses: lintFailureState.didFail ? null : deadCodeSummaryCacheMisses,
@@ -42326,4 +41989,4 @@ const toJsonReport = (result, options) => buildJsonReport({
42326
41989
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
42327
41990
 
42328
41991
  //# sourceMappingURL=index.js.map
42329
- //# debugId=b55ef8b2-8e9d-512b-81de-a01f6ce3e60e
41992
+ //# debugId=f615f76d-a949-5fb6-ace8-145f3e137af4