react-doctor 0.6.3-dev.ced746f → 0.6.3-dev.e257a5e
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 +308 -908
- package/dist/index.d.ts +0 -18
- package/dist/index.js +102 -541
- package/dist/lsp.js +107 -544
- package/package.json +4 -4
package/dist/lsp.js
CHANGED
|
@@ -8,14 +8,13 @@ import path from "node:path";
|
|
|
8
8
|
import * as NodeChildProcess from "node:child_process";
|
|
9
9
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
10
10
|
import * as ts from "typescript";
|
|
11
|
-
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS,
|
|
11
|
+
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
12
12
|
import { parseJSON5 } from "confbox";
|
|
13
13
|
import * as NodeUrl from "node:url";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
import { createJiti } from "jiti";
|
|
16
16
|
import * as Crypto from "node:crypto";
|
|
17
17
|
import crypto, { createHash } from "node:crypto";
|
|
18
|
-
import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
|
|
19
18
|
import { gzipSync } from "node:zlib";
|
|
20
19
|
import { CodeActionKind, CodeActionTriggerKind, DidChangeWatchedFilesNotification, DocumentDiagnosticReportKind, FileChangeType, TextDocumentSyncKind, TextDocuments, createConnection } from "vscode-languageserver/node.js";
|
|
21
20
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
@@ -32987,15 +32986,11 @@ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
|
|
|
32987
32986
|
const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
32988
32987
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
32989
32988
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
32990
|
-
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
32991
|
-
const CORE_PACKAGE_VERSION = "0.6.3";
|
|
32992
32989
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
32993
|
-
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
32994
32990
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
32995
32991
|
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
32996
32992
|
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
32997
32993
|
const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
32998
|
-
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
32999
32994
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
33000
32995
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
33001
32996
|
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
|
|
@@ -35653,29 +35648,6 @@ var PerFileLintCacheEnabled = class extends Reference("react-doctor/PerFileLintC
|
|
|
35653
35648
|
return true;
|
|
35654
35649
|
} }) {};
|
|
35655
35650
|
/**
|
|
35656
|
-
* Whether the sidecar lint cache (`runners/oxlint/sidecar-lint-cache.ts`) is
|
|
35657
|
-
* active. Defaults ON — warm rescans replay the cross-file rules' cached
|
|
35658
|
-
* diagnostics for every file whose dependency fingerprint (the probe set the
|
|
35659
|
-
* plugin's collectors recorded) still matches the tree, and re-lint only the
|
|
35660
|
-
* rest. Only reachable when the per-file lint cache itself is on (the
|
|
35661
|
-
* sidecar covers its cache hits), so `REACT_DOCTOR_NO_CACHE` /
|
|
35662
|
-
* `REACT_DOCTOR_NO_FILE_CACHE` implicitly disable it too. Opt-OUT knobs:
|
|
35663
|
-
*
|
|
35664
|
-
* - `REACT_DOCTOR_NO_CACHE` — the global off-switch.
|
|
35665
|
-
* - `REACT_DOCTOR_NO_SIDECAR_CACHE` — granular rollback hatch: keep the
|
|
35666
|
-
* per-file cache but run the always-fresh sidecar over every hit
|
|
35667
|
-
* (the pre-cache behavior).
|
|
35668
|
-
*
|
|
35669
|
-
* Tests override via `Layer.succeed(SidecarLintCacheEnabled, false)`.
|
|
35670
|
-
*/
|
|
35671
|
-
var SidecarLintCacheEnabled = class extends Reference("react-doctor/SidecarLintCacheEnabled", { defaultValue: () => {
|
|
35672
|
-
const noCache = process.env["REACT_DOCTOR_NO_CACHE"]?.toLowerCase() ?? "";
|
|
35673
|
-
const noSidecarCache = process.env["REACT_DOCTOR_NO_SIDECAR_CACHE"]?.toLowerCase() ?? "";
|
|
35674
|
-
if (CACHE_DISABLED_VALUES.has(noCache)) return false;
|
|
35675
|
-
if (CACHE_DISABLED_VALUES.has(noSidecarCache)) return false;
|
|
35676
|
-
return true;
|
|
35677
|
-
} }) {};
|
|
35678
|
-
/**
|
|
35679
35651
|
* Whether the whole-project dead-code result cache
|
|
35680
35652
|
* (`dead-code/dead-code-result-cache.ts`) is active. Defaults ON — a rescan
|
|
35681
35653
|
* whose inputs (source tree, manifests, configs, analyzer version) are
|
|
@@ -37351,37 +37323,51 @@ const failOpenReadJson = (filePath, fallback) => {
|
|
|
37351
37323
|
return fallback;
|
|
37352
37324
|
}
|
|
37353
37325
|
};
|
|
37354
|
-
const
|
|
37355
|
-
|
|
37356
|
-
|
|
37357
|
-
|
|
37358
|
-
|
|
37359
|
-
|
|
37360
|
-
|
|
37361
|
-
|
|
37362
|
-
|
|
37363
|
-
|
|
37326
|
+
const ANALYZED_FILE_EXTENSIONS = new Set([
|
|
37327
|
+
".ts",
|
|
37328
|
+
".tsx",
|
|
37329
|
+
".js",
|
|
37330
|
+
".jsx",
|
|
37331
|
+
".mts",
|
|
37332
|
+
".mjs",
|
|
37333
|
+
".cts",
|
|
37334
|
+
".cjs",
|
|
37335
|
+
".mdx",
|
|
37336
|
+
".astro",
|
|
37337
|
+
".graphql",
|
|
37338
|
+
".gql",
|
|
37339
|
+
".css",
|
|
37340
|
+
".scss",
|
|
37341
|
+
".vue",
|
|
37342
|
+
".svelte"
|
|
37343
|
+
]);
|
|
37344
|
+
const ANALYZED_MANIFEST_NAMES = new Set([
|
|
37345
|
+
"package.json",
|
|
37346
|
+
"knip.json",
|
|
37347
|
+
"app.json",
|
|
37348
|
+
"pnpm-workspace.yaml",
|
|
37349
|
+
"lerna.json",
|
|
37350
|
+
"pnpm-lock.yaml",
|
|
37351
|
+
"package-lock.json",
|
|
37352
|
+
"yarn.lock",
|
|
37353
|
+
"bun.lock",
|
|
37354
|
+
"bun.lockb",
|
|
37355
|
+
"deno.lock",
|
|
37356
|
+
".gitignore"
|
|
37357
|
+
]);
|
|
37364
37358
|
const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
|
|
37365
37359
|
const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
|
|
37366
|
-
|
|
37367
|
-
|
|
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
|
+
const collectAnalyzedFileFingerprints = (rootDirectory) => {
|
|
37361
|
+
const fingerprints = [];
|
|
37373
37362
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
37374
37363
|
if (!isFingerprintedFile(name)) continue;
|
|
37375
37364
|
try {
|
|
37376
37365
|
const fileStat = NFS.statSync(absolutePath);
|
|
37377
37366
|
const relativePath = Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/");
|
|
37378
|
-
|
|
37379
|
-
mtimeMs: fileStat.mtimeMs,
|
|
37380
|
-
size: fileStat.size
|
|
37381
|
-
});
|
|
37367
|
+
fingerprints.push(`${relativePath}:${fileStat.mtimeMs}:${fileStat.size}`);
|
|
37382
37368
|
} catch {}
|
|
37383
37369
|
}
|
|
37384
|
-
return
|
|
37370
|
+
return fingerprints.sort();
|
|
37385
37371
|
};
|
|
37386
37372
|
const bundledRequire$2 = createRequire(import.meta.url);
|
|
37387
37373
|
const resolveDeslopVersion = () => {
|
|
@@ -37393,85 +37379,33 @@ const resolveDeslopVersion = () => {
|
|
|
37393
37379
|
}
|
|
37394
37380
|
};
|
|
37395
37381
|
const computeDeadCodeCacheKey = (input) => crypto.createHash("sha1").update(JSON.stringify({
|
|
37396
|
-
schemaVersion:
|
|
37397
|
-
coreVersion: input.coreVersion,
|
|
37382
|
+
schemaVersion: 1,
|
|
37398
37383
|
deslopVersion: resolveDeslopVersion(),
|
|
37399
37384
|
deslopJsModuleSpecifier: input.deslopJsModuleSpecifier,
|
|
37400
37385
|
entryPatterns: input.entryPatterns,
|
|
37401
37386
|
ignorePatterns: input.ignorePatterns,
|
|
37402
|
-
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/")
|
|
37387
|
+
tsConfigFile: input.tsConfigPath === void 0 ? null : Path.relative(input.rootDirectory, input.tsConfigPath).replace(/\\/g, "/"),
|
|
37388
|
+
files: collectAnalyzedFileFingerprints(input.rootDirectory)
|
|
37403
37389
|
})).digest("hex");
|
|
37404
|
-
const validateDiagnostic$
|
|
37390
|
+
const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
|
|
37405
37391
|
const decodeCachedDiagnostics = (raw) => {
|
|
37406
37392
|
try {
|
|
37407
|
-
for (const entry of raw) validateDiagnostic$
|
|
37393
|
+
for (const entry of raw) validateDiagnostic$1(entry);
|
|
37408
37394
|
return raw;
|
|
37409
37395
|
} catch {
|
|
37410
37396
|
return null;
|
|
37411
37397
|
}
|
|
37412
37398
|
};
|
|
37413
|
-
const
|
|
37414
|
-
const
|
|
37415
|
-
|
|
37416
|
-
|
|
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;
|
|
37399
|
+
const lookupDeadCodeResultCache = (cacheDirectory, cacheKey) => {
|
|
37400
|
+
const persisted = failOpenReadJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), null);
|
|
37401
|
+
if (persisted === null || !isRecord(persisted) || persisted.version !== 1 || persisted.key !== cacheKey || !Array.isArray(persisted.diagnostics)) return null;
|
|
37402
|
+
return decodeCachedDiagnostics(persisted.diagnostics);
|
|
37450
37403
|
};
|
|
37451
|
-
const storeDeadCodeResultCache = (
|
|
37452
|
-
|
|
37453
|
-
|
|
37454
|
-
|
|
37455
|
-
|
|
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
|
|
37404
|
+
const storeDeadCodeResultCache = (cacheDirectory, cacheKey, diagnostics) => {
|
|
37405
|
+
atomicWriteJson(Path.join(cacheDirectory, DEAD_CODE_CACHE_FILENAME), {
|
|
37406
|
+
version: 1,
|
|
37407
|
+
key: cacheKey,
|
|
37408
|
+
diagnostics
|
|
37475
37409
|
});
|
|
37476
37410
|
};
|
|
37477
37411
|
const readSystemFacts = () => ({
|
|
@@ -37610,14 +37544,6 @@ process.stdin.on("end", () => {
|
|
|
37610
37544
|
circularDependencies: result.circularDependencies.map((cycle) => ({
|
|
37611
37545
|
files: cycle.files,
|
|
37612
37546
|
})),
|
|
37613
|
-
...(result.incrementalCacheStats
|
|
37614
|
-
? {
|
|
37615
|
-
summaryCacheStats: {
|
|
37616
|
-
hits: result.incrementalCacheStats.summaryHits,
|
|
37617
|
-
misses: result.incrementalCacheStats.summaryMisses,
|
|
37618
|
-
},
|
|
37619
|
-
}
|
|
37620
|
-
: {}),
|
|
37621
37547
|
});
|
|
37622
37548
|
|
|
37623
37549
|
const serializeError = (error) =>
|
|
@@ -37641,9 +37567,6 @@ process.stdin.on("end", () => {
|
|
|
37641
37567
|
...(workerInput.ignorePatterns.length > 0
|
|
37642
37568
|
? { ignorePatterns: workerInput.ignorePatterns }
|
|
37643
37569
|
: {}),
|
|
37644
|
-
...(workerInput.incrementalCachePath
|
|
37645
|
-
? { incrementalCachePath: workerInput.incrementalCachePath }
|
|
37646
|
-
: {}),
|
|
37647
37570
|
// We consume only deslop's GRAPH-based findings (unusedFiles, unusedExports,
|
|
37648
37571
|
// unusedDependencies, circularDependencies). Everything else deslop can compute
|
|
37649
37572
|
// is pure wasted work for us, and it's the bulk of the runtime:
|
|
@@ -37654,18 +37577,12 @@ process.stdin.on("end", () => {
|
|
|
37654
37577
|
// are the single most expensive pass — duplicate-block detection alone was
|
|
37655
37578
|
// ~83s of a ~130s Sentry scan — so skipping them is an ~8.5x dead-code
|
|
37656
37579
|
// speedup on a large repo.
|
|
37657
|
-
//
|
|
37658
|
-
// simplifiable functions, identity wrappers, …) — ~120 ms of discarded
|
|
37659
|
-
// output per scan, and skipping them lets the incremental cache drop the
|
|
37660
|
-
// DRY-pattern summary fields (the largest slice of the cache file).
|
|
37661
|
-
// All are provably safe: the consumed graph findings are computed by their own
|
|
37580
|
+
// Both are provably safe: the consumed graph findings are computed by their own
|
|
37662
37581
|
// detectors, independent of these passes (confirmed byte-identical on
|
|
37663
|
-
// excalidraw + mui-material + sentry
|
|
37664
|
-
//
|
|
37665
|
-
// for path-alias resolution in the import graph.
|
|
37582
|
+
// excalidraw + mui-material + sentry). tsConfigPath stays — the module resolver
|
|
37583
|
+
// needs it for path-alias resolution in the import graph.
|
|
37666
37584
|
semantic: { enabled: false },
|
|
37667
37585
|
reportCodeQuality: false,
|
|
37668
|
-
reportRedundancy: false,
|
|
37669
37586
|
};
|
|
37670
37587
|
const result = await analyze(defineConfig(config));
|
|
37671
37588
|
emit({ ok: true, result: normalizeResult(result) });
|
|
@@ -37749,23 +37666,13 @@ const parseCircularDependencies = (value) => {
|
|
|
37749
37666
|
}
|
|
37750
37667
|
return circularDependencies;
|
|
37751
37668
|
};
|
|
37752
|
-
const parseSummaryCacheStats = (value) => {
|
|
37753
|
-
if (!isRecord(value)) return void 0;
|
|
37754
|
-
if (typeof value.hits !== "number" || typeof value.misses !== "number") return void 0;
|
|
37755
|
-
return {
|
|
37756
|
-
hits: value.hits,
|
|
37757
|
-
misses: value.misses
|
|
37758
|
-
};
|
|
37759
|
-
};
|
|
37760
37669
|
const parseDeadCodeWorkerResult = (value) => {
|
|
37761
37670
|
if (!isRecord(value)) throw new Error("Dead-code worker returned an invalid result.");
|
|
37762
|
-
const summaryCacheStats = parseSummaryCacheStats(value.summaryCacheStats);
|
|
37763
37671
|
return {
|
|
37764
37672
|
unusedFiles: parseUnusedFiles(value.unusedFiles),
|
|
37765
37673
|
unusedExports: parseUnusedExports(value.unusedExports),
|
|
37766
37674
|
unusedDependencies: parseUnusedDependencies(value.unusedDependencies),
|
|
37767
|
-
circularDependencies: parseCircularDependencies(value.circularDependencies)
|
|
37768
|
-
...summaryCacheStats ? { summaryCacheStats } : {}
|
|
37675
|
+
circularDependencies: parseCircularDependencies(value.circularDependencies)
|
|
37769
37676
|
};
|
|
37770
37677
|
};
|
|
37771
37678
|
const parseDeadCodeWorkerError = (value) => {
|
|
@@ -37881,26 +37788,18 @@ const checkDeadCode = async (options) => {
|
|
|
37881
37788
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37882
37789
|
const tsConfigPath = resolveTsConfigPath(rootDirectory);
|
|
37883
37790
|
const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
|
|
37884
|
-
const
|
|
37885
|
-
const cacheKey = fileStatsSnapshot === null ? null : computeDeadCodeCacheKey({
|
|
37791
|
+
const cacheKey = options.cacheEnabled ? computeDeadCodeCacheKey({
|
|
37886
37792
|
rootDirectory,
|
|
37887
37793
|
entryPatterns,
|
|
37888
37794
|
ignorePatterns,
|
|
37889
37795
|
tsConfigPath,
|
|
37890
|
-
deslopJsModuleSpecifier
|
|
37891
|
-
|
|
37892
|
-
|
|
37893
|
-
|
|
37894
|
-
const cachedDiagnostics = lookupDeadCodeResultCache({
|
|
37895
|
-
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
37896
|
-
cacheKey,
|
|
37897
|
-
rootDirectory,
|
|
37898
|
-
currentFileStats: fileStatsSnapshot
|
|
37899
|
-
});
|
|
37796
|
+
deslopJsModuleSpecifier
|
|
37797
|
+
}) : null;
|
|
37798
|
+
if (cacheKey !== null) {
|
|
37799
|
+
const cachedDiagnostics = lookupDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey);
|
|
37900
37800
|
options.onCacheOutcome?.(cachedDiagnostics !== null);
|
|
37901
37801
|
if (cachedDiagnostics !== null) return [...cachedDiagnostics];
|
|
37902
37802
|
}
|
|
37903
|
-
const incrementalCachePath = options.cacheEnabled === true ? Path.join(resolveReactDoctorCacheDir(rootDirectory), DEAD_CODE_SUMMARY_CACHE_FILENAME) : void 0;
|
|
37904
37803
|
const spawnAndRun = () => {
|
|
37905
37804
|
return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
37906
37805
|
rootDirectory,
|
|
@@ -37908,12 +37807,10 @@ const checkDeadCode = async (options) => {
|
|
|
37908
37807
|
tsConfigPath,
|
|
37909
37808
|
ignorePatterns,
|
|
37910
37809
|
deslopJsModuleSpecifier,
|
|
37911
|
-
parseConcurrency: options.parseConcurrency
|
|
37912
|
-
incrementalCachePath
|
|
37810
|
+
parseConcurrency: options.parseConcurrency
|
|
37913
37811
|
}), options.workerTimeoutMs ?? 12e4, options.abortSignal);
|
|
37914
37812
|
};
|
|
37915
37813
|
const result = parseDeadCodeWorkerResult(options.createWorker === void 0 ? await withDeadCodeWorkerSlot(spawnAndRun, options.abortSignal) : await spawnAndRun());
|
|
37916
|
-
if (result.summaryCacheStats !== void 0) options.onSummaryCacheStats?.(result.summaryCacheStats);
|
|
37917
37814
|
const toRelative = (filePath) => toRelativeFilePath(rootDirectory, filePath);
|
|
37918
37815
|
const diagnostics = [];
|
|
37919
37816
|
for (const unusedFile of result.unusedFiles) diagnostics.push({
|
|
@@ -37970,13 +37867,7 @@ const checkDeadCode = async (options) => {
|
|
|
37970
37867
|
category: DEAD_CODE_CATEGORY
|
|
37971
37868
|
});
|
|
37972
37869
|
}
|
|
37973
|
-
if (cacheKey !== null
|
|
37974
|
-
cacheDirectory: resolveReactDoctorCacheDir(rootDirectory),
|
|
37975
|
-
cacheKey,
|
|
37976
|
-
rootDirectory,
|
|
37977
|
-
snapshotFileStats: fileStatsSnapshot,
|
|
37978
|
-
diagnostics
|
|
37979
|
-
});
|
|
37870
|
+
if (cacheKey !== null) storeDeadCodeResultCache(resolveReactDoctorCacheDir(rootDirectory), cacheKey, diagnostics);
|
|
37980
37871
|
return diagnostics;
|
|
37981
37872
|
};
|
|
37982
37873
|
const DEAD_CODE_RULE_KEY_PREFIX = `${DEAD_CODE_PLUGIN}/`;
|
|
@@ -38087,8 +37978,7 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
38087
37978
|
workerTimeoutMs: input.workerTimeoutMs,
|
|
38088
37979
|
abortSignal: signal,
|
|
38089
37980
|
cacheEnabled,
|
|
38090
|
-
onCacheOutcome: input.onCacheOutcome
|
|
38091
|
-
onSummaryCacheStats: input.onSummaryCacheStats
|
|
37981
|
+
onCacheOutcome: input.onCacheOutcome
|
|
38092
37982
|
}),
|
|
38093
37983
|
catch: (cause) => new ReactDoctorError({ reason: new DeadCodeAnalysisFailed({ cause }) })
|
|
38094
37984
|
}).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)));
|
|
@@ -38958,7 +38848,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38958
38848
|
}
|
|
38959
38849
|
return enabled;
|
|
38960
38850
|
};
|
|
38961
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection
|
|
38851
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection }) => {
|
|
38962
38852
|
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38963
38853
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38964
38854
|
const jsPlugins = [];
|
|
@@ -38970,7 +38860,6 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
38970
38860
|
if (!rule) continue;
|
|
38971
38861
|
if (ruleSelection === "cacheable" && CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
38972
38862
|
if (ruleSelection === "sidecar" && !CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
38973
|
-
if (ruleSelection === "sidecar" && sidecarRuleIdFilter !== void 0 && !sidecarRuleIdFilter.has(registryEntry.id)) continue;
|
|
38974
38863
|
if (rule.scan !== void 0) continue;
|
|
38975
38864
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
38976
38865
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
@@ -39015,23 +38904,23 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39015
38904
|
}
|
|
39016
38905
|
};
|
|
39017
38906
|
};
|
|
39018
|
-
const validateDiagnostic
|
|
38907
|
+
const validateDiagnostic = decodeUnknownSync(Diagnostic);
|
|
39019
38908
|
const decodeFileDiagnostics = (raw) => {
|
|
39020
38909
|
if (!Array.isArray(raw)) return null;
|
|
39021
38910
|
try {
|
|
39022
|
-
for (const entry of raw) validateDiagnostic
|
|
38911
|
+
for (const entry of raw) validateDiagnostic(entry);
|
|
39023
38912
|
return raw;
|
|
39024
38913
|
} catch {
|
|
39025
38914
|
return null;
|
|
39026
38915
|
}
|
|
39027
38916
|
};
|
|
39028
|
-
const emptyCache
|
|
38917
|
+
const emptyCache = () => ({
|
|
39029
38918
|
version: 1,
|
|
39030
38919
|
rulesets: {}
|
|
39031
38920
|
});
|
|
39032
|
-
const loadRulesetEntries
|
|
38921
|
+
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
39033
38922
|
const entries = /* @__PURE__ */ new Map();
|
|
39034
|
-
const persisted = failOpenReadJson(cacheFilePath, emptyCache
|
|
38923
|
+
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
39035
38924
|
if (persisted.version !== 1 || !isRecord(persisted.rulesets)) return entries;
|
|
39036
38925
|
const bucket = persisted.rulesets[rulesetHash];
|
|
39037
38926
|
if (!isRecord(bucket) || !isRecord(bucket.files)) return entries;
|
|
@@ -39043,149 +38932,20 @@ const loadRulesetEntries$1 = (cacheFilePath, rulesetHash) => {
|
|
|
39043
38932
|
};
|
|
39044
38933
|
const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
39045
38934
|
const cacheFilePath = Path.join(cacheDirectory, FILE_LINT_CACHE_FILENAME);
|
|
39046
|
-
const entries = loadRulesetEntries
|
|
38935
|
+
const entries = loadRulesetEntries(cacheFilePath, rulesetHash);
|
|
39047
38936
|
return {
|
|
39048
38937
|
lookup: (fileKey) => entries.get(fileKey) ?? null,
|
|
39049
38938
|
store: (fileKey, diagnostics) => {
|
|
39050
38939
|
entries.delete(fileKey);
|
|
39051
38940
|
entries.set(fileKey, diagnostics);
|
|
39052
38941
|
},
|
|
39053
|
-
persist: () => {
|
|
39054
|
-
const onDisk = failOpenReadJson(cacheFilePath, emptyCache$1());
|
|
39055
|
-
const rulesets = onDisk.version === 1 && isRecord(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
39056
|
-
const existingBucket = rulesets[rulesetHash];
|
|
39057
|
-
const existingFiles = isRecord(existingBucket) && isRecord(existingBucket.files) ? existingBucket.files : {};
|
|
39058
|
-
const ourFiles = {};
|
|
39059
|
-
for (const [fileKey, diagnostics] of entries) ourFiles[fileKey] = diagnostics;
|
|
39060
|
-
const cappedEntries = Object.entries({
|
|
39061
|
-
...existingFiles,
|
|
39062
|
-
...ourFiles
|
|
39063
|
-
}).slice(-FILE_LINT_CACHE_MAX_FILE_COUNT);
|
|
39064
|
-
rulesets[rulesetHash] = {
|
|
39065
|
-
updatedAtMs: Date.now(),
|
|
39066
|
-
files: Object.fromEntries(cappedEntries)
|
|
39067
|
-
};
|
|
39068
|
-
atomicWriteJson(cacheFilePath, {
|
|
39069
|
-
version: 1,
|
|
39070
|
-
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
39071
|
-
});
|
|
39072
|
-
}
|
|
39073
|
-
};
|
|
39074
|
-
};
|
|
39075
|
-
const ABSENT_CONTENT_ANSWER = "absent";
|
|
39076
|
-
/**
|
|
39077
|
-
* Answers dependency probes for the sidecar lint cache — used both when
|
|
39078
|
-
* STORING an entry (turn the collector's probe paths into answers) and when
|
|
39079
|
-
* VERIFYING one (re-answer each stored probe against the current tree).
|
|
39080
|
-
* Store and verify must agree exactly, so both go through this one resolver.
|
|
39081
|
-
*
|
|
39082
|
-
* - `content` — SHA-1 of the file's bytes, `"absent"` when unreadable
|
|
39083
|
-
* (missing, a directory, permission failure). Source files reuse the
|
|
39084
|
-
* hashes the cache-partition loop already computed
|
|
39085
|
-
* (`contentHashByRelativePath`); everything else (package.json,
|
|
39086
|
-
* tsconfig, ignored files) is hashed on demand.
|
|
39087
|
-
* - `exists` — the existence class a module-resolution candidate probe
|
|
39088
|
-
* sees: `"file"`, `"dir"`, or `"none"` (missing or an exotic entry —
|
|
39089
|
-
* `statSync` follows symlinks, matching the resolvers).
|
|
39090
|
-
*
|
|
39091
|
-
* Answers are memoized per scan: the filesystem is frozen for the run, and
|
|
39092
|
-
* hot dependency paths (a barrel imported by hundreds of files, the shared
|
|
39093
|
-
* tsconfig chain) repeat across many files' probe sets.
|
|
39094
|
-
*/
|
|
39095
|
-
const createSidecarProbeAnswerResolver = (input) => {
|
|
39096
|
-
const contentAnswerByPath = /* @__PURE__ */ new Map();
|
|
39097
|
-
const existsAnswerByPath = /* @__PURE__ */ new Map();
|
|
39098
|
-
const toRelativePath = (absolutePath) => Path.relative(input.rootDirectory, absolutePath).replaceAll("\\", "/");
|
|
39099
|
-
const contentAnswer = (relativePath) => {
|
|
39100
|
-
const memoized = contentAnswerByPath.get(relativePath);
|
|
39101
|
-
if (memoized !== void 0) return memoized;
|
|
39102
|
-
const answer = input.contentHashByRelativePath.get(relativePath) ?? hashFileContents(Path.resolve(input.rootDirectory, relativePath)) ?? ABSENT_CONTENT_ANSWER;
|
|
39103
|
-
contentAnswerByPath.set(relativePath, answer);
|
|
39104
|
-
return answer;
|
|
39105
|
-
};
|
|
39106
|
-
const existsAnswer = (relativePath) => {
|
|
39107
|
-
const memoized = existsAnswerByPath.get(relativePath);
|
|
39108
|
-
if (memoized !== void 0) return memoized;
|
|
39109
|
-
let answer;
|
|
39110
|
-
try {
|
|
39111
|
-
const stat = NFS.statSync(Path.resolve(input.rootDirectory, relativePath));
|
|
39112
|
-
answer = stat.isFile() ? "file" : stat.isDirectory() ? "dir" : "none";
|
|
39113
|
-
} catch {
|
|
39114
|
-
answer = "none";
|
|
39115
|
-
}
|
|
39116
|
-
existsAnswerByPath.set(relativePath, answer);
|
|
39117
|
-
return answer;
|
|
39118
|
-
};
|
|
39119
|
-
return {
|
|
39120
|
-
answerFor: (kind, relativePath) => kind === "content" ? contentAnswer(relativePath) : existsAnswer(relativePath),
|
|
39121
|
-
toRelativePath
|
|
39122
|
-
};
|
|
39123
|
-
};
|
|
39124
|
-
const validateDiagnostic = decodeUnknownSync(Diagnostic);
|
|
39125
|
-
const isProbeKind = (value) => value === "content" || value === "exists";
|
|
39126
|
-
const decodeSidecarFileEntry = (raw) => {
|
|
39127
|
-
if (!isRecord(raw) || !Array.isArray(raw.probes) || !Array.isArray(raw.diagnostics)) return null;
|
|
39128
|
-
const probes = [];
|
|
39129
|
-
for (const rawProbe of raw.probes) {
|
|
39130
|
-
if (!Array.isArray(rawProbe) || rawProbe.length !== 3) return null;
|
|
39131
|
-
const [kind, probePath, answer] = rawProbe;
|
|
39132
|
-
if (!isProbeKind(kind) || typeof probePath !== "string" || typeof answer !== "string") return null;
|
|
39133
|
-
probes.push({
|
|
39134
|
-
kind,
|
|
39135
|
-
path: probePath,
|
|
39136
|
-
answer
|
|
39137
|
-
});
|
|
39138
|
-
}
|
|
39139
|
-
try {
|
|
39140
|
-
for (const entry of raw.diagnostics) validateDiagnostic(entry);
|
|
39141
|
-
} catch {
|
|
39142
|
-
return null;
|
|
39143
|
-
}
|
|
39144
|
-
return {
|
|
39145
|
-
probes,
|
|
39146
|
-
diagnostics: raw.diagnostics
|
|
39147
|
-
};
|
|
39148
|
-
};
|
|
39149
|
-
const encodeSidecarFileEntry = (entry) => ({
|
|
39150
|
-
probes: entry.probes.map((probe) => [
|
|
39151
|
-
probe.kind,
|
|
39152
|
-
probe.path,
|
|
39153
|
-
probe.answer
|
|
39154
|
-
]),
|
|
39155
|
-
diagnostics: entry.diagnostics
|
|
39156
|
-
});
|
|
39157
|
-
const emptyCache = () => ({
|
|
39158
|
-
version: 1,
|
|
39159
|
-
rulesets: {}
|
|
39160
|
-
});
|
|
39161
|
-
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
39162
|
-
const entries = /* @__PURE__ */ new Map();
|
|
39163
|
-
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
39164
|
-
if (persisted.version !== 1 || !isRecord(persisted.rulesets)) return entries;
|
|
39165
|
-
const bucket = persisted.rulesets[rulesetHash];
|
|
39166
|
-
if (!isRecord(bucket) || !isRecord(bucket.files)) return entries;
|
|
39167
|
-
for (const [fileKey, rawEntry] of Object.entries(bucket.files)) {
|
|
39168
|
-
const decoded = decodeSidecarFileEntry(rawEntry);
|
|
39169
|
-
if (decoded !== null) entries.set(fileKey, decoded);
|
|
39170
|
-
}
|
|
39171
|
-
return entries;
|
|
39172
|
-
};
|
|
39173
|
-
const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
39174
|
-
const cacheFilePath = Path.join(cacheDirectory, SIDECAR_LINT_CACHE_FILENAME);
|
|
39175
|
-
const entries = loadRulesetEntries(cacheFilePath, rulesetHash);
|
|
39176
|
-
return {
|
|
39177
|
-
lookup: (fileKey) => entries.get(fileKey) ?? null,
|
|
39178
|
-
store: (fileKey, entry) => {
|
|
39179
|
-
entries.delete(fileKey);
|
|
39180
|
-
entries.set(fileKey, entry);
|
|
39181
|
-
},
|
|
39182
38942
|
persist: () => {
|
|
39183
38943
|
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
39184
38944
|
const rulesets = onDisk.version === 1 && isRecord(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
39185
38945
|
const existingBucket = rulesets[rulesetHash];
|
|
39186
38946
|
const existingFiles = isRecord(existingBucket) && isRecord(existingBucket.files) ? existingBucket.files : {};
|
|
39187
38947
|
const ourFiles = {};
|
|
39188
|
-
for (const [fileKey,
|
|
38948
|
+
for (const [fileKey, diagnostics] of entries) ourFiles[fileKey] = diagnostics;
|
|
39189
38949
|
const cappedEntries = Object.entries({
|
|
39190
38950
|
...existingFiles,
|
|
39191
38951
|
...ourFiles
|
|
@@ -40200,6 +39960,13 @@ const validateRuleRegistration = () => {
|
|
|
40200
39960
|
].filter((entry) => entry !== null).join("; ");
|
|
40201
39961
|
console.warn(`[react-doctor] rule-registration drift: ${detail}`);
|
|
40202
39962
|
};
|
|
39963
|
+
const hashFileContents = (filePath) => {
|
|
39964
|
+
try {
|
|
39965
|
+
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
39966
|
+
} catch {
|
|
39967
|
+
return null;
|
|
39968
|
+
}
|
|
39969
|
+
};
|
|
40203
39970
|
/**
|
|
40204
39971
|
* Balanced LPT (longest-processing-time-first) lint batch planner. Where
|
|
40205
39972
|
* `batchIncludePaths` greedily fills 100-file batches and leaves a small
|
|
@@ -40281,106 +40048,6 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
40281
40048
|
NFS.closeSync(fileHandle);
|
|
40282
40049
|
}
|
|
40283
40050
|
};
|
|
40284
|
-
/**
|
|
40285
|
-
* Attributes diagnostics back to the file that produced them by the
|
|
40286
|
-
* normalized path oxlint echoes. Returns `null` when ANY diagnostic can't be
|
|
40287
|
-
* attributed — the path forms don't align, so the caller must skip its cache
|
|
40288
|
-
* store rather than risk caching a wrong empty result for a file that
|
|
40289
|
-
* actually had diagnostics.
|
|
40290
|
-
*/
|
|
40291
|
-
const attributeDiagnosticsToFiles = (diagnostics, files) => {
|
|
40292
|
-
const fileByNormalizedPath = /* @__PURE__ */ new Map();
|
|
40293
|
-
for (const file of files) fileByNormalizedPath.set(file.replaceAll("\\", "/"), file);
|
|
40294
|
-
const diagnosticsByFile = /* @__PURE__ */ new Map();
|
|
40295
|
-
for (const diagnostic of diagnostics) {
|
|
40296
|
-
const file = fileByNormalizedPath.get(diagnostic.filePath);
|
|
40297
|
-
if (file === void 0) return null;
|
|
40298
|
-
const fileDiagnostics = diagnosticsByFile.get(file) ?? [];
|
|
40299
|
-
fileDiagnostics.push(diagnostic);
|
|
40300
|
-
diagnosticsByFile.set(file, fileDiagnostics);
|
|
40301
|
-
}
|
|
40302
|
-
return diagnosticsByFile;
|
|
40303
|
-
};
|
|
40304
|
-
/**
|
|
40305
|
-
* Collects each file's cross-file dependency probes (via the plugin's
|
|
40306
|
-
* collectors) with their current answers. Fail-open per file: an unreadable /
|
|
40307
|
-
* unparseable / collector-failing file maps to `null` (no entry stored — it
|
|
40308
|
-
* re-lints next scan). The filesystem is frozen for the scan, so this can run
|
|
40309
|
-
* CONCURRENTLY with an oxlint child-process await — the caller starts it
|
|
40310
|
-
* unawaited before a lint pass and awaits it at store time, hiding the
|
|
40311
|
-
* in-process parse + resolution cost under the subprocess wait. The loop
|
|
40312
|
-
* yields on the cooperative time budget so the child's stdout handling (and
|
|
40313
|
-
* sibling fibers) keep flowing; each per-file collection is synchronous, so
|
|
40314
|
-
* the module-level probe recorder never sees interleaved use. Never rejects.
|
|
40315
|
-
*/
|
|
40316
|
-
const collectSidecarProbesForFiles = async (input) => {
|
|
40317
|
-
const buildProbes = (file) => {
|
|
40318
|
-
const absoluteFilePath = Path.resolve(input.rootDirectory, file);
|
|
40319
|
-
let trace;
|
|
40320
|
-
try {
|
|
40321
|
-
trace = collectCrossFileDependencyProbes({
|
|
40322
|
-
absoluteFilePath,
|
|
40323
|
-
sourceText: NFS.readFileSync(absoluteFilePath, "utf8"),
|
|
40324
|
-
ruleIds: input.boundedSidecarRuleIds
|
|
40325
|
-
});
|
|
40326
|
-
} catch {
|
|
40327
|
-
return null;
|
|
40328
|
-
}
|
|
40329
|
-
if (trace === null) return null;
|
|
40330
|
-
const probes = [];
|
|
40331
|
-
for (const contentPath of trace.contentPaths) {
|
|
40332
|
-
const relativePath = input.probeAnswers.toRelativePath(contentPath);
|
|
40333
|
-
probes.push({
|
|
40334
|
-
kind: "content",
|
|
40335
|
-
path: relativePath,
|
|
40336
|
-
answer: input.probeAnswers.answerFor("content", relativePath)
|
|
40337
|
-
});
|
|
40338
|
-
}
|
|
40339
|
-
for (const existencePath of trace.existencePaths) {
|
|
40340
|
-
const relativePath = input.probeAnswers.toRelativePath(existencePath);
|
|
40341
|
-
probes.push({
|
|
40342
|
-
kind: "exists",
|
|
40343
|
-
path: relativePath,
|
|
40344
|
-
answer: input.probeAnswers.answerFor("exists", relativePath)
|
|
40345
|
-
});
|
|
40346
|
-
}
|
|
40347
|
-
return probes;
|
|
40348
|
-
};
|
|
40349
|
-
const probesByFile = /* @__PURE__ */ new Map();
|
|
40350
|
-
let collectSliceStartedAt = performance.now();
|
|
40351
|
-
for (const file of input.files) {
|
|
40352
|
-
probesByFile.set(file, buildProbes(file));
|
|
40353
|
-
if (performance.now() - collectSliceStartedAt >= 12) {
|
|
40354
|
-
await yieldToEventLoop();
|
|
40355
|
-
collectSliceStartedAt = performance.now();
|
|
40356
|
-
}
|
|
40357
|
-
}
|
|
40358
|
-
return probesByFile;
|
|
40359
|
-
};
|
|
40360
|
-
/**
|
|
40361
|
-
* Stores each freshly-linted file's probe set + cross-file diagnostics so
|
|
40362
|
-
* the next scan can replay instead of re-linting.
|
|
40363
|
-
*/
|
|
40364
|
-
const storeSidecarEntries = (input) => {
|
|
40365
|
-
let didStoreAnyEntry = false;
|
|
40366
|
-
for (const pass of input.storablePasses) {
|
|
40367
|
-
if (!pass.isTrusted) continue;
|
|
40368
|
-
const diagnosticsByFile = attributeDiagnosticsToFiles(pass.diagnostics, pass.files);
|
|
40369
|
-
if (diagnosticsByFile === null) continue;
|
|
40370
|
-
for (const file of pass.files) {
|
|
40371
|
-
const cacheKey = input.cacheKeyByFile.get(file);
|
|
40372
|
-
if (cacheKey === void 0) continue;
|
|
40373
|
-
const probes = pass.probesByFile.get(file);
|
|
40374
|
-
if (probes === void 0 || probes === null) continue;
|
|
40375
|
-
input.sidecarCache.store(cacheKey, {
|
|
40376
|
-
probes,
|
|
40377
|
-
diagnostics: diagnosticsByFile.get(file) ?? []
|
|
40378
|
-
});
|
|
40379
|
-
didStoreAnyEntry = true;
|
|
40380
|
-
}
|
|
40381
|
-
}
|
|
40382
|
-
if (didStoreAnyEntry) input.sidecarCache.persist();
|
|
40383
|
-
};
|
|
40384
40051
|
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
40385
40052
|
/**
|
|
40386
40053
|
* Detects an oxlint config-load crash caused by the optional
|
|
@@ -40422,7 +40089,7 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
40422
40089
|
* 6. always restore disable directives + clean up the temp dir
|
|
40423
40090
|
*/
|
|
40424
40091
|
const runOxlint = async (options) => {
|
|
40425
|
-
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, perFileLintCacheEnabled = false,
|
|
40092
|
+
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;
|
|
40426
40093
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
40427
40094
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
40428
40095
|
validateRuleRegistration();
|
|
@@ -40440,8 +40107,7 @@ const runOxlint = async (options) => {
|
|
|
40440
40107
|
severityControls,
|
|
40441
40108
|
userPlugins,
|
|
40442
40109
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
40443
|
-
ruleSelection: overrides.ruleSelection
|
|
40444
|
-
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
40110
|
+
ruleSelection: overrides.ruleSelection
|
|
40445
40111
|
});
|
|
40446
40112
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
40447
40113
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -40544,18 +40210,15 @@ const runOxlint = async (options) => {
|
|
|
40544
40210
|
});
|
|
40545
40211
|
const cache = createFileLintCache(resolveReactDoctorCacheDir(rootDirectory), rulesetHash);
|
|
40546
40212
|
const cacheKeyByFile = /* @__PURE__ */ new Map();
|
|
40547
|
-
const contentHashByRelativePath = /* @__PURE__ */ new Map();
|
|
40548
40213
|
const missFiles = [];
|
|
40549
40214
|
const replayedDiagnostics = [];
|
|
40550
40215
|
let hashSliceStartedAt = performance.now();
|
|
40551
40216
|
for (const candidateFile of candidateFiles) {
|
|
40552
|
-
const
|
|
40553
|
-
const contentHash = hashFileContents(absoluteCandidatePath);
|
|
40217
|
+
const contentHash = hashFileContents(Path.resolve(rootDirectory, candidateFile));
|
|
40554
40218
|
if (contentHash === null) {
|
|
40555
40219
|
missFiles.push(candidateFile);
|
|
40556
40220
|
continue;
|
|
40557
40221
|
}
|
|
40558
|
-
contentHashByRelativePath.set(Path.relative(rootDirectory, absoluteCandidatePath).replaceAll("\\", "/"), contentHash);
|
|
40559
40222
|
const cacheKey = `${candidateFile.replaceAll("\\", "/")}\u0000${contentHash}`;
|
|
40560
40223
|
cacheKeyByFile.set(candidateFile, cacheKey);
|
|
40561
40224
|
const cachedDiagnostics = cache.lookup(cacheKey);
|
|
@@ -40567,111 +40230,43 @@ const runOxlint = async (options) => {
|
|
|
40567
40230
|
}
|
|
40568
40231
|
}
|
|
40569
40232
|
const cacheHitFileCount = candidateFiles.length - missFiles.length;
|
|
40570
|
-
const enabledSidecarRuleIds = Object.keys(buildConfig({
|
|
40571
|
-
extendsPaths: [],
|
|
40572
|
-
ruleSelection: "sidecar"
|
|
40573
|
-
}).rules).map((ruleKey) => ruleKey.slice(ruleKey.lastIndexOf("/") + 1)).filter((ruleId) => CROSS_FILE_RULE_IDS.has(ruleId));
|
|
40574
|
-
const boundedSidecarRuleIds = enabledSidecarRuleIds.filter((ruleId) => CROSS_FILE_DEPENDENCY_COLLECTORS.has(ruleId));
|
|
40575
|
-
const boundedSidecarRuleIdSet = new Set(boundedSidecarRuleIds);
|
|
40576
|
-
const unboundedSidecarRuleIds = enabledSidecarRuleIds.filter((ruleId) => !CROSS_FILE_DEPENDENCY_COLLECTORS.has(ruleId));
|
|
40577
|
-
const useSidecarCache = sidecarLintCacheEnabled && boundedSidecarRuleIds.length > 0;
|
|
40578
|
-
const sidecarCache = useSidecarCache ? createSidecarLintCache(resolveReactDoctorCacheDir(rootDirectory), computeRulesetHash({
|
|
40579
|
-
config: buildConfig({
|
|
40580
|
-
extendsPaths: [],
|
|
40581
|
-
ruleSelection: "sidecar",
|
|
40582
|
-
sidecarRuleIdFilter: boundedSidecarRuleIdSet
|
|
40583
|
-
}),
|
|
40584
|
-
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
40585
|
-
ignorePatterns: combinedPatterns,
|
|
40586
|
-
tsconfigContent
|
|
40587
|
-
})) : null;
|
|
40588
|
-
const probeAnswers = createSidecarProbeAnswerResolver({
|
|
40589
|
-
rootDirectory,
|
|
40590
|
-
contentHashByRelativePath
|
|
40591
|
-
});
|
|
40592
|
-
const missProbesTask = sidecarCache === null ? null : collectSidecarProbesForFiles({
|
|
40593
|
-
files: missFiles,
|
|
40594
|
-
rootDirectory,
|
|
40595
|
-
boundedSidecarRuleIds,
|
|
40596
|
-
probeAnswers
|
|
40597
|
-
});
|
|
40598
40233
|
const fullResult = await runConfigOverFiles((overrides) => buildConfig({
|
|
40599
40234
|
extendsPaths: [],
|
|
40600
40235
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
40601
40236
|
}), "oxlintrc.full.json", missFiles, options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(scannedFileCount, candidateFiles.length)));
|
|
40602
40237
|
const missFileSet = new Set(missFiles);
|
|
40603
|
-
const
|
|
40604
|
-
const sidecarReplayedDiagnostics = [];
|
|
40605
|
-
const sidecarLintFiles = [];
|
|
40606
|
-
if (sidecarCache === null) sidecarLintFiles.push(...hitFiles);
|
|
40607
|
-
else {
|
|
40608
|
-
let verifySliceStartedAt = performance.now();
|
|
40609
|
-
for (const hitFile of hitFiles) {
|
|
40610
|
-
const cacheKey = cacheKeyByFile.get(hitFile);
|
|
40611
|
-
const entry = cacheKey === void 0 ? null : sidecarCache.lookup(cacheKey);
|
|
40612
|
-
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer)) sidecarReplayedDiagnostics.push(...entry.diagnostics);
|
|
40613
|
-
else sidecarLintFiles.push(hitFile);
|
|
40614
|
-
if (performance.now() - verifySliceStartedAt >= 12) {
|
|
40615
|
-
await yieldToEventLoop();
|
|
40616
|
-
verifySliceStartedAt = performance.now();
|
|
40617
|
-
}
|
|
40618
|
-
}
|
|
40619
|
-
}
|
|
40620
|
-
const sidecarProbesTask = sidecarCache === null ? null : collectSidecarProbesForFiles({
|
|
40621
|
-
files: sidecarLintFiles,
|
|
40622
|
-
rootDirectory,
|
|
40623
|
-
boundedSidecarRuleIds,
|
|
40624
|
-
probeAnswers
|
|
40625
|
-
});
|
|
40626
|
-
const sidecarReplayedFileCount = hitFiles.length - sidecarLintFiles.length;
|
|
40627
|
-
if (sidecarReplayedFileCount > 0) options.onFileProgress?.(missFiles.length + sidecarReplayedFileCount, candidateFiles.length);
|
|
40628
|
-
const boundedSidecarResult = await runConfigOverFiles(() => buildConfig({
|
|
40629
|
-
extendsPaths: [],
|
|
40630
|
-
ruleSelection: "sidecar",
|
|
40631
|
-
...useSidecarCache ? { sidecarRuleIdFilter: boundedSidecarRuleIdSet } : {}
|
|
40632
|
-
}), "oxlintrc.sidecar.json", sidecarLintFiles, options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(missFiles.length + sidecarReplayedFileCount + scannedFileCount, candidateFiles.length)));
|
|
40633
|
-
const unboundedSidecarResult = useSidecarCache && unboundedSidecarRuleIds.length > 0 ? await runConfigOverFiles(() => buildConfig({
|
|
40238
|
+
const sidecarResult = await runConfigOverFiles(() => buildConfig({
|
|
40634
40239
|
extendsPaths: [],
|
|
40635
|
-
ruleSelection: "sidecar"
|
|
40636
|
-
|
|
40637
|
-
}), "oxlintrc.sidecar-unbounded.json", hitFiles, void 0) : {
|
|
40638
|
-
diagnostics: [],
|
|
40639
|
-
didDropReactHooksJsPlugin: false,
|
|
40640
|
-
hadPartialFailure: false
|
|
40641
|
-
};
|
|
40240
|
+
ruleSelection: "sidecar"
|
|
40241
|
+
}), "oxlintrc.sidecar.json", candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile)), options.onFileProgress && ((scannedFileCount) => options.onFileProgress?.(missFiles.length + scannedFileCount, candidateFiles.length)));
|
|
40642
40242
|
const freshCacheableDiagnostics = [];
|
|
40643
40243
|
for (const diagnostic of fullResult.diagnostics) if (!CROSS_FILE_RULE_IDS.has(diagnostic.rule)) freshCacheableDiagnostics.push(diagnostic);
|
|
40644
40244
|
onCacheStats?.(cacheHitFileCount, candidateFiles.length);
|
|
40645
|
-
|
|
40646
|
-
const
|
|
40647
|
-
|
|
40245
|
+
const missFileByNormalizedPath = /* @__PURE__ */ new Map();
|
|
40246
|
+
for (const missFile of missFiles) missFileByNormalizedPath.set(missFile.replaceAll("\\", "/"), missFile);
|
|
40247
|
+
const freshDiagnosticsByFile = /* @__PURE__ */ new Map();
|
|
40248
|
+
let isAttributionSound = true;
|
|
40249
|
+
for (const diagnostic of freshCacheableDiagnostics) {
|
|
40250
|
+
const missFile = missFileByNormalizedPath.get(diagnostic.filePath);
|
|
40251
|
+
if (missFile === void 0) {
|
|
40252
|
+
isAttributionSound = false;
|
|
40253
|
+
break;
|
|
40254
|
+
}
|
|
40255
|
+
const fileDiagnostics = freshDiagnosticsByFile.get(missFile) ?? [];
|
|
40256
|
+
fileDiagnostics.push(diagnostic);
|
|
40257
|
+
freshDiagnosticsByFile.set(missFile, fileDiagnostics);
|
|
40258
|
+
}
|
|
40259
|
+
if (!fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure && isAttributionSound) {
|
|
40648
40260
|
for (const missFile of missFiles) {
|
|
40649
40261
|
const cacheKey = cacheKeyByFile.get(missFile);
|
|
40650
40262
|
if (cacheKey !== void 0) cache.store(cacheKey, freshDiagnosticsByFile.get(missFile) ?? []);
|
|
40651
40263
|
}
|
|
40652
40264
|
cache.persist();
|
|
40653
40265
|
}
|
|
40654
|
-
if (sidecarCache !== null && missProbesTask !== null && sidecarProbesTask !== null) storeSidecarEntries({
|
|
40655
|
-
sidecarCache,
|
|
40656
|
-
cacheKeyByFile,
|
|
40657
|
-
storablePasses: [{
|
|
40658
|
-
files: sidecarLintFiles,
|
|
40659
|
-
diagnostics: boundedSidecarResult.diagnostics,
|
|
40660
|
-
isTrusted: !boundedSidecarResult.hadPartialFailure,
|
|
40661
|
-
probesByFile: await sidecarProbesTask
|
|
40662
|
-
}, {
|
|
40663
|
-
files: missFiles,
|
|
40664
|
-
diagnostics: fullResult.diagnostics.filter((diagnostic) => boundedSidecarRuleIdSet.has(diagnostic.rule)),
|
|
40665
|
-
isTrusted: !fullResult.didDropReactHooksJsPlugin && !fullResult.hadPartialFailure,
|
|
40666
|
-
probesByFile: await missProbesTask
|
|
40667
|
-
}]
|
|
40668
|
-
});
|
|
40669
40266
|
return dedupeDiagnostics([
|
|
40670
40267
|
...replayedDiagnostics,
|
|
40671
40268
|
...fullResult.diagnostics,
|
|
40672
|
-
...
|
|
40673
|
-
...boundedSidecarResult.diagnostics,
|
|
40674
|
-
...unboundedSidecarResult.diagnostics
|
|
40269
|
+
...sidecarResult.diagnostics
|
|
40675
40270
|
]);
|
|
40676
40271
|
}
|
|
40677
40272
|
const baseArgs = makeBaseArgs(configPath);
|
|
@@ -40769,7 +40364,6 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
40769
40364
|
const concurrency = yield* OxlintConcurrency;
|
|
40770
40365
|
const lintBatchOrdering = yield* LintBatchOrdering;
|
|
40771
40366
|
const perFileLintCacheEnabled = yield* PerFileLintCacheEnabled;
|
|
40772
|
-
const sidecarLintCacheEnabled = yield* SidecarLintCacheEnabled;
|
|
40773
40367
|
const collectedFailures = [];
|
|
40774
40368
|
const diagnostics = yield* tryPromise({
|
|
40775
40369
|
try: (signal) => runOxlint({
|
|
@@ -40788,9 +40382,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
40788
40382
|
},
|
|
40789
40383
|
onFileProgress: input.onFileProgress,
|
|
40790
40384
|
perFileLintCacheEnabled,
|
|
40791
|
-
sidecarLintCacheEnabled,
|
|
40792
40385
|
onCacheStats: input.onCacheStats,
|
|
40793
|
-
onSidecarStats: input.onSidecarStats,
|
|
40794
40386
|
spawnTimeoutMs,
|
|
40795
40387
|
outputMaxBytes,
|
|
40796
40388
|
concurrency,
|
|
@@ -41212,20 +40804,6 @@ const writeCachedSocketBody = (cacheFile, body) => {
|
|
|
41212
40804
|
}));
|
|
41213
40805
|
} catch {}
|
|
41214
40806
|
};
|
|
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
|
-
};
|
|
41229
40807
|
const fetchSocketArtifact = (dependency, cacheDirectory) => tryPromise(async (signal) => {
|
|
41230
40808
|
const cacheFile = cacheDirectory === null ? null : supplyChainCacheFile(cacheDirectory, dependency);
|
|
41231
40809
|
if (cacheFile !== null) {
|
|
@@ -41353,7 +40931,6 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
41353
40931
|
const dependencies = collectDependenciesToScore(readPackageJson(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies);
|
|
41354
40932
|
if (dependencies.length === 0) return [];
|
|
41355
40933
|
const cacheDirectory = isSupplyChainCacheDisabled() ? null : resolveReactDoctorCacheDir(input.rootDirectory);
|
|
41356
|
-
if (cacheDirectory !== null) pruneExpiredSocketCache(cacheDirectory);
|
|
41357
40934
|
const artifacts = yield* forEach$1(dependencies, (dependency) => fetchSocketArtifact(dependency, cacheDirectory), { concurrency: 8 }).pipe(timeoutOption(input.totalTimeoutMs ?? 9e4), map$3((maybeArtifacts) => getOrElse$1(maybeArtifacts, () => [])));
|
|
41358
40935
|
const diagnostics = [];
|
|
41359
40936
|
for (let index = 0; index < dependencies.length; index += 1) {
|
|
@@ -41583,10 +41160,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41583
41160
|
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
|
|
41584
41161
|
onCacheOutcome: (didHitCache) => {
|
|
41585
41162
|
deadCodeCacheHit = didHitCache;
|
|
41586
|
-
},
|
|
41587
|
-
onSummaryCacheStats: (stats) => {
|
|
41588
|
-
deadCodeSummaryCacheHits = stats.hits;
|
|
41589
|
-
deadCodeSummaryCacheMisses = stats.misses;
|
|
41590
41163
|
}
|
|
41591
41164
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
41592
41165
|
yield* set(deadCodeFailure, {
|
|
@@ -41615,11 +41188,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41615
41188
|
let lastReportedTotalFileCount = 0;
|
|
41616
41189
|
let lintCacheHitFileCount = null;
|
|
41617
41190
|
let lintCacheTotalFileCount = null;
|
|
41618
|
-
let lintSidecarReplayedFileCount = null;
|
|
41619
|
-
let lintSidecarTotalFileCount = null;
|
|
41620
41191
|
let deadCodeCacheHit = null;
|
|
41621
|
-
let deadCodeSummaryCacheHits = null;
|
|
41622
|
-
let deadCodeSummaryCacheMisses = null;
|
|
41623
41192
|
const baseLintStream = linterService.run({
|
|
41624
41193
|
rootDirectory: scanDirectory,
|
|
41625
41194
|
project,
|
|
@@ -41639,10 +41208,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41639
41208
|
lintCacheHitFileCount = cacheHitFileCount;
|
|
41640
41209
|
lintCacheTotalFileCount = totalConsideredFileCount;
|
|
41641
41210
|
},
|
|
41642
|
-
onSidecarStats: (sidecarReplayedFileCount, sidecarConsideredFileCount) => {
|
|
41643
|
-
lintSidecarReplayedFileCount = sidecarReplayedFileCount;
|
|
41644
|
-
lintSidecarTotalFileCount = sidecarConsideredFileCount;
|
|
41645
|
-
},
|
|
41646
41211
|
deadlineEpochMs: input.deadlineEpochMs
|
|
41647
41212
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
41648
41213
|
yield* set(lintFailure, {
|
|
@@ -41753,11 +41318,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41753
41318
|
securityScanFailed,
|
|
41754
41319
|
lintCacheHitFileCount,
|
|
41755
41320
|
lintCacheTotalFileCount,
|
|
41756
|
-
lintSidecarReplayedFileCount,
|
|
41757
|
-
lintSidecarTotalFileCount,
|
|
41758
41321
|
deadCodeCacheHit: lintFailureState.didFail ? null : deadCodeCacheHit,
|
|
41759
|
-
deadCodeSummaryCacheHits: lintFailureState.didFail ? null : deadCodeSummaryCacheHits,
|
|
41760
|
-
deadCodeSummaryCacheMisses: lintFailureState.didFail ? null : deadCodeSummaryCacheMisses,
|
|
41761
41322
|
suppressedRuleCounts: transform.summarizeSuppressions()
|
|
41762
41323
|
};
|
|
41763
41324
|
}).pipe(withSpan("runInspect", { attributes: {
|
|
@@ -42070,9 +41631,11 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
42070
41631
|
const parts = [`v=${version}`];
|
|
42071
41632
|
let directory = projectDirectory;
|
|
42072
41633
|
for (;;) {
|
|
42073
|
-
for (const filename of CONFIG_FINGERPRINT_FILENAMES) {
|
|
42074
|
-
const
|
|
42075
|
-
|
|
41634
|
+
for (const filename of CONFIG_FINGERPRINT_FILENAMES) try {
|
|
41635
|
+
const stat = fs.statSync(path.join(directory, filename));
|
|
41636
|
+
parts.push(`${directory}/${filename}=${stat.mtimeMs}:${stat.size}`);
|
|
41637
|
+
} catch {
|
|
41638
|
+
continue;
|
|
42076
41639
|
}
|
|
42077
41640
|
const parent = path.dirname(directory);
|
|
42078
41641
|
if (parent === directory) break;
|
|
@@ -44135,5 +43698,5 @@ const startLanguageServer = () => {
|
|
|
44135
43698
|
};
|
|
44136
43699
|
//#endregion
|
|
44137
43700
|
export { startLanguageServer };
|
|
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]="
|
|
44139
|
-
//# debugId=
|
|
43701
|
+
!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]="46e851cc-7b86-5c73-afb0-e09296beab28")}catch(e){}}();
|
|
43702
|
+
//# debugId=46e851cc-7b86-5c73-afb0-e09296beab28
|