react-doctor 0.5.8-dev.f853efd → 0.5.8-dev.fff9466
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/LICENSE +14 -1
- package/dist/cli.js +513 -220
- package/dist/index.d.ts +2 -2
- package/dist/index.js +236 -64
- package/dist/lsp.js +176 -65
- package/package.json +6 -5
package/dist/lsp.js
CHANGED
|
@@ -6021,7 +6021,7 @@ const composePassthrough = /* @__PURE__ */ dual(2, (left, right) => (input) => {
|
|
|
6021
6021
|
* @since 2.0.0
|
|
6022
6022
|
*/
|
|
6023
6023
|
const Scheduler = /* @__PURE__ */ Reference("effect/Scheduler", { defaultValue: () => new MixedScheduler() });
|
|
6024
|
-
const setImmediate = "setImmediate" in globalThis ? (f) => {
|
|
6024
|
+
const setImmediate$1 = "setImmediate" in globalThis ? (f) => {
|
|
6025
6025
|
const timer = globalThis.setImmediate(f);
|
|
6026
6026
|
return () => globalThis.clearImmediate(timer);
|
|
6027
6027
|
} : (f) => {
|
|
@@ -6065,7 +6065,7 @@ var PriorityBuckets = class {
|
|
|
6065
6065
|
var MixedScheduler = class {
|
|
6066
6066
|
executionMode;
|
|
6067
6067
|
setImmediate;
|
|
6068
|
-
constructor(executionMode = "async", setImmediateFn = setImmediate) {
|
|
6068
|
+
constructor(executionMode = "async", setImmediateFn = setImmediate$1) {
|
|
6069
6069
|
this.executionMode = executionMode;
|
|
6070
6070
|
this.setImmediate = setImmediateFn;
|
|
6071
6071
|
}
|
|
@@ -6090,7 +6090,7 @@ var MixedSchedulerDispatcher = class {
|
|
|
6090
6090
|
tasks = /* @__PURE__ */ new PriorityBuckets();
|
|
6091
6091
|
running = void 0;
|
|
6092
6092
|
setImmediate;
|
|
6093
|
-
constructor(setImmediateFn = setImmediate) {
|
|
6093
|
+
constructor(setImmediateFn = setImmediate$1) {
|
|
6094
6094
|
this.setImmediate = setImmediateFn;
|
|
6095
6095
|
}
|
|
6096
6096
|
/**
|
|
@@ -33730,6 +33730,7 @@ const MILLISECONDS_PER_SECOND = 1e3;
|
|
|
33730
33730
|
const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
33731
33731
|
const FETCH_TIMEOUT_MS = 1e4;
|
|
33732
33732
|
const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
|
|
33733
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
|
|
33733
33734
|
const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
|
|
33734
33735
|
const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
|
|
33735
33736
|
const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
|
|
@@ -33810,6 +33811,7 @@ const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
|
33810
33811
|
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
33811
33812
|
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
33812
33813
|
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
33814
|
+
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
33813
33815
|
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
33814
33816
|
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
33815
33817
|
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
@@ -35401,7 +35403,7 @@ const resolveScanConcurrency = (requested) => {
|
|
|
35401
35403
|
if (!Number.isFinite(requested) || requested < 1) return 1;
|
|
35402
35404
|
return Math.min(Math.floor(requested), 32);
|
|
35403
35405
|
};
|
|
35404
|
-
const readSystemFacts = () => ({
|
|
35406
|
+
const readSystemFacts$1 = () => ({
|
|
35405
35407
|
availableCores: os.availableParallelism(),
|
|
35406
35408
|
totalMemoryBytes: os.totalmem(),
|
|
35407
35409
|
cgroupMemoryLimitBytes: readCgroupMemoryLimitBytes()
|
|
@@ -35422,7 +35424,7 @@ const readSystemFacts = () => ({
|
|
|
35422
35424
|
* `facts` is injectable so tests exercise core-bound, memory-bound, cgroup-
|
|
35423
35425
|
* limited, and ceiling cases without mocking `os` or the filesystem.
|
|
35424
35426
|
*/
|
|
35425
|
-
const resolveAutoScanConcurrency = (facts = readSystemFacts()) => {
|
|
35427
|
+
const resolveAutoScanConcurrency = (facts = readSystemFacts$1()) => {
|
|
35426
35428
|
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
35427
35429
|
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / PER_WORKER_MEM_BUDGET_BYTES);
|
|
35428
35430
|
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
@@ -36907,7 +36909,10 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledBy)
|
|
|
36907
36909
|
}
|
|
36908
36910
|
return true;
|
|
36909
36911
|
};
|
|
36910
|
-
const
|
|
36912
|
+
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
36913
|
+
setImmediate(resolve);
|
|
36914
|
+
});
|
|
36915
|
+
const createSecurityScanSession = (rootDirectory, options) => {
|
|
36911
36916
|
const capabilities = options.project ? buildCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
36912
36917
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
36913
36918
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
@@ -36922,7 +36927,7 @@ const checkSecurityScan = (rootDirectory, options = {}) => {
|
|
|
36922
36927
|
committedFilesOnly: rule.committedFilesOnly === true
|
|
36923
36928
|
}];
|
|
36924
36929
|
});
|
|
36925
|
-
if (enabledScanRules.length === 0) return
|
|
36930
|
+
if (enabledScanRules.length === 0) return null;
|
|
36926
36931
|
const diagnostics = [];
|
|
36927
36932
|
const seen = /* @__PURE__ */ new Set();
|
|
36928
36933
|
const gitIgnoredCache = /* @__PURE__ */ new Map();
|
|
@@ -36934,15 +36939,34 @@ const checkSecurityScan = (rootDirectory, options = {}) => {
|
|
|
36934
36939
|
}
|
|
36935
36940
|
return status === true;
|
|
36936
36941
|
};
|
|
36937
|
-
|
|
36938
|
-
|
|
36939
|
-
|
|
36940
|
-
|
|
36941
|
-
|
|
36942
|
-
|
|
36943
|
-
|
|
36942
|
+
const scanFile = (file) => {
|
|
36943
|
+
for (const { entry, scan, committedFilesOnly } of enabledScanRules) for (const finding of scan(file)) {
|
|
36944
|
+
if (committedFilesOnly && isFileGitIgnored(file)) continue;
|
|
36945
|
+
const diagnostic = buildSecurityScanDiagnostic(finding, entry, file.relativePath);
|
|
36946
|
+
const key = `${diagnostic.rule}:${diagnostic.filePath}:${diagnostic.line}:${diagnostic.column}:${diagnostic.message}`;
|
|
36947
|
+
if (seen.has(key)) continue;
|
|
36948
|
+
seen.add(key);
|
|
36949
|
+
diagnostics.push(diagnostic);
|
|
36950
|
+
}
|
|
36951
|
+
};
|
|
36952
|
+
return {
|
|
36953
|
+
scanFile,
|
|
36954
|
+
diagnostics
|
|
36955
|
+
};
|
|
36956
|
+
};
|
|
36957
|
+
const checkSecurityScanCooperative = async (rootDirectory, options = {}) => {
|
|
36958
|
+
const session = createSecurityScanSession(rootDirectory, options);
|
|
36959
|
+
if (session === null) return [];
|
|
36960
|
+
let filesSinceYield = 0;
|
|
36961
|
+
for (const file of collectSecurityScanFiles(rootDirectory)) {
|
|
36962
|
+
session.scanFile(file);
|
|
36963
|
+
filesSinceYield += 1;
|
|
36964
|
+
if (filesSinceYield >= 16) {
|
|
36965
|
+
filesSinceYield = 0;
|
|
36966
|
+
await yieldToEventLoop();
|
|
36967
|
+
}
|
|
36944
36968
|
}
|
|
36945
|
-
return diagnostics;
|
|
36969
|
+
return session.diagnostics;
|
|
36946
36970
|
};
|
|
36947
36971
|
var import_picocolors = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
36948
36972
|
let p = process || {}, argv = p.argv || [], env = p.env || {};
|
|
@@ -37159,6 +37183,74 @@ const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
|
37159
37183
|
return [...seen].filter((pattern) => pattern.length > 0);
|
|
37160
37184
|
};
|
|
37161
37185
|
const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
|
|
37186
|
+
const readSystemFacts = () => ({
|
|
37187
|
+
availableCores: os.availableParallelism(),
|
|
37188
|
+
totalMemoryBytes: os.totalmem(),
|
|
37189
|
+
cgroupMemoryLimitBytes: readCgroupMemoryLimitBytes()
|
|
37190
|
+
});
|
|
37191
|
+
/**
|
|
37192
|
+
* How many real deslop dead-code child processes may run at once, across the
|
|
37193
|
+
* concurrent per-project `runInspect` fibers of one CLI run. The cap is the
|
|
37194
|
+
* smaller of the core count and the number of `DEAD_CODE_WORKER_MEM_BUDGET_BYTES`
|
|
37195
|
+
* workers that fit in available memory, floored at 1.
|
|
37196
|
+
*
|
|
37197
|
+
* On a roomy dev box / CI runner this resolves high enough that every
|
|
37198
|
+
* concurrently-scanned project still spawns its own worker (no serialization vs
|
|
37199
|
+
* the prior uncapped behavior); on a memory-constrained runner it collapses
|
|
37200
|
+
* toward 1, so the `withDeadCodeWorkerSlot` semaphore serializes the spawns
|
|
37201
|
+
* instead of oversubscribing memory with N simultaneous children — the global
|
|
37202
|
+
* cap the per-project spawn path lacked.
|
|
37203
|
+
*
|
|
37204
|
+
* Mirrors `resolveAutoScanConcurrency` (lint), but budgets memory per the
|
|
37205
|
+
* heavier dead-code worker. `facts` is injectable for tests.
|
|
37206
|
+
*/
|
|
37207
|
+
const resolveDeadCodeConcurrency = (facts = readSystemFacts()) => {
|
|
37208
|
+
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
37209
|
+
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / DEAD_CODE_WORKER_MEM_BUDGET_BYTES);
|
|
37210
|
+
return Math.max(1, Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
37211
|
+
};
|
|
37212
|
+
let availableSlots = -1;
|
|
37213
|
+
const waiters = [];
|
|
37214
|
+
const releaseSlot = () => {
|
|
37215
|
+
const nextWaiter = waiters.shift();
|
|
37216
|
+
if (nextWaiter !== void 0) nextWaiter();
|
|
37217
|
+
else availableSlots += 1;
|
|
37218
|
+
};
|
|
37219
|
+
/**
|
|
37220
|
+
* Runs `task` once a dead-code worker slot is free, releasing the slot when the
|
|
37221
|
+
* task settles (success or failure). With a high cap (roomy machine) every
|
|
37222
|
+
* caller proceeds immediately; with a low cap (constrained runner) callers
|
|
37223
|
+
* queue and run as slots free.
|
|
37224
|
+
*
|
|
37225
|
+
* `abortSignal` short-circuits the WAIT: if it's already aborted, or fires while
|
|
37226
|
+
* this caller is queued, the call rejects without acquiring a slot or running
|
|
37227
|
+
* `task` — so a cancelled scan (e.g. lint failed) doesn't sit in the queue and
|
|
37228
|
+
* then spawn a child only to tear it down. A queued caller that aborts removes
|
|
37229
|
+
* its own waiter so a later release never hands a slot to a dead request.
|
|
37230
|
+
*/
|
|
37231
|
+
const withDeadCodeWorkerSlot = async (task, abortSignal) => {
|
|
37232
|
+
if (abortSignal?.aborted) throw new Error("Dead-code worker aborted.");
|
|
37233
|
+
if (availableSlots < 0) availableSlots = resolveDeadCodeConcurrency();
|
|
37234
|
+
if (availableSlots > 0) availableSlots -= 1;
|
|
37235
|
+
else await new Promise((resolve, reject) => {
|
|
37236
|
+
const waiter = () => {
|
|
37237
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
37238
|
+
resolve();
|
|
37239
|
+
};
|
|
37240
|
+
const onAbort = () => {
|
|
37241
|
+
const queuedIndex = waiters.indexOf(waiter);
|
|
37242
|
+
if (queuedIndex !== -1) waiters.splice(queuedIndex, 1);
|
|
37243
|
+
reject(/* @__PURE__ */ new Error("Dead-code worker aborted."));
|
|
37244
|
+
};
|
|
37245
|
+
waiters.push(waiter);
|
|
37246
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
37247
|
+
});
|
|
37248
|
+
try {
|
|
37249
|
+
return await task();
|
|
37250
|
+
} finally {
|
|
37251
|
+
releaseSlot();
|
|
37252
|
+
}
|
|
37253
|
+
};
|
|
37162
37254
|
/**
|
|
37163
37255
|
* Resolves a path to its canonical, symlink-free form, falling back to
|
|
37164
37256
|
* the input when it cannot be realpath'd (broken symlink, permission
|
|
@@ -37183,6 +37275,11 @@ const toCanonicalPath = (filePath) => {
|
|
|
37183
37275
|
};
|
|
37184
37276
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
37185
37277
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
37278
|
+
const REACT_DOCTOR_TOOLCHAIN_PACKAGES = new Set([
|
|
37279
|
+
"react-doctor",
|
|
37280
|
+
"eslint-plugin-react-doctor",
|
|
37281
|
+
"oxlint-plugin-react-doctor"
|
|
37282
|
+
]);
|
|
37186
37283
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
37187
37284
|
const inputChunks = [];
|
|
37188
37285
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -37449,14 +37546,17 @@ const checkDeadCode = async (options) => {
|
|
|
37449
37546
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
37450
37547
|
const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
|
|
37451
37548
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37452
|
-
const
|
|
37453
|
-
|
|
37454
|
-
|
|
37455
|
-
|
|
37456
|
-
|
|
37457
|
-
|
|
37458
|
-
|
|
37459
|
-
|
|
37549
|
+
const spawnAndRun = () => {
|
|
37550
|
+
return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
37551
|
+
rootDirectory,
|
|
37552
|
+
entryPatterns,
|
|
37553
|
+
tsConfigPath: resolveTsConfigPath(rootDirectory),
|
|
37554
|
+
ignorePatterns,
|
|
37555
|
+
deslopJsModuleSpecifier: options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js"),
|
|
37556
|
+
parseConcurrency: options.parseConcurrency
|
|
37557
|
+
}), options.workerTimeoutMs ?? 12e4, options.abortSignal);
|
|
37558
|
+
};
|
|
37559
|
+
const result = parseDeadCodeWorkerResult(options.createWorker === void 0 ? await withDeadCodeWorkerSlot(spawnAndRun, options.abortSignal) : await spawnAndRun());
|
|
37460
37560
|
const toRelative = (filePath) => toRelativeFilePath(rootDirectory, filePath);
|
|
37461
37561
|
const diagnostics = [];
|
|
37462
37562
|
for (const unusedFile of result.unusedFiles) diagnostics.push({
|
|
@@ -37485,6 +37585,7 @@ const checkDeadCode = async (options) => {
|
|
|
37485
37585
|
});
|
|
37486
37586
|
}
|
|
37487
37587
|
for (const unusedDependency of result.unusedDependencies) {
|
|
37588
|
+
if (REACT_DOCTOR_TOOLCHAIN_PACKAGES.has(unusedDependency.name)) continue;
|
|
37488
37589
|
const label = unusedDependency.isDevDependency ? "devDependency" : "dependency";
|
|
37489
37590
|
diagnostics.push({
|
|
37490
37591
|
filePath: "package.json",
|
|
@@ -37857,43 +37958,46 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37857
37958
|
* reason: GitInvocationFailed })` so the rest of the codebase
|
|
37858
37959
|
* sees a single failure channel.
|
|
37859
37960
|
*/
|
|
37860
|
-
const runCommand = (input) =>
|
|
37861
|
-
const
|
|
37862
|
-
cwd: input.directory,
|
|
37863
|
-
env: input.env,
|
|
37864
|
-
extendEnv: true
|
|
37865
|
-
}));
|
|
37866
|
-
const maxStdoutBytes = input.maxStdoutBytes;
|
|
37867
|
-
const stdoutByteCount = yield* make$13(0);
|
|
37868
|
-
const [stdout, stderr, status] = yield* all([
|
|
37869
|
-
mkString(decodeText(maxStdoutBytes === void 0 ? handle.stdout : handle.stdout.pipe(tap((chunk) => updateAndGet(stdoutByteCount, (total) => total + chunk.length).pipe(flatMap$2((total) => total > maxStdoutBytes ? fail$4(new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
37870
|
-
args: [...input.args],
|
|
37871
|
-
directory: input.directory,
|
|
37872
|
-
cause: /* @__PURE__ */ new Error(`git stdout exceeded ${maxStdoutBytes} bytes`)
|
|
37873
|
-
}) })) : void_)))))),
|
|
37874
|
-
mkString(decodeText(handle.stderr)),
|
|
37875
|
-
handle.exitCode
|
|
37876
|
-
], { concurrency: 3 });
|
|
37877
|
-
return {
|
|
37878
|
-
status,
|
|
37879
|
-
stdout,
|
|
37880
|
-
stderr
|
|
37881
|
-
};
|
|
37882
|
-
})).pipe(catchTag$1("PlatformError", (cause) => {
|
|
37883
|
-
if (input.command !== "git") return succeed$2({
|
|
37961
|
+
const runCommand = (input) => {
|
|
37962
|
+
const foldSpawnFailure = (cause) => input.command !== "git" ? succeed$2({
|
|
37884
37963
|
status: 127,
|
|
37885
37964
|
stdout: "",
|
|
37886
37965
|
stderr: String(cause)
|
|
37887
|
-
})
|
|
37888
|
-
return new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
37966
|
+
}) : fail$4(new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
37889
37967
|
args: [...input.args],
|
|
37890
37968
|
directory: input.directory,
|
|
37891
37969
|
cause
|
|
37892
|
-
}) });
|
|
37893
|
-
|
|
37894
|
-
|
|
37895
|
-
|
|
37896
|
-
|
|
37970
|
+
}) }));
|
|
37971
|
+
return scoped(gen(function* () {
|
|
37972
|
+
if (!isDirectory(input.directory)) return yield* foldSpawnFailure(`spawn ENOTDIR (cwd is not a directory: ${input.directory})`);
|
|
37973
|
+
const argvLengthChars = input.command.length + 1 + input.args.reduce((total, arg) => total + arg.length + 1, 0);
|
|
37974
|
+
if (argvLengthChars > 24e3) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${SPAWN_ARGS_MAX_LENGTH_CHARS})`);
|
|
37975
|
+
const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
|
|
37976
|
+
cwd: input.directory,
|
|
37977
|
+
env: input.env,
|
|
37978
|
+
extendEnv: true
|
|
37979
|
+
}));
|
|
37980
|
+
const maxStdoutBytes = input.maxStdoutBytes;
|
|
37981
|
+
const stdoutByteCount = yield* make$13(0);
|
|
37982
|
+
const [stdout, stderr, status] = yield* all([
|
|
37983
|
+
mkString(decodeText(maxStdoutBytes === void 0 ? handle.stdout : handle.stdout.pipe(tap((chunk) => updateAndGet(stdoutByteCount, (total) => total + chunk.length).pipe(flatMap$2((total) => total > maxStdoutBytes ? fail$4(new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
37984
|
+
args: [...input.args],
|
|
37985
|
+
directory: input.directory,
|
|
37986
|
+
cause: /* @__PURE__ */ new Error(`git stdout exceeded ${maxStdoutBytes} bytes`)
|
|
37987
|
+
}) })) : void_)))))),
|
|
37988
|
+
mkString(decodeText(handle.stderr)),
|
|
37989
|
+
handle.exitCode
|
|
37990
|
+
], { concurrency: 3 });
|
|
37991
|
+
return {
|
|
37992
|
+
status,
|
|
37993
|
+
stdout,
|
|
37994
|
+
stderr
|
|
37995
|
+
};
|
|
37996
|
+
})).pipe(catchTag$1("PlatformError", foldSpawnFailure), withSpan("git.exec", { attributes: {
|
|
37997
|
+
"git.command": input.command,
|
|
37998
|
+
"git.subcommand": input.args[0] ?? ""
|
|
37999
|
+
} }));
|
|
38000
|
+
};
|
|
37897
38001
|
const runGit = (directory, args) => runCommand({
|
|
37898
38002
|
command: "git",
|
|
37899
38003
|
args,
|
|
@@ -38140,7 +38244,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38140
38244
|
]);
|
|
38141
38245
|
if (result.status !== 0) return null;
|
|
38142
38246
|
return parseChangedLineRanges(result.stdout);
|
|
38143
|
-
}).pipe(withSpan("Git.changedLineRanges"))
|
|
38247
|
+
}).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
|
|
38144
38248
|
});
|
|
38145
38249
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
38146
38250
|
/**
|
|
@@ -40617,7 +40721,10 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
40617
40721
|
* diagnostics).
|
|
40618
40722
|
* 2. beforeLint hook (e.g. CLI renders the project-detection block)
|
|
40619
40723
|
* 3. environment checks (reduced-motion + pnpm hardening +
|
|
40620
|
-
* expo/react-native
|
|
40724
|
+
* expo/react-native), collected synchronously. The heavier
|
|
40725
|
+
* content-regex security scan is forked instead (like supply-chain
|
|
40726
|
+
* below) and joined before the concat, so its CPU overlaps lint
|
|
40727
|
+
* rather than blocking the event loop before it.
|
|
40621
40728
|
* 4. The supply-chain check (Socket.dev) is forked onto a background
|
|
40622
40729
|
* fiber so its ~100% network-bound time overlaps the ~100%
|
|
40623
40730
|
* CPU/subprocess-bound lint pass below, collapsing two serial
|
|
@@ -40637,7 +40744,7 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
40637
40744
|
* order, so terminal output is identical either way; supply-chain
|
|
40638
40745
|
* rides alongside without a spinner.
|
|
40639
40746
|
* 6. Join the supply-chain fiber, then assemble the diagnostics in a
|
|
40640
|
-
* FIXED order (env, supply-chain, lint, dead-code) so the output is
|
|
40747
|
+
* FIXED order (env, security-scan, supply-chain, lint, dead-code) so the output is
|
|
40641
40748
|
* byte-identical regardless of which fiber settled first. The
|
|
40642
40749
|
* viewer-permission fiber is joined later, during score-metadata
|
|
40643
40750
|
* assembly (it feeds score metadata, not diagnostics). The per-element
|
|
@@ -40698,12 +40805,12 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40698
40805
|
...checkPnpmHardening(scanDirectory),
|
|
40699
40806
|
...checkReactServerComponentsAdvisory(scanDirectory, project),
|
|
40700
40807
|
...checkExpoProject(scanDirectory, project),
|
|
40701
|
-
...checkReactNativeProject(scanDirectory, project)
|
|
40702
|
-
...checkSecurityScan(scanDirectory, {
|
|
40703
|
-
project,
|
|
40704
|
-
ignoredTags: input.ignoredTags
|
|
40705
|
-
})
|
|
40808
|
+
...checkReactNativeProject(scanDirectory, project)
|
|
40706
40809
|
])));
|
|
40810
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(promise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
40811
|
+
project,
|
|
40812
|
+
ignoredTags: input.ignoredTags
|
|
40813
|
+
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)))))).pipe(withSpan("SecurityScan.run")));
|
|
40707
40814
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
40708
40815
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
40709
40816
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
@@ -40839,9 +40946,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40839
40946
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
40840
40947
|
const supplyChainResult = yield* join(supplyChainFiber);
|
|
40841
40948
|
const supplyChainCollected = supplyChainResult.diagnostics;
|
|
40949
|
+
const securityScanCollected = yield* join(securityScanFiber);
|
|
40842
40950
|
yield* reporterService.finalize;
|
|
40843
40951
|
const finalDiagnostics = sortDiagnosticsStable(assignFixGroups([
|
|
40844
40952
|
...envCollected,
|
|
40953
|
+
...securityScanCollected,
|
|
40845
40954
|
...supplyChainCollected,
|
|
40846
40955
|
...lintCollected,
|
|
40847
40956
|
...deadCodeCollected
|
|
@@ -42943,7 +43052,9 @@ const METRIC = {
|
|
|
42943
43052
|
lspSessionStarted: "lsp.session.started",
|
|
42944
43053
|
lspScanCompleted: "lsp.scan.completed",
|
|
42945
43054
|
lspScanDuration: "lsp.scan.duration",
|
|
42946
|
-
lspScanDiagnostics: "lsp.scan.diagnostics"
|
|
43055
|
+
lspScanDiagnostics: "lsp.scan.diagnostics",
|
|
43056
|
+
aiTrainingWarningShown: "ai.training.warning_shown",
|
|
43057
|
+
jsonOutUsed: "json.out_used"
|
|
42947
43058
|
};
|
|
42948
43059
|
//#endregion
|
|
42949
43060
|
//#region src/cli/utils/to-category-key.ts
|
|
@@ -43260,5 +43371,5 @@ const startLanguageServer = () => {
|
|
|
43260
43371
|
};
|
|
43261
43372
|
//#endregion
|
|
43262
43373
|
export { startLanguageServer };
|
|
43263
|
-
!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]="
|
|
43264
|
-
//# debugId=
|
|
43374
|
+
!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]="47940f68-872d-59ed-bdd2-40ef7848566c")}catch(e){}}();
|
|
43375
|
+
//# debugId=47940f68-872d-59ed-bdd2-40ef7848566c
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.5.8-dev.
|
|
3
|
+
"version": "0.5.8-dev.fff9466",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"bugs": {
|
|
21
21
|
"url": "https://github.com/millionco/react-doctor/issues"
|
|
22
22
|
},
|
|
23
|
-
"license": "
|
|
23
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
24
24
|
"author": "Million Software, Inc",
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"bin/**",
|
|
35
35
|
"dist/**/*.js",
|
|
36
36
|
"dist/**/*.d.ts",
|
|
37
|
-
"dist/skills/**"
|
|
37
|
+
"dist/skills/**",
|
|
38
|
+
"LICENSE"
|
|
38
39
|
],
|
|
39
40
|
"type": "module",
|
|
40
41
|
"sideEffects": false,
|
|
@@ -59,12 +60,12 @@
|
|
|
59
60
|
"magicast": "^0.5.3",
|
|
60
61
|
"oxlint": ">=1.66.0 <1.67.0",
|
|
61
62
|
"prompts": "^2.4.2",
|
|
62
|
-
"typescript": ">=5.0.4 <
|
|
63
|
+
"typescript": ">=5.0.4 <6",
|
|
63
64
|
"vscode-languageserver": "^9.0.1",
|
|
64
65
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
65
66
|
"vscode-uri": "^3.1.0",
|
|
66
67
|
"deslop-js": "0.5.8",
|
|
67
|
-
"oxlint-plugin-react-doctor": "0.5.8-dev.
|
|
68
|
+
"oxlint-plugin-react-doctor": "0.5.8-dev.fff9466"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
70
71
|
"@types/babel__code-frame": "^7.27.0",
|