react-doctor 0.6.3-dev.bdf8074 → 0.6.3-dev.ce49250
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +319 -737
- package/dist/index.d.ts +0 -8
- package/dist/index.js +42 -379
- package/dist/lsp.js +42 -379
- 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]="cb06d1e4-d50b-5715-af77-13eb97c43e07")}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,
|
|
12
|
+
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
13
13
|
import * as OS from "node:os";
|
|
14
14
|
import os, { tmpdir } from "node:os";
|
|
15
15
|
import { parseJSON5 } from "confbox";
|
|
@@ -36129,7 +36129,6 @@ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
|
|
|
36129
36129
|
const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
36130
36130
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
36131
36131
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
36132
|
-
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
36133
36132
|
const CORE_PACKAGE_VERSION = "0.6.3";
|
|
36134
36133
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
36135
36134
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
@@ -38818,29 +38817,6 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
|
|
|
38818
38817
|
return true;
|
|
38819
38818
|
} }) {};
|
|
38820
38819
|
/**
|
|
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
|
-
/**
|
|
38844
38820
|
* Whether the whole-project dead-code result cache
|
|
38845
38821
|
* (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
|
|
38846
38822
|
* whose inputs (source tree, manifests, configs, analyzer version) are
|
|
@@ -40644,10 +40620,10 @@ const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON
|
|
|
40644
40620
|
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
|
|
40645
40621
|
files: collectAnalyzedFileFingerprints(input.rootDirectory)
|
|
40646
40622
|
})).digest("hex");
|
|
40647
|
-
const validateDiagnostic$
|
|
40623
|
+
const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
|
|
40648
40624
|
const decodeCachedDiagnostics = (raw) => {
|
|
40649
40625
|
try {
|
|
40650
|
-
for (const entry of raw) validateDiagnostic$
|
|
40626
|
+
for (const entry of raw) validateDiagnostic$1(entry);
|
|
40651
40627
|
return raw;
|
|
40652
40628
|
} catch {
|
|
40653
40629
|
return null;
|
|
@@ -42137,7 +42113,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
42137
42113
|
}
|
|
42138
42114
|
return enabled;
|
|
42139
42115
|
};
|
|
42140
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection
|
|
42116
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection }) => {
|
|
42141
42117
|
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
42142
42118
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
42143
42119
|
const jsPlugins = [];
|
|
@@ -42149,7 +42125,6 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42149
42125
|
if (!rule) continue;
|
|
42150
42126
|
if (ruleSelection === "cacheable" && CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
42151
42127
|
if (ruleSelection === "sidecar" && !CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
42152
|
-
if (ruleSelection === "sidecar" && sidecarRuleIdFilter !== void 0 && !sidecarRuleIdFilter.has(registryEntry.id)) continue;
|
|
42153
42128
|
if (rule.scan !== void 0) continue;
|
|
42154
42129
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
42155
42130
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
@@ -42194,23 +42169,23 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42194
42169
|
}
|
|
42195
42170
|
};
|
|
42196
42171
|
};
|
|
42197
|
-
const validateDiagnostic
|
|
42172
|
+
const validateDiagnostic = decodeUnknownSync(Diagnostic);
|
|
42198
42173
|
const decodeFileDiagnostics = (raw) => {
|
|
42199
42174
|
if (!Array.isArray(raw)) return null;
|
|
42200
42175
|
try {
|
|
42201
|
-
for (const entry of raw) validateDiagnostic
|
|
42176
|
+
for (const entry of raw) validateDiagnostic(entry);
|
|
42202
42177
|
return raw;
|
|
42203
42178
|
} catch {
|
|
42204
42179
|
return null;
|
|
42205
42180
|
}
|
|
42206
42181
|
};
|
|
42207
|
-
const emptyCache
|
|
42182
|
+
const emptyCache = () => ({
|
|
42208
42183
|
version: 1,
|
|
42209
42184
|
rulesets: {}
|
|
42210
42185
|
});
|
|
42211
|
-
const loadRulesetEntries
|
|
42186
|
+
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
42212
42187
|
const entries = /* @__PURE__ */ new Map();
|
|
42213
|
-
const persisted = failOpenReadJson(cacheFilePath, emptyCache
|
|
42188
|
+
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42214
42189
|
if (persisted.version !== 1 || !isRecord$1(persisted.rulesets)) return entries;
|
|
42215
42190
|
const bucket = persisted.rulesets[rulesetHash];
|
|
42216
42191
|
if (!isRecord$1(bucket) || !isRecord$1(bucket.files)) return entries;
|
|
@@ -42222,156 +42197,20 @@ const loadRulesetEntries$1 = (cacheFilePath, rulesetHash) => {
|
|
|
42222
42197
|
};
|
|
42223
42198
|
const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
42224
42199
|
const cacheFilePath = Path.join(cacheDirectory, FILE_LINT_CACHE_FILENAME);
|
|
42225
|
-
const entries = loadRulesetEntries
|
|
42200
|
+
const entries = loadRulesetEntries(cacheFilePath, rulesetHash);
|
|
42226
42201
|
return {
|
|
42227
42202
|
lookup: (fileKey) => entries.get(fileKey) ?? null,
|
|
42228
42203
|
store: (fileKey, diagnostics) => {
|
|
42229
42204
|
entries.delete(fileKey);
|
|
42230
42205
|
entries.set(fileKey, diagnostics);
|
|
42231
42206
|
},
|
|
42232
|
-
persist: () => {
|
|
42233
|
-
const onDisk = failOpenReadJson(cacheFilePath, emptyCache$1());
|
|
42234
|
-
const rulesets = onDisk.version === 1 && isRecord$1(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
42235
|
-
const existingBucket = rulesets[rulesetHash];
|
|
42236
|
-
const existingFiles = isRecord$1(existingBucket) && isRecord$1(existingBucket.files) ? existingBucket.files : {};
|
|
42237
|
-
const ourFiles = {};
|
|
42238
|
-
for (const [fileKey, diagnostics] of entries) ourFiles[fileKey] = diagnostics;
|
|
42239
|
-
const cappedEntries = Object.entries({
|
|
42240
|
-
...existingFiles,
|
|
42241
|
-
...ourFiles
|
|
42242
|
-
}).slice(-FILE_LINT_CACHE_MAX_FILE_COUNT);
|
|
42243
|
-
rulesets[rulesetHash] = {
|
|
42244
|
-
updatedAtMs: Date.now(),
|
|
42245
|
-
files: Object.fromEntries(cappedEntries)
|
|
42246
|
-
};
|
|
42247
|
-
atomicWriteJson(cacheFilePath, {
|
|
42248
|
-
version: 1,
|
|
42249
|
-
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))
|
|
42250
|
-
});
|
|
42251
|
-
}
|
|
42252
|
-
};
|
|
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
42207
|
persist: () => {
|
|
42369
42208
|
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42370
42209
|
const rulesets = onDisk.version === 1 && isRecord$1(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
42371
42210
|
const existingBucket = rulesets[rulesetHash];
|
|
42372
42211
|
const existingFiles = isRecord$1(existingBucket) && isRecord$1(existingBucket.files) ? existingBucket.files : {};
|
|
42373
42212
|
const ourFiles = {};
|
|
42374
|
-
for (const [fileKey,
|
|
42213
|
+
for (const [fileKey, diagnostics] of entries) ourFiles[fileKey] = diagnostics;
|
|
42375
42214
|
const cappedEntries = Object.entries({
|
|
42376
42215
|
...existingFiles,
|
|
42377
42216
|
...ourFiles
|
|
@@ -43386,6 +43225,13 @@ const validateRuleRegistration = () => {
|
|
|
43386
43225
|
].filter((entry) => entry !== null).join("; ");
|
|
43387
43226
|
console.warn(`[react-doctor] rule-registration drift: ${detail}`);
|
|
43388
43227
|
};
|
|
43228
|
+
const hashFileContents = (filePath) => {
|
|
43229
|
+
try {
|
|
43230
|
+
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
43231
|
+
} catch {
|
|
43232
|
+
return null;
|
|
43233
|
+
}
|
|
43234
|
+
};
|
|
43389
43235
|
/**
|
|
43390
43236
|
* Balanced LPT (longest-processing-time-first) lint batch planner. Where
|
|
43391
43237
|
* `batchIncludePaths` greedily fills 100-file batches and leaves a small
|
|
@@ -43467,106 +43313,6 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
43467
43313
|
NFS.closeSync(fileHandle);
|
|
43468
43314
|
}
|
|
43469
43315
|
};
|
|
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
|
-
};
|
|
43570
43316
|
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
43571
43317
|
/**
|
|
43572
43318
|
* Detects an oxlint config-load crash caused by the optional
|
|
@@ -43608,7 +43354,7 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
43608
43354
|
* 6. always restore disable directives + clean up the temp dir
|
|
43609
43355
|
*/
|
|
43610
43356
|
const runOxlint = async (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,
|
|
43357
|
+
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;
|
|
43612
43358
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
43613
43359
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
43614
43360
|
validateRuleRegistration();
|
|
@@ -43626,8 +43372,7 @@ const runOxlint = async (options) => {
|
|
|
43626
43372
|
severityControls,
|
|
43627
43373
|
userPlugins,
|
|
43628
43374
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
43629
|
-
ruleSelection: overrides.ruleSelection
|
|
43630
|
-
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
43375
|
+
ruleSelection: overrides.ruleSelection
|
|
43631
43376
|
});
|
|
43632
43377
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
43633
43378
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -43730,18 +43475,15 @@ const runOxlint = async (options) => {
|
|
|
43730
43475
|
});
|
|
43731
43476
|
const cache = createFileLintCache(resolveReactDoctorCacheDir(rootDirectory), rulesetHash);
|
|
43732
43477
|
const cacheKeyByFile = /* @__PURE__ */ new Map();
|
|
43733
|
-
const contentHashByRelativePath = /* @__PURE__ */ new Map();
|
|
43734
43478
|
const missFiles = [];
|
|
43735
43479
|
const replayedDiagnostics = [];
|
|
43736
43480
|
let hashSliceStartedAt = performance.now();
|
|
43737
43481
|
for (const candidateFile of candidateFiles) {
|
|
43738
|
-
const
|
|
43739
|
-
const contentHash = hashFileContents(absoluteCandidatePath);
|
|
43482
|
+
const contentHash = hashFileContents(Path.resolve(rootDirectory, candidateFile));
|
|
43740
43483
|
if (contentHash === null) {
|
|
43741
43484
|
missFiles.push(candidateFile);
|
|
43742
43485
|
continue;
|
|
43743
43486
|
}
|
|
43744
|
-
contentHashByRelativePath.set(Path.relative(rootDirectory, absoluteCandidatePath).replaceAll("\\", "/"), contentHash);
|
|
43745
43487
|
const cacheKey = `${candidateFile.replaceAll("\\", "/")}\u0000${contentHash}`;
|
|
43746
43488
|
cacheKeyByFile.set(candidateFile, cacheKey);
|
|
43747
43489
|
const cachedDiagnostics = cache.lookup(cacheKey);
|
|
@@ -43753,111 +43495,43 @@ const runOxlint = async (options) => {
|
|
|
43753
43495
|
}
|
|
43754
43496
|
}
|
|
43755
43497
|
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
|
-
});
|
|
43784
43498
|
const fullResult = await runConfigOverFiles((overrides) => buildConfig({
|
|
43785
43499
|
extendsPaths: [],
|
|
43786
43500
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
43787
43501
|
}), "oxlintrc.full.json", missFiles, options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(scannedFileCount, candidateFiles.length)));
|
|
43788
43502
|
const missFileSet = new Set(missFiles);
|
|
43789
|
-
const
|
|
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({
|
|
43815
|
-
extendsPaths: [],
|
|
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({
|
|
43503
|
+
const sidecarResult = await runConfigOverFiles(() => buildConfig({
|
|
43820
43504
|
extendsPaths: [],
|
|
43821
|
-
ruleSelection: "sidecar"
|
|
43822
|
-
|
|
43823
|
-
}), "oxlintrc.sidecar-unbounded.json", hitFiles, void 0) : {
|
|
43824
|
-
diagnostics: [],
|
|
43825
|
-
didDropReactHooksJsPlugin: false,
|
|
43826
|
-
hadPartialFailure: false
|
|
43827
|
-
};
|
|
43505
|
+
ruleSelection: "sidecar"
|
|
43506
|
+
}), "oxlintrc.sidecar.json", candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile)), options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(missFiles.length + scannedFileCount, candidateFiles.length)));
|
|
43828
43507
|
const freshCacheableDiagnostics = [];
|
|
43829
43508
|
for (const diagnostic of fullResult.diagnostics) if (!CROSS_FILE_RULE_IDS.has(diagnostic.rule)) freshCacheableDiagnostics.push(diagnostic);
|
|
43830
43509
|
onCacheStats?.(cacheHitFileCount, candidateFiles.length);
|
|
43831
|
-
|
|
43832
|
-
const
|
|
43833
|
-
|
|
43510
|
+
const missFileByNormalizedPath = /* @__PURE__ */ new Map();
|
|
43511
|
+
for (const missFile of missFiles) missFileByNormalizedPath.set(missFile.replaceAll("\\", "/"), missFile);
|
|
43512
|
+
const freshDiagnosticsByFile = /* @__PURE__ */ new Map();
|
|
43513
|
+
let isAttributionSound = true;
|
|
43514
|
+
for (const diagnostic of freshCacheableDiagnostics) {
|
|
43515
|
+
const missFile = missFileByNormalizedPath.get(diagnostic.filePath);
|
|
43516
|
+
if (missFile === void 0) {
|
|
43517
|
+
isAttributionSound = false;
|
|
43518
|
+
break;
|
|
43519
|
+
}
|
|
43520
|
+
const fileDiagnostics = freshDiagnosticsByFile.get(missFile) ?? [];
|
|
43521
|
+
fileDiagnostics.push(diagnostic);
|
|
43522
|
+
freshDiagnosticsByFile.set(missFile, fileDiagnostics);
|
|
43523
|
+
}
|
|
43524
|
+
if (!fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure && isAttributionSound) {
|
|
43834
43525
|
for (const missFile of missFiles) {
|
|
43835
43526
|
const cacheKey = cacheKeyByFile.get(missFile);
|
|
43836
43527
|
if (cacheKey !== void 0) cache.store(cacheKey, freshDiagnosticsByFile.get(missFile) ?? []);
|
|
43837
43528
|
}
|
|
43838
43529
|
cache.persist();
|
|
43839
43530
|
}
|
|
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
|
-
});
|
|
43855
43531
|
return dedupeDiagnostics([
|
|
43856
43532
|
...replayedDiagnostics,
|
|
43857
43533
|
...fullResult.diagnostics,
|
|
43858
|
-
...
|
|
43859
|
-
...boundedSidecarResult.diagnostics,
|
|
43860
|
-
...unboundedSidecarResult.diagnostics
|
|
43534
|
+
...sidecarResult.diagnostics
|
|
43861
43535
|
]);
|
|
43862
43536
|
}
|
|
43863
43537
|
const baseArgs = makeBaseArgs(configPath);
|
|
@@ -43955,7 +43629,6 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
43955
43629
|
const concurrency = yield* OxlintConcurrency;
|
|
43956
43630
|
const lintBatchOrdering = yield* LintBatchOrdering;
|
|
43957
43631
|
const perFileLintCacheEnabled = yield* PerFileLintCacheEnabled;
|
|
43958
|
-
const sidecarLintCacheEnabled = yield* SidecarLintCacheEnabled;
|
|
43959
43632
|
const collectedFailures = [];
|
|
43960
43633
|
const diagnostics = yield* tryPromise({
|
|
43961
43634
|
try: (signal) => runOxlint({
|
|
@@ -43974,9 +43647,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
43974
43647
|
},
|
|
43975
43648
|
onFileProgress: input.onFileProgress,
|
|
43976
43649
|
perFileLintCacheEnabled,
|
|
43977
|
-
sidecarLintCacheEnabled,
|
|
43978
43650
|
onCacheStats: input.onCacheStats,
|
|
43979
|
-
onSidecarStats: input.onSidecarStats,
|
|
43980
43651
|
spawnTimeoutMs,
|
|
43981
43652
|
outputMaxBytes,
|
|
43982
43653
|
concurrency,
|
|
@@ -44786,8 +44457,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44786
44457
|
let lastReportedTotalFileCount = 0;
|
|
44787
44458
|
let lintCacheHitFileCount = null;
|
|
44788
44459
|
let lintCacheTotalFileCount = null;
|
|
44789
|
-
let lintSidecarReplayedFileCount = null;
|
|
44790
|
-
let lintSidecarTotalFileCount = null;
|
|
44791
44460
|
let deadCodeCacheHit = null;
|
|
44792
44461
|
let deadCodeSummaryCacheHits = null;
|
|
44793
44462
|
let deadCodeSummaryCacheMisses = null;
|
|
@@ -44810,10 +44479,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44810
44479
|
lintCacheHitFileCount = cacheHitFileCount;
|
|
44811
44480
|
lintCacheTotalFileCount = totalConsideredFileCount;
|
|
44812
44481
|
},
|
|
44813
|
-
onSidecarStats: (sidecarReplayedFileCount, sidecarConsideredFileCount) => {
|
|
44814
|
-
lintSidecarReplayedFileCount = sidecarReplayedFileCount;
|
|
44815
|
-
lintSidecarTotalFileCount = sidecarConsideredFileCount;
|
|
44816
|
-
},
|
|
44817
44482
|
deadlineEpochMs: input.deadlineEpochMs
|
|
44818
44483
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
44819
44484
|
yield* set(lintFailure, {
|
|
@@ -44924,8 +44589,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
44924
44589
|
securityScanFailed,
|
|
44925
44590
|
lintCacheHitFileCount,
|
|
44926
44591
|
lintCacheTotalFileCount,
|
|
44927
|
-
lintSidecarReplayedFileCount,
|
|
44928
|
-
lintSidecarTotalFileCount,
|
|
44929
44592
|
deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
|
|
44930
44593
|
deadCodeSummaryCacheHits: lintFailureState.didFail ? null : deadCodeSummaryCacheHits,
|
|
44931
44594
|
deadCodeSummaryCacheMisses: lintFailureState.didFail ? null : deadCodeSummaryCacheMisses,
|
|
@@ -45801,7 +45464,7 @@ const makeNoopConsole = () => ({
|
|
|
45801
45464
|
});
|
|
45802
45465
|
//#endregion
|
|
45803
45466
|
//#region src/cli/utils/version.ts
|
|
45804
|
-
const VERSION = "0.6.3-dev.
|
|
45467
|
+
const VERSION = "0.6.3-dev.ce49250";
|
|
45805
45468
|
//#endregion
|
|
45806
45469
|
//#region src/cli/utils/json-mode.ts
|
|
45807
45470
|
let context = null;
|
|
@@ -46170,13 +45833,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
46170
45833
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
46171
45834
|
* standard `SENTRY_RELEASE` override.
|
|
46172
45835
|
*/
|
|
46173
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.
|
|
45836
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.ce49250`;
|
|
46174
45837
|
/**
|
|
46175
45838
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
46176
45839
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
46177
45840
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
46178
45841
|
*/
|
|
46179
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.
|
|
45842
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.ce49250") ? "development" : "production");
|
|
46180
45843
|
/**
|
|
46181
45844
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
46182
45845
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -58254,284 +57917,6 @@ const buildRuleBlastRadii = (diagnostics) => buildSortedRuleGroups(diagnostics).
|
|
|
58254
57917
|
})).toSorted((left, right) => right.fileCount - left.fileCount);
|
|
58255
57918
|
const findMigrationScaleBuckets = (diagnostics) => buildRuleBlastRadii(diagnostics).filter((bucket) => bucket.fileCount >= 40);
|
|
58256
57919
|
//#endregion
|
|
58257
|
-
//#region src/cli/utils/scan-result-cache.ts
|
|
58258
|
-
const CACHE_DISABLED_VALUES = new Set(["1", "true"]);
|
|
58259
|
-
const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
58260
|
-
"oxlint",
|
|
58261
|
-
"oxlint/package.json",
|
|
58262
|
-
"oxlint-plugin-react-doctor",
|
|
58263
|
-
"deslop-js/package.json",
|
|
58264
|
-
"eslint-plugin-react-hooks/package.json"
|
|
58265
|
-
];
|
|
58266
|
-
const bundledRequire = createRequire(import.meta.url);
|
|
58267
|
-
const normalizeForStableJson = (value) => {
|
|
58268
|
-
if (value === null) return null;
|
|
58269
|
-
if (value === void 0) return void 0;
|
|
58270
|
-
const valueType = typeof value;
|
|
58271
|
-
if (valueType === "string" || valueType === "number" || valueType === "boolean") return value;
|
|
58272
|
-
if (valueType === "bigint" || valueType === "function" || valueType === "symbol") throw new Error("Unsupported cache key value");
|
|
58273
|
-
if (Array.isArray(value)) return value.map((item) => {
|
|
58274
|
-
const normalized = normalizeForStableJson(item);
|
|
58275
|
-
return normalized === void 0 ? null : normalized;
|
|
58276
|
-
});
|
|
58277
|
-
const prototype = Object.getPrototypeOf(value);
|
|
58278
|
-
if (prototype !== Object.prototype && prototype !== null) throw new Error("Unsupported cache key object");
|
|
58279
|
-
if (!isRecord(value)) throw new Error("Unsupported cache key object");
|
|
58280
|
-
const normalizedRecord = {};
|
|
58281
|
-
for (const key of Object.keys(value).sort()) {
|
|
58282
|
-
const normalized = normalizeForStableJson(value[key]);
|
|
58283
|
-
if (normalized !== void 0) normalizedRecord[key] = normalized;
|
|
58284
|
-
}
|
|
58285
|
-
return normalizedRecord;
|
|
58286
|
-
};
|
|
58287
|
-
const stringifyStableJson = (value) => {
|
|
58288
|
-
try {
|
|
58289
|
-
return JSON.stringify(normalizeForStableJson(value));
|
|
58290
|
-
} catch {
|
|
58291
|
-
return null;
|
|
58292
|
-
}
|
|
58293
|
-
};
|
|
58294
|
-
const hashString = (value) => crypto.createHash("sha1").update(value).digest("hex");
|
|
58295
|
-
const readHeadSha = (projectDirectory) => runGit(projectDirectory, ["rev-parse", "HEAD"]);
|
|
58296
|
-
const parseWorktreeStatusRecords = (statusOutput) => {
|
|
58297
|
-
const entries = [];
|
|
58298
|
-
const tokens = statusOutput.split("\0");
|
|
58299
|
-
for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
58300
|
-
let record = tokens[tokenIndex];
|
|
58301
|
-
if (record.length === 0) continue;
|
|
58302
|
-
if (record.length < 3 || record[2] !== " ") {
|
|
58303
|
-
if (tokenIndex !== 0) return null;
|
|
58304
|
-
record = ` ${record}`;
|
|
58305
|
-
}
|
|
58306
|
-
if (record.length < 4 || record[2] !== " ") return null;
|
|
58307
|
-
const statusCode = record.slice(0, 2);
|
|
58308
|
-
const recordPath = record.slice(3);
|
|
58309
|
-
if (statusCode.includes("R") || statusCode.includes("C")) {
|
|
58310
|
-
tokenIndex += 1;
|
|
58311
|
-
const originPath = tokens[tokenIndex];
|
|
58312
|
-
if (originPath === void 0 || originPath.length === 0) return null;
|
|
58313
|
-
entries.push({
|
|
58314
|
-
statusCode,
|
|
58315
|
-
path: recordPath,
|
|
58316
|
-
originPath
|
|
58317
|
-
});
|
|
58318
|
-
continue;
|
|
58319
|
-
}
|
|
58320
|
-
entries.push({
|
|
58321
|
-
statusCode,
|
|
58322
|
-
path: recordPath
|
|
58323
|
-
});
|
|
58324
|
-
}
|
|
58325
|
-
return entries;
|
|
58326
|
-
};
|
|
58327
|
-
const buildDirtyPathContentFingerprint = (absolutePath, statusCode) => {
|
|
58328
|
-
let stats;
|
|
58329
|
-
try {
|
|
58330
|
-
stats = fs.lstatSync(absolutePath);
|
|
58331
|
-
} catch {
|
|
58332
|
-
return statusCode.includes("D") ? "deleted" : null;
|
|
58333
|
-
}
|
|
58334
|
-
if (stats.isSymbolicLink()) try {
|
|
58335
|
-
return `link:${fs.readlinkSync(absolutePath)}`;
|
|
58336
|
-
} catch {
|
|
58337
|
-
return null;
|
|
58338
|
-
}
|
|
58339
|
-
if (!stats.isFile()) return null;
|
|
58340
|
-
if (stats.size > 10485760) return `stat:${stats.mtimeMs}:${stats.size}`;
|
|
58341
|
-
return hashFileContents(absolutePath);
|
|
58342
|
-
};
|
|
58343
|
-
const buildWorktreeFingerprint = (projectDirectory) => {
|
|
58344
|
-
const statusOutput = runGit(projectDirectory, [
|
|
58345
|
-
"status",
|
|
58346
|
-
"--porcelain=v1",
|
|
58347
|
-
"-z",
|
|
58348
|
-
"--untracked-files=all"
|
|
58349
|
-
]);
|
|
58350
|
-
if (statusOutput === null) return null;
|
|
58351
|
-
if (statusOutput.length === 0) return [];
|
|
58352
|
-
const statusEntries = parseWorktreeStatusRecords(statusOutput);
|
|
58353
|
-
if (statusEntries === null) return null;
|
|
58354
|
-
if (statusEntries.length > 300) return null;
|
|
58355
|
-
const repositoryRoot = runGit(projectDirectory, ["rev-parse", "--show-toplevel"]);
|
|
58356
|
-
if (repositoryRoot === null) return null;
|
|
58357
|
-
const dirtyEntries = [];
|
|
58358
|
-
for (const statusEntry of statusEntries) {
|
|
58359
|
-
const contentFingerprint = buildDirtyPathContentFingerprint(path.join(repositoryRoot, statusEntry.path), statusEntry.statusCode);
|
|
58360
|
-
if (contentFingerprint === null) return null;
|
|
58361
|
-
dirtyEntries.push({
|
|
58362
|
-
...statusEntry,
|
|
58363
|
-
contentFingerprint
|
|
58364
|
-
});
|
|
58365
|
-
}
|
|
58366
|
-
return dirtyEntries.sort((firstEntry, secondEntry) => {
|
|
58367
|
-
const firstSortKey = `${firstEntry.path}${firstEntry.statusCode}`;
|
|
58368
|
-
const secondSortKey = `${secondEntry.path}${secondEntry.statusCode}`;
|
|
58369
|
-
return firstSortKey < secondSortKey ? -1 : firstSortKey > secondSortKey ? 1 : 0;
|
|
58370
|
-
});
|
|
58371
|
-
};
|
|
58372
|
-
const DOTENV_FILE_NAME_PATTERN = /^\.env(\.|$)/;
|
|
58373
|
-
const resolveDotenvFingerprint = (projectDirectory) => {
|
|
58374
|
-
try {
|
|
58375
|
-
return fs.readdirSync(projectDirectory).filter((entryName) => DOTENV_FILE_NAME_PATTERN.test(entryName)).sort().map((entryName) => `${entryName}=${fileFingerprint(path.join(projectDirectory, entryName)) ?? "unreadable"}`);
|
|
58376
|
-
} catch {
|
|
58377
|
-
return [];
|
|
58378
|
-
}
|
|
58379
|
-
};
|
|
58380
|
-
const hasHiddenTrackedFileState = (projectDirectory) => {
|
|
58381
|
-
const output = runGit(projectDirectory, ["ls-files", "-v"]);
|
|
58382
|
-
if (output === null) return true;
|
|
58383
|
-
return output.split("\n").some((line) => line.length > 0 && line[0] !== "H");
|
|
58384
|
-
};
|
|
58385
|
-
const resolveCacheFilePath = (projectDirectory) => {
|
|
58386
|
-
const nodeModulesDirectory = path.join(projectDirectory, "node_modules");
|
|
58387
|
-
if (fs.existsSync(nodeModulesDirectory)) return path.join(nodeModulesDirectory, ".cache", "react-doctor", "scan-cache.json");
|
|
58388
|
-
const projectHash = hashString(projectDirectory).slice(0, 16);
|
|
58389
|
-
return path.join(os.tmpdir(), "react-doctor-cache", `scan-${projectHash}.json`);
|
|
58390
|
-
};
|
|
58391
|
-
const readPersistedCache = (cacheFilePath) => {
|
|
58392
|
-
try {
|
|
58393
|
-
const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
|
|
58394
|
-
if (!isRecord(parsed) || parsed.version !== 3) return {
|
|
58395
|
-
version: 3,
|
|
58396
|
-
entries: []
|
|
58397
|
-
};
|
|
58398
|
-
if (!Array.isArray(parsed.entries)) return {
|
|
58399
|
-
version: 3,
|
|
58400
|
-
entries: []
|
|
58401
|
-
};
|
|
58402
|
-
const entries = [];
|
|
58403
|
-
for (const entry of parsed.entries) {
|
|
58404
|
-
if (!isRecord(entry) || typeof entry.key !== "string" || typeof entry.createdAtMs !== "number") continue;
|
|
58405
|
-
if (!isRecord(entry.payload) || !Array.isArray(entry.payload.diagnostics)) continue;
|
|
58406
|
-
entries.push(entry);
|
|
58407
|
-
}
|
|
58408
|
-
return {
|
|
58409
|
-
version: 3,
|
|
58410
|
-
entries
|
|
58411
|
-
};
|
|
58412
|
-
} catch {
|
|
58413
|
-
return {
|
|
58414
|
-
version: 3,
|
|
58415
|
-
entries: []
|
|
58416
|
-
};
|
|
58417
|
-
}
|
|
58418
|
-
};
|
|
58419
|
-
const writePersistedCache = (cacheFilePath, cache) => {
|
|
58420
|
-
try {
|
|
58421
|
-
fs.mkdirSync(path.dirname(cacheFilePath), { recursive: true });
|
|
58422
|
-
const tempPath = `${cacheFilePath}.${process.pid}.tmp`;
|
|
58423
|
-
fs.writeFileSync(tempPath, JSON.stringify(cache));
|
|
58424
|
-
fs.renameSync(tempPath, cacheFilePath);
|
|
58425
|
-
} catch {
|
|
58426
|
-
return;
|
|
58427
|
-
}
|
|
58428
|
-
};
|
|
58429
|
-
/**
|
|
58430
|
-
* The global cache off-switch (`REACT_DOCTOR_NO_CACHE`), which disables every
|
|
58431
|
-
* cache subsystem: this whole-repo scan cache plus core's per-file lint,
|
|
58432
|
-
* sidecar, and dead-code caches (their `Context.Reference` defaults read the
|
|
58433
|
-
* same variable). Exported for the wide event's `cache.temperature`
|
|
58434
|
-
* derivation, which reports `"disabled"` instead of `"cold"` when the switch
|
|
58435
|
-
* is on. Granular knobs (`REACT_DOCTOR_NO_FILE_CACHE`, …) are deliberately
|
|
58436
|
-
* not consulted — they leave the other subsystems live.
|
|
58437
|
-
*/
|
|
58438
|
-
const isCacheGloballyDisabled = () => CACHE_DISABLED_VALUES.has(process.env.REACT_DOCTOR_NO_CACHE?.toLowerCase() ?? "");
|
|
58439
|
-
const resolveProjectIdentity = (projectDirectory) => {
|
|
58440
|
-
try {
|
|
58441
|
-
return fs.realpathSync.native(projectDirectory);
|
|
58442
|
-
} catch {
|
|
58443
|
-
return path.resolve(projectDirectory);
|
|
58444
|
-
}
|
|
58445
|
-
};
|
|
58446
|
-
const fileFingerprint = (filePath) => {
|
|
58447
|
-
try {
|
|
58448
|
-
const stat = fs.statSync(filePath);
|
|
58449
|
-
return `${filePath}:${stat.mtimeMs}:${stat.size}`;
|
|
58450
|
-
} catch {
|
|
58451
|
-
return null;
|
|
58452
|
-
}
|
|
58453
|
-
};
|
|
58454
|
-
const resolveToolchainFingerprint = (nodeBinaryPath) => {
|
|
58455
|
-
const fingerprints = [];
|
|
58456
|
-
if (nodeBinaryPath !== null) {
|
|
58457
|
-
const fingerprint = fileFingerprint(nodeBinaryPath);
|
|
58458
|
-
if (fingerprint !== null) fingerprints.push(`node=${fingerprint}`);
|
|
58459
|
-
}
|
|
58460
|
-
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
|
|
58461
|
-
const fingerprint = fileFingerprint(bundledRequire.resolve(specifier));
|
|
58462
|
-
if (fingerprint !== null) fingerprints.push(`${specifier}=${fingerprint}`);
|
|
58463
|
-
} catch {
|
|
58464
|
-
continue;
|
|
58465
|
-
}
|
|
58466
|
-
return fingerprints;
|
|
58467
|
-
};
|
|
58468
|
-
const buildScanResultCacheKey = (input) => {
|
|
58469
|
-
if (isCacheGloballyDisabled()) return null;
|
|
58470
|
-
if (hasHiddenTrackedFileState(input.projectDirectory)) return null;
|
|
58471
|
-
const worktreeFingerprint = buildWorktreeFingerprint(input.projectDirectory);
|
|
58472
|
-
if (worktreeFingerprint === null) return null;
|
|
58473
|
-
const headSha = readHeadSha(input.projectDirectory);
|
|
58474
|
-
if (headSha === null) return null;
|
|
58475
|
-
if (stringifyStableJson(input.userConfig) === null) return null;
|
|
58476
|
-
const cacheKeyJson = stringifyStableJson({
|
|
58477
|
-
schemaVersion: 3,
|
|
58478
|
-
projectIdentity: resolveProjectIdentity(input.projectDirectory),
|
|
58479
|
-
headSha,
|
|
58480
|
-
worktreeFingerprint,
|
|
58481
|
-
dotenvFingerprint: resolveDotenvFingerprint(input.projectDirectory),
|
|
58482
|
-
reactDoctorVersion: input.version,
|
|
58483
|
-
nodeVersion: process.version,
|
|
58484
|
-
toolchainFingerprint: resolveToolchainFingerprint(input.nodeBinaryPath),
|
|
58485
|
-
configFingerprint: computeConfigFingerprint(input.projectDirectory, input.version),
|
|
58486
|
-
hasConfigOverride: input.hasConfigOverride,
|
|
58487
|
-
configSourceDirectory: input.configSourceDirectory,
|
|
58488
|
-
userConfig: input.userConfig,
|
|
58489
|
-
engineOptions: {
|
|
58490
|
-
lint: input.options.lint,
|
|
58491
|
-
deadCode: input.options.deadCode,
|
|
58492
|
-
includePaths: [...input.options.includePaths].sort(),
|
|
58493
|
-
customRulesOnly: input.options.customRulesOnly,
|
|
58494
|
-
respectInlineDisables: input.options.respectInlineDisables,
|
|
58495
|
-
warnings: input.options.warnings,
|
|
58496
|
-
adoptExistingLintConfig: input.options.adoptExistingLintConfig,
|
|
58497
|
-
ignoredTags: [...input.options.ignoredTags].sort(),
|
|
58498
|
-
concurrency: input.options.concurrency,
|
|
58499
|
-
lintBatchOrdering: resolveLintBatchOrdering(),
|
|
58500
|
-
baselineRef: input.options.baseline?.ref,
|
|
58501
|
-
changedLineRanges: input.options.changedLineRanges ?? void 0,
|
|
58502
|
-
noScore: input.options.noScore,
|
|
58503
|
-
isCi: input.options.isCi,
|
|
58504
|
-
suppressRendering: input.options.suppressRendering,
|
|
58505
|
-
supplyChainManifestChanged: input.options.supplyChainManifestChanged
|
|
58506
|
-
}
|
|
58507
|
-
});
|
|
58508
|
-
return cacheKeyJson === null ? null : hashString(cacheKeyJson);
|
|
58509
|
-
};
|
|
58510
|
-
const createScanResultCache = (projectDirectory) => {
|
|
58511
|
-
const cacheFilePath = resolveCacheFilePath(projectDirectory);
|
|
58512
|
-
const persistedCache = readPersistedCache(cacheFilePath);
|
|
58513
|
-
const entries = /* @__PURE__ */ new Map();
|
|
58514
|
-
for (const entry of persistedCache.entries) entries.set(entry.key, entry);
|
|
58515
|
-
const persist = () => {
|
|
58516
|
-
writePersistedCache(cacheFilePath, {
|
|
58517
|
-
version: 3,
|
|
58518
|
-
entries: [...entries.values()].sort((firstEntry, secondEntry) => secondEntry.createdAtMs - firstEntry.createdAtMs).slice(0, 20)
|
|
58519
|
-
});
|
|
58520
|
-
};
|
|
58521
|
-
return {
|
|
58522
|
-
lookup: (key) => entries.get(key)?.payload ?? null,
|
|
58523
|
-
store: (key, payload) => {
|
|
58524
|
-
entries.set(key, {
|
|
58525
|
-
key,
|
|
58526
|
-
createdAtMs: Date.now(),
|
|
58527
|
-
payload
|
|
58528
|
-
});
|
|
58529
|
-
persist();
|
|
58530
|
-
}
|
|
58531
|
-
};
|
|
58532
|
-
};
|
|
58533
|
-
const shouldStoreScanPayload = (payload) => !payload.didLintFail && !payload.didDeadCodeFail && payload.lintPartialFailures.length === 0 && !payload.supplyChainOverlapTimedOut && payload.securityScanFailed !== true;
|
|
58534
|
-
//#endregion
|
|
58535
57920
|
//#region src/cli/utils/should-block-ci.ts
|
|
58536
57921
|
const shouldBlockCi = (diagnostics, blockingLevel) => {
|
|
58537
57922
|
if (blockingLevel === "none") return false;
|
|
@@ -58573,63 +57958,6 @@ const readEnvBoolean = (name) => {
|
|
|
58573
57958
|
if (value === void 0) return null;
|
|
58574
57959
|
return value.toLowerCase() === "true" || value === "1";
|
|
58575
57960
|
};
|
|
58576
|
-
const ratioOf = (numerator, denominator) => denominator != null && denominator > 0 ? (numerator ?? 0) / denominator : null;
|
|
58577
|
-
const resolveDeadCodeReuseRatio = (result) => {
|
|
58578
|
-
if (result.deadCodeCacheHit === true) return 1;
|
|
58579
|
-
const summaryTotal = (result.deadCodeSummaryCacheHits ?? 0) + (result.deadCodeSummaryCacheMisses ?? 0);
|
|
58580
|
-
if (summaryTotal > 0) return (result.deadCodeSummaryCacheHits ?? 0) / summaryTotal;
|
|
58581
|
-
return result.deadCodeCacheHit === false ? 0 : null;
|
|
58582
|
-
};
|
|
58583
|
-
/**
|
|
58584
|
-
* One queryable cache temperature per scan, derived from the whole stack:
|
|
58585
|
-
*
|
|
58586
|
-
* - `"turbo"` — whole-repo scan-result replay (the explicit
|
|
58587
|
-
* `wholeRepoCacheHit` flag from the CLI's cachedPayload
|
|
58588
|
-
* branch; no scan work ran).
|
|
58589
|
-
* - `"warm"` — any incremental reuse: per-file lint hits, sidecar
|
|
58590
|
-
* replays, a dead-code whole-result hit, or dead-code
|
|
58591
|
-
* summary-cache hits.
|
|
58592
|
-
* - `"disabled"` — zero reuse because the global `REACT_DOCTOR_NO_CACHE`
|
|
58593
|
-
* off-switch is on. Granular per-cache opt-outs
|
|
58594
|
-
* (`REACT_DOCTOR_NO_FILE_CACHE`, …) still read warm/cold,
|
|
58595
|
-
* since the other subsystems stay live.
|
|
58596
|
-
* - `"cold"` — caches on, zero reuse (first scan / everything changed).
|
|
58597
|
-
*
|
|
58598
|
-
* `cache.warmth` is the headline reuse magnitude in [0, 1]: the plain mean of
|
|
58599
|
-
* the subsystem reuse fractions known this run (lint hit ratio, sidecar
|
|
58600
|
-
* replay ratio, dead-code reuse), skipping subsystems that never consulted a
|
|
58601
|
-
* cache; `1` on turbo, dropped when nothing consulted any cache. Deliberately
|
|
58602
|
-
* unweighted — the per-subsystem dims stay the precise signal; warmth is the
|
|
58603
|
-
* p50/p90-able summary. Emitted only on the success path.
|
|
58604
|
-
*/
|
|
58605
|
-
const buildCacheAttributes = (input) => {
|
|
58606
|
-
if (input.result === void 0) return {};
|
|
58607
|
-
if (input.wholeRepoCacheHit) return withNamespace("cache", {
|
|
58608
|
-
wholeRepoHit: true,
|
|
58609
|
-
temperature: "turbo",
|
|
58610
|
-
warmth: 1
|
|
58611
|
-
});
|
|
58612
|
-
const result = input.result;
|
|
58613
|
-
const subsystemReuseRatios = [
|
|
58614
|
-
ratioOf(result.lintCacheHitFileCount, result.lintCacheTotalFileCount),
|
|
58615
|
-
ratioOf(result.lintSidecarReplayedFileCount, result.lintSidecarTotalFileCount),
|
|
58616
|
-
resolveDeadCodeReuseRatio(result)
|
|
58617
|
-
];
|
|
58618
|
-
let knownSubsystemCount = 0;
|
|
58619
|
-
let reuseRatioSum = 0;
|
|
58620
|
-
for (const reuseRatio of subsystemReuseRatios) {
|
|
58621
|
-
if (reuseRatio === null) continue;
|
|
58622
|
-
knownSubsystemCount += 1;
|
|
58623
|
-
reuseRatioSum += reuseRatio;
|
|
58624
|
-
}
|
|
58625
|
-
const warmth = knownSubsystemCount > 0 ? reuseRatioSum / knownSubsystemCount : null;
|
|
58626
|
-
const temperature = warmth !== null && warmth > 0 ? "warm" : isCacheGloballyDisabled() ? "disabled" : "cold";
|
|
58627
|
-
return withNamespace("cache", {
|
|
58628
|
-
wholeRepoHit: input.wholeRepoCacheHit ?? null,
|
|
58629
|
-
temperature,
|
|
58630
|
-
warmth
|
|
58631
|
-
});
|
|
58632
|
-
};
|
|
58633
57961
|
const resolveVersionPin = (versionInput) => {
|
|
58634
57962
|
if (versionInput === void 0 || versionInput.trim() === "") return null;
|
|
58635
57963
|
if (versionInput === "latest") return "latest";
|
|
@@ -58735,10 +58063,7 @@ const buildOutcomeAttributes = (input) => {
|
|
|
58735
58063
|
deadlineSkippedFileCount: input.lintDeadlineSkippedFileCount ?? null,
|
|
58736
58064
|
cacheHitFiles: result.lintCacheHitFileCount ?? null,
|
|
58737
58065
|
cacheTotalFiles: result.lintCacheTotalFileCount ?? null,
|
|
58738
|
-
cacheHitRatio:
|
|
58739
|
-
sidecarReplayedFiles: result.lintSidecarReplayedFileCount ?? null,
|
|
58740
|
-
sidecarTotalFiles: result.lintSidecarTotalFileCount ?? null,
|
|
58741
|
-
sidecarReplayRatio: ratioOf(result.lintSidecarReplayedFileCount, result.lintSidecarTotalFileCount)
|
|
58066
|
+
cacheHitRatio: result.lintCacheTotalFileCount != null && result.lintCacheTotalFileCount > 0 ? (result.lintCacheHitFileCount ?? 0) / result.lintCacheTotalFileCount : null
|
|
58742
58067
|
}),
|
|
58743
58068
|
...withNamespace("deadCode", {
|
|
58744
58069
|
failed: input.didDeadCodeFail ?? null,
|
|
@@ -58805,7 +58130,7 @@ const buildScanAttributes = (input) => {
|
|
|
58805
58130
|
* Projects a scan into the namespaced attribute set for its root span — the
|
|
58806
58131
|
* canonical per-scan "wide event". Every attribute carries a dotted namespace
|
|
58807
58132
|
* that groups it by concept (`scan.*` config, `action.*` CI knobs, `outcome.*`
|
|
58808
|
-
* verdict, `diag.*` findings, `score.*`, `lint.*`, `deadCode.*`,
|
|
58133
|
+
* verdict, `diag.*` findings, `score.*`, `lint.*`, `deadCode.*`,
|
|
58809
58134
|
* `supplyChain.*`, `timing.*`, `migration.*`, `baseline.*`) so the attributes
|
|
58810
58135
|
* tree up in Sentry's attribute browser and stay filter-/group-/aggregate-able
|
|
58811
58136
|
* in the Spans dataset. Pure and exported so the projection (outcome
|
|
@@ -58819,8 +58144,7 @@ const buildScanAttributes = (input) => {
|
|
|
58819
58144
|
const buildRunEventAttributes = (input) => toSpanAttributes({
|
|
58820
58145
|
...buildScanAttributes(input),
|
|
58821
58146
|
...buildActionAttributes(),
|
|
58822
|
-
...buildOutcomeAttributes(input)
|
|
58823
|
-
...buildCacheAttributes(input)
|
|
58147
|
+
...buildOutcomeAttributes(input)
|
|
58824
58148
|
});
|
|
58825
58149
|
/**
|
|
58826
58150
|
* Stamps the wide-event attributes onto the run's root span. A guarded no-op
|
|
@@ -60030,6 +59354,275 @@ const resolveCliCategories = (categoryFlag) => {
|
|
|
60030
59354
|
return resolvedCategories.length > 0 ? resolvedCategories : void 0;
|
|
60031
59355
|
};
|
|
60032
59356
|
//#endregion
|
|
59357
|
+
//#region src/cli/utils/scan-result-cache.ts
|
|
59358
|
+
const CACHE_DISABLED_VALUES = new Set(["1", "true"]);
|
|
59359
|
+
const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
59360
|
+
"oxlint",
|
|
59361
|
+
"oxlint/package.json",
|
|
59362
|
+
"oxlint-plugin-react-doctor",
|
|
59363
|
+
"deslop-js/package.json",
|
|
59364
|
+
"eslint-plugin-react-hooks/package.json"
|
|
59365
|
+
];
|
|
59366
|
+
const bundledRequire = createRequire(import.meta.url);
|
|
59367
|
+
const normalizeForStableJson = (value) => {
|
|
59368
|
+
if (value === null) return null;
|
|
59369
|
+
if (value === void 0) return void 0;
|
|
59370
|
+
const valueType = typeof value;
|
|
59371
|
+
if (valueType === "string" || valueType === "number" || valueType === "boolean") return value;
|
|
59372
|
+
if (valueType === "bigint" || valueType === "function" || valueType === "symbol") throw new Error("Unsupported cache key value");
|
|
59373
|
+
if (Array.isArray(value)) return value.map((item) => {
|
|
59374
|
+
const normalized = normalizeForStableJson(item);
|
|
59375
|
+
return normalized === void 0 ? null : normalized;
|
|
59376
|
+
});
|
|
59377
|
+
const prototype = Object.getPrototypeOf(value);
|
|
59378
|
+
if (prototype !== Object.prototype && prototype !== null) throw new Error("Unsupported cache key object");
|
|
59379
|
+
if (!isRecord(value)) throw new Error("Unsupported cache key object");
|
|
59380
|
+
const normalizedRecord = {};
|
|
59381
|
+
for (const key of Object.keys(value).sort()) {
|
|
59382
|
+
const normalized = normalizeForStableJson(value[key]);
|
|
59383
|
+
if (normalized !== void 0) normalizedRecord[key] = normalized;
|
|
59384
|
+
}
|
|
59385
|
+
return normalizedRecord;
|
|
59386
|
+
};
|
|
59387
|
+
const stringifyStableJson = (value) => {
|
|
59388
|
+
try {
|
|
59389
|
+
return JSON.stringify(normalizeForStableJson(value));
|
|
59390
|
+
} catch {
|
|
59391
|
+
return null;
|
|
59392
|
+
}
|
|
59393
|
+
};
|
|
59394
|
+
const hashString = (value) => crypto.createHash("sha1").update(value).digest("hex");
|
|
59395
|
+
const readHeadSha = (projectDirectory) => runGit(projectDirectory, ["rev-parse", "HEAD"]);
|
|
59396
|
+
const parseWorktreeStatusRecords = (statusOutput) => {
|
|
59397
|
+
const entries = [];
|
|
59398
|
+
const tokens = statusOutput.split("\0");
|
|
59399
|
+
for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex += 1) {
|
|
59400
|
+
let record = tokens[tokenIndex];
|
|
59401
|
+
if (record.length === 0) continue;
|
|
59402
|
+
if (record.length < 3 || record[2] !== " ") {
|
|
59403
|
+
if (tokenIndex !== 0) return null;
|
|
59404
|
+
record = ` ${record}`;
|
|
59405
|
+
}
|
|
59406
|
+
if (record.length < 4 || record[2] !== " ") return null;
|
|
59407
|
+
const statusCode = record.slice(0, 2);
|
|
59408
|
+
const recordPath = record.slice(3);
|
|
59409
|
+
if (statusCode.includes("R") || statusCode.includes("C")) {
|
|
59410
|
+
tokenIndex += 1;
|
|
59411
|
+
const originPath = tokens[tokenIndex];
|
|
59412
|
+
if (originPath === void 0 || originPath.length === 0) return null;
|
|
59413
|
+
entries.push({
|
|
59414
|
+
statusCode,
|
|
59415
|
+
path: recordPath,
|
|
59416
|
+
originPath
|
|
59417
|
+
});
|
|
59418
|
+
continue;
|
|
59419
|
+
}
|
|
59420
|
+
entries.push({
|
|
59421
|
+
statusCode,
|
|
59422
|
+
path: recordPath
|
|
59423
|
+
});
|
|
59424
|
+
}
|
|
59425
|
+
return entries;
|
|
59426
|
+
};
|
|
59427
|
+
const buildDirtyPathContentFingerprint = (absolutePath, statusCode) => {
|
|
59428
|
+
let stats;
|
|
59429
|
+
try {
|
|
59430
|
+
stats = fs.lstatSync(absolutePath);
|
|
59431
|
+
} catch {
|
|
59432
|
+
return statusCode.includes("D") ? "deleted" : null;
|
|
59433
|
+
}
|
|
59434
|
+
if (stats.isSymbolicLink()) try {
|
|
59435
|
+
return `link:${fs.readlinkSync(absolutePath)}`;
|
|
59436
|
+
} catch {
|
|
59437
|
+
return null;
|
|
59438
|
+
}
|
|
59439
|
+
if (!stats.isFile()) return null;
|
|
59440
|
+
if (stats.size > 10485760) return `stat:${stats.mtimeMs}:${stats.size}`;
|
|
59441
|
+
return hashFileContents(absolutePath);
|
|
59442
|
+
};
|
|
59443
|
+
const buildWorktreeFingerprint = (projectDirectory) => {
|
|
59444
|
+
const statusOutput = runGit(projectDirectory, [
|
|
59445
|
+
"status",
|
|
59446
|
+
"--porcelain=v1",
|
|
59447
|
+
"-z",
|
|
59448
|
+
"--untracked-files=all"
|
|
59449
|
+
]);
|
|
59450
|
+
if (statusOutput === null) return null;
|
|
59451
|
+
if (statusOutput.length === 0) return [];
|
|
59452
|
+
const statusEntries = parseWorktreeStatusRecords(statusOutput);
|
|
59453
|
+
if (statusEntries === null) return null;
|
|
59454
|
+
if (statusEntries.length > 300) return null;
|
|
59455
|
+
const repositoryRoot = runGit(projectDirectory, ["rev-parse", "--show-toplevel"]);
|
|
59456
|
+
if (repositoryRoot === null) return null;
|
|
59457
|
+
const dirtyEntries = [];
|
|
59458
|
+
for (const statusEntry of statusEntries) {
|
|
59459
|
+
const contentFingerprint = buildDirtyPathContentFingerprint(path.join(repositoryRoot, statusEntry.path), statusEntry.statusCode);
|
|
59460
|
+
if (contentFingerprint === null) return null;
|
|
59461
|
+
dirtyEntries.push({
|
|
59462
|
+
...statusEntry,
|
|
59463
|
+
contentFingerprint
|
|
59464
|
+
});
|
|
59465
|
+
}
|
|
59466
|
+
return dirtyEntries.sort((firstEntry, secondEntry) => {
|
|
59467
|
+
const firstSortKey = `${firstEntry.path}${firstEntry.statusCode}`;
|
|
59468
|
+
const secondSortKey = `${secondEntry.path}${secondEntry.statusCode}`;
|
|
59469
|
+
return firstSortKey < secondSortKey ? -1 : firstSortKey > secondSortKey ? 1 : 0;
|
|
59470
|
+
});
|
|
59471
|
+
};
|
|
59472
|
+
const DOTENV_FILE_NAME_PATTERN = /^\.env(\.|$)/;
|
|
59473
|
+
const resolveDotenvFingerprint = (projectDirectory) => {
|
|
59474
|
+
try {
|
|
59475
|
+
return fs.readdirSync(projectDirectory).filter((entryName) => DOTENV_FILE_NAME_PATTERN.test(entryName)).sort().map((entryName) => `${entryName}=${fileFingerprint(path.join(projectDirectory, entryName)) ?? "unreadable"}`);
|
|
59476
|
+
} catch {
|
|
59477
|
+
return [];
|
|
59478
|
+
}
|
|
59479
|
+
};
|
|
59480
|
+
const hasHiddenTrackedFileState = (projectDirectory) => {
|
|
59481
|
+
const output = runGit(projectDirectory, ["ls-files", "-v"]);
|
|
59482
|
+
if (output === null) return true;
|
|
59483
|
+
return output.split("\n").some((line) => line.length > 0 && line[0] !== "H");
|
|
59484
|
+
};
|
|
59485
|
+
const resolveCacheFilePath = (projectDirectory) => {
|
|
59486
|
+
const nodeModulesDirectory = path.join(projectDirectory, "node_modules");
|
|
59487
|
+
if (fs.existsSync(nodeModulesDirectory)) return path.join(nodeModulesDirectory, ".cache", "react-doctor", "scan-cache.json");
|
|
59488
|
+
const projectHash = hashString(projectDirectory).slice(0, 16);
|
|
59489
|
+
return path.join(os.tmpdir(), "react-doctor-cache", `scan-${projectHash}.json`);
|
|
59490
|
+
};
|
|
59491
|
+
const readPersistedCache = (cacheFilePath) => {
|
|
59492
|
+
try {
|
|
59493
|
+
const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
|
|
59494
|
+
if (!isRecord(parsed) || parsed.version !== 3) return {
|
|
59495
|
+
version: 3,
|
|
59496
|
+
entries: []
|
|
59497
|
+
};
|
|
59498
|
+
if (!Array.isArray(parsed.entries)) return {
|
|
59499
|
+
version: 3,
|
|
59500
|
+
entries: []
|
|
59501
|
+
};
|
|
59502
|
+
const entries = [];
|
|
59503
|
+
for (const entry of parsed.entries) {
|
|
59504
|
+
if (!isRecord(entry) || typeof entry.key !== "string" || typeof entry.createdAtMs !== "number") continue;
|
|
59505
|
+
if (!isRecord(entry.payload) || !Array.isArray(entry.payload.diagnostics)) continue;
|
|
59506
|
+
entries.push(entry);
|
|
59507
|
+
}
|
|
59508
|
+
return {
|
|
59509
|
+
version: 3,
|
|
59510
|
+
entries
|
|
59511
|
+
};
|
|
59512
|
+
} catch {
|
|
59513
|
+
return {
|
|
59514
|
+
version: 3,
|
|
59515
|
+
entries: []
|
|
59516
|
+
};
|
|
59517
|
+
}
|
|
59518
|
+
};
|
|
59519
|
+
const writePersistedCache = (cacheFilePath, cache) => {
|
|
59520
|
+
try {
|
|
59521
|
+
fs.mkdirSync(path.dirname(cacheFilePath), { recursive: true });
|
|
59522
|
+
const tempPath = `${cacheFilePath}.${process.pid}.tmp`;
|
|
59523
|
+
fs.writeFileSync(tempPath, JSON.stringify(cache));
|
|
59524
|
+
fs.renameSync(tempPath, cacheFilePath);
|
|
59525
|
+
} catch {
|
|
59526
|
+
return;
|
|
59527
|
+
}
|
|
59528
|
+
};
|
|
59529
|
+
const isScanResultCacheDisabled = () => CACHE_DISABLED_VALUES.has(process.env.REACT_DOCTOR_NO_CACHE?.toLowerCase() ?? "");
|
|
59530
|
+
const resolveProjectIdentity = (projectDirectory) => {
|
|
59531
|
+
try {
|
|
59532
|
+
return fs.realpathSync.native(projectDirectory);
|
|
59533
|
+
} catch {
|
|
59534
|
+
return path.resolve(projectDirectory);
|
|
59535
|
+
}
|
|
59536
|
+
};
|
|
59537
|
+
const fileFingerprint = (filePath) => {
|
|
59538
|
+
try {
|
|
59539
|
+
const stat = fs.statSync(filePath);
|
|
59540
|
+
return `${filePath}:${stat.mtimeMs}:${stat.size}`;
|
|
59541
|
+
} catch {
|
|
59542
|
+
return null;
|
|
59543
|
+
}
|
|
59544
|
+
};
|
|
59545
|
+
const resolveToolchainFingerprint = (nodeBinaryPath) => {
|
|
59546
|
+
const fingerprints = [];
|
|
59547
|
+
if (nodeBinaryPath !== null) {
|
|
59548
|
+
const fingerprint = fileFingerprint(nodeBinaryPath);
|
|
59549
|
+
if (fingerprint !== null) fingerprints.push(`node=${fingerprint}`);
|
|
59550
|
+
}
|
|
59551
|
+
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
|
|
59552
|
+
const fingerprint = fileFingerprint(bundledRequire.resolve(specifier));
|
|
59553
|
+
if (fingerprint !== null) fingerprints.push(`${specifier}=${fingerprint}`);
|
|
59554
|
+
} catch {
|
|
59555
|
+
continue;
|
|
59556
|
+
}
|
|
59557
|
+
return fingerprints;
|
|
59558
|
+
};
|
|
59559
|
+
const buildScanResultCacheKey = (input) => {
|
|
59560
|
+
if (isScanResultCacheDisabled()) return null;
|
|
59561
|
+
if (hasHiddenTrackedFileState(input.projectDirectory)) return null;
|
|
59562
|
+
const worktreeFingerprint = buildWorktreeFingerprint(input.projectDirectory);
|
|
59563
|
+
if (worktreeFingerprint === null) return null;
|
|
59564
|
+
const headSha = readHeadSha(input.projectDirectory);
|
|
59565
|
+
if (headSha === null) return null;
|
|
59566
|
+
if (stringifyStableJson(input.userConfig) === null) return null;
|
|
59567
|
+
const cacheKeyJson = stringifyStableJson({
|
|
59568
|
+
schemaVersion: 3,
|
|
59569
|
+
projectIdentity: resolveProjectIdentity(input.projectDirectory),
|
|
59570
|
+
headSha,
|
|
59571
|
+
worktreeFingerprint,
|
|
59572
|
+
dotenvFingerprint: resolveDotenvFingerprint(input.projectDirectory),
|
|
59573
|
+
reactDoctorVersion: input.version,
|
|
59574
|
+
nodeVersion: process.version,
|
|
59575
|
+
toolchainFingerprint: resolveToolchainFingerprint(input.nodeBinaryPath),
|
|
59576
|
+
configFingerprint: computeConfigFingerprint(input.projectDirectory, input.version),
|
|
59577
|
+
hasConfigOverride: input.hasConfigOverride,
|
|
59578
|
+
configSourceDirectory: input.configSourceDirectory,
|
|
59579
|
+
userConfig: input.userConfig,
|
|
59580
|
+
engineOptions: {
|
|
59581
|
+
lint: input.options.lint,
|
|
59582
|
+
deadCode: input.options.deadCode,
|
|
59583
|
+
includePaths: [...input.options.includePaths].sort(),
|
|
59584
|
+
customRulesOnly: input.options.customRulesOnly,
|
|
59585
|
+
respectInlineDisables: input.options.respectInlineDisables,
|
|
59586
|
+
warnings: input.options.warnings,
|
|
59587
|
+
adoptExistingLintConfig: input.options.adoptExistingLintConfig,
|
|
59588
|
+
ignoredTags: [...input.options.ignoredTags].sort(),
|
|
59589
|
+
concurrency: input.options.concurrency,
|
|
59590
|
+
lintBatchOrdering: resolveLintBatchOrdering(),
|
|
59591
|
+
baselineRef: input.options.baseline?.ref,
|
|
59592
|
+
changedLineRanges: input.options.changedLineRanges ?? void 0,
|
|
59593
|
+
noScore: input.options.noScore,
|
|
59594
|
+
isCi: input.options.isCi,
|
|
59595
|
+
suppressRendering: input.options.suppressRendering,
|
|
59596
|
+
supplyChainManifestChanged: input.options.supplyChainManifestChanged
|
|
59597
|
+
}
|
|
59598
|
+
});
|
|
59599
|
+
return cacheKeyJson === null ? null : hashString(cacheKeyJson);
|
|
59600
|
+
};
|
|
59601
|
+
const createScanResultCache = (projectDirectory) => {
|
|
59602
|
+
const cacheFilePath = resolveCacheFilePath(projectDirectory);
|
|
59603
|
+
const persistedCache = readPersistedCache(cacheFilePath);
|
|
59604
|
+
const entries = /* @__PURE__ */ new Map();
|
|
59605
|
+
for (const entry of persistedCache.entries) entries.set(entry.key, entry);
|
|
59606
|
+
const persist = () => {
|
|
59607
|
+
writePersistedCache(cacheFilePath, {
|
|
59608
|
+
version: 3,
|
|
59609
|
+
entries: [...entries.values()].sort((firstEntry, secondEntry) => secondEntry.createdAtMs - firstEntry.createdAtMs).slice(0, 20)
|
|
59610
|
+
});
|
|
59611
|
+
};
|
|
59612
|
+
return {
|
|
59613
|
+
lookup: (key) => entries.get(key)?.payload ?? null,
|
|
59614
|
+
store: (key, payload) => {
|
|
59615
|
+
entries.set(key, {
|
|
59616
|
+
key,
|
|
59617
|
+
createdAtMs: Date.now(),
|
|
59618
|
+
payload
|
|
59619
|
+
});
|
|
59620
|
+
persist();
|
|
59621
|
+
}
|
|
59622
|
+
};
|
|
59623
|
+
};
|
|
59624
|
+
const shouldStoreScanPayload = (payload) => !payload.didLintFail && !payload.didDeadCodeFail && payload.lintPartialFailures.length === 0 && !payload.supplyChainOverlapTimedOut && payload.securityScanFailed !== true;
|
|
59625
|
+
//#endregion
|
|
60033
59626
|
//#region src/inspect.ts
|
|
60034
59627
|
const silentConsole = makeNoopConsole();
|
|
60035
59628
|
const runConsole = (effect) => {
|
|
@@ -60259,8 +59852,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
60259
59852
|
startTime,
|
|
60260
59853
|
rootSentrySpan,
|
|
60261
59854
|
scanMode: cachedPayload.baselineDelta ? "baseline" : isDiffMode ? "diff" : "full",
|
|
60262
|
-
baselineDegraded
|
|
60263
|
-
wholeRepoCacheHit: true
|
|
59855
|
+
baselineDegraded
|
|
60264
59856
|
});
|
|
60265
59857
|
recordOnboardingCompletion(options);
|
|
60266
59858
|
return result;
|
|
@@ -60369,11 +59961,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
60369
59961
|
rootSentrySpan,
|
|
60370
59962
|
scanMode: baselineDelta ? "baseline" : isDiffMode ? "diff" : "full",
|
|
60371
59963
|
baselineDegraded,
|
|
60372
|
-
wholeRepoCacheHit: false,
|
|
60373
59964
|
lintCacheHitFileCount: output.lintCacheHitFileCount,
|
|
60374
59965
|
lintCacheTotalFileCount: output.lintCacheTotalFileCount,
|
|
60375
|
-
lintSidecarReplayedFileCount: output.lintSidecarReplayedFileCount,
|
|
60376
|
-
lintSidecarTotalFileCount: output.lintSidecarTotalFileCount,
|
|
60377
59966
|
deadCodeCacheHit: output.deadCodeCacheHit,
|
|
60378
59967
|
deadCodeSummaryCacheHits: output.deadCodeSummaryCacheHits,
|
|
60379
59968
|
deadCodeSummaryCacheMisses: output.deadCodeSummaryCacheMisses
|
|
@@ -60411,8 +60000,6 @@ const renderAndRecordScan = async (input) => {
|
|
|
60411
60000
|
scanElapsedMilliseconds: input.payload.scanElapsedMilliseconds,
|
|
60412
60001
|
lintCacheHitFileCount: input.lintCacheHitFileCount ?? null,
|
|
60413
60002
|
lintCacheTotalFileCount: input.lintCacheTotalFileCount ?? null,
|
|
60414
|
-
lintSidecarReplayedFileCount: input.lintSidecarReplayedFileCount ?? null,
|
|
60415
|
-
lintSidecarTotalFileCount: input.lintSidecarTotalFileCount ?? null,
|
|
60416
60003
|
deadCodeCacheHit: input.deadCodeCacheHit ?? null,
|
|
60417
60004
|
deadCodeSummaryCacheHits: input.deadCodeSummaryCacheHits ?? null,
|
|
60418
60005
|
deadCodeSummaryCacheMisses: input.deadCodeSummaryCacheMisses ?? null,
|
|
@@ -60440,7 +60027,6 @@ const renderAndRecordScan = async (input) => {
|
|
|
60440
60027
|
result,
|
|
60441
60028
|
mode: input.scanMode,
|
|
60442
60029
|
gateExempt: input.baselineDegraded,
|
|
60443
|
-
wholeRepoCacheHit: input.wholeRepoCacheHit,
|
|
60444
60030
|
didLintFail: input.payload.didLintFail,
|
|
60445
60031
|
lintFailureReasonKind: input.payload.lintFailureReasonKind,
|
|
60446
60032
|
lintPartialFailureCount: input.payload.lintPartialFailures.length,
|
|
@@ -60455,7 +60041,7 @@ const renderAndRecordScan = async (input) => {
|
|
|
60455
60041
|
return result;
|
|
60456
60042
|
};
|
|
60457
60043
|
const finalizeAndRender = (input) => gen(function* () {
|
|
60458
|
-
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount,
|
|
60044
|
+
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, deadCodeCacheHit, deadCodeSummaryCacheHits, deadCodeSummaryCacheMisses, baselineDelta } = input;
|
|
60459
60045
|
const { skippedChecks, skippedCheckReasons } = buildSkippedChecks({
|
|
60460
60046
|
didLintFail,
|
|
60461
60047
|
lintFailureReason,
|
|
@@ -60479,10 +60065,6 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
60479
60065
|
lintCacheHitFileCount,
|
|
60480
60066
|
lintCacheTotalFileCount
|
|
60481
60067
|
} : {},
|
|
60482
|
-
...lintSidecarTotalFileCount !== null ? {
|
|
60483
|
-
lintSidecarReplayedFileCount,
|
|
60484
|
-
lintSidecarTotalFileCount
|
|
60485
|
-
} : {},
|
|
60486
60068
|
...deadCodeCacheHit !== null ? { deadCodeCacheHit } : {},
|
|
60487
60069
|
...deadCodeSummaryCacheHits !== null && deadCodeSummaryCacheMisses !== null ? {
|
|
60488
60070
|
deadCodeSummaryCacheHits,
|
|
@@ -64334,4 +63916,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
64334
63916
|
export {};
|
|
64335
63917
|
|
|
64336
63918
|
//# sourceMappingURL=cli.js.map
|
|
64337
|
-
//# debugId=
|
|
63919
|
+
//# debugId=cb06d1e4-d50b-5715-af77-13eb97c43e07
|