react-doctor 0.6.2 → 0.6.3-dev.20d81f6
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 +346 -71
- package/dist/index.d.ts +8 -0
- package/dist/index.js +247 -57
- package/dist/lsp.js +248 -58
- package/package.json +6 -6
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]="d7bda084-a223-5aa7-8605-578888bd1b33")}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";
|
|
@@ -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,6 +36129,8 @@ 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 CORE_PACKAGE_VERSION = "0.6.3";
|
|
36133
|
+
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
36131
36134
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
36132
36135
|
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
36133
36136
|
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
@@ -38678,7 +38681,7 @@ const resolveAutoScanConcurrency = (facts = readSystemFacts$1()) => {
|
|
|
38678
38681
|
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
38679
38682
|
};
|
|
38680
38683
|
const resolveLintBatchOrdering = () => {
|
|
38681
|
-
return process.env["REACT_DOCTOR_LINT_BATCH_ORDERING"]?.trim().toLowerCase() === "
|
|
38684
|
+
return process.env["REACT_DOCTOR_LINT_BATCH_ORDERING"]?.trim().toLowerCase() === "arrival" ? "arrival" : "cost";
|
|
38682
38685
|
};
|
|
38683
38686
|
/**
|
|
38684
38687
|
* Per-batch oxlint wall-clock budget. Reads from the env var on
|
|
@@ -38775,17 +38778,19 @@ var DeadCodeOverlap = class extends Reference("react-doctor/DeadCodeOverlap", {
|
|
|
38775
38778
|
return "auto";
|
|
38776
38779
|
} }) {};
|
|
38777
38780
|
/**
|
|
38778
|
-
* How the full-scan lint pass
|
|
38779
|
-
*
|
|
38780
|
-
*
|
|
38781
|
-
*
|
|
38782
|
-
* the
|
|
38783
|
-
*
|
|
38784
|
-
*
|
|
38785
|
-
*
|
|
38786
|
-
* `
|
|
38787
|
-
*
|
|
38788
|
-
*
|
|
38781
|
+
* How the full-scan lint pass plans its file batches. `"cost"` (the default)
|
|
38782
|
+
* builds size-balanced LPT batches (`planLintBatches`): the same mandatory
|
|
38783
|
+
* batch count as greedy chunking (`ceil(files / 100)`), but every batch gets
|
|
38784
|
+
* an even share of files AND bytes, so no 100-file chunk is a straggler while
|
|
38785
|
+
* the remainder-batch worker idles — and the heavy files are SPREAD across
|
|
38786
|
+
* batches, the precondition the old sort-desc-then-chunk-100 `cost` mode
|
|
38787
|
+
* lacked (it packed the heaviest files into one wave-1 straggler batch,
|
|
38788
|
+
* measurably regressing size-skewed repos, which is why it never earned the
|
|
38789
|
+
* default). `"arrival"` (`REACT_DOCTOR_LINT_BATCH_ORDERING=arrival`) is the
|
|
38790
|
+
* rollback hatch to plain greedy 100-file chunking in discovery order. Tests
|
|
38791
|
+
* override via `Layer.succeed(LintBatchOrdering, ...)`. Diff / staged scans
|
|
38792
|
+
* never reach this — they pass user-scoped `includePaths` that skip discovery
|
|
38793
|
+
* and stay in arrival order; only the full-scan branch reads it.
|
|
38789
38794
|
*/
|
|
38790
38795
|
var LintBatchOrdering = class extends Reference("react-doctor/LintBatchOrdering", { defaultValue: resolveLintBatchOrdering }) {};
|
|
38791
38796
|
const CACHE_DISABLED_VALUES$1 = new Set(["1", "true"]);
|
|
@@ -38810,6 +38815,25 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
|
|
|
38810
38815
|
if (CACHE_DISABLED_VALUES$1.has(noFileCache)) return false;
|
|
38811
38816
|
return true;
|
|
38812
38817
|
} }) {};
|
|
38818
|
+
/**
|
|
38819
|
+
* Whether the whole-project dead-code result cache
|
|
38820
|
+
* (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
|
|
38821
|
+
* whose inputs (source tree, manifests, configs, analyzer version) are
|
|
38822
|
+
* unchanged replays the stored diagnostics instead of re-running the
|
|
38823
|
+
* analysis worker. Opt-OUT, two knobs (matching the per-file lint cache):
|
|
38824
|
+
*
|
|
38825
|
+
* - `REACT_DOCTOR_NO_CACHE` — the global off-switch.
|
|
38826
|
+
* - `REACT_DOCTOR_NO_DEAD_CODE_CACHE` — granular: bust only this cache.
|
|
38827
|
+
*
|
|
38828
|
+
* Tests override via `Layer.succeed(DeadCodeResultCacheEnabled, false)`.
|
|
38829
|
+
*/
|
|
38830
|
+
var DeadCodeResultCacheEnabled = class extends Reference("react-doctor/DeadCodeResultCacheEnabled", { defaultValue: () => {
|
|
38831
|
+
const noCache = process.env["REACT_DOCTOR_NO_CACHE"]?.toLowerCase() ?? "";
|
|
38832
|
+
const noDeadCodeCache = process.env["REACT_DOCTOR_NO_DEAD_CODE_CACHE"]?.toLowerCase() ?? "";
|
|
38833
|
+
if (CACHE_DISABLED_VALUES$1.has(noCache)) return false;
|
|
38834
|
+
if (CACHE_DISABLED_VALUES$1.has(noDeadCodeCache)) return false;
|
|
38835
|
+
return true;
|
|
38836
|
+
} }) {};
|
|
38813
38837
|
const DIAGNOSTIC_SURFACES = [
|
|
38814
38838
|
"cli",
|
|
38815
38839
|
"prComment",
|
|
@@ -40170,6 +40194,7 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
40170
40194
|
isGeneratedBundleByName: classification.isGeneratedBundleByName
|
|
40171
40195
|
});
|
|
40172
40196
|
}
|
|
40197
|
+
yield null;
|
|
40173
40198
|
}
|
|
40174
40199
|
for (const candidates of [
|
|
40175
40200
|
priorityCandidates,
|
|
@@ -40295,9 +40320,18 @@ const checkSecurityScanCooperative = async (rootDirectory, options = {}) => {
|
|
|
40295
40320
|
const session = createSecurityScanSession(rootDirectory, options);
|
|
40296
40321
|
if (session === null) return [];
|
|
40297
40322
|
let sliceStartedAt = performance.now();
|
|
40298
|
-
for (const file of collectSecurityScanFiles(rootDirectory))
|
|
40299
|
-
|
|
40300
|
-
|
|
40323
|
+
for (const file of collectSecurityScanFiles(rootDirectory)) {
|
|
40324
|
+
if (file === null) {
|
|
40325
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
40326
|
+
await yieldToEventLoop();
|
|
40327
|
+
sliceStartedAt = performance.now();
|
|
40328
|
+
}
|
|
40329
|
+
continue;
|
|
40330
|
+
}
|
|
40331
|
+
for (const _ruleStep of session.scanFileByRule(file)) if (performance.now() - sliceStartedAt >= 12) {
|
|
40332
|
+
await yieldToEventLoop();
|
|
40333
|
+
sliceStartedAt = performance.now();
|
|
40334
|
+
}
|
|
40301
40335
|
}
|
|
40302
40336
|
return session.diagnostics;
|
|
40303
40337
|
};
|
|
@@ -40532,6 +40566,80 @@ const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
|
40532
40566
|
return [...seen].filter((pattern) => pattern.length > 0);
|
|
40533
40567
|
};
|
|
40534
40568
|
const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
|
|
40569
|
+
const atomicWriteJson = (filePath, value) => {
|
|
40570
|
+
try {
|
|
40571
|
+
NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
|
|
40572
|
+
const temporaryPath = `${filePath}.${process.pid}.tmp`;
|
|
40573
|
+
NFS.writeFileSync(temporaryPath, JSON.stringify(value));
|
|
40574
|
+
NFS.renameSync(temporaryPath, filePath);
|
|
40575
|
+
} catch {
|
|
40576
|
+
return;
|
|
40577
|
+
}
|
|
40578
|
+
};
|
|
40579
|
+
const failOpenReadJson = (filePath, fallback) => {
|
|
40580
|
+
try {
|
|
40581
|
+
return JSON.parse(NFS.readFileSync(filePath, "utf8"));
|
|
40582
|
+
} catch {
|
|
40583
|
+
return fallback;
|
|
40584
|
+
}
|
|
40585
|
+
};
|
|
40586
|
+
const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
|
|
40587
|
+
const CORE_SIDE_MANIFEST_NAMES = ["knip.json", "deno.lock"];
|
|
40588
|
+
const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
|
|
40589
|
+
const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
|
|
40590
|
+
const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
|
|
40591
|
+
const collectAnalyzedFileFingerprints = (rootDirectory) => {
|
|
40592
|
+
const fingerprints = [];
|
|
40593
|
+
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
40594
|
+
if (!isFingerprintedFile(name)) continue;
|
|
40595
|
+
try {
|
|
40596
|
+
const fileStat = NFS.statSync(absolutePath);
|
|
40597
|
+
const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
|
|
40598
|
+
fingerprints.push(`${relativePath}:${fileStat.mtimeMs}:${fileStat.size}`);
|
|
40599
|
+
} catch {}
|
|
40600
|
+
}
|
|
40601
|
+
return fingerprints.sort();
|
|
40602
|
+
};
|
|
40603
|
+
const bundledRequire$2 = createRequire(import.meta.url);
|
|
40604
|
+
const resolveDeslopVersion = () => {
|
|
40605
|
+
try {
|
|
40606
|
+
const packageJson = JSON.parse(NFS.readFileSync(bundledRequire$2.resolve("deslop-js/package.json"), "utf8"));
|
|
40607
|
+
return isRecord$1(packageJson) && typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
40608
|
+
} catch {
|
|
40609
|
+
return "unknown";
|
|
40610
|
+
}
|
|
40611
|
+
};
|
|
40612
|
+
const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
|
|
40613
|
+
schemaVersion: 1,
|
|
40614
|
+
coreVersion: input.coreVersion,
|
|
40615
|
+
deslopVersion: resolveDeslopVersion(),
|
|
40616
|
+
deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
|
|
40617
|
+
entryPatterns: input.entryPatterns,
|
|
40618
|
+
ignorePatterns: input.ignorePatterns,
|
|
40619
|
+
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
|
|
40620
|
+
files: collectAnalyzedFileFingerprints(input.rootDirectory)
|
|
40621
|
+
})).digest("hex");
|
|
40622
|
+
const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
|
|
40623
|
+
const decodeCachedDiagnostics = (raw) => {
|
|
40624
|
+
try {
|
|
40625
|
+
for (const entry of raw) validateDiagnostic$1(entry);
|
|
40626
|
+
return raw;
|
|
40627
|
+
} catch {
|
|
40628
|
+
return null;
|
|
40629
|
+
}
|
|
40630
|
+
};
|
|
40631
|
+
const lookupDeadCodeResultCache = (cacheDirectory, cacheKey) => {
|
|
40632
|
+
const persisted = failOpenReadJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), null);
|
|
40633
|
+
if (persisted === null || !isRecord$1(persisted) || persisted.version !== 1 || persisted.key !== cacheKey || !Array.isArray(persisted.diagnostics)) return null;
|
|
40634
|
+
return decodeCachedDiagnostics(persisted.diagnostics);
|
|
40635
|
+
};
|
|
40636
|
+
const storeDeadCodeResultCache = (cacheDirectory, cacheKey, diagnostics) => {
|
|
40637
|
+
atomicWriteJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
|
|
40638
|
+
version: 1,
|
|
40639
|
+
key: cacheKey,
|
|
40640
|
+
diagnostics
|
|
40641
|
+
});
|
|
40642
|
+
};
|
|
40535
40643
|
const readSystemFacts = () => ({
|
|
40536
40644
|
availableCores: os.availableParallelism(),
|
|
40537
40645
|
totalMemoryBytes: os.totalmem(),
|
|
@@ -40600,6 +40708,21 @@ const withDeadCodeWorkerSlot = async (task, abortSignal) => {
|
|
|
40600
40708
|
releaseSlot();
|
|
40601
40709
|
}
|
|
40602
40710
|
};
|
|
40711
|
+
const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
|
|
40712
|
+
const resolveReactDoctorCacheDir = (projectDirectory) => {
|
|
40713
|
+
const cacheDirOverride = process.env["REACT_DOCTOR_CACHE_DIR"]?.trim();
|
|
40714
|
+
if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
|
|
40715
|
+
const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
|
|
40716
|
+
if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
|
|
40717
|
+
return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
|
|
40718
|
+
};
|
|
40719
|
+
const resolveUserCacheScope = () => {
|
|
40720
|
+
try {
|
|
40721
|
+
return String(process.getuid?.() ?? os.userInfo().username);
|
|
40722
|
+
} catch {
|
|
40723
|
+
return "shared";
|
|
40724
|
+
}
|
|
40725
|
+
};
|
|
40603
40726
|
/**
|
|
40604
40727
|
* Resolves a path to its canonical, symlink-free form, falling back to
|
|
40605
40728
|
* the input when it cannot be realpath'd (broken symlink, permission
|
|
@@ -40895,13 +41018,28 @@ const checkDeadCode = async (options) => {
|
|
|
40895
41018
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
40896
41019
|
const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
|
|
40897
41020
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
41021
|
+
const tsConfigPath = resolveTsConfigPath(rootDirectory);
|
|
41022
|
+
const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
|
|
41023
|
+
const cacheKey = options.cacheEnabled ? computeDeadCodeCacheKey({
|
|
41024
|
+
rootDirectory,
|
|
41025
|
+
entryPatterns,
|
|
41026
|
+
ignorePatterns,
|
|
41027
|
+
tsConfigPath,
|
|
41028
|
+
deslopJsModuleSpecifier,
|
|
41029
|
+
coreVersion: CORE_PACKAGE_VERSION
|
|
41030
|
+
}) : null;
|
|
41031
|
+
if (cacheKey !== null) {
|
|
41032
|
+
const cachedDiagnostics = lookupDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey);
|
|
41033
|
+
options.onCacheOutcome?.(cachedDiagnostics !== null);
|
|
41034
|
+
if (cachedDiagnostics !== null) return [...cachedDiagnostics];
|
|
41035
|
+
}
|
|
40898
41036
|
const spawnAndRun = () => {
|
|
40899
41037
|
return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
40900
41038
|
rootDirectory,
|
|
40901
41039
|
entryPatterns,
|
|
40902
|
-
tsConfigPath
|
|
41040
|
+
tsConfigPath,
|
|
40903
41041
|
ignorePatterns,
|
|
40904
|
-
deslopJsModuleSpecifier
|
|
41042
|
+
deslopJsModuleSpecifier,
|
|
40905
41043
|
parseConcurrency: options.parseConcurrency
|
|
40906
41044
|
}), options.workerTimeoutMs ?? 12e4, options.abortSignal);
|
|
40907
41045
|
};
|
|
@@ -40962,6 +41100,7 @@ const checkDeadCode = async (options) => {
|
|
|
40962
41100
|
category: DEAD_CODE_CATEGORY
|
|
40963
41101
|
});
|
|
40964
41102
|
}
|
|
41103
|
+
if (cacheKey !== null) storeDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey, diagnostics);
|
|
40965
41104
|
return diagnostics;
|
|
40966
41105
|
};
|
|
40967
41106
|
const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
|
|
@@ -41064,12 +41203,15 @@ var Config = class Config extends Service()("react-doctor/Config") {
|
|
|
41064
41203
|
*/
|
|
41065
41204
|
var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
41066
41205
|
static layerNode = succeed$3(DeadCode, DeadCode.of({ run: (input) => unwrap(fn("DeadCode.run")(function* () {
|
|
41206
|
+
const cacheEnabled = yield* DeadCodeResultCacheEnabled;
|
|
41067
41207
|
return yield* tryPromise({
|
|
41068
41208
|
try: (signal) => checkDeadCode({
|
|
41069
41209
|
rootDirectory: input.rootDirectory,
|
|
41070
41210
|
parseConcurrency: input.parseConcurrency,
|
|
41071
41211
|
workerTimeoutMs: input.workerTimeoutMs,
|
|
41072
|
-
abortSignal: signal
|
|
41212
|
+
abortSignal: signal,
|
|
41213
|
+
cacheEnabled,
|
|
41214
|
+
onCacheOutcome: input.onCacheOutcome
|
|
41073
41215
|
}),
|
|
41074
41216
|
catch: (cause) => new ReactDoctorError({ reason: new DeadCodeAnalysisFailed({ cause }) })
|
|
41075
41217
|
}).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)));
|
|
@@ -41995,23 +42137,6 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
41995
42137
|
}
|
|
41996
42138
|
};
|
|
41997
42139
|
};
|
|
41998
|
-
const atomicWriteJson = (filePath, value) => {
|
|
41999
|
-
try {
|
|
42000
|
-
NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
|
|
42001
|
-
const temporaryPath = `${filePath}.${process.pid}.tmp`;
|
|
42002
|
-
NFS.writeFileSync(temporaryPath, JSON.stringify(value));
|
|
42003
|
-
NFS.renameSync(temporaryPath, filePath);
|
|
42004
|
-
} catch {
|
|
42005
|
-
return;
|
|
42006
|
-
}
|
|
42007
|
-
};
|
|
42008
|
-
const failOpenReadJson = (filePath, fallback) => {
|
|
42009
|
-
try {
|
|
42010
|
-
return JSON.parse(NFS.readFileSync(filePath, "utf8"));
|
|
42011
|
-
} catch {
|
|
42012
|
-
return fallback;
|
|
42013
|
-
}
|
|
42014
|
-
};
|
|
42015
42140
|
const validateDiagnostic = decodeUnknownSync(Diagnostic);
|
|
42016
42141
|
const decodeFileDiagnostics = (raw) => {
|
|
42017
42142
|
if (!Array.isArray(raw)) return null;
|
|
@@ -42069,7 +42194,7 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
42069
42194
|
}
|
|
42070
42195
|
};
|
|
42071
42196
|
};
|
|
42072
|
-
const bundledRequire$
|
|
42197
|
+
const bundledRequire$3 = createRequire(import.meta.url);
|
|
42073
42198
|
const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
|
|
42074
42199
|
const resolveChildNodeVersion = (nodeBinaryPath) => {
|
|
42075
42200
|
if (nodeBinaryPath === process.execPath) return process.version;
|
|
@@ -42095,7 +42220,7 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
|
|
|
42095
42220
|
const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
42096
42221
|
const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
|
|
42097
42222
|
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
|
|
42098
|
-
const packageJson = bundledRequire$
|
|
42223
|
+
const packageJson = bundledRequire$3(specifier);
|
|
42099
42224
|
const version = typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
42100
42225
|
versions.push(`${specifier}=${version}`);
|
|
42101
42226
|
} catch {
|
|
@@ -43075,22 +43200,70 @@ const hashFileContents = (filePath) => {
|
|
|
43075
43200
|
return null;
|
|
43076
43201
|
}
|
|
43077
43202
|
};
|
|
43078
|
-
|
|
43079
|
-
|
|
43080
|
-
|
|
43081
|
-
|
|
43082
|
-
|
|
43083
|
-
|
|
43084
|
-
|
|
43085
|
-
|
|
43086
|
-
|
|
43087
|
-
|
|
43088
|
-
|
|
43089
|
-
|
|
43090
|
-
|
|
43203
|
+
/**
|
|
43204
|
+
* Balanced LPT (longest-processing-time-first) lint batch planner. Where
|
|
43205
|
+
* `batchIncludePaths` greedily fills 100-file batches and leaves a small
|
|
43206
|
+
* remainder batch (617 files → 6×100 + 17, so the parallel pool's wall clock
|
|
43207
|
+
* is set by whichever 100-file chunk happened to collect the most work while
|
|
43208
|
+
* the remainder's worker idles), this planner keeps the SAME mandatory batch
|
|
43209
|
+
* count — `ceil(files / OXLINT_MAX_FILES_PER_BATCH)`, the JS-plugin
|
|
43210
|
+
* perf-cliff / native-binding SIGABRT guard — and assigns files largest-first,
|
|
43211
|
+
* each to the least-loaded batch by cumulative byte size. Every batch ends up
|
|
43212
|
+
* with an even share of files AND bytes, so no batch is a straggler; heavy
|
|
43213
|
+
* files are SPREAD across batches (the documented precondition for `cost`
|
|
43214
|
+
* ordering to beat `arrival`) instead of concentrated in one.
|
|
43215
|
+
*
|
|
43216
|
+
* Deliberately NOT worker-count-aware: splitting into extra batches to feed
|
|
43217
|
+
* idle workers was measured (619-file corpus, 10 cores) to REGRESS the lint
|
|
43218
|
+
* wall — each additional concurrent subprocess pays a contended cold start
|
|
43219
|
+
* (node boot + plugin import + native dlopen, ~180 ms uncontended and 2-3×
|
|
43220
|
+
* that in a full wave) that outweighs the smaller per-batch file share.
|
|
43221
|
+
*
|
|
43222
|
+
* Every batch also respects the spawn-args char budget; a file that fits no
|
|
43223
|
+
* existing batch opens a new one, mirroring `batchIncludePaths`. Within a
|
|
43224
|
+
* batch, files return in arrival order, and the assignment is fully
|
|
43225
|
+
* deterministic (ties broken by lowest batch index), so a plan is
|
|
43226
|
+
* reproducible for a fixed (files, sizes) input. Batch composition cannot
|
|
43227
|
+
* change diagnostics — rules that look beyond one file (`CROSS_FILE_RULE_IDS`)
|
|
43228
|
+
* read the OTHER files via the filesystem, never via batch-mates — so the
|
|
43229
|
+
* plan only moves wall-clock time.
|
|
43230
|
+
*
|
|
43231
|
+
* O(files × batches); the linear least-loaded scan is fine at real-world
|
|
43232
|
+
* scale (a 3,500-file monorepo is 36 batches ≈ 126k comparisons).
|
|
43233
|
+
*/
|
|
43234
|
+
const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
|
|
43235
|
+
if (files.length === 0) return [];
|
|
43236
|
+
const batchCount = Math.ceil(files.length / 100);
|
|
43237
|
+
const maxFilesPerBatch = Math.ceil(files.length / batchCount);
|
|
43238
|
+
const baseArgsLengthChars = estimateArgsLength(baseArgs);
|
|
43239
|
+
const descendingSizeIndexes = [...files.keys()].sort((leftIndex, rightIndex) => (sizeByFile.get(files[rightIndex]) ?? 0) - (sizeByFile.get(files[leftIndex]) ?? 0));
|
|
43240
|
+
const batches = Array.from({ length: batchCount }, () => ({
|
|
43241
|
+
fileIndexes: [],
|
|
43242
|
+
totalSizeBytes: 0,
|
|
43243
|
+
argsLengthChars: baseArgsLengthChars
|
|
43244
|
+
}));
|
|
43245
|
+
for (const fileIndex of descendingSizeIndexes) {
|
|
43246
|
+
const entryLengthChars = files[fileIndex].length + 1;
|
|
43247
|
+
let targetBatch = null;
|
|
43248
|
+
for (const batch of batches) {
|
|
43249
|
+
if (batch.fileIndexes.length >= maxFilesPerBatch) continue;
|
|
43250
|
+
if (batch.fileIndexes.length > 0 && batch.argsLengthChars + entryLengthChars > 24e3) continue;
|
|
43251
|
+
if (targetBatch === null || batch.totalSizeBytes < targetBatch.totalSizeBytes || batch.totalSizeBytes === targetBatch.totalSizeBytes && batch.fileIndexes.length < targetBatch.fileIndexes.length) targetBatch = batch;
|
|
43252
|
+
}
|
|
43253
|
+
if (targetBatch === null) {
|
|
43254
|
+
targetBatch = {
|
|
43255
|
+
fileIndexes: [],
|
|
43256
|
+
totalSizeBytes: 0,
|
|
43257
|
+
argsLengthChars: baseArgsLengthChars
|
|
43258
|
+
};
|
|
43259
|
+
batches.push(targetBatch);
|
|
43260
|
+
}
|
|
43261
|
+
targetBatch.fileIndexes.push(fileIndex);
|
|
43262
|
+
targetBatch.totalSizeBytes += sizeByFile.get(files[fileIndex]) ?? 0;
|
|
43263
|
+
targetBatch.argsLengthChars += entryLengthChars;
|
|
43091
43264
|
}
|
|
43265
|
+
return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
|
|
43092
43266
|
};
|
|
43093
|
-
const sortSourceFilesByCost = (entries) => [...entries].sort((left, right) => right.sizeBytes - left.sizeBytes).map((entry) => entry.path);
|
|
43094
43267
|
/**
|
|
43095
43268
|
* Atomically (re)writes the generated oxlintrc.json. Used twice in
|
|
43096
43269
|
* the runner: once for the primary scan, once for the
|
|
@@ -43149,7 +43322,7 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
43149
43322
|
* 6. always restore disable directives + clean up the temp dir
|
|
43150
43323
|
*/
|
|
43151
43324
|
const runOxlint = async (options) => {
|
|
43152
|
-
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 = "
|
|
43325
|
+
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;
|
|
43153
43326
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
43154
43327
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
43155
43328
|
validateRuleRegistration();
|
|
@@ -43201,8 +43374,15 @@ const runOxlint = async (options) => {
|
|
|
43201
43374
|
"json",
|
|
43202
43375
|
...sharedArgs
|
|
43203
43376
|
];
|
|
43204
|
-
|
|
43205
|
-
const
|
|
43377
|
+
await yieldToEventLoop();
|
|
43378
|
+
const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
|
|
43379
|
+
const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
|
|
43380
|
+
const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
|
|
43381
|
+
const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
|
|
43382
|
+
baseArgs: passBaseArgs,
|
|
43383
|
+
files: passFiles,
|
|
43384
|
+
sizeByFile
|
|
43385
|
+
}) : batchIncludePaths(passBaseArgs, passFiles);
|
|
43206
43386
|
const runConfigOverFiles = async (buildConfigForPass, configFileName, files, fileProgress) => {
|
|
43207
43387
|
if (files.length === 0) return {
|
|
43208
43388
|
diagnostics: [],
|
|
@@ -43216,7 +43396,7 @@ const runOxlint = async (options) => {
|
|
|
43216
43396
|
};
|
|
43217
43397
|
const passConfigPath = Path.join(configDirectory, configFileName);
|
|
43218
43398
|
const passBaseArgs = makeBaseArgs(passConfigPath);
|
|
43219
|
-
const passFileBatches =
|
|
43399
|
+
const passFileBatches = buildFileBatches(passBaseArgs, files);
|
|
43220
43400
|
const spawnPass = () => spawnLintBatches({
|
|
43221
43401
|
baseArgs: passBaseArgs,
|
|
43222
43402
|
fileBatches: passFileBatches,
|
|
@@ -43265,6 +43445,7 @@ const runOxlint = async (options) => {
|
|
|
43265
43445
|
const cacheKeyByFile = /* @__PURE__ */ new Map();
|
|
43266
43446
|
const missFiles = [];
|
|
43267
43447
|
const replayedDiagnostics = [];
|
|
43448
|
+
let hashSliceStartedAt = performance.now();
|
|
43268
43449
|
for (const candidateFile of candidateFiles) {
|
|
43269
43450
|
const contentHash = hashFileContents(Path.resolve(rootDirectory, candidateFile));
|
|
43270
43451
|
if (contentHash === null) {
|
|
@@ -43276,6 +43457,10 @@ const runOxlint = async (options) => {
|
|
|
43276
43457
|
const cachedDiagnostics = cache.lookup(cacheKey);
|
|
43277
43458
|
if (cachedDiagnostics === null) missFiles.push(candidateFile);
|
|
43278
43459
|
else replayedDiagnostics.push(...cachedDiagnostics);
|
|
43460
|
+
if (performance.now() - hashSliceStartedAt >= 12) {
|
|
43461
|
+
await yieldToEventLoop();
|
|
43462
|
+
hashSliceStartedAt = performance.now();
|
|
43463
|
+
}
|
|
43279
43464
|
}
|
|
43280
43465
|
const cacheHitFileCount = candidateFiles.length - missFiles.length;
|
|
43281
43466
|
const fullResult = await runConfigOverFiles((overrides) => buildConfig({
|
|
@@ -43318,7 +43503,7 @@ const runOxlint = async (options) => {
|
|
|
43318
43503
|
]);
|
|
43319
43504
|
}
|
|
43320
43505
|
const baseArgs = makeBaseArgs(configPath);
|
|
43321
|
-
const fileBatches =
|
|
43506
|
+
const fileBatches = buildFileBatches(baseArgs, candidateFiles);
|
|
43322
43507
|
const runBatches = () => spawnLintBatches({
|
|
43323
43508
|
baseArgs,
|
|
43324
43509
|
fileBatches,
|
|
@@ -44205,7 +44390,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44205
44390
|
const buildCollectDeadCode = (deadCodeTimeout) => runCollect(applyPerElementPipeline(deadCodeService.run({
|
|
44206
44391
|
rootDirectory: scanDirectory,
|
|
44207
44392
|
parseConcurrency: deadCodeParseConcurrency,
|
|
44208
|
-
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs
|
|
44393
|
+
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
|
|
44394
|
+
onCacheOutcome: (didHitCache) => {
|
|
44395
|
+
deadCodeCacheHit = didHitCache;
|
|
44396
|
+
}
|
|
44209
44397
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
44210
44398
|
yield* set(deadCodeFailure, {
|
|
44211
44399
|
didFail: true,
|
|
@@ -44233,6 +44421,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44233
44421
|
let lastReportedTotalFileCount = 0;
|
|
44234
44422
|
let lintCacheHitFileCount = null;
|
|
44235
44423
|
let lintCacheTotalFileCount = null;
|
|
44424
|
+
let deadCodeCacheHit = null;
|
|
44236
44425
|
const baseLintStream = linterService.run({
|
|
44237
44426
|
rootDirectory: scanDirectory,
|
|
44238
44427
|
project,
|
|
@@ -44362,6 +44551,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44362
44551
|
securityScanFailed,
|
|
44363
44552
|
lintCacheHitFileCount,
|
|
44364
44553
|
lintCacheTotalFileCount,
|
|
44554
|
+
deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
|
|
44365
44555
|
suppressedRuleCounts: transform.summarizeSuppressions()
|
|
44366
44556
|
};
|
|
44367
44557
|
}).pipe(withSpan("runInspect", { attributes: {
|
|
@@ -45143,6 +45333,7 @@ const isNonInteractiveEnvironment = () => NON_INTERACTIVE_ENVIRONMENT_VARIABLES.
|
|
|
45143
45333
|
const REACT_DOCTOR_CONFIG_PROJECT_NAME = "react-doctor";
|
|
45144
45334
|
const STAGED_FILES_TEMP_DIR_PREFIX = "react-doctor-staged-";
|
|
45145
45335
|
const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
|
|
45336
|
+
const RUN_GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
45146
45337
|
const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
|
|
45147
45338
|
const CI_TRUST_COMPANIES = "PayPal, Rippling, and Alibaba";
|
|
45148
45339
|
const WELCOME_EXPLANATION_HOLD_MS = 1e3;
|
|
@@ -45233,7 +45424,7 @@ const makeNoopConsole = () => ({
|
|
|
45233
45424
|
});
|
|
45234
45425
|
//#endregion
|
|
45235
45426
|
//#region src/cli/utils/version.ts
|
|
45236
|
-
const VERSION = "0.6.
|
|
45427
|
+
const VERSION = "0.6.3-dev.20d81f6";
|
|
45237
45428
|
//#endregion
|
|
45238
45429
|
//#region src/cli/utils/json-mode.ts
|
|
45239
45430
|
let context = null;
|
|
@@ -45602,13 +45793,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
45602
45793
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
45603
45794
|
* standard `SENTRY_RELEASE` override.
|
|
45604
45795
|
*/
|
|
45605
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.
|
|
45796
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.20d81f6`;
|
|
45606
45797
|
/**
|
|
45607
45798
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
45608
45799
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
45609
45800
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
45610
45801
|
*/
|
|
45611
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.
|
|
45802
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.20d81f6") ? "development" : "production");
|
|
45612
45803
|
/**
|
|
45613
45804
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
45614
45805
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -45809,7 +46000,8 @@ const runGit = (projectRoot, args) => {
|
|
|
45809
46000
|
"ignore",
|
|
45810
46001
|
"pipe",
|
|
45811
46002
|
"ignore"
|
|
45812
|
-
]
|
|
46003
|
+
],
|
|
46004
|
+
maxBuffer: RUN_GIT_MAX_BUFFER_BYTES
|
|
45813
46005
|
}).trim();
|
|
45814
46006
|
} catch {
|
|
45815
46007
|
return null;
|
|
@@ -57835,7 +58027,8 @@ const buildOutcomeAttributes = (input) => {
|
|
|
57835
58027
|
}),
|
|
57836
58028
|
...withNamespace("deadCode", {
|
|
57837
58029
|
failed: input.didDeadCodeFail ?? null,
|
|
57838
|
-
overlapped: input.deadCodeOverlapped ?? null
|
|
58030
|
+
overlapped: input.deadCodeOverlapped ?? null,
|
|
58031
|
+
cacheHit: result.deadCodeCacheHit ?? null
|
|
57839
58032
|
}),
|
|
57840
58033
|
...withNamespace("supplyChain", { overlapTimedOut: input.supplyChainOverlapTimedOut ?? null }),
|
|
57841
58034
|
...withNamespace("securityScan", { failed: input.securityScanFailed ?? null }),
|
|
@@ -59158,13 +59351,89 @@ const stringifyStableJson = (value) => {
|
|
|
59158
59351
|
};
|
|
59159
59352
|
const hashString = (value) => crypto.createHash("sha1").update(value).digest("hex");
|
|
59160
59353
|
const readHeadSha = (projectDirectory) => runGit(projectDirectory, ["rev-parse", "HEAD"]);
|
|
59161
|
-
const
|
|
59162
|
-
const
|
|
59354
|
+
const parseWorktreeStatusRecords = (statusOutput) => {
|
|
59355
|
+
const entries = [];
|
|
59356
|
+
const tokens = statusOutput.split("\0");
|
|
59357
|
+
for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
59358
|
+
let record = tokens[tokenIndex];
|
|
59359
|
+
if (record.length === 0) continue;
|
|
59360
|
+
if (record.length < 3 || record[2] !== " ") {
|
|
59361
|
+
if (tokenIndex !== 0) return null;
|
|
59362
|
+
record = ` ${record}`;
|
|
59363
|
+
}
|
|
59364
|
+
if (record.length < 4 || record[2] !== " ") return null;
|
|
59365
|
+
const statusCode = record.slice(0, 2);
|
|
59366
|
+
const recordPath = record.slice(3);
|
|
59367
|
+
if (statusCode.includes("R") || statusCode.includes("C")) {
|
|
59368
|
+
tokenIndex += 1;
|
|
59369
|
+
const originPath = tokens[tokenIndex];
|
|
59370
|
+
if (originPath === void 0 || originPath.length === 0) return null;
|
|
59371
|
+
entries.push({
|
|
59372
|
+
statusCode,
|
|
59373
|
+
path: recordPath,
|
|
59374
|
+
originPath
|
|
59375
|
+
});
|
|
59376
|
+
continue;
|
|
59377
|
+
}
|
|
59378
|
+
entries.push({
|
|
59379
|
+
statusCode,
|
|
59380
|
+
path: recordPath
|
|
59381
|
+
});
|
|
59382
|
+
}
|
|
59383
|
+
return entries;
|
|
59384
|
+
};
|
|
59385
|
+
const buildDirtyPathContentFingerprint = (absolutePath, statusCode) => {
|
|
59386
|
+
let stats;
|
|
59387
|
+
try {
|
|
59388
|
+
stats = fs.lstatSync(absolutePath);
|
|
59389
|
+
} catch {
|
|
59390
|
+
return statusCode.includes("D") ? "deleted" : null;
|
|
59391
|
+
}
|
|
59392
|
+
if (stats.isSymbolicLink()) try {
|
|
59393
|
+
return `link:${fs.readlinkSync(absolutePath)}`;
|
|
59394
|
+
} catch {
|
|
59395
|
+
return null;
|
|
59396
|
+
}
|
|
59397
|
+
if (!stats.isFile()) return null;
|
|
59398
|
+
if (stats.size > 10485760) return `stat:${stats.mtimeMs}:${stats.size}`;
|
|
59399
|
+
return hashFileContents(absolutePath);
|
|
59400
|
+
};
|
|
59401
|
+
const buildWorktreeFingerprint = (projectDirectory) => {
|
|
59402
|
+
const statusOutput = runGit(projectDirectory, [
|
|
59163
59403
|
"status",
|
|
59164
59404
|
"--porcelain=v1",
|
|
59165
|
-
"
|
|
59405
|
+
"-z",
|
|
59406
|
+
"--untracked-files=all"
|
|
59166
59407
|
]);
|
|
59167
|
-
|
|
59408
|
+
if (statusOutput === null) return null;
|
|
59409
|
+
if (statusOutput.length === 0) return [];
|
|
59410
|
+
const statusEntries = parseWorktreeStatusRecords(statusOutput);
|
|
59411
|
+
if (statusEntries === null) return null;
|
|
59412
|
+
if (statusEntries.length > 300) return null;
|
|
59413
|
+
const repositoryRoot = runGit(projectDirectory, ["rev-parse", "--show-toplevel"]);
|
|
59414
|
+
if (repositoryRoot === null) return null;
|
|
59415
|
+
const dirtyEntries = [];
|
|
59416
|
+
for (const statusEntry of statusEntries) {
|
|
59417
|
+
const contentFingerprint = buildDirtyPathContentFingerprint(path.join(repositoryRoot, statusEntry.path), statusEntry.statusCode);
|
|
59418
|
+
if (contentFingerprint === null) return null;
|
|
59419
|
+
dirtyEntries.push({
|
|
59420
|
+
...statusEntry,
|
|
59421
|
+
contentFingerprint
|
|
59422
|
+
});
|
|
59423
|
+
}
|
|
59424
|
+
return dirtyEntries.sort((firstEntry, secondEntry) => {
|
|
59425
|
+
const firstSortKey = `${firstEntry.path}${firstEntry.statusCode}`;
|
|
59426
|
+
const secondSortKey = `${secondEntry.path}${secondEntry.statusCode}`;
|
|
59427
|
+
return firstSortKey < secondSortKey ? -1 : firstSortKey > secondSortKey ? 1 : 0;
|
|
59428
|
+
});
|
|
59429
|
+
};
|
|
59430
|
+
const DOTENV_FILE_NAME_PATTERN = /^\.env(\.|$)/;
|
|
59431
|
+
const resolveDotenvFingerprint = (projectDirectory) => {
|
|
59432
|
+
try {
|
|
59433
|
+
return fs.readdirSync(projectDirectory).filter((entryName) => DOTENV_FILE_NAME_PATTERN.test(entryName)).sort().map((entryName) => `${entryName}=${fileFingerprint(path.join(projectDirectory, entryName)) ?? "unreadable"}`);
|
|
59434
|
+
} catch {
|
|
59435
|
+
return [];
|
|
59436
|
+
}
|
|
59168
59437
|
};
|
|
59169
59438
|
const hasHiddenTrackedFileState = (projectDirectory) => {
|
|
59170
59439
|
const output = runGit(projectDirectory, ["ls-files", "-v"]);
|
|
@@ -59247,8 +59516,9 @@ const resolveToolchainFingerprint = (nodeBinaryPath) => {
|
|
|
59247
59516
|
};
|
|
59248
59517
|
const buildScanResultCacheKey = (input) => {
|
|
59249
59518
|
if (isScanResultCacheDisabled()) return null;
|
|
59250
|
-
if (!isWorktreeClean(input.projectDirectory)) return null;
|
|
59251
59519
|
if (hasHiddenTrackedFileState(input.projectDirectory)) return null;
|
|
59520
|
+
const worktreeFingerprint = buildWorktreeFingerprint(input.projectDirectory);
|
|
59521
|
+
if (worktreeFingerprint === null) return null;
|
|
59252
59522
|
const headSha = readHeadSha(input.projectDirectory);
|
|
59253
59523
|
if (headSha === null) return null;
|
|
59254
59524
|
if (stringifyStableJson(input.userConfig) === null) return null;
|
|
@@ -59256,6 +59526,8 @@ const buildScanResultCacheKey = (input) => {
|
|
|
59256
59526
|
schemaVersion: 3,
|
|
59257
59527
|
projectIdentity: resolveProjectIdentity(input.projectDirectory),
|
|
59258
59528
|
headSha,
|
|
59529
|
+
worktreeFingerprint,
|
|
59530
|
+
dotenvFingerprint: resolveDotenvFingerprint(input.projectDirectory),
|
|
59259
59531
|
reactDoctorVersion: input.version,
|
|
59260
59532
|
nodeVersion: process.version,
|
|
59261
59533
|
toolchainFingerprint: resolveToolchainFingerprint(input.nodeBinaryPath),
|
|
@@ -59648,7 +59920,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
59648
59920
|
scanMode: baselineDelta ? "baseline" : isDiffMode ? "diff" : "full",
|
|
59649
59921
|
baselineDegraded,
|
|
59650
59922
|
lintCacheHitFileCount: output.lintCacheHitFileCount,
|
|
59651
|
-
lintCacheTotalFileCount: output.lintCacheTotalFileCount
|
|
59923
|
+
lintCacheTotalFileCount: output.lintCacheTotalFileCount,
|
|
59924
|
+
deadCodeCacheHit: output.deadCodeCacheHit
|
|
59652
59925
|
});
|
|
59653
59926
|
recordOnboardingCompletion(options);
|
|
59654
59927
|
return result;
|
|
@@ -59683,6 +59956,7 @@ const renderAndRecordScan = async (input) => {
|
|
|
59683
59956
|
scanElapsedMilliseconds: input.payload.scanElapsedMilliseconds,
|
|
59684
59957
|
lintCacheHitFileCount: input.lintCacheHitFileCount ?? null,
|
|
59685
59958
|
lintCacheTotalFileCount: input.lintCacheTotalFileCount ?? null,
|
|
59959
|
+
deadCodeCacheHit: input.deadCodeCacheHit ?? null,
|
|
59686
59960
|
baselineDelta: input.payload.baselineDelta
|
|
59687
59961
|
}), input.options.silent));
|
|
59688
59962
|
const { workerCount: resolvedWorkerCount, parallel } = resolveWorkerTelemetry(input.payload.scanConcurrency, input.options.concurrency);
|
|
@@ -59721,7 +59995,7 @@ const renderAndRecordScan = async (input) => {
|
|
|
59721
59995
|
return result;
|
|
59722
59996
|
};
|
|
59723
59997
|
const finalizeAndRender = (input) => gen(function* () {
|
|
59724
|
-
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, baselineDelta } = input;
|
|
59998
|
+
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, deadCodeCacheHit, baselineDelta } = input;
|
|
59725
59999
|
const { skippedChecks, skippedCheckReasons } = buildSkippedChecks({
|
|
59726
60000
|
didLintFail,
|
|
59727
60001
|
lintFailureReason,
|
|
@@ -59745,6 +60019,7 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
59745
60019
|
lintCacheHitFileCount,
|
|
59746
60020
|
lintCacheTotalFileCount
|
|
59747
60021
|
} : {},
|
|
60022
|
+
...deadCodeCacheHit !== null ? { deadCodeCacheHit } : {},
|
|
59748
60023
|
...baselineDelta ? { baselineDelta } : {}
|
|
59749
60024
|
});
|
|
59750
60025
|
if (options.suppressRendering) return buildResult();
|
|
@@ -63591,4 +63866,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
63591
63866
|
export {};
|
|
63592
63867
|
|
|
63593
63868
|
//# sourceMappingURL=cli.js.map
|
|
63594
|
-
//# debugId=
|
|
63869
|
+
//# debugId=d7bda084-a223-5aa7-8605-578888bd1b33
|