react-doctor 0.6.3-dev.e257a5e → 0.6.3-dev.ea9a775
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 +545 -93
- package/dist/index.d.ts +18 -0
- package/dist/index.js +433 -81
- package/dist/lsp.js +433 -81
- package/package.json +2 -2
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]="
|
|
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]="d9c72b21-3e94-5923-b692-077f137a0078")}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";
|
|
@@ -9,7 +9,7 @@ import * as NFS from "node:fs";
|
|
|
9
9
|
import fs, { mkdtempSync, rmSync } from "node:fs";
|
|
10
10
|
import process$1 from "node:process";
|
|
11
11
|
import * as ts from "typescript";
|
|
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";
|
|
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";
|
|
13
13
|
import * as OS from "node:os";
|
|
14
14
|
import os, { tmpdir } from "node:os";
|
|
15
15
|
import { parseJSON5 } from "confbox";
|
|
@@ -18,6 +18,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
18
18
|
import { createJiti } from "jiti";
|
|
19
19
|
import * as Crypto from "node:crypto";
|
|
20
20
|
import crypto, { createHash, randomUUID } from "node:crypto";
|
|
21
|
+
import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
|
|
21
22
|
import { gzipSync } from "node:zlib";
|
|
22
23
|
import * as Sentry from "@sentry/node";
|
|
23
24
|
import { performance as performance$1 } from "node:perf_hooks";
|
|
@@ -36128,7 +36129,10 @@ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
|
|
|
36128
36129
|
const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
36129
36130
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
36130
36131
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
36132
|
+
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
36133
|
+
const CORE_PACKAGE_VERSION = "0.6.3";
|
|
36131
36134
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
36135
|
+
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
36132
36136
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
36133
36137
|
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
36134
36138
|
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
@@ -38814,6 +38818,29 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
|
|
|
38814
38818
|
return true;
|
|
38815
38819
|
} }) {};
|
|
38816
38820
|
/**
|
|
38821
|
+
* Whether the sidecar lint cache (`runners/oxlint/sidecar-lint-cache.ts`) is
|
|
38822
|
+
* active. Defaults ON — warm rescans replay the cross-file rules' cached
|
|
38823
|
+
* diagnostics for every file whose dependency fingerprint (the probe set the
|
|
38824
|
+
* plugin's collectors recorded) still matches the tree, and re-lint only the
|
|
38825
|
+
* rest. Only reachable when the per-file lint cache itself is on (the
|
|
38826
|
+
* sidecar covers its cache hits), so `REACT_DOCTOR_NO_CACHE` /
|
|
38827
|
+
* `REACT_DOCTOR_NO_FILE_CACHE` implicitly disable it too. Opt-OUT knobs:
|
|
38828
|
+
*
|
|
38829
|
+
* - `REACT_DOCTOR_NO_CACHE` — the global off-switch.
|
|
38830
|
+
* - `REACT_DOCTOR_NO_SIDECAR_CACHE` — granular rollback hatch: keep the
|
|
38831
|
+
* per-file cache but run the always-fresh sidecar over every hit
|
|
38832
|
+
* (the pre-cache behavior).
|
|
38833
|
+
*
|
|
38834
|
+
* Tests override via `Layer.succeed(SidecarLintCacheEnabled, false)`.
|
|
38835
|
+
*/
|
|
38836
|
+
var SidecarLintCacheEnabled = class extends Reference("react-doctor/SidecarLintCacheEnabled", { defaultValue: () => {
|
|
38837
|
+
const noCache = process.env["REACT_DOCTOR_NO_CACHE"]?.toLowerCase() ?? "";
|
|
38838
|
+
const noSidecarCache = process.env["REACT_DOCTOR_NO_SIDECAR_CACHE"]?.toLowerCase() ?? "";
|
|
38839
|
+
if (CACHE_DISABLED_VALUES$1.has(noCache)) return false;
|
|
38840
|
+
if (CACHE_DISABLED_VALUES$1.has(noSidecarCache)) return false;
|
|
38841
|
+
return true;
|
|
38842
|
+
} }) {};
|
|
38843
|
+
/**
|
|
38817
38844
|
* Whether the whole-project dead-code result cache
|
|
38818
38845
|
* (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
|
|
38819
38846
|
* whose inputs (source tree, manifests, configs, analyzer version) are
|
|
@@ -40581,38 +40608,9 @@ const failOpenReadJson = (filePath, fallback) => {
|
|
|
40581
40608
|
return fallback;
|
|
40582
40609
|
}
|
|
40583
40610
|
};
|
|
40584
|
-
const ANALYZED_FILE_EXTENSIONS = new Set(
|
|
40585
|
-
|
|
40586
|
-
|
|
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
|
-
]);
|
|
40611
|
+
const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
|
|
40612
|
+
const CORE_SIDE_MANIFEST_NAMES = ["knip.json", "deno.lock"];
|
|
40613
|
+
const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
|
|
40616
40614
|
const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
|
|
40617
40615
|
const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
|
|
40618
40616
|
const collectAnalyzedFileFingerprints = (rootDirectory) => {
|
|
@@ -40638,6 +40636,7 @@ const resolveDeslopVersion = () => {
|
|
|
40638
40636
|
};
|
|
40639
40637
|
const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
|
|
40640
40638
|
schemaVersion: 1,
|
|
40639
|
+
coreVersion: input.coreVersion,
|
|
40641
40640
|
deslopVersion: resolveDeslopVersion(),
|
|
40642
40641
|
deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
|
|
40643
40642
|
entryPatterns: input.entryPatterns,
|
|
@@ -40645,10 +40644,10 @@ const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON
|
|
|
40645
40644
|
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
|
|
40646
40645
|
files: collectAnalyzedFileFingerprints(input.rootDirectory)
|
|
40647
40646
|
})).digest("hex");
|
|
40648
|
-
const validateDiagnostic$
|
|
40647
|
+
const validateDiagnostic$2 = decodeUnknownSync(Diagnostic);
|
|
40649
40648
|
const decodeCachedDiagnostics = (raw) => {
|
|
40650
40649
|
try {
|
|
40651
|
-
for (const entry of raw) validateDiagnostic$
|
|
40650
|
+
for (const entry of raw) validateDiagnostic$2(entry);
|
|
40652
40651
|
return raw;
|
|
40653
40652
|
} catch {
|
|
40654
40653
|
return null;
|
|
@@ -40802,6 +40801,14 @@ process.stdin.on("end", () => {
|
|
|
40802
40801
|
circularDependencies: result.circularDependencies.map((cycle) => ({
|
|
40803
40802
|
files: cycle.files,
|
|
40804
40803
|
})),
|
|
40804
|
+
...(result.incrementalCacheStats
|
|
40805
|
+
? {
|
|
40806
|
+
summaryCacheStats: {
|
|
40807
|
+
hits: result.incrementalCacheStats.summaryHits,
|
|
40808
|
+
misses: result.incrementalCacheStats.summaryMisses,
|
|
40809
|
+
},
|
|
40810
|
+
}
|
|
40811
|
+
: {}),
|
|
40805
40812
|
});
|
|
40806
40813
|
|
|
40807
40814
|
const serializeError = (error) =>
|
|
@@ -40825,6 +40832,9 @@ process.stdin.on("end", () => {
|
|
|
40825
40832
|
...(workerInput.ignorePatterns.length > 0
|
|
40826
40833
|
? { ignorePatterns: workerInput.ignorePatterns }
|
|
40827
40834
|
: {}),
|
|
40835
|
+
...(workerInput.incrementalCachePath
|
|
40836
|
+
? { incrementalCachePath: workerInput.incrementalCachePath }
|
|
40837
|
+
: {}),
|
|
40828
40838
|
// We consume only deslop's GRAPH-based findings (unusedFiles, unusedExports,
|
|
40829
40839
|
// unusedDependencies, circularDependencies). Everything else deslop can compute
|
|
40830
40840
|
// is pure wasted work for us, and it's the bulk of the runtime:
|
|
@@ -40835,12 +40845,18 @@ process.stdin.on("end", () => {
|
|
|
40835
40845
|
// are the single most expensive pass — duplicate-block detection alone was
|
|
40836
40846
|
// ~83s of a ~130s Sentry scan — so skipping them is an ~8.5x dead-code
|
|
40837
40847
|
// speedup on a large repo.
|
|
40838
|
-
//
|
|
40848
|
+
// - reportRedundancy: the DRY-pattern detectors (duplicate types/constants,
|
|
40849
|
+
// simplifiable functions, identity wrappers, …) — ~120 ms of discarded
|
|
40850
|
+
// output per scan, and skipping them lets the incremental cache drop the
|
|
40851
|
+
// DRY-pattern summary fields (the largest slice of the cache file).
|
|
40852
|
+
// All are provably safe: the consumed graph findings are computed by their own
|
|
40839
40853
|
// detectors, independent of these passes (confirmed byte-identical on
|
|
40840
|
-
// excalidraw + mui-material + sentry
|
|
40841
|
-
//
|
|
40854
|
+
// excalidraw + mui-material + sentry; re-verified on sentry after the
|
|
40855
|
+
// reportRedundancy flip). tsConfigPath stays — the module resolver needs it
|
|
40856
|
+
// for path-alias resolution in the import graph.
|
|
40842
40857
|
semantic: { enabled: false },
|
|
40843
40858
|
reportCodeQuality: false,
|
|
40859
|
+
reportRedundancy: false,
|
|
40844
40860
|
};
|
|
40845
40861
|
const result = await analyze(defineConfig(config));
|
|
40846
40862
|
emit({ ok: true, result: normalizeResult(result) });
|
|
@@ -40924,13 +40940,23 @@ const parseCircularDependencies = (value) => {
|
|
|
40924
40940
|
}
|
|
40925
40941
|
return circularDependencies;
|
|
40926
40942
|
};
|
|
40943
|
+
const parseSummaryCacheStats = (value) => {
|
|
40944
|
+
if (!isRecord$1(value)) return void 0;
|
|
40945
|
+
if (typeof value.hits !== "number" || typeof value.misses !== "number") return void 0;
|
|
40946
|
+
return {
|
|
40947
|
+
hits: value.hits,
|
|
40948
|
+
misses: value.misses
|
|
40949
|
+
};
|
|
40950
|
+
};
|
|
40927
40951
|
const parseDeadCodeWorkerResult = (value) => {
|
|
40928
40952
|
if (!isRecord$1(value)) throw new Error("Dead-code worker returned an invalid result.");
|
|
40953
|
+
const summaryCacheStats = parseSummaryCacheStats(value.summaryCacheStats);
|
|
40929
40954
|
return {
|
|
40930
40955
|
unusedFiles: parseUnusedFiles(value.unusedFiles),
|
|
40931
40956
|
unusedExports: parseUnusedExports(value.unusedExports),
|
|
40932
40957
|
unusedDependencies: parseUnusedDependencies(value.unusedDependencies),
|
|
40933
|
-
circularDependencies: parseCircularDependencies(value.circularDependencies)
|
|
40958
|
+
circularDependencies: parseCircularDependencies(value.circularDependencies),
|
|
40959
|
+
...summaryCacheStats ? { summaryCacheStats } : {}
|
|
40934
40960
|
};
|
|
40935
40961
|
};
|
|
40936
40962
|
const parseDeadCodeWorkerError = (value) => {
|
|
@@ -41051,13 +41077,15 @@ const checkDeadCode = async (options) => {
|
|
|
41051
41077
|
entryPatterns,
|
|
41052
41078
|
ignorePatterns,
|
|
41053
41079
|
tsConfigPath,
|
|
41054
|
-
deslopJsModuleSpecifier
|
|
41080
|
+
deslopJsModuleSpecifier,
|
|
41081
|
+
coreVersion: CORE_PACKAGE_VERSION
|
|
41055
41082
|
}) : null;
|
|
41056
41083
|
if (cacheKey !== null) {
|
|
41057
41084
|
const cachedDiagnostics = lookupDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey);
|
|
41058
41085
|
options.onCacheOutcome?.(cachedDiagnostics !== null);
|
|
41059
41086
|
if (cachedDiagnostics !== null) return [...cachedDiagnostics];
|
|
41060
41087
|
}
|
|
41088
|
+
const incrementalCachePath = options.cacheEnabled === true ? Path.join(resolveReactDoctorCacheDir(rootDirectory), DEAD_CODE_SUMMARY_CACHE_FILENAME) : void 0;
|
|
41061
41089
|
const spawnAndRun = () => {
|
|
41062
41090
|
return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
41063
41091
|
rootDirectory,
|
|
@@ -41065,10 +41093,12 @@ const checkDeadCode = async (options) => {
|
|
|
41065
41093
|
tsConfigPath,
|
|
41066
41094
|
ignorePatterns,
|
|
41067
41095
|
deslopJsModuleSpecifier,
|
|
41068
|
-
parseConcurrency: options.parseConcurrency
|
|
41096
|
+
parseConcurrency: options.parseConcurrency,
|
|
41097
|
+
incrementalCachePath
|
|
41069
41098
|
}), options.workerTimeoutMs ?? 12e4, options.abortSignal);
|
|
41070
41099
|
};
|
|
41071
41100
|
const result = parseDeadCodeWorkerResult(options.createWorker === void 0 ? await withDeadCodeWorkerSlot(spawnAndRun, options.abortSignal) : await spawnAndRun());
|
|
41101
|
+
if (result.summaryCacheStats !== void 0) options.onSummaryCacheStats?.(result.summaryCacheStats);
|
|
41072
41102
|
const toRelative = (filePath) => toRelativeFilePath(rootDirectory, filePath);
|
|
41073
41103
|
const diagnostics = [];
|
|
41074
41104
|
for (const unusedFile of result.unusedFiles) diagnostics.push({
|
|
@@ -41236,7 +41266,8 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
41236
41266
|
workerTimeoutMs: input.workerTimeoutMs,
|
|
41237
41267
|
abortSignal: signal,
|
|
41238
41268
|
cacheEnabled,
|
|
41239
|
-
onCacheOutcome: input.onCacheOutcome
|
|
41269
|
+
onCacheOutcome: input.onCacheOutcome,
|
|
41270
|
+
onSummaryCacheStats: input.onSummaryCacheStats
|
|
41240
41271
|
}),
|
|
41241
41272
|
catch: (cause) => new ReactDoctorError({ reason: new DeadCodeAnalysisFailed({ cause }) })
|
|
41242
41273
|
}).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)));
|
|
@@ -42106,7 +42137,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
42106
42137
|
}
|
|
42107
42138
|
return enabled;
|
|
42108
42139
|
};
|
|
42109
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection }) => {
|
|
42140
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
42110
42141
|
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
42111
42142
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
42112
42143
|
const jsPlugins = [];
|
|
@@ -42118,6 +42149,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42118
42149
|
if (!rule) continue;
|
|
42119
42150
|
if (ruleSelection === "cacheable" && CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
42120
42151
|
if (ruleSelection === "sidecar" && !CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
42152
|
+
if (ruleSelection === "sidecar" && sidecarRuleIdFilter !== void 0 && !sidecarRuleIdFilter.has(registryEntry.id)) continue;
|
|
42121
42153
|
if (rule.scan !== void 0) continue;
|
|
42122
42154
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
42123
42155
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
@@ -42162,23 +42194,23 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42162
42194
|
}
|
|
42163
42195
|
};
|
|
42164
42196
|
};
|
|
42165
|
-
const validateDiagnostic = decodeUnknownSync(Diagnostic);
|
|
42197
|
+
const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
|
|
42166
42198
|
const decodeFileDiagnostics = (raw) => {
|
|
42167
42199
|
if (!Array.isArray(raw)) return null;
|
|
42168
42200
|
try {
|
|
42169
|
-
for (const entry of raw) validateDiagnostic(entry);
|
|
42201
|
+
for (const entry of raw) validateDiagnostic$1(entry);
|
|
42170
42202
|
return raw;
|
|
42171
42203
|
} catch {
|
|
42172
42204
|
return null;
|
|
42173
42205
|
}
|
|
42174
42206
|
};
|
|
42175
|
-
const emptyCache = () => ({
|
|
42207
|
+
const emptyCache$1 = () => ({
|
|
42176
42208
|
version: 1,
|
|
42177
42209
|
rulesets: {}
|
|
42178
42210
|
});
|
|
42179
|
-
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
42211
|
+
const loadRulesetEntries$1 = (cacheFilePath, rulesetHash) => {
|
|
42180
42212
|
const entries = /* @__PURE__ */ new Map();
|
|
42181
|
-
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42213
|
+
const persisted = failOpenReadJson(cacheFilePath, emptyCache$1());
|
|
42182
42214
|
if (persisted.version !== 1 || !isRecord$1(persisted.rulesets)) return entries;
|
|
42183
42215
|
const bucket = persisted.rulesets[rulesetHash];
|
|
42184
42216
|
if (!isRecord$1(bucket) || !isRecord$1(bucket.files)) return entries;
|
|
@@ -42190,7 +42222,7 @@ const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
|
42190
42222
|
};
|
|
42191
42223
|
const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
42192
42224
|
const cacheFilePath = Path.join(cacheDirectory, FILE_LINT_CACHE_FILENAME);
|
|
42193
|
-
const entries = loadRulesetEntries(cacheFilePath, rulesetHash);
|
|
42225
|
+
const entries = loadRulesetEntries$1(cacheFilePath, rulesetHash);
|
|
42194
42226
|
return {
|
|
42195
42227
|
lookup: (fileKey) => entries.get(fileKey) ?? null,
|
|
42196
42228
|
store: (fileKey, diagnostics) => {
|
|
@@ -42198,7 +42230,7 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
42198
42230
|
entries.set(fileKey, diagnostics);
|
|
42199
42231
|
},
|
|
42200
42232
|
persist: () => {
|
|
42201
|
-
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42233
|
+
const onDisk = failOpenReadJson(cacheFilePath, emptyCache$1());
|
|
42202
42234
|
const rulesets = onDisk.version === 1 && isRecord$1(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
42203
42235
|
const existingBucket = rulesets[rulesetHash];
|
|
42204
42236
|
const existingFiles = isRecord$1(existingBucket) && isRecord$1(existingBucket.files) ? existingBucket.files : {};
|
|
@@ -42219,6 +42251,142 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
42219
42251
|
}
|
|
42220
42252
|
};
|
|
42221
42253
|
};
|
|
42254
|
+
const hashFileContents = (filePath) => {
|
|
42255
|
+
try {
|
|
42256
|
+
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
42257
|
+
} catch {
|
|
42258
|
+
return null;
|
|
42259
|
+
}
|
|
42260
|
+
};
|
|
42261
|
+
const ABSENT_CONTENT_ANSWER = "absent";
|
|
42262
|
+
/**
|
|
42263
|
+
* Answers dependency probes for the sidecar lint cache — used both when
|
|
42264
|
+
* STORING an entry (turn the collector's probe paths into answers) and when
|
|
42265
|
+
* VERIFYING one (re-answer each stored probe against the current tree).
|
|
42266
|
+
* Store and verify must agree exactly, so both go through this one resolver.
|
|
42267
|
+
*
|
|
42268
|
+
* - `content` — SHA-1 of the file's bytes, `"absent"` when unreadable
|
|
42269
|
+
* (missing, a directory, permission failure). Source files reuse the
|
|
42270
|
+
* hashes the cache-partition loop already computed
|
|
42271
|
+
* (`contentHashByRelativePath`); everything else (package.json,
|
|
42272
|
+
* tsconfig, ignored files) is hashed on demand.
|
|
42273
|
+
* - `exists` — the existence class a module-resolution candidate probe
|
|
42274
|
+
* sees: `"file"`, `"dir"`, or `"none"` (missing or an exotic entry —
|
|
42275
|
+
* `statSync` follows symlinks, matching the resolvers).
|
|
42276
|
+
*
|
|
42277
|
+
* Answers are memoized per scan: the filesystem is frozen for the run, and
|
|
42278
|
+
* hot dependency paths (a barrel imported by hundreds of files, the shared
|
|
42279
|
+
* tsconfig chain) repeat across many files' probe sets.
|
|
42280
|
+
*/
|
|
42281
|
+
const createSidecarProbeAnswerResolver = (input) => {
|
|
42282
|
+
const contentAnswerByPath = /* @__PURE__ */ new Map();
|
|
42283
|
+
const existsAnswerByPath = /* @__PURE__ */ new Map();
|
|
42284
|
+
const toRelativePath = (absolutePath) => Path.relative(input.rootDirectory, absolutePath).replaceAll("\\", "/");
|
|
42285
|
+
const contentAnswer = (relativePath) => {
|
|
42286
|
+
const memoized = contentAnswerByPath.get(relativePath);
|
|
42287
|
+
if (memoized !== void 0) return memoized;
|
|
42288
|
+
const answer = input.contentHashByRelativePath.get(relativePath) ?? hashFileContents(Path.resolve(input.rootDirectory, relativePath)) ?? ABSENT_CONTENT_ANSWER;
|
|
42289
|
+
contentAnswerByPath.set(relativePath, answer);
|
|
42290
|
+
return answer;
|
|
42291
|
+
};
|
|
42292
|
+
const existsAnswer = (relativePath) => {
|
|
42293
|
+
const memoized = existsAnswerByPath.get(relativePath);
|
|
42294
|
+
if (memoized !== void 0) return memoized;
|
|
42295
|
+
let answer;
|
|
42296
|
+
try {
|
|
42297
|
+
const stat = NFS.statSync(Path.resolve(input.rootDirectory, relativePath));
|
|
42298
|
+
answer = stat.isFile() ? "file" : stat.isDirectory() ? "dir" : "none";
|
|
42299
|
+
} catch {
|
|
42300
|
+
answer = "none";
|
|
42301
|
+
}
|
|
42302
|
+
existsAnswerByPath.set(relativePath, answer);
|
|
42303
|
+
return answer;
|
|
42304
|
+
};
|
|
42305
|
+
return {
|
|
42306
|
+
answerFor: (kind, relativePath) => kind === "content" ? contentAnswer(relativePath) : existsAnswer(relativePath),
|
|
42307
|
+
toRelativePath
|
|
42308
|
+
};
|
|
42309
|
+
};
|
|
42310
|
+
const validateDiagnostic = decodeUnknownSync(Diagnostic);
|
|
42311
|
+
const isProbeKind = (value) => value === "content" || value === "exists";
|
|
42312
|
+
const decodeSidecarFileEntry = (raw) => {
|
|
42313
|
+
if (!isRecord$1(raw) || !Array.isArray(raw.probes) || !Array.isArray(raw.diagnostics)) return null;
|
|
42314
|
+
const probes = [];
|
|
42315
|
+
for (const rawProbe of raw.probes) {
|
|
42316
|
+
if (!Array.isArray(rawProbe) || rawProbe.length !== 3) return null;
|
|
42317
|
+
const [kind, probePath, answer] = rawProbe;
|
|
42318
|
+
if (!isProbeKind(kind) || typeof probePath !== "string" || typeof answer !== "string") return null;
|
|
42319
|
+
probes.push({
|
|
42320
|
+
kind,
|
|
42321
|
+
path: probePath,
|
|
42322
|
+
answer
|
|
42323
|
+
});
|
|
42324
|
+
}
|
|
42325
|
+
try {
|
|
42326
|
+
for (const entry of raw.diagnostics) validateDiagnostic(entry);
|
|
42327
|
+
} catch {
|
|
42328
|
+
return null;
|
|
42329
|
+
}
|
|
42330
|
+
return {
|
|
42331
|
+
probes,
|
|
42332
|
+
diagnostics: raw.diagnostics
|
|
42333
|
+
};
|
|
42334
|
+
};
|
|
42335
|
+
const encodeSidecarFileEntry = (entry) => ({
|
|
42336
|
+
probes: entry.probes.map((probe) => [
|
|
42337
|
+
probe.kind,
|
|
42338
|
+
probe.path,
|
|
42339
|
+
probe.answer
|
|
42340
|
+
]),
|
|
42341
|
+
diagnostics: entry.diagnostics
|
|
42342
|
+
});
|
|
42343
|
+
const emptyCache = () => ({
|
|
42344
|
+
version: 1,
|
|
42345
|
+
rulesets: {}
|
|
42346
|
+
});
|
|
42347
|
+
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
42348
|
+
const entries = /* @__PURE__ */ new Map();
|
|
42349
|
+
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42350
|
+
if (persisted.version !== 1 || !isRecord$1(persisted.rulesets)) return entries;
|
|
42351
|
+
const bucket = persisted.rulesets[rulesetHash];
|
|
42352
|
+
if (!isRecord$1(bucket) || !isRecord$1(bucket.files)) return entries;
|
|
42353
|
+
for (const [fileKey, rawEntry] of Object.entries(bucket.files)) {
|
|
42354
|
+
const decoded = decodeSidecarFileEntry(rawEntry);
|
|
42355
|
+
if (decoded !== null) entries.set(fileKey, decoded);
|
|
42356
|
+
}
|
|
42357
|
+
return entries;
|
|
42358
|
+
};
|
|
42359
|
+
const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
42360
|
+
const cacheFilePath = Path.join(cacheDirectory, SIDECAR_LINT_CACHE_FILENAME);
|
|
42361
|
+
const entries = loadRulesetEntries(cacheFilePath, rulesetHash);
|
|
42362
|
+
return {
|
|
42363
|
+
lookup: (fileKey) => entries.get(fileKey) ?? null,
|
|
42364
|
+
store: (fileKey, entry) => {
|
|
42365
|
+
entries.delete(fileKey);
|
|
42366
|
+
entries.set(fileKey, entry);
|
|
42367
|
+
},
|
|
42368
|
+
persist: () => {
|
|
42369
|
+
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42370
|
+
const rulesets = onDisk.version === 1 && isRecord$1(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
42371
|
+
const existingBucket = rulesets[rulesetHash];
|
|
42372
|
+
const existingFiles = isRecord$1(existingBucket) && isRecord$1(existingBucket.files) ? existingBucket.files : {};
|
|
42373
|
+
const ourFiles = {};
|
|
42374
|
+
for (const [fileKey, entry] of entries) ourFiles[fileKey] = encodeSidecarFileEntry(entry);
|
|
42375
|
+
const cappedEntries = Object.entries({
|
|
42376
|
+
...existingFiles,
|
|
42377
|
+
...ourFiles
|
|
42378
|
+
}).slice(-FILE_LINT_CACHE_MAX_FILE_COUNT);
|
|
42379
|
+
rulesets[rulesetHash] = {
|
|
42380
|
+
updatedAtMs: Date.now(),
|
|
42381
|
+
files: Object.fromEntries(cappedEntries)
|
|
42382
|
+
};
|
|
42383
|
+
atomicWriteJson(cacheFilePath, {
|
|
42384
|
+
version: 1,
|
|
42385
|
+
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord$1(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
42386
|
+
});
|
|
42387
|
+
}
|
|
42388
|
+
};
|
|
42389
|
+
};
|
|
42222
42390
|
const bundledRequire$3 = createRequire(import.meta.url);
|
|
42223
42391
|
const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
|
|
42224
42392
|
const resolveChildNodeVersion = (nodeBinaryPath) => {
|
|
@@ -43218,13 +43386,6 @@ const validateRuleRegistration = () => {
|
|
|
43218
43386
|
].filter((entry) => entry !== null).join("; ");
|
|
43219
43387
|
console.warn(`[react-doctor] rule-registration drift: ${detail}`);
|
|
43220
43388
|
};
|
|
43221
|
-
const hashFileContents = (filePath) => {
|
|
43222
|
-
try {
|
|
43223
|
-
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
43224
|
-
} catch {
|
|
43225
|
-
return null;
|
|
43226
|
-
}
|
|
43227
|
-
};
|
|
43228
43389
|
/**
|
|
43229
43390
|
* Balanced LPT (longest-processing-time-first) lint batch planner. Where
|
|
43230
43391
|
* `batchIncludePaths` greedily fills 100-file batches and leaves a small
|
|
@@ -43306,6 +43467,106 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
43306
43467
|
NFS.closeSync(fileHandle);
|
|
43307
43468
|
}
|
|
43308
43469
|
};
|
|
43470
|
+
/**
|
|
43471
|
+
* Attributes diagnostics back to the file that produced them by the
|
|
43472
|
+
* normalized path oxlint echoes. Returns `null` when ANY diagnostic can't be
|
|
43473
|
+
* attributed — the path forms don't align, so the caller must skip its cache
|
|
43474
|
+
* store rather than risk caching a wrong empty result for a file that
|
|
43475
|
+
* actually had diagnostics.
|
|
43476
|
+
*/
|
|
43477
|
+
const attributeDiagnosticsToFiles = (diagnostics, files) => {
|
|
43478
|
+
const fileByNormalizedPath = /* @__PURE__ */ new Map();
|
|
43479
|
+
for (const file of files) fileByNormalizedPath.set(file.replaceAll("\\", "/"), file);
|
|
43480
|
+
const diagnosticsByFile = /* @__PURE__ */ new Map();
|
|
43481
|
+
for (const diagnostic of diagnostics) {
|
|
43482
|
+
const file = fileByNormalizedPath.get(diagnostic.filePath);
|
|
43483
|
+
if (file === void 0) return null;
|
|
43484
|
+
const fileDiagnostics = diagnosticsByFile.get(file) ?? [];
|
|
43485
|
+
fileDiagnostics.push(diagnostic);
|
|
43486
|
+
diagnosticsByFile.set(file, fileDiagnostics);
|
|
43487
|
+
}
|
|
43488
|
+
return diagnosticsByFile;
|
|
43489
|
+
};
|
|
43490
|
+
/**
|
|
43491
|
+
* Collects each file's cross-file dependency probes (via the plugin's
|
|
43492
|
+
* collectors) with their current answers. Fail-open per file: an unreadable /
|
|
43493
|
+
* unparseable / collector-failing file maps to `null` (no entry stored — it
|
|
43494
|
+
* re-lints next scan). The filesystem is frozen for the scan, so this can run
|
|
43495
|
+
* CONCURRENTLY with an oxlint child-process await — the caller starts it
|
|
43496
|
+
* unawaited before a lint pass and awaits it at store time, hiding the
|
|
43497
|
+
* in-process parse + resolution cost under the subprocess wait. The loop
|
|
43498
|
+
* yields on the cooperative time budget so the child's stdout handling (and
|
|
43499
|
+
* sibling fibers) keep flowing; each per-file collection is synchronous, so
|
|
43500
|
+
* the module-level probe recorder never sees interleaved use. Never rejects.
|
|
43501
|
+
*/
|
|
43502
|
+
const collectSidecarProbesForFiles = async (input) => {
|
|
43503
|
+
const buildProbes = (file) => {
|
|
43504
|
+
const absoluteFilePath = Path.resolve(input.rootDirectory, file);
|
|
43505
|
+
let trace;
|
|
43506
|
+
try {
|
|
43507
|
+
trace = collectCrossFileDependencyProbes({
|
|
43508
|
+
absoluteFilePath,
|
|
43509
|
+
sourceText: NFS.readFileSync(absoluteFilePath, "utf8"),
|
|
43510
|
+
ruleIds: input.boundedSidecarRuleIds
|
|
43511
|
+
});
|
|
43512
|
+
} catch {
|
|
43513
|
+
return null;
|
|
43514
|
+
}
|
|
43515
|
+
if (trace === null) return null;
|
|
43516
|
+
const probes = [];
|
|
43517
|
+
for (const contentPath of trace.contentPaths) {
|
|
43518
|
+
const relativePath = input.probeAnswers.toRelativePath(contentPath);
|
|
43519
|
+
probes.push({
|
|
43520
|
+
kind: "content",
|
|
43521
|
+
path: relativePath,
|
|
43522
|
+
answer: input.probeAnswers.answerFor("content", relativePath)
|
|
43523
|
+
});
|
|
43524
|
+
}
|
|
43525
|
+
for (const existencePath of trace.existencePaths) {
|
|
43526
|
+
const relativePath = input.probeAnswers.toRelativePath(existencePath);
|
|
43527
|
+
probes.push({
|
|
43528
|
+
kind: "exists",
|
|
43529
|
+
path: relativePath,
|
|
43530
|
+
answer: input.probeAnswers.answerFor("exists", relativePath)
|
|
43531
|
+
});
|
|
43532
|
+
}
|
|
43533
|
+
return probes;
|
|
43534
|
+
};
|
|
43535
|
+
const probesByFile = /* @__PURE__ */ new Map();
|
|
43536
|
+
let collectSliceStartedAt = performance.now();
|
|
43537
|
+
for (const file of input.files) {
|
|
43538
|
+
probesByFile.set(file, buildProbes(file));
|
|
43539
|
+
if (performance.now() - collectSliceStartedAt >= 12) {
|
|
43540
|
+
await yieldToEventLoop();
|
|
43541
|
+
collectSliceStartedAt = performance.now();
|
|
43542
|
+
}
|
|
43543
|
+
}
|
|
43544
|
+
return probesByFile;
|
|
43545
|
+
};
|
|
43546
|
+
/**
|
|
43547
|
+
* Stores each freshly-linted file's probe set + cross-file diagnostics so
|
|
43548
|
+
* the next scan can replay instead of re-linting.
|
|
43549
|
+
*/
|
|
43550
|
+
const storeSidecarEntries = (input) => {
|
|
43551
|
+
let didStoreAnyEntry = false;
|
|
43552
|
+
for (const pass of input.storablePasses) {
|
|
43553
|
+
if (!pass.isTrusted) continue;
|
|
43554
|
+
const diagnosticsByFile = attributeDiagnosticsToFiles(pass.diagnostics, pass.files);
|
|
43555
|
+
if (diagnosticsByFile === null) continue;
|
|
43556
|
+
for (const file of pass.files) {
|
|
43557
|
+
const cacheKey = input.cacheKeyByFile.get(file);
|
|
43558
|
+
if (cacheKey === void 0) continue;
|
|
43559
|
+
const probes = pass.probesByFile.get(file);
|
|
43560
|
+
if (probes === void 0 || probes === null) continue;
|
|
43561
|
+
input.sidecarCache.store(cacheKey, {
|
|
43562
|
+
probes,
|
|
43563
|
+
diagnostics: diagnosticsByFile.get(file) ?? []
|
|
43564
|
+
});
|
|
43565
|
+
didStoreAnyEntry = true;
|
|
43566
|
+
}
|
|
43567
|
+
}
|
|
43568
|
+
if (didStoreAnyEntry) input.sidecarCache.persist();
|
|
43569
|
+
};
|
|
43309
43570
|
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
43310
43571
|
/**
|
|
43311
43572
|
* Detects an oxlint config-load crash caused by the optional
|
|
@@ -43347,7 +43608,7 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
43347
43608
|
* 6. always restore disable directives + clean up the temp dir
|
|
43348
43609
|
*/
|
|
43349
43610
|
const runOxlint = async (options) => {
|
|
43350
|
-
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;
|
|
43611
|
+
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;
|
|
43351
43612
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
43352
43613
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
43353
43614
|
validateRuleRegistration();
|
|
@@ -43365,7 +43626,8 @@ const runOxlint = async (options) => {
|
|
|
43365
43626
|
severityControls,
|
|
43366
43627
|
userPlugins,
|
|
43367
43628
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
43368
|
-
ruleSelection: overrides.ruleSelection
|
|
43629
|
+
ruleSelection: overrides.ruleSelection,
|
|
43630
|
+
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
43369
43631
|
});
|
|
43370
43632
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
43371
43633
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -43468,15 +43730,18 @@ const runOxlint = async (options) => {
|
|
|
43468
43730
|
});
|
|
43469
43731
|
const cache = createFileLintCache(resolveReactDoctorCacheDir(rootDirectory), rulesetHash);
|
|
43470
43732
|
const cacheKeyByFile = /* @__PURE__ */ new Map();
|
|
43733
|
+
const contentHashByRelativePath = /* @__PURE__ */ new Map();
|
|
43471
43734
|
const missFiles = [];
|
|
43472
43735
|
const replayedDiagnostics = [];
|
|
43473
43736
|
let hashSliceStartedAt = performance.now();
|
|
43474
43737
|
for (const candidateFile of candidateFiles) {
|
|
43475
|
-
const
|
|
43738
|
+
const absoluteCandidatePath = Path.resolve(rootDirectory, candidateFile);
|
|
43739
|
+
const contentHash = hashFileContents(absoluteCandidatePath);
|
|
43476
43740
|
if (contentHash === null) {
|
|
43477
43741
|
missFiles.push(candidateFile);
|
|
43478
43742
|
continue;
|
|
43479
43743
|
}
|
|
43744
|
+
contentHashByRelativePath.set(Path.relative(rootDirectory, absoluteCandidatePath).replaceAll("\\", "/"), contentHash);
|
|
43480
43745
|
const cacheKey = `${candidateFile.replaceAll("\\", "/")}\u0000${contentHash}`;
|
|
43481
43746
|
cacheKeyByFile.set(candidateFile, cacheKey);
|
|
43482
43747
|
const cachedDiagnostics = cache.lookup(cacheKey);
|
|
@@ -43488,43 +43753,111 @@ const runOxlint = async (options) => {
|
|
|
43488
43753
|
}
|
|
43489
43754
|
}
|
|
43490
43755
|
const cacheHitFileCount = candidateFiles.length - missFiles.length;
|
|
43756
|
+
const enabledSidecarRuleIds = Object.keys(buildConfig({
|
|
43757
|
+
extendsPaths: [],
|
|
43758
|
+
ruleSelection: "sidecar"
|
|
43759
|
+
}).rules).map((ruleKey) => ruleKey.slice(ruleKey.lastIndexOf("/") + 1)).filter((ruleId) => CROSS_FILE_RULE_IDS.has(ruleId));
|
|
43760
|
+
const boundedSidecarRuleIds = enabledSidecarRuleIds.filter((ruleId) => CROSS_FILE_DEPENDENCY_COLLECTORS.has(ruleId));
|
|
43761
|
+
const boundedSidecarRuleIdSet = new Set(boundedSidecarRuleIds);
|
|
43762
|
+
const unboundedSidecarRuleIds = enabledSidecarRuleIds.filter((ruleId) => !CROSS_FILE_DEPENDENCY_COLLECTORS.has(ruleId));
|
|
43763
|
+
const useSidecarCache = sidecarLintCacheEnabled && boundedSidecarRuleIds.length > 0;
|
|
43764
|
+
const sidecarCache = useSidecarCache ? createSidecarLintCache(resolveReactDoctorCacheDir(rootDirectory), computeRulesetHash({
|
|
43765
|
+
config: buildConfig({
|
|
43766
|
+
extendsPaths: [],
|
|
43767
|
+
ruleSelection: "sidecar",
|
|
43768
|
+
sidecarRuleIdFilter: boundedSidecarRuleIdSet
|
|
43769
|
+
}),
|
|
43770
|
+
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
43771
|
+
ignorePatterns: combinedPatterns,
|
|
43772
|
+
tsconfigContent
|
|
43773
|
+
})) : null;
|
|
43774
|
+
const probeAnswers = createSidecarProbeAnswerResolver({
|
|
43775
|
+
rootDirectory,
|
|
43776
|
+
contentHashByRelativePath
|
|
43777
|
+
});
|
|
43778
|
+
const missProbesTask = sidecarCache === null ? null : collectSidecarProbesForFiles({
|
|
43779
|
+
files: missFiles,
|
|
43780
|
+
rootDirectory,
|
|
43781
|
+
boundedSidecarRuleIds,
|
|
43782
|
+
probeAnswers
|
|
43783
|
+
});
|
|
43491
43784
|
const fullResult = await runConfigOverFiles((overrides) => buildConfig({
|
|
43492
43785
|
extendsPaths: [],
|
|
43493
43786
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
43494
43787
|
}), "oxlintrc.full.json", missFiles, options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(scannedFileCount, candidateFiles.length)));
|
|
43495
43788
|
const missFileSet = new Set(missFiles);
|
|
43496
|
-
const
|
|
43789
|
+
const hitFiles = candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile));
|
|
43790
|
+
const sidecarReplayedDiagnostics = [];
|
|
43791
|
+
const sidecarLintFiles = [];
|
|
43792
|
+
if (sidecarCache === null) sidecarLintFiles.push(...hitFiles);
|
|
43793
|
+
else {
|
|
43794
|
+
let verifySliceStartedAt = performance.now();
|
|
43795
|
+
for (const hitFile of hitFiles) {
|
|
43796
|
+
const cacheKey = cacheKeyByFile.get(hitFile);
|
|
43797
|
+
const entry = cacheKey === void 0 ? null : sidecarCache.lookup(cacheKey);
|
|
43798
|
+
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer)) sidecarReplayedDiagnostics.push(...entry.diagnostics);
|
|
43799
|
+
else sidecarLintFiles.push(hitFile);
|
|
43800
|
+
if (performance.now() - verifySliceStartedAt >= 12) {
|
|
43801
|
+
await yieldToEventLoop();
|
|
43802
|
+
verifySliceStartedAt = performance.now();
|
|
43803
|
+
}
|
|
43804
|
+
}
|
|
43805
|
+
}
|
|
43806
|
+
const sidecarProbesTask = sidecarCache === null ? null : collectSidecarProbesForFiles({
|
|
43807
|
+
files: sidecarLintFiles,
|
|
43808
|
+
rootDirectory,
|
|
43809
|
+
boundedSidecarRuleIds,
|
|
43810
|
+
probeAnswers
|
|
43811
|
+
});
|
|
43812
|
+
const sidecarReplayedFileCount = hitFiles.length - sidecarLintFiles.length;
|
|
43813
|
+
if (sidecarReplayedFileCount > 0) options.onFileProgress?.(missFiles.length + sidecarReplayedFileCount, candidateFiles.length);
|
|
43814
|
+
const boundedSidecarResult = await runConfigOverFiles(() => buildConfig({
|
|
43497
43815
|
extendsPaths: [],
|
|
43498
|
-
ruleSelection: "sidecar"
|
|
43499
|
-
|
|
43816
|
+
ruleSelection: "sidecar",
|
|
43817
|
+
...useSidecarCache ? { sidecarRuleIdFilter: boundedSidecarRuleIdSet } : {}
|
|
43818
|
+
}), "oxlintrc.sidecar.json", sidecarLintFiles, options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(missFiles.length + sidecarReplayedFileCount + scannedFileCount, candidateFiles.length)));
|
|
43819
|
+
const unboundedSidecarResult = useSidecarCache && unboundedSidecarRuleIds.length > 0 ? await runConfigOverFiles(() => buildConfig({
|
|
43820
|
+
extendsPaths: [],
|
|
43821
|
+
ruleSelection: "sidecar",
|
|
43822
|
+
sidecarRuleIdFilter: new Set(unboundedSidecarRuleIds)
|
|
43823
|
+
}), "oxlintrc.sidecar-unbounded.json", hitFiles, void 0) : {
|
|
43824
|
+
diagnostics: [],
|
|
43825
|
+
didDropReactHooksJsPlugin: false,
|
|
43826
|
+
hadPartialFailure: false
|
|
43827
|
+
};
|
|
43500
43828
|
const freshCacheableDiagnostics = [];
|
|
43501
43829
|
for (const diagnostic of fullResult.diagnostics) if (!CROSS_FILE_RULE_IDS.has(diagnostic.rule)) freshCacheableDiagnostics.push(diagnostic);
|
|
43502
43830
|
onCacheStats?.(cacheHitFileCount, candidateFiles.length);
|
|
43503
|
-
|
|
43504
|
-
|
|
43505
|
-
|
|
43506
|
-
let isAttributionSound = true;
|
|
43507
|
-
for (const diagnostic of freshCacheableDiagnostics) {
|
|
43508
|
-
const missFile = missFileByNormalizedPath.get(diagnostic.filePath);
|
|
43509
|
-
if (missFile === void 0) {
|
|
43510
|
-
isAttributionSound = false;
|
|
43511
|
-
break;
|
|
43512
|
-
}
|
|
43513
|
-
const fileDiagnostics = freshDiagnosticsByFile.get(missFile) ?? [];
|
|
43514
|
-
fileDiagnostics.push(diagnostic);
|
|
43515
|
-
freshDiagnosticsByFile.set(missFile, fileDiagnostics);
|
|
43516
|
-
}
|
|
43517
|
-
if (!fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure && isAttributionSound) {
|
|
43831
|
+
if (sidecarCache !== null) onSidecarStats?.(hitFiles.length - sidecarLintFiles.length, hitFiles.length);
|
|
43832
|
+
const freshDiagnosticsByFile = attributeDiagnosticsToFiles(freshCacheableDiagnostics, missFiles);
|
|
43833
|
+
if (!fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure && freshDiagnosticsByFile !== null) {
|
|
43518
43834
|
for (const missFile of missFiles) {
|
|
43519
43835
|
const cacheKey = cacheKeyByFile.get(missFile);
|
|
43520
43836
|
if (cacheKey !== void 0) cache.store(cacheKey, freshDiagnosticsByFile.get(missFile) ?? []);
|
|
43521
43837
|
}
|
|
43522
43838
|
cache.persist();
|
|
43523
43839
|
}
|
|
43840
|
+
if (sidecarCache !== null && missProbesTask !== null && sidecarProbesTask !== null) storeSidecarEntries({
|
|
43841
|
+
sidecarCache,
|
|
43842
|
+
cacheKeyByFile,
|
|
43843
|
+
storablePasses: [{
|
|
43844
|
+
files: sidecarLintFiles,
|
|
43845
|
+
diagnostics: boundedSidecarResult.diagnostics,
|
|
43846
|
+
isTrusted: !boundedSidecarResult.hadPartialFailure,
|
|
43847
|
+
probesByFile: await sidecarProbesTask
|
|
43848
|
+
}, {
|
|
43849
|
+
files: missFiles,
|
|
43850
|
+
diagnostics: fullResult.diagnostics.filter((diagnostic) => boundedSidecarRuleIdSet.has(diagnostic.rule)),
|
|
43851
|
+
isTrusted: !fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure,
|
|
43852
|
+
probesByFile: await missProbesTask
|
|
43853
|
+
}]
|
|
43854
|
+
});
|
|
43524
43855
|
return dedupeDiagnostics([
|
|
43525
43856
|
...replayedDiagnostics,
|
|
43526
43857
|
...fullResult.diagnostics,
|
|
43527
|
-
...
|
|
43858
|
+
...sidecarReplayedDiagnostics,
|
|
43859
|
+
...boundedSidecarResult.diagnostics,
|
|
43860
|
+
...unboundedSidecarResult.diagnostics
|
|
43528
43861
|
]);
|
|
43529
43862
|
}
|
|
43530
43863
|
const baseArgs = makeBaseArgs(configPath);
|
|
@@ -43622,6 +43955,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
43622
43955
|
const concurrency = yield* OxlintConcurrency;
|
|
43623
43956
|
const lintBatchOrdering = yield* LintBatchOrdering;
|
|
43624
43957
|
const perFileLintCacheEnabled = yield* PerFileLintCacheEnabled;
|
|
43958
|
+
const sidecarLintCacheEnabled = yield* SidecarLintCacheEnabled;
|
|
43625
43959
|
const collectedFailures = [];
|
|
43626
43960
|
const diagnostics = yield* tryPromise({
|
|
43627
43961
|
try: (signal) => runOxlint({
|
|
@@ -43640,7 +43974,9 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
43640
43974
|
},
|
|
43641
43975
|
onFileProgress: input.onFileProgress,
|
|
43642
43976
|
perFileLintCacheEnabled,
|
|
43977
|
+
sidecarLintCacheEnabled,
|
|
43643
43978
|
onCacheStats: input.onCacheStats,
|
|
43979
|
+
onSidecarStats: input.onSidecarStats,
|
|
43644
43980
|
spawnTimeoutMs,
|
|
43645
43981
|
outputMaxBytes,
|
|
43646
43982
|
concurrency,
|
|
@@ -44418,6 +44754,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44418
44754
|
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
|
|
44419
44755
|
onCacheOutcome: (didHitCache) => {
|
|
44420
44756
|
deadCodeCacheHit = didHitCache;
|
|
44757
|
+
},
|
|
44758
|
+
onSummaryCacheStats: (stats) => {
|
|
44759
|
+
deadCodeSummaryCacheHits = stats.hits;
|
|
44760
|
+
deadCodeSummaryCacheMisses = stats.misses;
|
|
44421
44761
|
}
|
|
44422
44762
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
44423
44763
|
yield* set(deadCodeFailure, {
|
|
@@ -44446,7 +44786,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44446
44786
|
let lastReportedTotalFileCount = 0;
|
|
44447
44787
|
let lintCacheHitFileCount = null;
|
|
44448
44788
|
let lintCacheTotalFileCount = null;
|
|
44789
|
+
let lintSidecarReplayedFileCount = null;
|
|
44790
|
+
let lintSidecarTotalFileCount = null;
|
|
44449
44791
|
let deadCodeCacheHit = null;
|
|
44792
|
+
let deadCodeSummaryCacheHits = null;
|
|
44793
|
+
let deadCodeSummaryCacheMisses = null;
|
|
44450
44794
|
const baseLintStream = linterService.run({
|
|
44451
44795
|
rootDirectory: scanDirectory,
|
|
44452
44796
|
project,
|
|
@@ -44466,6 +44810,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44466
44810
|
lintCacheHitFileCount = cacheHitFileCount;
|
|
44467
44811
|
lintCacheTotalFileCount = totalConsideredFileCount;
|
|
44468
44812
|
},
|
|
44813
|
+
onSidecarStats: (sidecarReplayedFileCount, sidecarConsideredFileCount) => {
|
|
44814
|
+
lintSidecarReplayedFileCount = sidecarReplayedFileCount;
|
|
44815
|
+
lintSidecarTotalFileCount = sidecarConsideredFileCount;
|
|
44816
|
+
},
|
|
44469
44817
|
deadlineEpochMs: input.deadlineEpochMs
|
|
44470
44818
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
44471
44819
|
yield* set(lintFailure, {
|
|
@@ -44576,7 +44924,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44576
44924
|
securityScanFailed,
|
|
44577
44925
|
lintCacheHitFileCount,
|
|
44578
44926
|
lintCacheTotalFileCount,
|
|
44927
|
+
lintSidecarReplayedFileCount,
|
|
44928
|
+
lintSidecarTotalFileCount,
|
|
44579
44929
|
deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
|
|
44930
|
+
deadCodeSummaryCacheHits: lintFailureState.didFail ? null : deadCodeSummaryCacheHits,
|
|
44931
|
+
deadCodeSummaryCacheMisses: lintFailureState.didFail ? null : deadCodeSummaryCacheMisses,
|
|
44580
44932
|
suppressedRuleCounts: transform.summarizeSuppressions()
|
|
44581
44933
|
};
|
|
44582
44934
|
}).pipe(withSpan("runInspect", { attributes: {
|
|
@@ -45449,7 +45801,7 @@ const makeNoopConsole = () => ({
|
|
|
45449
45801
|
});
|
|
45450
45802
|
//#endregion
|
|
45451
45803
|
//#region src/cli/utils/version.ts
|
|
45452
|
-
const VERSION = "0.6.3-dev.
|
|
45804
|
+
const VERSION = "0.6.3-dev.ea9a775";
|
|
45453
45805
|
//#endregion
|
|
45454
45806
|
//#region src/cli/utils/json-mode.ts
|
|
45455
45807
|
let context = null;
|
|
@@ -45818,13 +46170,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
45818
46170
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
45819
46171
|
* standard `SENTRY_RELEASE` override.
|
|
45820
46172
|
*/
|
|
45821
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.
|
|
46173
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.ea9a775`;
|
|
45822
46174
|
/**
|
|
45823
46175
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
45824
46176
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
45825
46177
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
45826
46178
|
*/
|
|
45827
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.
|
|
46179
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.ea9a775") ? "development" : "production");
|
|
45828
46180
|
/**
|
|
45829
46181
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
45830
46182
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -58048,12 +58400,17 @@ const buildOutcomeAttributes = (input) => {
|
|
|
58048
58400
|
deadlineSkippedFileCount: input.lintDeadlineSkippedFileCount ?? null,
|
|
58049
58401
|
cacheHitFiles: result.lintCacheHitFileCount ?? null,
|
|
58050
58402
|
cacheTotalFiles: result.lintCacheTotalFileCount ?? null,
|
|
58051
|
-
cacheHitRatio: result.lintCacheTotalFileCount != null && result.lintCacheTotalFileCount > 0 ? (result.lintCacheHitFileCount ?? 0) / result.lintCacheTotalFileCount : null
|
|
58403
|
+
cacheHitRatio: result.lintCacheTotalFileCount != null && result.lintCacheTotalFileCount > 0 ? (result.lintCacheHitFileCount ?? 0) / result.lintCacheTotalFileCount : null,
|
|
58404
|
+
sidecarReplayedFiles: result.lintSidecarReplayedFileCount ?? null,
|
|
58405
|
+
sidecarTotalFiles: result.lintSidecarTotalFileCount ?? null,
|
|
58406
|
+
sidecarReplayRatio: result.lintSidecarTotalFileCount != null && result.lintSidecarTotalFileCount > 0 ? (result.lintSidecarReplayedFileCount ?? 0) / result.lintSidecarTotalFileCount : null
|
|
58052
58407
|
}),
|
|
58053
58408
|
...withNamespace("deadCode", {
|
|
58054
58409
|
failed: input.didDeadCodeFail ?? null,
|
|
58055
58410
|
overlapped: input.deadCodeOverlapped ?? null,
|
|
58056
|
-
cacheHit: result.deadCodeCacheHit ?? null
|
|
58411
|
+
cacheHit: result.deadCodeCacheHit ?? null,
|
|
58412
|
+
summaryCacheHits: result.deadCodeSummaryCacheHits ?? null,
|
|
58413
|
+
summaryCacheMisses: result.deadCodeSummaryCacheMisses ?? null
|
|
58057
58414
|
}),
|
|
58058
58415
|
...withNamespace("supplyChain", { overlapTimedOut: input.supplyChainOverlapTimedOut ?? null }),
|
|
58059
58416
|
...withNamespace("securityScan", { failed: input.securityScanFailed ?? null }),
|
|
@@ -59376,13 +59733,89 @@ const stringifyStableJson = (value) => {
|
|
|
59376
59733
|
};
|
|
59377
59734
|
const hashString = (value) => crypto.createHash("sha1").update(value).digest("hex");
|
|
59378
59735
|
const readHeadSha = (projectDirectory) => runGit(projectDirectory, ["rev-parse", "HEAD"]);
|
|
59379
|
-
const
|
|
59380
|
-
const
|
|
59736
|
+
const parseWorktreeStatusRecords = (statusOutput) => {
|
|
59737
|
+
const entries = [];
|
|
59738
|
+
const tokens = statusOutput.split("\0");
|
|
59739
|
+
for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
59740
|
+
let record = tokens[tokenIndex];
|
|
59741
|
+
if (record.length === 0) continue;
|
|
59742
|
+
if (record.length < 3 || record[2] !== " ") {
|
|
59743
|
+
if (tokenIndex !== 0) return null;
|
|
59744
|
+
record = ` ${record}`;
|
|
59745
|
+
}
|
|
59746
|
+
if (record.length < 4 || record[2] !== " ") return null;
|
|
59747
|
+
const statusCode = record.slice(0, 2);
|
|
59748
|
+
const recordPath = record.slice(3);
|
|
59749
|
+
if (statusCode.includes("R") || statusCode.includes("C")) {
|
|
59750
|
+
tokenIndex += 1;
|
|
59751
|
+
const originPath = tokens[tokenIndex];
|
|
59752
|
+
if (originPath === void 0 || originPath.length === 0) return null;
|
|
59753
|
+
entries.push({
|
|
59754
|
+
statusCode,
|
|
59755
|
+
path: recordPath,
|
|
59756
|
+
originPath
|
|
59757
|
+
});
|
|
59758
|
+
continue;
|
|
59759
|
+
}
|
|
59760
|
+
entries.push({
|
|
59761
|
+
statusCode,
|
|
59762
|
+
path: recordPath
|
|
59763
|
+
});
|
|
59764
|
+
}
|
|
59765
|
+
return entries;
|
|
59766
|
+
};
|
|
59767
|
+
const buildDirtyPathContentFingerprint = (absolutePath, statusCode) => {
|
|
59768
|
+
let stats;
|
|
59769
|
+
try {
|
|
59770
|
+
stats = fs.lstatSync(absolutePath);
|
|
59771
|
+
} catch {
|
|
59772
|
+
return statusCode.includes("D") ? "deleted" : null;
|
|
59773
|
+
}
|
|
59774
|
+
if (stats.isSymbolicLink()) try {
|
|
59775
|
+
return `link:${fs.readlinkSync(absolutePath)}`;
|
|
59776
|
+
} catch {
|
|
59777
|
+
return null;
|
|
59778
|
+
}
|
|
59779
|
+
if (!stats.isFile()) return null;
|
|
59780
|
+
if (stats.size > 10485760) return `stat:${stats.mtimeMs}:${stats.size}`;
|
|
59781
|
+
return hashFileContents(absolutePath);
|
|
59782
|
+
};
|
|
59783
|
+
const buildWorktreeFingerprint = (projectDirectory) => {
|
|
59784
|
+
const statusOutput = runGit(projectDirectory, [
|
|
59381
59785
|
"status",
|
|
59382
59786
|
"--porcelain=v1",
|
|
59383
|
-
"
|
|
59787
|
+
"-z",
|
|
59788
|
+
"--untracked-files=all"
|
|
59384
59789
|
]);
|
|
59385
|
-
|
|
59790
|
+
if (statusOutput === null) return null;
|
|
59791
|
+
if (statusOutput.length === 0) return [];
|
|
59792
|
+
const statusEntries = parseWorktreeStatusRecords(statusOutput);
|
|
59793
|
+
if (statusEntries === null) return null;
|
|
59794
|
+
if (statusEntries.length > 300) return null;
|
|
59795
|
+
const repositoryRoot = runGit(projectDirectory, ["rev-parse", "--show-toplevel"]);
|
|
59796
|
+
if (repositoryRoot === null) return null;
|
|
59797
|
+
const dirtyEntries = [];
|
|
59798
|
+
for (const statusEntry of statusEntries) {
|
|
59799
|
+
const contentFingerprint = buildDirtyPathContentFingerprint(path.join(repositoryRoot, statusEntry.path), statusEntry.statusCode);
|
|
59800
|
+
if (contentFingerprint === null) return null;
|
|
59801
|
+
dirtyEntries.push({
|
|
59802
|
+
...statusEntry,
|
|
59803
|
+
contentFingerprint
|
|
59804
|
+
});
|
|
59805
|
+
}
|
|
59806
|
+
return dirtyEntries.sort((firstEntry, secondEntry) => {
|
|
59807
|
+
const firstSortKey = `${firstEntry.path}${firstEntry.statusCode}`;
|
|
59808
|
+
const secondSortKey = `${secondEntry.path}${secondEntry.statusCode}`;
|
|
59809
|
+
return firstSortKey < secondSortKey ? -1 : firstSortKey > secondSortKey ? 1 : 0;
|
|
59810
|
+
});
|
|
59811
|
+
};
|
|
59812
|
+
const DOTENV_FILE_NAME_PATTERN = /^\.env(\.|$)/;
|
|
59813
|
+
const resolveDotenvFingerprint = (projectDirectory) => {
|
|
59814
|
+
try {
|
|
59815
|
+
return fs.readdirSync(projectDirectory).filter((entryName) => DOTENV_FILE_NAME_PATTERN.test(entryName)).sort().map((entryName) => `${entryName}=${fileFingerprint(path.join(projectDirectory, entryName)) ?? "unreadable"}`);
|
|
59816
|
+
} catch {
|
|
59817
|
+
return [];
|
|
59818
|
+
}
|
|
59386
59819
|
};
|
|
59387
59820
|
const hasHiddenTrackedFileState = (projectDirectory) => {
|
|
59388
59821
|
const output = runGit(projectDirectory, ["ls-files", "-v"]);
|
|
@@ -59465,8 +59898,9 @@ const resolveToolchainFingerprint = (nodeBinaryPath) => {
|
|
|
59465
59898
|
};
|
|
59466
59899
|
const buildScanResultCacheKey = (input) => {
|
|
59467
59900
|
if (isScanResultCacheDisabled()) return null;
|
|
59468
|
-
if (!isWorktreeClean(input.projectDirectory)) return null;
|
|
59469
59901
|
if (hasHiddenTrackedFileState(input.projectDirectory)) return null;
|
|
59902
|
+
const worktreeFingerprint = buildWorktreeFingerprint(input.projectDirectory);
|
|
59903
|
+
if (worktreeFingerprint === null) return null;
|
|
59470
59904
|
const headSha = readHeadSha(input.projectDirectory);
|
|
59471
59905
|
if (headSha === null) return null;
|
|
59472
59906
|
if (stringifyStableJson(input.userConfig) === null) return null;
|
|
@@ -59474,6 +59908,8 @@ const buildScanResultCacheKey = (input) => {
|
|
|
59474
59908
|
schemaVersion: 3,
|
|
59475
59909
|
projectIdentity: resolveProjectIdentity(input.projectDirectory),
|
|
59476
59910
|
headSha,
|
|
59911
|
+
worktreeFingerprint,
|
|
59912
|
+
dotenvFingerprint: resolveDotenvFingerprint(input.projectDirectory),
|
|
59477
59913
|
reactDoctorVersion: input.version,
|
|
59478
59914
|
nodeVersion: process.version,
|
|
59479
59915
|
toolchainFingerprint: resolveToolchainFingerprint(input.nodeBinaryPath),
|
|
@@ -59867,7 +60303,11 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
59867
60303
|
baselineDegraded,
|
|
59868
60304
|
lintCacheHitFileCount: output.lintCacheHitFileCount,
|
|
59869
60305
|
lintCacheTotalFileCount: output.lintCacheTotalFileCount,
|
|
59870
|
-
|
|
60306
|
+
lintSidecarReplayedFileCount: output.lintSidecarReplayedFileCount,
|
|
60307
|
+
lintSidecarTotalFileCount: output.lintSidecarTotalFileCount,
|
|
60308
|
+
deadCodeCacheHit: output.deadCodeCacheHit,
|
|
60309
|
+
deadCodeSummaryCacheHits: output.deadCodeSummaryCacheHits,
|
|
60310
|
+
deadCodeSummaryCacheMisses: output.deadCodeSummaryCacheMisses
|
|
59871
60311
|
});
|
|
59872
60312
|
recordOnboardingCompletion(options);
|
|
59873
60313
|
return result;
|
|
@@ -59902,7 +60342,11 @@ const renderAndRecordScan = async (input) => {
|
|
|
59902
60342
|
scanElapsedMilliseconds: input.payload.scanElapsedMilliseconds,
|
|
59903
60343
|
lintCacheHitFileCount: input.lintCacheHitFileCount ?? null,
|
|
59904
60344
|
lintCacheTotalFileCount: input.lintCacheTotalFileCount ?? null,
|
|
60345
|
+
lintSidecarReplayedFileCount: input.lintSidecarReplayedFileCount ?? null,
|
|
60346
|
+
lintSidecarTotalFileCount: input.lintSidecarTotalFileCount ?? null,
|
|
59905
60347
|
deadCodeCacheHit: input.deadCodeCacheHit ?? null,
|
|
60348
|
+
deadCodeSummaryCacheHits: input.deadCodeSummaryCacheHits ?? null,
|
|
60349
|
+
deadCodeSummaryCacheMisses: input.deadCodeSummaryCacheMisses ?? null,
|
|
59906
60350
|
baselineDelta: input.payload.baselineDelta
|
|
59907
60351
|
}), input.options.silent));
|
|
59908
60352
|
const { workerCount: resolvedWorkerCount, parallel } = resolveWorkerTelemetry(input.payload.scanConcurrency, input.options.concurrency);
|
|
@@ -59941,7 +60385,7 @@ const renderAndRecordScan = async (input) => {
|
|
|
59941
60385
|
return result;
|
|
59942
60386
|
};
|
|
59943
60387
|
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;
|
|
60388
|
+
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, lintSidecarReplayedFileCount, lintSidecarTotalFileCount, deadCodeCacheHit, deadCodeSummaryCacheHits, deadCodeSummaryCacheMisses, baselineDelta } = input;
|
|
59945
60389
|
const { skippedChecks, skippedCheckReasons } = buildSkippedChecks({
|
|
59946
60390
|
didLintFail,
|
|
59947
60391
|
lintFailureReason,
|
|
@@ -59965,7 +60409,15 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
59965
60409
|
lintCacheHitFileCount,
|
|
59966
60410
|
lintCacheTotalFileCount
|
|
59967
60411
|
} : {},
|
|
60412
|
+
...lintSidecarTotalFileCount !== null ? {
|
|
60413
|
+
lintSidecarReplayedFileCount,
|
|
60414
|
+
lintSidecarTotalFileCount
|
|
60415
|
+
} : {},
|
|
59968
60416
|
...deadCodeCacheHit !== null ? { deadCodeCacheHit } : {},
|
|
60417
|
+
...deadCodeSummaryCacheHits !== null && deadCodeSummaryCacheMisses !== null ? {
|
|
60418
|
+
deadCodeSummaryCacheHits,
|
|
60419
|
+
deadCodeSummaryCacheMisses
|
|
60420
|
+
} : {},
|
|
59969
60421
|
...baselineDelta ? { baselineDelta } : {}
|
|
59970
60422
|
});
|
|
59971
60423
|
if (options.suppressRendering) return buildResult();
|
|
@@ -63812,4 +64264,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
63812
64264
|
export {};
|
|
63813
64265
|
|
|
63814
64266
|
//# sourceMappingURL=cli.js.map
|
|
63815
|
-
//# debugId=
|
|
64267
|
+
//# debugId=d9c72b21-3e94-5923-b692-077f137a0078
|