react-doctor 0.6.3-dev.bdf8074 → 0.6.3-dev.ced746f
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 +133 -55
- package/dist/index.js +117 -30
- package/dist/lsp.js +120 -35
- package/package.json +3 -3
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]="1722becf-6e91-56ae-afc9-1e1410647bc3")}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";
|
|
@@ -36137,6 +36137,7 @@ const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
|
36137
36137
|
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
36138
36138
|
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
36139
36139
|
const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
36140
|
+
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
36140
36141
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
36141
36142
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
36142
36143
|
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
|
|
@@ -40608,22 +40609,37 @@ const failOpenReadJson = (filePath, fallback) => {
|
|
|
40608
40609
|
return fallback;
|
|
40609
40610
|
}
|
|
40610
40611
|
};
|
|
40612
|
+
const hashFileContents = (filePath) => {
|
|
40613
|
+
try {
|
|
40614
|
+
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
40615
|
+
} catch {
|
|
40616
|
+
return null;
|
|
40617
|
+
}
|
|
40618
|
+
};
|
|
40611
40619
|
const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
|
|
40612
40620
|
const CORE_SIDE_MANIFEST_NAMES = ["knip.json", "deno.lock"];
|
|
40613
40621
|
const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
|
|
40614
40622
|
const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
|
|
40615
40623
|
const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
|
|
40616
|
-
|
|
40617
|
-
|
|
40624
|
+
/**
|
|
40625
|
+
* Stat snapshot of every file the analysis reads, keyed by root-relative
|
|
40626
|
+
* `/`-separated path. Taken BEFORE the (long) analysis so a stored result is
|
|
40627
|
+
* verified against the tree it started from.
|
|
40628
|
+
*/
|
|
40629
|
+
const collectAnalyzedFileStats = (rootDirectory) => {
|
|
40630
|
+
const statByRelativePath = /* @__PURE__ */ new Map();
|
|
40618
40631
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
40619
40632
|
if (!isFingerprintedFile(name)) continue;
|
|
40620
40633
|
try {
|
|
40621
40634
|
const fileStat = NFS.statSync(absolutePath);
|
|
40622
40635
|
const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
|
|
40623
|
-
|
|
40636
|
+
statByRelativePath.set(relativePath, {
|
|
40637
|
+
mtimeMs: fileStat.mtimeMs,
|
|
40638
|
+
size: fileStat.size
|
|
40639
|
+
});
|
|
40624
40640
|
} catch {}
|
|
40625
40641
|
}
|
|
40626
|
-
return
|
|
40642
|
+
return statByRelativePath;
|
|
40627
40643
|
};
|
|
40628
40644
|
const bundledRequire$2 = createRequire(import.meta.url);
|
|
40629
40645
|
const resolveDeslopVersion = () => {
|
|
@@ -40635,14 +40651,13 @@ const resolveDeslopVersion = () => {
|
|
|
40635
40651
|
}
|
|
40636
40652
|
};
|
|
40637
40653
|
const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
|
|
40638
|
-
schemaVersion:
|
|
40654
|
+
schemaVersion: 2,
|
|
40639
40655
|
coreVersion: input.coreVersion,
|
|
40640
40656
|
deslopVersion: resolveDeslopVersion(),
|
|
40641
40657
|
deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
|
|
40642
40658
|
entryPatterns: input.entryPatterns,
|
|
40643
40659
|
ignorePatterns: input.ignorePatterns,
|
|
40644
|
-
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/")
|
|
40645
|
-
files: collectAnalyzedFileFingerprints(input.rootDirectory)
|
|
40660
|
+
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/")
|
|
40646
40661
|
})).digest("hex");
|
|
40647
40662
|
const validateDiagnostic$2 = decodeUnknownSync(Diagnostic);
|
|
40648
40663
|
const decodeCachedDiagnostics = (raw) => {
|
|
@@ -40653,16 +40668,68 @@ const decodeCachedDiagnostics = (raw) => {
|
|
|
40653
40668
|
return null;
|
|
40654
40669
|
}
|
|
40655
40670
|
};
|
|
40656
|
-
const
|
|
40657
|
-
|
|
40658
|
-
|
|
40659
|
-
|
|
40671
|
+
const isPersistedFileIdentity = (value) => Array.isArray(value) && value.length === 3 && typeof value[0] === "number" && typeof value[1] === "number" && typeof value[2] === "string";
|
|
40672
|
+
const lookupDeadCodeResultCache = (input) => {
|
|
40673
|
+
const cacheFilePath = Path.join(input.cacheDirectory, DEAD_CODE_CACHE_FILENAME);
|
|
40674
|
+
const persisted = failOpenReadJson(cacheFilePath, null);
|
|
40675
|
+
if (persisted === null || !isRecord$1(persisted) || persisted.version !== 2 || persisted.key !== input.cacheKey || !isRecord$1(persisted.files) || !Array.isArray(persisted.diagnostics)) return null;
|
|
40676
|
+
const storedFileEntries = Object.entries(persisted.files);
|
|
40677
|
+
if (storedFileEntries.length !== input.currentFileStats.size) return null;
|
|
40678
|
+
const repairedFiles = {};
|
|
40679
|
+
let repairedCount = 0;
|
|
40680
|
+
for (const [relativePath, storedIdentity] of storedFileEntries) {
|
|
40681
|
+
if (!isPersistedFileIdentity(storedIdentity)) return null;
|
|
40682
|
+
const currentStat = input.currentFileStats.get(relativePath);
|
|
40683
|
+
if (currentStat === void 0) return null;
|
|
40684
|
+
const [storedMtimeMs, storedSize, storedContentHash] = storedIdentity;
|
|
40685
|
+
if (currentStat.mtimeMs === storedMtimeMs && currentStat.size === storedSize) {
|
|
40686
|
+
repairedFiles[relativePath] = storedIdentity;
|
|
40687
|
+
continue;
|
|
40688
|
+
}
|
|
40689
|
+
if (currentStat.size !== storedSize) return null;
|
|
40690
|
+
const currentContentHash = hashFileContents(Path.join(input.rootDirectory, relativePath));
|
|
40691
|
+
if (currentContentHash === null || currentContentHash !== storedContentHash) return null;
|
|
40692
|
+
repairedFiles[relativePath] = [
|
|
40693
|
+
currentStat.mtimeMs,
|
|
40694
|
+
currentStat.size,
|
|
40695
|
+
storedContentHash
|
|
40696
|
+
];
|
|
40697
|
+
repairedCount += 1;
|
|
40698
|
+
}
|
|
40699
|
+
const diagnostics = decodeCachedDiagnostics(persisted.diagnostics);
|
|
40700
|
+
if (diagnostics === null) return null;
|
|
40701
|
+
if (repairedCount > 0) atomicWriteJson(cacheFilePath, {
|
|
40702
|
+
version: 2,
|
|
40703
|
+
key: input.cacheKey,
|
|
40704
|
+
files: repairedFiles,
|
|
40705
|
+
diagnostics: persisted.diagnostics
|
|
40706
|
+
});
|
|
40707
|
+
return diagnostics;
|
|
40660
40708
|
};
|
|
40661
|
-
const storeDeadCodeResultCache = (
|
|
40662
|
-
|
|
40663
|
-
|
|
40664
|
-
|
|
40665
|
-
|
|
40709
|
+
const storeDeadCodeResultCache = (input) => {
|
|
40710
|
+
const persistedFiles = {};
|
|
40711
|
+
for (const [relativePath, snapshotStat] of input.snapshotFileStats) {
|
|
40712
|
+
const absolutePath = Path.join(input.rootDirectory, relativePath);
|
|
40713
|
+
const contentHash = hashFileContents(absolutePath);
|
|
40714
|
+
if (contentHash === null) return;
|
|
40715
|
+
let currentStat;
|
|
40716
|
+
try {
|
|
40717
|
+
currentStat = NFS.statSync(absolutePath);
|
|
40718
|
+
} catch {
|
|
40719
|
+
return;
|
|
40720
|
+
}
|
|
40721
|
+
if (currentStat.mtimeMs !== snapshotStat.mtimeMs || currentStat.size !== snapshotStat.size) return;
|
|
40722
|
+
persistedFiles[relativePath] = [
|
|
40723
|
+
snapshotStat.mtimeMs,
|
|
40724
|
+
snapshotStat.size,
|
|
40725
|
+
contentHash
|
|
40726
|
+
];
|
|
40727
|
+
}
|
|
40728
|
+
atomicWriteJson(Path.join(input.cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
|
|
40729
|
+
version: 2,
|
|
40730
|
+
key: input.cacheKey,
|
|
40731
|
+
files: persistedFiles,
|
|
40732
|
+
diagnostics: input.diagnostics
|
|
40666
40733
|
});
|
|
40667
40734
|
};
|
|
40668
40735
|
const readSystemFacts = () => ({
|
|
@@ -41072,16 +41139,22 @@ const checkDeadCode = async (options) => {
|
|
|
41072
41139
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
41073
41140
|
const tsConfigPath = resolveTsConfigPath(rootDirectory);
|
|
41074
41141
|
const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
|
|
41075
|
-
const
|
|
41142
|
+
const fileStatsSnapshot = options.cacheEnabled ? collectAnalyzedFileStats(rootDirectory) : null;
|
|
41143
|
+
const cacheKey = fileStatsSnapshot === null ? null : computeDeadCodeCacheKey({
|
|
41076
41144
|
rootDirectory,
|
|
41077
41145
|
entryPatterns,
|
|
41078
41146
|
ignorePatterns,
|
|
41079
41147
|
tsConfigPath,
|
|
41080
41148
|
deslopJsModuleSpecifier,
|
|
41081
41149
|
coreVersion: CORE_PACKAGE_VERSION
|
|
41082
|
-
})
|
|
41083
|
-
if (cacheKey !== null) {
|
|
41084
|
-
const cachedDiagnostics = lookupDeadCodeResultCache(
|
|
41150
|
+
});
|
|
41151
|
+
if (cacheKey !== null && fileStatsSnapshot !== null) {
|
|
41152
|
+
const cachedDiagnostics = lookupDeadCodeResultCache({
|
|
41153
|
+
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
41154
|
+
cacheKey,
|
|
41155
|
+
rootDirectory,
|
|
41156
|
+
currentFileStats: fileStatsSnapshot
|
|
41157
|
+
});
|
|
41085
41158
|
options.onCacheOutcome?.(cachedDiagnostics !== null);
|
|
41086
41159
|
if (cachedDiagnostics !== null) return [...cachedDiagnostics];
|
|
41087
41160
|
}
|
|
@@ -41155,7 +41228,13 @@ const checkDeadCode = async (options) => {
|
|
|
41155
41228
|
category: DEAD_CODE_CATEGORY
|
|
41156
41229
|
});
|
|
41157
41230
|
}
|
|
41158
|
-
if (cacheKey !== null) storeDeadCodeResultCache(
|
|
41231
|
+
if (cacheKey !== null && fileStatsSnapshot !== null) storeDeadCodeResultCache({
|
|
41232
|
+
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
41233
|
+
cacheKey,
|
|
41234
|
+
rootDirectory,
|
|
41235
|
+
snapshotFileStats: fileStatsSnapshot,
|
|
41236
|
+
diagnostics
|
|
41237
|
+
});
|
|
41159
41238
|
return diagnostics;
|
|
41160
41239
|
};
|
|
41161
41240
|
const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
|
|
@@ -42251,13 +42330,6 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
42251
42330
|
}
|
|
42252
42331
|
};
|
|
42253
42332
|
};
|
|
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
42333
|
const ABSENT_CONTENT_ANSWER = "absent";
|
|
42262
42334
|
/**
|
|
42263
42335
|
* Answers dependency probes for the sidecar lint cache — used both when
|
|
@@ -44398,6 +44470,20 @@ const writeCachedSocketBody = (cacheFile, body) => {
|
|
|
44398
44470
|
}));
|
|
44399
44471
|
} catch {}
|
|
44400
44472
|
};
|
|
44473
|
+
const pruneExpiredSocketCache = (cacheDirectory) => {
|
|
44474
|
+
try {
|
|
44475
|
+
const supplyChainCacheDirectory = Path.join(cacheDirectory, SUPPLY_CHAIN_CACHE_SUBDIR);
|
|
44476
|
+
const expiryThresholdMs = Date.now() - SUPPLY_CHAIN_CACHE_TTL_MS;
|
|
44477
|
+
for (const entryName of NFS.readdirSync(supplyChainCacheDirectory)) {
|
|
44478
|
+
const entryPath = Path.join(supplyChainCacheDirectory, entryName);
|
|
44479
|
+
try {
|
|
44480
|
+
if (NFS.statSync(entryPath).mtimeMs < expiryThresholdMs) NFS.rmSync(entryPath);
|
|
44481
|
+
} catch {
|
|
44482
|
+
continue;
|
|
44483
|
+
}
|
|
44484
|
+
}
|
|
44485
|
+
} catch {}
|
|
44486
|
+
};
|
|
44401
44487
|
const fetchSocketArtifact = (dependency, cacheDirectory) => tryPromise(async (signal) => {
|
|
44402
44488
|
const cacheFile = cacheDirectory === null ? null : supplyChainCacheFile(cacheDirectory, dependency);
|
|
44403
44489
|
if (cacheFile !== null) {
|
|
@@ -44525,6 +44611,7 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
44525
44611
|
const dependencies = collectDependenciesToScore(readPackageJson$1(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies);
|
|
44526
44612
|
if (dependencies.length === 0) return [];
|
|
44527
44613
|
const cacheDirectory = isSupplyChainCacheDisabled() ? null : resolveReactDoctorCacheDir(input.rootDirectory);
|
|
44614
|
+
if (cacheDirectory !== null) pruneExpiredSocketCache(cacheDirectory);
|
|
44528
44615
|
const artifacts = yield* forEach$1(dependencies, (dependency) => fetchSocketArtifact(dependency, cacheDirectory), { concurrency: 8 }).pipe(timeoutOption(input.totalTimeoutMs ?? 9e4), map$3((maybeArtifacts) => getOrElse$1(maybeArtifacts, () => [])));
|
|
44529
44616
|
const diagnostics = [];
|
|
44530
44617
|
for (let index = 0; index < dependencies.length; index += 1) {
|
|
@@ -45410,11 +45497,9 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
45410
45497
|
const parts = [`v=${version}`];
|
|
45411
45498
|
let directory = projectDirectory;
|
|
45412
45499
|
for (;;) {
|
|
45413
|
-
for (const filename of CONFIG_FINGERPRINT_FILENAMES)
|
|
45414
|
-
const
|
|
45415
|
-
parts.push(`${directory}/${filename}=${
|
|
45416
|
-
} catch {
|
|
45417
|
-
continue;
|
|
45500
|
+
for (const filename of CONFIG_FINGERPRINT_FILENAMES) {
|
|
45501
|
+
const contentHash = hashFileContents(path.join(directory, filename));
|
|
45502
|
+
if (contentHash !== null) parts.push(`${directory}/${filename}=${contentHash}`);
|
|
45418
45503
|
}
|
|
45419
45504
|
const parent = path.dirname(directory);
|
|
45420
45505
|
if (parent === directory) break;
|
|
@@ -45710,6 +45795,7 @@ const isNonInteractiveEnvironment = () => NON_INTERACTIVE_ENVIRONMENT_VARIABLES.
|
|
|
45710
45795
|
const REACT_DOCTOR_CONFIG_PROJECT_NAME = "react-doctor";
|
|
45711
45796
|
const STAGED_FILES_TEMP_DIR_PREFIX = "react-doctor-staged-";
|
|
45712
45797
|
const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
|
|
45798
|
+
const SCAN_RESULT_CACHE_FILENAME = "scan-cache.json";
|
|
45713
45799
|
const RUN_GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
45714
45800
|
const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
|
|
45715
45801
|
const CI_TRUST_COMPANIES = "PayPal, Rippling, and Alibaba";
|
|
@@ -45801,7 +45887,7 @@ const makeNoopConsole = () => ({
|
|
|
45801
45887
|
});
|
|
45802
45888
|
//#endregion
|
|
45803
45889
|
//#region src/cli/utils/version.ts
|
|
45804
|
-
const VERSION = "0.6.3-dev.
|
|
45890
|
+
const VERSION = "0.6.3-dev.ced746f";
|
|
45805
45891
|
//#endregion
|
|
45806
45892
|
//#region src/cli/utils/json-mode.ts
|
|
45807
45893
|
let context = null;
|
|
@@ -46170,13 +46256,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
46170
46256
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
46171
46257
|
* standard `SENTRY_RELEASE` override.
|
|
46172
46258
|
*/
|
|
46173
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.
|
|
46259
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.6.3-dev.ced746f`;
|
|
46174
46260
|
/**
|
|
46175
46261
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
46176
46262
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
46177
46263
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
46178
46264
|
*/
|
|
46179
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.
|
|
46265
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.6.3-dev.ced746f") ? "development" : "production");
|
|
46180
46266
|
/**
|
|
46181
46267
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
46182
46268
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -58257,9 +58343,8 @@ const findMigrationScaleBuckets = (diagnostics) => buildRuleBlastRadii(diagnosti
|
|
|
58257
58343
|
//#region src/cli/utils/scan-result-cache.ts
|
|
58258
58344
|
const CACHE_DISABLED_VALUES = new Set(["1", "true"]);
|
|
58259
58345
|
const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
58260
|
-
"oxlint",
|
|
58261
58346
|
"oxlint/package.json",
|
|
58262
|
-
"oxlint-plugin-react-doctor",
|
|
58347
|
+
"oxlint-plugin-react-doctor/package.json",
|
|
58263
58348
|
"deslop-js/package.json",
|
|
58264
58349
|
"eslint-plugin-react-hooks/package.json"
|
|
58265
58350
|
];
|
|
@@ -58372,7 +58457,7 @@ const buildWorktreeFingerprint = (projectDirectory) => {
|
|
|
58372
58457
|
const DOTENV_FILE_NAME_PATTERN = /^\.env(\.|$)/;
|
|
58373
58458
|
const resolveDotenvFingerprint = (projectDirectory) => {
|
|
58374
58459
|
try {
|
|
58375
|
-
return fs.readdirSync(projectDirectory).filter((entryName) => DOTENV_FILE_NAME_PATTERN.test(entryName)).sort().map((entryName) => `${entryName}=${
|
|
58460
|
+
return fs.readdirSync(projectDirectory).filter((entryName) => DOTENV_FILE_NAME_PATTERN.test(entryName)).sort().map((entryName) => `${entryName}=${hashFileContents(path.join(projectDirectory, entryName)) ?? "unreadable"}`);
|
|
58376
58461
|
} catch {
|
|
58377
58462
|
return [];
|
|
58378
58463
|
}
|
|
@@ -58382,12 +58467,7 @@ const hasHiddenTrackedFileState = (projectDirectory) => {
|
|
|
58382
58467
|
if (output === null) return true;
|
|
58383
58468
|
return output.split("\n").some((line) => line.length > 0 && line[0] !== "H");
|
|
58384
58469
|
};
|
|
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
|
-
};
|
|
58470
|
+
const resolveCacheFilePath = (projectDirectory) => path.join(resolveReactDoctorCacheDir(projectDirectory), SCAN_RESULT_CACHE_FILENAME);
|
|
58391
58471
|
const readPersistedCache = (cacheFilePath) => {
|
|
58392
58472
|
try {
|
|
58393
58473
|
const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
|
|
@@ -58453,15 +58533,13 @@ const fileFingerprint = (filePath) => {
|
|
|
58453
58533
|
};
|
|
58454
58534
|
const resolveToolchainFingerprint = (nodeBinaryPath) => {
|
|
58455
58535
|
const fingerprints = [];
|
|
58456
|
-
if (nodeBinaryPath !== null) {
|
|
58457
|
-
const fingerprint = fileFingerprint(nodeBinaryPath);
|
|
58458
|
-
if (fingerprint !== null) fingerprints.push(`node=${fingerprint}`);
|
|
58459
|
-
}
|
|
58536
|
+
if (nodeBinaryPath !== null) fingerprints.push(nodeBinaryPath === process.execPath ? `node=${process.version}` : `node=${fileFingerprint(nodeBinaryPath) ?? "unreadable"}`);
|
|
58460
58537
|
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
|
|
58461
|
-
const
|
|
58462
|
-
|
|
58538
|
+
const packageJson = bundledRequire(specifier);
|
|
58539
|
+
const version = typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
58540
|
+
fingerprints.push(`${specifier}=${version}`);
|
|
58463
58541
|
} catch {
|
|
58464
|
-
|
|
58542
|
+
fingerprints.push(`${specifier}=missing`);
|
|
58465
58543
|
}
|
|
58466
58544
|
return fingerprints;
|
|
58467
58545
|
};
|
|
@@ -60206,7 +60284,7 @@ const runBaselineComparison = async (params) => {
|
|
|
60206
60284
|
suppressScanSummary: true,
|
|
60207
60285
|
supplyChainManifestChanged: params.options.supplyChainManifestChanged,
|
|
60208
60286
|
deadlineEpochMs: params.deadlineEpochMs ?? void 0
|
|
60209
|
-
}, {}).pipe(provide(baseLayers), provideService$2(Console, silentConsole))));
|
|
60287
|
+
}, {}).pipe(provide(baseLayers), provideService$2(PerFileLintCacheEnabled, false), provideService$2(SidecarLintCacheEnabled, false), provideService$2(Console, silentConsole))));
|
|
60210
60288
|
if (baseOutput.didLintFail || countIncompleteLintFiles(baseOutput.lintPartialFailures) > 0) return null;
|
|
60211
60289
|
const delta = computeDiagnosticDelta({
|
|
60212
60290
|
headDiagnostics: params.headDiagnostics,
|
|
@@ -64334,4 +64412,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
64334
64412
|
export {};
|
|
64335
64413
|
|
|
64336
64414
|
//# sourceMappingURL=cli.js.map
|
|
64337
|
-
//# debugId=
|
|
64415
|
+
//# debugId=1722becf-6e91-56ae-afc9-1e1410647bc3
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
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]="b81c51d5-0ead-51a4-a9f9-ae499fd19a52")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as NFS from "node:fs";
|
|
@@ -32936,6 +32936,7 @@ const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
|
32936
32936
|
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
32937
32937
|
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
32938
32938
|
const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
32939
|
+
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
32939
32940
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
32940
32941
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
32941
32942
|
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
|
|
@@ -37365,22 +37366,37 @@ const failOpenReadJson = (filePath, fallback) => {
|
|
|
37365
37366
|
return fallback;
|
|
37366
37367
|
}
|
|
37367
37368
|
};
|
|
37369
|
+
const hashFileContents = (filePath) => {
|
|
37370
|
+
try {
|
|
37371
|
+
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
37372
|
+
} catch {
|
|
37373
|
+
return null;
|
|
37374
|
+
}
|
|
37375
|
+
};
|
|
37368
37376
|
const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
|
|
37369
37377
|
const CORE_SIDE_MANIFEST_NAMES = ["knip.json", "deno.lock"];
|
|
37370
37378
|
const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
|
|
37371
37379
|
const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
|
|
37372
37380
|
const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
|
|
37373
|
-
|
|
37374
|
-
|
|
37381
|
+
/**
|
|
37382
|
+
* Stat snapshot of every file the analysis reads, keyed by root-relative
|
|
37383
|
+
* `/`-separated path. Taken BEFORE the (long) analysis so a stored result is
|
|
37384
|
+
* verified against the tree it started from.
|
|
37385
|
+
*/
|
|
37386
|
+
const collectAnalyzedFileStats = (rootDirectory) => {
|
|
37387
|
+
const statByRelativePath = /* @__PURE__ */ new Map();
|
|
37375
37388
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
37376
37389
|
if (!isFingerprintedFile(name)) continue;
|
|
37377
37390
|
try {
|
|
37378
37391
|
const fileStat = NFS.statSync(absolutePath);
|
|
37379
37392
|
const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
|
|
37380
|
-
|
|
37393
|
+
statByRelativePath.set(relativePath, {
|
|
37394
|
+
mtimeMs: fileStat.mtimeMs,
|
|
37395
|
+
size: fileStat.size
|
|
37396
|
+
});
|
|
37381
37397
|
} catch {}
|
|
37382
37398
|
}
|
|
37383
|
-
return
|
|
37399
|
+
return statByRelativePath;
|
|
37384
37400
|
};
|
|
37385
37401
|
const bundledRequire$2 = createRequire(import.meta.url);
|
|
37386
37402
|
const resolveDeslopVersion = () => {
|
|
@@ -37392,14 +37408,13 @@ const resolveDeslopVersion = () => {
|
|
|
37392
37408
|
}
|
|
37393
37409
|
};
|
|
37394
37410
|
const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
|
|
37395
|
-
schemaVersion:
|
|
37411
|
+
schemaVersion: 2,
|
|
37396
37412
|
coreVersion: input.coreVersion,
|
|
37397
37413
|
deslopVersion: resolveDeslopVersion(),
|
|
37398
37414
|
deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
|
|
37399
37415
|
entryPatterns: input.entryPatterns,
|
|
37400
37416
|
ignorePatterns: input.ignorePatterns,
|
|
37401
|
-
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/")
|
|
37402
|
-
files: collectAnalyzedFileFingerprints(input.rootDirectory)
|
|
37417
|
+
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/")
|
|
37403
37418
|
})).digest("hex");
|
|
37404
37419
|
const validateDiagnostic$2 = decodeUnknownSync(Diagnostic);
|
|
37405
37420
|
const decodeCachedDiagnostics = (raw) => {
|
|
@@ -37410,16 +37425,68 @@ const decodeCachedDiagnostics = (raw) => {
|
|
|
37410
37425
|
return null;
|
|
37411
37426
|
}
|
|
37412
37427
|
};
|
|
37413
|
-
const
|
|
37414
|
-
|
|
37415
|
-
|
|
37416
|
-
|
|
37428
|
+
const isPersistedFileIdentity = (value) => Array.isArray(value) && value.length === 3 && typeof value[0] === "number" && typeof value[1] === "number" && typeof value[2] === "string";
|
|
37429
|
+
const lookupDeadCodeResultCache = (input) => {
|
|
37430
|
+
const cacheFilePath = Path.join(input.cacheDirectory, DEAD_CODE_CACHE_FILENAME);
|
|
37431
|
+
const persisted = failOpenReadJson(cacheFilePath, null);
|
|
37432
|
+
if (persisted === null || !isRecord(persisted) || persisted.version !== 2 || persisted.key !== input.cacheKey || !isRecord(persisted.files) || !Array.isArray(persisted.diagnostics)) return null;
|
|
37433
|
+
const storedFileEntries = Object.entries(persisted.files);
|
|
37434
|
+
if (storedFileEntries.length !== input.currentFileStats.size) return null;
|
|
37435
|
+
const repairedFiles = {};
|
|
37436
|
+
let repairedCount = 0;
|
|
37437
|
+
for (const [relativePath, storedIdentity] of storedFileEntries) {
|
|
37438
|
+
if (!isPersistedFileIdentity(storedIdentity)) return null;
|
|
37439
|
+
const currentStat = input.currentFileStats.get(relativePath);
|
|
37440
|
+
if (currentStat === void 0) return null;
|
|
37441
|
+
const [storedMtimeMs, storedSize, storedContentHash] = storedIdentity;
|
|
37442
|
+
if (currentStat.mtimeMs === storedMtimeMs && currentStat.size === storedSize) {
|
|
37443
|
+
repairedFiles[relativePath] = storedIdentity;
|
|
37444
|
+
continue;
|
|
37445
|
+
}
|
|
37446
|
+
if (currentStat.size !== storedSize) return null;
|
|
37447
|
+
const currentContentHash = hashFileContents(Path.join(input.rootDirectory, relativePath));
|
|
37448
|
+
if (currentContentHash === null || currentContentHash !== storedContentHash) return null;
|
|
37449
|
+
repairedFiles[relativePath] = [
|
|
37450
|
+
currentStat.mtimeMs,
|
|
37451
|
+
currentStat.size,
|
|
37452
|
+
storedContentHash
|
|
37453
|
+
];
|
|
37454
|
+
repairedCount += 1;
|
|
37455
|
+
}
|
|
37456
|
+
const diagnostics = decodeCachedDiagnostics(persisted.diagnostics);
|
|
37457
|
+
if (diagnostics === null) return null;
|
|
37458
|
+
if (repairedCount > 0) atomicWriteJson(cacheFilePath, {
|
|
37459
|
+
version: 2,
|
|
37460
|
+
key: input.cacheKey,
|
|
37461
|
+
files: repairedFiles,
|
|
37462
|
+
diagnostics: persisted.diagnostics
|
|
37463
|
+
});
|
|
37464
|
+
return diagnostics;
|
|
37417
37465
|
};
|
|
37418
|
-
const storeDeadCodeResultCache = (
|
|
37419
|
-
|
|
37420
|
-
|
|
37421
|
-
|
|
37422
|
-
|
|
37466
|
+
const storeDeadCodeResultCache = (input) => {
|
|
37467
|
+
const persistedFiles = {};
|
|
37468
|
+
for (const [relativePath, snapshotStat] of input.snapshotFileStats) {
|
|
37469
|
+
const absolutePath = Path.join(input.rootDirectory, relativePath);
|
|
37470
|
+
const contentHash = hashFileContents(absolutePath);
|
|
37471
|
+
if (contentHash === null) return;
|
|
37472
|
+
let currentStat;
|
|
37473
|
+
try {
|
|
37474
|
+
currentStat = NFS.statSync(absolutePath);
|
|
37475
|
+
} catch {
|
|
37476
|
+
return;
|
|
37477
|
+
}
|
|
37478
|
+
if (currentStat.mtimeMs !== snapshotStat.mtimeMs || currentStat.size !== snapshotStat.size) return;
|
|
37479
|
+
persistedFiles[relativePath] = [
|
|
37480
|
+
snapshotStat.mtimeMs,
|
|
37481
|
+
snapshotStat.size,
|
|
37482
|
+
contentHash
|
|
37483
|
+
];
|
|
37484
|
+
}
|
|
37485
|
+
atomicWriteJson(Path.join(input.cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
|
|
37486
|
+
version: 2,
|
|
37487
|
+
key: input.cacheKey,
|
|
37488
|
+
files: persistedFiles,
|
|
37489
|
+
diagnostics: input.diagnostics
|
|
37423
37490
|
});
|
|
37424
37491
|
};
|
|
37425
37492
|
const readSystemFacts = () => ({
|
|
@@ -37829,16 +37896,22 @@ const checkDeadCode = async (options) => {
|
|
|
37829
37896
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37830
37897
|
const tsConfigPath = resolveTsConfigPath(rootDirectory);
|
|
37831
37898
|
const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
|
|
37832
|
-
const
|
|
37899
|
+
const fileStatsSnapshot = options.cacheEnabled ? collectAnalyzedFileStats(rootDirectory) : null;
|
|
37900
|
+
const cacheKey = fileStatsSnapshot === null ? null : computeDeadCodeCacheKey({
|
|
37833
37901
|
rootDirectory,
|
|
37834
37902
|
entryPatterns,
|
|
37835
37903
|
ignorePatterns,
|
|
37836
37904
|
tsConfigPath,
|
|
37837
37905
|
deslopJsModuleSpecifier,
|
|
37838
37906
|
coreVersion: CORE_PACKAGE_VERSION
|
|
37839
|
-
})
|
|
37840
|
-
if (cacheKey !== null) {
|
|
37841
|
-
const cachedDiagnostics = lookupDeadCodeResultCache(
|
|
37907
|
+
});
|
|
37908
|
+
if (cacheKey !== null && fileStatsSnapshot !== null) {
|
|
37909
|
+
const cachedDiagnostics = lookupDeadCodeResultCache({
|
|
37910
|
+
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
37911
|
+
cacheKey,
|
|
37912
|
+
rootDirectory,
|
|
37913
|
+
currentFileStats: fileStatsSnapshot
|
|
37914
|
+
});
|
|
37842
37915
|
options.onCacheOutcome?.(cachedDiagnostics !== null);
|
|
37843
37916
|
if (cachedDiagnostics !== null) return [...cachedDiagnostics];
|
|
37844
37917
|
}
|
|
@@ -37912,7 +37985,13 @@ const checkDeadCode = async (options) => {
|
|
|
37912
37985
|
category: DEAD_CODE_CATEGORY
|
|
37913
37986
|
});
|
|
37914
37987
|
}
|
|
37915
|
-
if (cacheKey !== null) storeDeadCodeResultCache(
|
|
37988
|
+
if (cacheKey !== null && fileStatsSnapshot !== null) storeDeadCodeResultCache({
|
|
37989
|
+
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
37990
|
+
cacheKey,
|
|
37991
|
+
rootDirectory,
|
|
37992
|
+
snapshotFileStats: fileStatsSnapshot,
|
|
37993
|
+
diagnostics
|
|
37994
|
+
});
|
|
37916
37995
|
return diagnostics;
|
|
37917
37996
|
};
|
|
37918
37997
|
const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
|
|
@@ -39008,13 +39087,6 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
39008
39087
|
}
|
|
39009
39088
|
};
|
|
39010
39089
|
};
|
|
39011
|
-
const hashFileContents = (filePath) => {
|
|
39012
|
-
try {
|
|
39013
|
-
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
39014
|
-
} catch {
|
|
39015
|
-
return null;
|
|
39016
|
-
}
|
|
39017
|
-
};
|
|
39018
39090
|
const ABSENT_CONTENT_ANSWER = "absent";
|
|
39019
39091
|
/**
|
|
39020
39092
|
* Answers dependency probes for the sidecar lint cache — used both when
|
|
@@ -41155,6 +41227,20 @@ const writeCachedSocketBody = (cacheFile, body) => {
|
|
|
41155
41227
|
}));
|
|
41156
41228
|
} catch {}
|
|
41157
41229
|
};
|
|
41230
|
+
const pruneExpiredSocketCache = (cacheDirectory) => {
|
|
41231
|
+
try {
|
|
41232
|
+
const supplyChainCacheDirectory = Path.join(cacheDirectory, SUPPLY_CHAIN_CACHE_SUBDIR);
|
|
41233
|
+
const expiryThresholdMs = Date.now() - SUPPLY_CHAIN_CACHE_TTL_MS;
|
|
41234
|
+
for (const entryName of NFS.readdirSync(supplyChainCacheDirectory)) {
|
|
41235
|
+
const entryPath = Path.join(supplyChainCacheDirectory, entryName);
|
|
41236
|
+
try {
|
|
41237
|
+
if (NFS.statSync(entryPath).mtimeMs < expiryThresholdMs) NFS.rmSync(entryPath);
|
|
41238
|
+
} catch {
|
|
41239
|
+
continue;
|
|
41240
|
+
}
|
|
41241
|
+
}
|
|
41242
|
+
} catch {}
|
|
41243
|
+
};
|
|
41158
41244
|
const fetchSocketArtifact = (dependency, cacheDirectory) => tryPromise(async (signal) => {
|
|
41159
41245
|
const cacheFile = cacheDirectory === null ? null : supplyChainCacheFile(cacheDirectory, dependency);
|
|
41160
41246
|
if (cacheFile !== null) {
|
|
@@ -41282,6 +41368,7 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
41282
41368
|
const dependencies = collectDependenciesToScore(readPackageJson(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies);
|
|
41283
41369
|
if (dependencies.length === 0) return [];
|
|
41284
41370
|
const cacheDirectory = isSupplyChainCacheDisabled() ? null : resolveReactDoctorCacheDir(input.rootDirectory);
|
|
41371
|
+
if (cacheDirectory !== null) pruneExpiredSocketCache(cacheDirectory);
|
|
41285
41372
|
const artifacts = yield* forEach$1(dependencies, (dependency) => fetchSocketArtifact(dependency, cacheDirectory), { concurrency: 8 }).pipe(timeoutOption(input.totalTimeoutMs ?? 9e4), map$3((maybeArtifacts) => getOrElse$1(maybeArtifacts, () => [])));
|
|
41286
41373
|
const diagnostics = [];
|
|
41287
41374
|
for (let index = 0; index < dependencies.length; index += 1) {
|
|
@@ -42326,4 +42413,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
42326
42413
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
42327
42414
|
|
|
42328
42415
|
//# sourceMappingURL=index.js.map
|
|
42329
|
-
//# debugId=
|
|
42416
|
+
//# debugId=b81c51d5-0ead-51a4-a9f9-ae499fd19a52
|
package/dist/lsp.js
CHANGED
|
@@ -32995,6 +32995,7 @@ const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
|
32995
32995
|
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
32996
32996
|
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
32997
32997
|
const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
32998
|
+
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
32998
32999
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
32999
33000
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
33000
33001
|
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
|
|
@@ -37350,22 +37351,37 @@ const failOpenReadJson = (filePath, fallback) => {
|
|
|
37350
37351
|
return fallback;
|
|
37351
37352
|
}
|
|
37352
37353
|
};
|
|
37354
|
+
const hashFileContents = (filePath) => {
|
|
37355
|
+
try {
|
|
37356
|
+
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
37357
|
+
} catch {
|
|
37358
|
+
return null;
|
|
37359
|
+
}
|
|
37360
|
+
};
|
|
37353
37361
|
const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
|
|
37354
37362
|
const CORE_SIDE_MANIFEST_NAMES = ["knip.json", "deno.lock"];
|
|
37355
37363
|
const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
|
|
37356
37364
|
const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
|
|
37357
37365
|
const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
|
|
37358
|
-
|
|
37359
|
-
|
|
37366
|
+
/**
|
|
37367
|
+
* Stat snapshot of every file the analysis reads, keyed by root-relative
|
|
37368
|
+
* `/`-separated path. Taken BEFORE the (long) analysis so a stored result is
|
|
37369
|
+
* verified against the tree it started from.
|
|
37370
|
+
*/
|
|
37371
|
+
const collectAnalyzedFileStats = (rootDirectory) => {
|
|
37372
|
+
const statByRelativePath = /* @__PURE__ */ new Map();
|
|
37360
37373
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
37361
37374
|
if (!isFingerprintedFile(name)) continue;
|
|
37362
37375
|
try {
|
|
37363
37376
|
const fileStat = NFS.statSync(absolutePath);
|
|
37364
37377
|
const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
|
|
37365
|
-
|
|
37378
|
+
statByRelativePath.set(relativePath, {
|
|
37379
|
+
mtimeMs: fileStat.mtimeMs,
|
|
37380
|
+
size: fileStat.size
|
|
37381
|
+
});
|
|
37366
37382
|
} catch {}
|
|
37367
37383
|
}
|
|
37368
|
-
return
|
|
37384
|
+
return statByRelativePath;
|
|
37369
37385
|
};
|
|
37370
37386
|
const bundledRequire$2 = createRequire(import.meta.url);
|
|
37371
37387
|
const resolveDeslopVersion = () => {
|
|
@@ -37377,14 +37393,13 @@ const resolveDeslopVersion = () => {
|
|
|
37377
37393
|
}
|
|
37378
37394
|
};
|
|
37379
37395
|
const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
|
|
37380
|
-
schemaVersion:
|
|
37396
|
+
schemaVersion: 2,
|
|
37381
37397
|
coreVersion: input.coreVersion,
|
|
37382
37398
|
deslopVersion: resolveDeslopVersion(),
|
|
37383
37399
|
deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
|
|
37384
37400
|
entryPatterns: input.entryPatterns,
|
|
37385
37401
|
ignorePatterns: input.ignorePatterns,
|
|
37386
|
-
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/")
|
|
37387
|
-
files: collectAnalyzedFileFingerprints(input.rootDirectory)
|
|
37402
|
+
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/")
|
|
37388
37403
|
})).digest("hex");
|
|
37389
37404
|
const validateDiagnostic$2 = decodeUnknownSync(Diagnostic);
|
|
37390
37405
|
const decodeCachedDiagnostics = (raw) => {
|
|
@@ -37395,16 +37410,68 @@ const decodeCachedDiagnostics = (raw) => {
|
|
|
37395
37410
|
return null;
|
|
37396
37411
|
}
|
|
37397
37412
|
};
|
|
37398
|
-
const
|
|
37399
|
-
|
|
37400
|
-
|
|
37401
|
-
|
|
37413
|
+
const isPersistedFileIdentity = (value) => Array.isArray(value) && value.length === 3 && typeof value[0] === "number" && typeof value[1] === "number" && typeof value[2] === "string";
|
|
37414
|
+
const lookupDeadCodeResultCache = (input) => {
|
|
37415
|
+
const cacheFilePath = Path.join(input.cacheDirectory, DEAD_CODE_CACHE_FILENAME);
|
|
37416
|
+
const persisted = failOpenReadJson(cacheFilePath, null);
|
|
37417
|
+
if (persisted === null || !isRecord(persisted) || persisted.version !== 2 || persisted.key !== input.cacheKey || !isRecord(persisted.files) || !Array.isArray(persisted.diagnostics)) return null;
|
|
37418
|
+
const storedFileEntries = Object.entries(persisted.files);
|
|
37419
|
+
if (storedFileEntries.length !== input.currentFileStats.size) return null;
|
|
37420
|
+
const repairedFiles = {};
|
|
37421
|
+
let repairedCount = 0;
|
|
37422
|
+
for (const [relativePath, storedIdentity] of storedFileEntries) {
|
|
37423
|
+
if (!isPersistedFileIdentity(storedIdentity)) return null;
|
|
37424
|
+
const currentStat = input.currentFileStats.get(relativePath);
|
|
37425
|
+
if (currentStat === void 0) return null;
|
|
37426
|
+
const [storedMtimeMs, storedSize, storedContentHash] = storedIdentity;
|
|
37427
|
+
if (currentStat.mtimeMs === storedMtimeMs && currentStat.size === storedSize) {
|
|
37428
|
+
repairedFiles[relativePath] = storedIdentity;
|
|
37429
|
+
continue;
|
|
37430
|
+
}
|
|
37431
|
+
if (currentStat.size !== storedSize) return null;
|
|
37432
|
+
const currentContentHash = hashFileContents(Path.join(input.rootDirectory, relativePath));
|
|
37433
|
+
if (currentContentHash === null || currentContentHash !== storedContentHash) return null;
|
|
37434
|
+
repairedFiles[relativePath] = [
|
|
37435
|
+
currentStat.mtimeMs,
|
|
37436
|
+
currentStat.size,
|
|
37437
|
+
storedContentHash
|
|
37438
|
+
];
|
|
37439
|
+
repairedCount += 1;
|
|
37440
|
+
}
|
|
37441
|
+
const diagnostics = decodeCachedDiagnostics(persisted.diagnostics);
|
|
37442
|
+
if (diagnostics === null) return null;
|
|
37443
|
+
if (repairedCount > 0) atomicWriteJson(cacheFilePath, {
|
|
37444
|
+
version: 2,
|
|
37445
|
+
key: input.cacheKey,
|
|
37446
|
+
files: repairedFiles,
|
|
37447
|
+
diagnostics: persisted.diagnostics
|
|
37448
|
+
});
|
|
37449
|
+
return diagnostics;
|
|
37402
37450
|
};
|
|
37403
|
-
const storeDeadCodeResultCache = (
|
|
37404
|
-
|
|
37405
|
-
|
|
37406
|
-
|
|
37407
|
-
|
|
37451
|
+
const storeDeadCodeResultCache = (input) => {
|
|
37452
|
+
const persistedFiles = {};
|
|
37453
|
+
for (const [relativePath, snapshotStat] of input.snapshotFileStats) {
|
|
37454
|
+
const absolutePath = Path.join(input.rootDirectory, relativePath);
|
|
37455
|
+
const contentHash = hashFileContents(absolutePath);
|
|
37456
|
+
if (contentHash === null) return;
|
|
37457
|
+
let currentStat;
|
|
37458
|
+
try {
|
|
37459
|
+
currentStat = NFS.statSync(absolutePath);
|
|
37460
|
+
} catch {
|
|
37461
|
+
return;
|
|
37462
|
+
}
|
|
37463
|
+
if (currentStat.mtimeMs !== snapshotStat.mtimeMs || currentStat.size !== snapshotStat.size) return;
|
|
37464
|
+
persistedFiles[relativePath] = [
|
|
37465
|
+
snapshotStat.mtimeMs,
|
|
37466
|
+
snapshotStat.size,
|
|
37467
|
+
contentHash
|
|
37468
|
+
];
|
|
37469
|
+
}
|
|
37470
|
+
atomicWriteJson(Path.join(input.cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
|
|
37471
|
+
version: 2,
|
|
37472
|
+
key: input.cacheKey,
|
|
37473
|
+
files: persistedFiles,
|
|
37474
|
+
diagnostics: input.diagnostics
|
|
37408
37475
|
});
|
|
37409
37476
|
};
|
|
37410
37477
|
const readSystemFacts = () => ({
|
|
@@ -37814,16 +37881,22 @@ const checkDeadCode = async (options) => {
|
|
|
37814
37881
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37815
37882
|
const tsConfigPath = resolveTsConfigPath(rootDirectory);
|
|
37816
37883
|
const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
|
|
37817
|
-
const
|
|
37884
|
+
const fileStatsSnapshot = options.cacheEnabled ? collectAnalyzedFileStats(rootDirectory) : null;
|
|
37885
|
+
const cacheKey = fileStatsSnapshot === null ? null : computeDeadCodeCacheKey({
|
|
37818
37886
|
rootDirectory,
|
|
37819
37887
|
entryPatterns,
|
|
37820
37888
|
ignorePatterns,
|
|
37821
37889
|
tsConfigPath,
|
|
37822
37890
|
deslopJsModuleSpecifier,
|
|
37823
37891
|
coreVersion: CORE_PACKAGE_VERSION
|
|
37824
|
-
})
|
|
37825
|
-
if (cacheKey !== null) {
|
|
37826
|
-
const cachedDiagnostics = lookupDeadCodeResultCache(
|
|
37892
|
+
});
|
|
37893
|
+
if (cacheKey !== null && fileStatsSnapshot !== null) {
|
|
37894
|
+
const cachedDiagnostics = lookupDeadCodeResultCache({
|
|
37895
|
+
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
37896
|
+
cacheKey,
|
|
37897
|
+
rootDirectory,
|
|
37898
|
+
currentFileStats: fileStatsSnapshot
|
|
37899
|
+
});
|
|
37827
37900
|
options.onCacheOutcome?.(cachedDiagnostics !== null);
|
|
37828
37901
|
if (cachedDiagnostics !== null) return [...cachedDiagnostics];
|
|
37829
37902
|
}
|
|
@@ -37897,7 +37970,13 @@ const checkDeadCode = async (options) => {
|
|
|
37897
37970
|
category: DEAD_CODE_CATEGORY
|
|
37898
37971
|
});
|
|
37899
37972
|
}
|
|
37900
|
-
if (cacheKey !== null) storeDeadCodeResultCache(
|
|
37973
|
+
if (cacheKey !== null && fileStatsSnapshot !== null) storeDeadCodeResultCache({
|
|
37974
|
+
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
37975
|
+
cacheKey,
|
|
37976
|
+
rootDirectory,
|
|
37977
|
+
snapshotFileStats: fileStatsSnapshot,
|
|
37978
|
+
diagnostics
|
|
37979
|
+
});
|
|
37901
37980
|
return diagnostics;
|
|
37902
37981
|
};
|
|
37903
37982
|
const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
|
|
@@ -38993,13 +39072,6 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
38993
39072
|
}
|
|
38994
39073
|
};
|
|
38995
39074
|
};
|
|
38996
|
-
const hashFileContents = (filePath) => {
|
|
38997
|
-
try {
|
|
38998
|
-
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
38999
|
-
} catch {
|
|
39000
|
-
return null;
|
|
39001
|
-
}
|
|
39002
|
-
};
|
|
39003
39075
|
const ABSENT_CONTENT_ANSWER = "absent";
|
|
39004
39076
|
/**
|
|
39005
39077
|
* Answers dependency probes for the sidecar lint cache — used both when
|
|
@@ -41140,6 +41212,20 @@ const writeCachedSocketBody = (cacheFile, body) => {
|
|
|
41140
41212
|
}));
|
|
41141
41213
|
} catch {}
|
|
41142
41214
|
};
|
|
41215
|
+
const pruneExpiredSocketCache = (cacheDirectory) => {
|
|
41216
|
+
try {
|
|
41217
|
+
const supplyChainCacheDirectory = Path.join(cacheDirectory, SUPPLY_CHAIN_CACHE_SUBDIR);
|
|
41218
|
+
const expiryThresholdMs = Date.now() - SUPPLY_CHAIN_CACHE_TTL_MS;
|
|
41219
|
+
for (const entryName of NFS.readdirSync(supplyChainCacheDirectory)) {
|
|
41220
|
+
const entryPath = Path.join(supplyChainCacheDirectory, entryName);
|
|
41221
|
+
try {
|
|
41222
|
+
if (NFS.statSync(entryPath).mtimeMs < expiryThresholdMs) NFS.rmSync(entryPath);
|
|
41223
|
+
} catch {
|
|
41224
|
+
continue;
|
|
41225
|
+
}
|
|
41226
|
+
}
|
|
41227
|
+
} catch {}
|
|
41228
|
+
};
|
|
41143
41229
|
const fetchSocketArtifact = (dependency, cacheDirectory) => tryPromise(async (signal) => {
|
|
41144
41230
|
const cacheFile = cacheDirectory === null ? null : supplyChainCacheFile(cacheDirectory, dependency);
|
|
41145
41231
|
if (cacheFile !== null) {
|
|
@@ -41267,6 +41353,7 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
41267
41353
|
const dependencies = collectDependenciesToScore(readPackageJson(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies);
|
|
41268
41354
|
if (dependencies.length === 0) return [];
|
|
41269
41355
|
const cacheDirectory = isSupplyChainCacheDisabled() ? null : resolveReactDoctorCacheDir(input.rootDirectory);
|
|
41356
|
+
if (cacheDirectory !== null) pruneExpiredSocketCache(cacheDirectory);
|
|
41270
41357
|
const artifacts = yield* forEach$1(dependencies, (dependency) => fetchSocketArtifact(dependency, cacheDirectory), { concurrency: 8 }).pipe(timeoutOption(input.totalTimeoutMs ?? 9e4), map$3((maybeArtifacts) => getOrElse$1(maybeArtifacts, () => [])));
|
|
41271
41358
|
const diagnostics = [];
|
|
41272
41359
|
for (let index = 0; index < dependencies.length; index += 1) {
|
|
@@ -41983,11 +42070,9 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
41983
42070
|
const parts = [`v=${version}`];
|
|
41984
42071
|
let directory = projectDirectory;
|
|
41985
42072
|
for (;;) {
|
|
41986
|
-
for (const filename of CONFIG_FINGERPRINT_FILENAMES)
|
|
41987
|
-
const
|
|
41988
|
-
parts.push(`${directory}/${filename}=${
|
|
41989
|
-
} catch {
|
|
41990
|
-
continue;
|
|
42073
|
+
for (const filename of CONFIG_FINGERPRINT_FILENAMES) {
|
|
42074
|
+
const contentHash = hashFileContents(path.join(directory, filename));
|
|
42075
|
+
if (contentHash !== null) parts.push(`${directory}/${filename}=${contentHash}`);
|
|
41991
42076
|
}
|
|
41992
42077
|
const parent = path.dirname(directory);
|
|
41993
42078
|
if (parent === directory) break;
|
|
@@ -44050,5 +44135,5 @@ const startLanguageServer = () => {
|
|
|
44050
44135
|
};
|
|
44051
44136
|
//#endregion
|
|
44052
44137
|
export { startLanguageServer };
|
|
44053
|
-
!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]="
|
|
44054
|
-
//# debugId=
|
|
44138
|
+
!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]="35802bcf-f0e9-56fb-8cd9-6aee4dd99007")}catch(e){}}();
|
|
44139
|
+
//# debugId=35802bcf-f0e9-56fb-8cd9-6aee4dd99007
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.6.3-dev.
|
|
3
|
+
"version": "0.6.3-dev.ced746f",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"vscode-uri": "^3.1.0",
|
|
67
67
|
"yaml": "^2.9.0",
|
|
68
68
|
"deslop-js": "0.6.3",
|
|
69
|
-
"oxlint-plugin-react-doctor": "0.6.3-dev.
|
|
69
|
+
"oxlint-plugin-react-doctor": "0.6.3-dev.ced746f"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/babel__code-frame": "^7.27.0",
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"@xterm/headless": "^6.0.0",
|
|
75
75
|
"commander": "^14.0.3",
|
|
76
76
|
"ora": "^9.4.0",
|
|
77
|
-
"@react-doctor/api": "0.6.3",
|
|
78
77
|
"@react-doctor/core": "0.6.3",
|
|
78
|
+
"@react-doctor/api": "0.6.3",
|
|
79
79
|
"@react-doctor/language-server": "0.6.3"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|