react-doctor 0.9.3-dev.9bb44e7 → 0.9.3-dev.afd60db
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 +896 -237
- package/dist/index.d.ts +9 -2
- package/dist/index.js +467 -123
- package/dist/lsp.js +473 -123
- package/dist/run-scan-app-BphjJB7x.js +2325 -0
- package/package.json +5 -4
- package/dist/run-scan-app-DHRvqfkX.js +0 -1733
package/dist/lsp.js
CHANGED
|
@@ -9,7 +9,7 @@ import { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FIL
|
|
|
9
9
|
import * as Crypto from "node:crypto";
|
|
10
10
|
import crypto, { createHash } from "node:crypto";
|
|
11
11
|
import * as NodeChildProcess from "node:child_process";
|
|
12
|
-
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
12
|
+
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
13
13
|
import { ResolverFactory } from "oxc-resolver";
|
|
14
14
|
import ts from "typescript";
|
|
15
15
|
import * as NodeUrl from "node:url";
|
|
@@ -3647,7 +3647,7 @@ const flatMap$5 = /* @__PURE__ */ dual(2, (self, f) => isNone(self) ? none() : f
|
|
|
3647
3647
|
* @category filtering
|
|
3648
3648
|
* @since 2.0.0
|
|
3649
3649
|
*/
|
|
3650
|
-
const filter = /* @__PURE__ */ dual(2, (self, predicate) => isNone(self) ? none() : predicate(self.value) ? some(self.value) : none());
|
|
3650
|
+
const filter$1 = /* @__PURE__ */ dual(2, (self, predicate) => isNone(self) ? none() : predicate(self.value) ? some(self.value) : none());
|
|
3651
3651
|
//#endregion
|
|
3652
3652
|
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.70/node_modules/effect/dist/Result.js
|
|
3653
3653
|
/**
|
|
@@ -15586,7 +15586,7 @@ function transformOptional(f) {
|
|
|
15586
15586
|
*/
|
|
15587
15587
|
function withDefault$1(defaultValue) {
|
|
15588
15588
|
return new Getter((o) => {
|
|
15589
|
-
const filtered = filter(o, isNotUndefined);
|
|
15589
|
+
const filtered = filter$1(o, isNotUndefined);
|
|
15590
15590
|
return isSome(filtered) ? succeed$2(filtered) : mapEager(defaultValue, some);
|
|
15591
15591
|
});
|
|
15592
15592
|
}
|
|
@@ -19434,6 +19434,10 @@ var JsonReportProjectEntryV3 = class extends Class("JsonReportProjectEntryV3")({
|
|
|
19434
19434
|
scannedFileCount: optional(Number$1),
|
|
19435
19435
|
elapsedMilliseconds: Number$1
|
|
19436
19436
|
}) {};
|
|
19437
|
+
var JsonReportSkippedProject = class extends Class("JsonReportSkippedProject")({
|
|
19438
|
+
directory: String$1,
|
|
19439
|
+
reason: Literal("max-duration")
|
|
19440
|
+
}) {};
|
|
19437
19441
|
/** Original full, diff, and staged report contract. */
|
|
19438
19442
|
var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
19439
19443
|
schemaVersion: Literal(1),
|
|
@@ -19462,6 +19466,7 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
19462
19466
|
reactDetected: optional(Boolean$1),
|
|
19463
19467
|
diff: NullOr(JsonReportDiffInfo),
|
|
19464
19468
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19469
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19465
19470
|
diagnostics: ArraySchema(Diagnostic),
|
|
19466
19471
|
summary: JsonReportSummary,
|
|
19467
19472
|
elapsedMilliseconds: Number$1,
|
|
@@ -19490,6 +19495,7 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
19490
19495
|
diff: NullOr(JsonReportDiffInfo),
|
|
19491
19496
|
baseline: JsonReportBaseline,
|
|
19492
19497
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19498
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19493
19499
|
diagnostics: ArraySchema(Diagnostic),
|
|
19494
19500
|
summary: JsonReportSummary,
|
|
19495
19501
|
elapsedMilliseconds: Number$1,
|
|
@@ -19506,6 +19512,7 @@ var JsonReportV3 = class extends Class("JsonReportV3")({
|
|
|
19506
19512
|
diff: NullOr(JsonReportDiffInfo),
|
|
19507
19513
|
baseline: optional(JsonReportBaseline),
|
|
19508
19514
|
projects: ArraySchema(JsonReportProjectEntryV3),
|
|
19515
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19509
19516
|
diagnostics: ArraySchema(JsonReportDiagnosticV3),
|
|
19510
19517
|
summary: JsonReportSummary,
|
|
19511
19518
|
elapsedMilliseconds: Number$1,
|
|
@@ -53488,6 +53495,47 @@ const flattenArray = (self) => transformPull$1(self, (pull) => {
|
|
|
53488
53495
|
}));
|
|
53489
53496
|
});
|
|
53490
53497
|
/**
|
|
53498
|
+
* Filters arrays of elements emitted by a channel, applying the filter
|
|
53499
|
+
* to each element within the arrays and only emitting non-empty filtered arrays.
|
|
53500
|
+
*
|
|
53501
|
+
* **Example** (Filtering array output)
|
|
53502
|
+
*
|
|
53503
|
+
* ```ts
|
|
53504
|
+
* import { Array, Channel } from "effect"
|
|
53505
|
+
*
|
|
53506
|
+
* const nonEmptyArrayPredicate = Array.isReadonlyArrayNonEmpty
|
|
53507
|
+
*
|
|
53508
|
+
* // Create a channel that outputs arrays of mixed data
|
|
53509
|
+
* const arrayChannel = Channel.fromIterable([
|
|
53510
|
+
* Array.make(1, 2, 3, 4, 5),
|
|
53511
|
+
* Array.make(6, 7, 8, 9, 10),
|
|
53512
|
+
* Array.make(11, 12, 13, 14, 15)
|
|
53513
|
+
* ]).pipe(Channel.filter(nonEmptyArrayPredicate))
|
|
53514
|
+
*
|
|
53515
|
+
* // Filter arrays to keep only even numbers
|
|
53516
|
+
* const evenArraysChannel = Channel.filterArray(arrayChannel, (n) => n % 2 === 0)
|
|
53517
|
+
* // Outputs: [2, 4], [6, 8, 10], [12, 14]
|
|
53518
|
+
* // Note: Only non-empty filtered arrays are emitted
|
|
53519
|
+
*
|
|
53520
|
+
* // Arrays that would become empty after filtering are discarded entirely
|
|
53521
|
+
* const oddChannel = Channel.fromIterable([
|
|
53522
|
+
* Array.make(1, 3, 5),
|
|
53523
|
+
* Array.make(2, 4),
|
|
53524
|
+
* Array.make(7, 9)
|
|
53525
|
+
* ]).pipe(Channel.filter(nonEmptyArrayPredicate))
|
|
53526
|
+
* const filteredOddChannel = Channel.filterArray(oddChannel, (n) => n % 2 === 0)
|
|
53527
|
+
* // Outputs: [2, 4] (the arrays [1,3,5] and [7,9] are discarded)
|
|
53528
|
+
* ```
|
|
53529
|
+
*
|
|
53530
|
+
* @category filtering
|
|
53531
|
+
* @since 4.0.0
|
|
53532
|
+
*/
|
|
53533
|
+
const filterArray = /* @__PURE__ */ dual(2, (self, predicate) => transformPull$1(self, (pull) => succeed$2(flatMap$2(pull, function loop(arr) {
|
|
53534
|
+
const passes = [];
|
|
53535
|
+
for (let i = 0; i < arr.length; i++) if (predicate(arr[i])) passes.push(arr[i]);
|
|
53536
|
+
return isReadonlyArrayNonEmpty(passes) ? succeed$2(passes) : flatMap$2(pull, loop);
|
|
53537
|
+
}))));
|
|
53538
|
+
/**
|
|
53491
53539
|
* Filters and maps each element inside emitted non-empty arrays using a
|
|
53492
53540
|
* `Filter`.
|
|
53493
53541
|
*
|
|
@@ -55125,6 +55173,30 @@ const concat = /* @__PURE__ */ dual(2, (self, that) => flatten(fromArray([self,
|
|
|
55125
55173
|
*/
|
|
55126
55174
|
const merge$1 = /* @__PURE__ */ dual((args) => isStream(args[0]) && isStream(args[1]), (self, that, options) => fromChannel(merge$2(toChannel(self), toChannel(that), options)));
|
|
55127
55175
|
/**
|
|
55176
|
+
* Filters a stream to the elements that satisfy a predicate.
|
|
55177
|
+
*
|
|
55178
|
+
* **Example** (Filtering stream values)
|
|
55179
|
+
*
|
|
55180
|
+
* ```ts
|
|
55181
|
+
* import { Console, Effect, Stream } from "effect"
|
|
55182
|
+
*
|
|
55183
|
+
* const program = Effect.gen(function*() {
|
|
55184
|
+
* const stream = Stream.make(1, 2, 3, 4).pipe(
|
|
55185
|
+
* Stream.filter((n) => n % 2 === 0)
|
|
55186
|
+
* )
|
|
55187
|
+
* const values = yield* Stream.runCollect(stream)
|
|
55188
|
+
* yield* Console.log(values)
|
|
55189
|
+
* })
|
|
55190
|
+
*
|
|
55191
|
+
* Effect.runPromise(program)
|
|
55192
|
+
* // Output: [ 2, 4 ]
|
|
55193
|
+
* ```
|
|
55194
|
+
*
|
|
55195
|
+
* @category filtering
|
|
55196
|
+
* @since 2.0.0
|
|
55197
|
+
*/
|
|
55198
|
+
const filter = /* @__PURE__ */ dual(2, (self, predicate) => fromChannel(filterArray(toChannel(self), predicate)));
|
|
55199
|
+
/**
|
|
55128
55200
|
* Filters and maps stream elements in one pass using a `Filter`.
|
|
55129
55201
|
*
|
|
55130
55202
|
* @category filtering
|
|
@@ -61908,6 +61980,7 @@ const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
|
61908
61980
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
61909
61981
|
const MINIFIED_SNIFF_BYTES = 65536;
|
|
61910
61982
|
const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
61983
|
+
const GIT_CHECK_ATTR_MAX_BUFFER_BYTES = GIT_LS_FILES_MAX_BUFFER_BYTES;
|
|
61911
61984
|
const SCANNED_DOT_DIRECTORIES = new Set([".dumi", ".storybook"]);
|
|
61912
61985
|
const IGNORED_DIRECTORIES = new Set([
|
|
61913
61986
|
".angular",
|
|
@@ -62216,13 +62289,9 @@ const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
|
|
|
62216
62289
|
const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
|
|
62217
62290
|
const ABORT_EXIT_CODES = new Set([134, 3221226505]);
|
|
62218
62291
|
const OXLINT_OOM_RESCUE_BUDGET_MS = 6e4;
|
|
62219
|
-
const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
62220
|
-
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
62221
|
-
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
62222
62292
|
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
62223
62293
|
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
62224
62294
|
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
62225
|
-
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
62226
62295
|
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
62227
62296
|
const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
|
|
62228
62297
|
const REACT_SERVER_DOM_PACKAGES = [
|
|
@@ -62317,6 +62386,66 @@ const isPlainObject = (value) => {
|
|
|
62317
62386
|
const prototype = Object.getPrototypeOf(value);
|
|
62318
62387
|
return prototype === null || prototype === Object.prototype;
|
|
62319
62388
|
};
|
|
62389
|
+
const LINGUIST_ATTRIBUTES = ["linguist-generated", "linguist-vendored"];
|
|
62390
|
+
const DISABLED_ATTRIBUTE_VALUES = new Set([
|
|
62391
|
+
"unspecified",
|
|
62392
|
+
"unset",
|
|
62393
|
+
"false",
|
|
62394
|
+
"0",
|
|
62395
|
+
"off",
|
|
62396
|
+
"no"
|
|
62397
|
+
]);
|
|
62398
|
+
const buildInput = (relativePaths) => `${relativePaths.join("\0")}\0`;
|
|
62399
|
+
const parseIgnoredPaths = (output) => {
|
|
62400
|
+
const ignoredPaths = /* @__PURE__ */ new Set();
|
|
62401
|
+
const fields = output.split("\0");
|
|
62402
|
+
for (let fieldIndex = 0; fieldIndex + 2 < fields.length; fieldIndex += 3) {
|
|
62403
|
+
const filePath = fields[fieldIndex];
|
|
62404
|
+
const value = fields[fieldIndex + 2]?.toLowerCase();
|
|
62405
|
+
if (filePath && value && !DISABLED_ATTRIBUTE_VALUES.has(value)) ignoredPaths.add(filePath);
|
|
62406
|
+
}
|
|
62407
|
+
return ignoredPaths;
|
|
62408
|
+
};
|
|
62409
|
+
const collectGitLinguistIgnoredPaths = (rootDirectory, relativePaths) => {
|
|
62410
|
+
if (relativePaths.length === 0) return /* @__PURE__ */ new Set();
|
|
62411
|
+
const result = spawnSync("git", [
|
|
62412
|
+
"check-attr",
|
|
62413
|
+
"-z",
|
|
62414
|
+
"--stdin",
|
|
62415
|
+
...LINGUIST_ATTRIBUTES
|
|
62416
|
+
], {
|
|
62417
|
+
cwd: rootDirectory,
|
|
62418
|
+
encoding: "utf-8",
|
|
62419
|
+
input: buildInput(relativePaths),
|
|
62420
|
+
maxBuffer: GIT_CHECK_ATTR_MAX_BUFFER_BYTES
|
|
62421
|
+
});
|
|
62422
|
+
if (result.error || result.status !== 0) return /* @__PURE__ */ new Set();
|
|
62423
|
+
return parseIgnoredPaths(result.stdout);
|
|
62424
|
+
};
|
|
62425
|
+
const collectGitLinguistIgnoredPathsCooperative = (rootDirectory, relativePaths, signal) => {
|
|
62426
|
+
if (relativePaths.length === 0) return Promise.resolve(/* @__PURE__ */ new Set());
|
|
62427
|
+
return new Promise((resolve, reject) => {
|
|
62428
|
+
signal?.throwIfAborted();
|
|
62429
|
+
execFile("git", [
|
|
62430
|
+
"check-attr",
|
|
62431
|
+
"-z",
|
|
62432
|
+
"--stdin",
|
|
62433
|
+
...LINGUIST_ATTRIBUTES
|
|
62434
|
+
], {
|
|
62435
|
+
cwd: rootDirectory,
|
|
62436
|
+
encoding: "utf-8",
|
|
62437
|
+
killSignal: "SIGKILL",
|
|
62438
|
+
maxBuffer: GIT_CHECK_ATTR_MAX_BUFFER_BYTES,
|
|
62439
|
+
signal
|
|
62440
|
+
}, (error, stdout) => {
|
|
62441
|
+
if (signal?.aborted) {
|
|
62442
|
+
reject(signal.reason);
|
|
62443
|
+
return;
|
|
62444
|
+
}
|
|
62445
|
+
resolve(error ? /* @__PURE__ */ new Set() : parseIgnoredPaths(stdout));
|
|
62446
|
+
}).stdin?.end(buildInput(relativePaths));
|
|
62447
|
+
});
|
|
62448
|
+
};
|
|
62320
62449
|
const lastSourceMappingUrl = (fileContent) => {
|
|
62321
62450
|
const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
|
|
62322
62451
|
return lastReference ? lastReference[1] : null;
|
|
@@ -62421,6 +62550,9 @@ function* walkSourceTreeFiles(rootDirectory) {
|
|
|
62421
62550
|
}
|
|
62422
62551
|
}
|
|
62423
62552
|
}
|
|
62553
|
+
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
62554
|
+
setImmediate(resolve);
|
|
62555
|
+
});
|
|
62424
62556
|
const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
62425
62557
|
const entries = [];
|
|
62426
62558
|
for (const relativePath of relativePaths) {
|
|
@@ -62434,23 +62566,55 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
|
62434
62566
|
}
|
|
62435
62567
|
return entries;
|
|
62436
62568
|
};
|
|
62437
|
-
const
|
|
62569
|
+
const collectSizedSourceFilesCooperative = async (rootDirectory, relativePaths, signal) => {
|
|
62570
|
+
const entries = [];
|
|
62571
|
+
let sliceStartedAt = performance.now();
|
|
62572
|
+
for (const relativePath of relativePaths) {
|
|
62573
|
+
signal?.throwIfAborted();
|
|
62574
|
+
const absolutePath = Path.resolve(rootDirectory, relativePath);
|
|
62575
|
+
const sizeBytes = statSourceFileSize(absolutePath);
|
|
62576
|
+
if (!isLargeMinifiedFile(absolutePath, sizeBytes)) entries.push({
|
|
62577
|
+
path: relativePath,
|
|
62578
|
+
sizeBytes: sizeBytes ?? 0
|
|
62579
|
+
});
|
|
62580
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
62581
|
+
await yieldToEventLoop();
|
|
62582
|
+
sliceStartedAt = performance.now();
|
|
62583
|
+
}
|
|
62584
|
+
}
|
|
62585
|
+
return entries;
|
|
62586
|
+
};
|
|
62587
|
+
const parseGitSourceFilePaths = (output) => {
|
|
62588
|
+
const trackedPaths = /* @__PURE__ */ new Set();
|
|
62589
|
+
const untrackedPaths = [];
|
|
62590
|
+
for (const entry of output.split("\0")) {
|
|
62591
|
+
if (entry.length === 0) continue;
|
|
62592
|
+
const trackedPath = /^[0-7]{6} [0-9a-f]+ [0-3]\t([\s\S]+)$/.exec(entry)?.[1];
|
|
62593
|
+
if (trackedPath === void 0) untrackedPaths.push(entry);
|
|
62594
|
+
else trackedPaths.add(trackedPath);
|
|
62595
|
+
}
|
|
62596
|
+
return {
|
|
62597
|
+
trackedPaths: [...trackedPaths],
|
|
62598
|
+
untrackedPaths
|
|
62599
|
+
};
|
|
62600
|
+
};
|
|
62601
|
+
const listGitSourceFilePaths = (rootDirectory) => {
|
|
62438
62602
|
const result = spawnSync("git", [
|
|
62439
62603
|
"ls-files",
|
|
62440
62604
|
"-z",
|
|
62441
|
-
|
|
62605
|
+
"--stage",
|
|
62606
|
+
"--others",
|
|
62607
|
+
"--exclude-standard"
|
|
62442
62608
|
], {
|
|
62443
62609
|
cwd: rootDirectory,
|
|
62444
62610
|
encoding: "utf-8",
|
|
62445
62611
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
62446
62612
|
});
|
|
62447
62613
|
if (result.error || result.status !== 0) return null;
|
|
62448
|
-
return result.stdout
|
|
62614
|
+
return parseGitSourceFilePaths(result.stdout);
|
|
62449
62615
|
};
|
|
62450
|
-
const
|
|
62451
|
-
const trackedPaths =
|
|
62452
|
-
const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
|
|
62453
|
-
if (trackedPaths === null || untrackedPaths === null) return null;
|
|
62616
|
+
const collectGitCandidateSourceFilePaths = (rootDirectory, paths) => {
|
|
62617
|
+
const { trackedPaths, untrackedPaths } = paths;
|
|
62454
62618
|
const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
|
|
62455
62619
|
trackedPaths: new Set(trackedPaths),
|
|
62456
62620
|
untrackedPaths,
|
|
@@ -62458,12 +62622,65 @@ const listSourceFilesViaGit = (rootDirectory) => {
|
|
|
62458
62622
|
});
|
|
62459
62623
|
return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
|
|
62460
62624
|
};
|
|
62625
|
+
const filterGitSourceFilePaths = (rootDirectory, paths) => {
|
|
62626
|
+
const candidatePaths = collectGitCandidateSourceFilePaths(rootDirectory, paths);
|
|
62627
|
+
const linguistIgnoredPaths = collectGitLinguistIgnoredPaths(rootDirectory, candidatePaths);
|
|
62628
|
+
return candidatePaths.filter((filePath) => !linguistIgnoredPaths.has(filePath));
|
|
62629
|
+
};
|
|
62630
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
62631
|
+
const paths = listGitSourceFilePaths(rootDirectory);
|
|
62632
|
+
return paths === null ? null : filterGitSourceFilePaths(rootDirectory, paths);
|
|
62633
|
+
};
|
|
62634
|
+
const listSourceFilesViaGitCooperative = async (rootDirectory, signal) => {
|
|
62635
|
+
const paths = await new Promise((resolve, reject) => {
|
|
62636
|
+
signal?.throwIfAborted();
|
|
62637
|
+
execFile("git", [
|
|
62638
|
+
"ls-files",
|
|
62639
|
+
"-z",
|
|
62640
|
+
"--stage",
|
|
62641
|
+
"--others",
|
|
62642
|
+
"--exclude-standard"
|
|
62643
|
+
], {
|
|
62644
|
+
cwd: rootDirectory,
|
|
62645
|
+
encoding: "utf-8",
|
|
62646
|
+
killSignal: "SIGKILL",
|
|
62647
|
+
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,
|
|
62648
|
+
signal
|
|
62649
|
+
}, (error, stdout) => {
|
|
62650
|
+
if (signal?.aborted) {
|
|
62651
|
+
reject(signal.reason);
|
|
62652
|
+
return;
|
|
62653
|
+
}
|
|
62654
|
+
resolve(error ? null : parseGitSourceFilePaths(stdout));
|
|
62655
|
+
});
|
|
62656
|
+
});
|
|
62657
|
+
if (paths === null) return null;
|
|
62658
|
+
const candidatePaths = collectGitCandidateSourceFilePaths(rootDirectory, paths);
|
|
62659
|
+
const linguistIgnoredPaths = await collectGitLinguistIgnoredPathsCooperative(rootDirectory, candidatePaths, signal);
|
|
62660
|
+
return candidatePaths.filter((filePath) => !linguistIgnoredPaths.has(filePath));
|
|
62661
|
+
};
|
|
62461
62662
|
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
62462
62663
|
const filePaths = [];
|
|
62463
62664
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
62464
62665
|
return filePaths;
|
|
62465
62666
|
};
|
|
62466
|
-
const
|
|
62667
|
+
const listSourceFilesViaFilesystemCooperative = async (rootDirectory, signal) => {
|
|
62668
|
+
const filePaths = [];
|
|
62669
|
+
let sliceStartedAt = performance.now();
|
|
62670
|
+
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
62671
|
+
signal?.throwIfAborted();
|
|
62672
|
+
if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
62673
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
62674
|
+
await yieldToEventLoop();
|
|
62675
|
+
sliceStartedAt = performance.now();
|
|
62676
|
+
}
|
|
62677
|
+
}
|
|
62678
|
+
return filePaths;
|
|
62679
|
+
};
|
|
62680
|
+
const listSourceFilePaths = (rootDirectory) => (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort();
|
|
62681
|
+
const listSourceFilePathsCooperative = async (rootDirectory, signal) => (await listSourceFilesViaGitCooperative(rootDirectory, signal) ?? await listSourceFilesViaFilesystemCooperative(rootDirectory, signal)).sort();
|
|
62682
|
+
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, listSourceFilePaths(rootDirectory));
|
|
62683
|
+
const listSourceFilesCooperative = async (rootDirectory, signal) => (await collectSizedSourceFilesCooperative(rootDirectory, await listSourceFilePathsCooperative(rootDirectory, signal), signal)).map((entry) => entry.path);
|
|
62467
62684
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
62468
62685
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
62469
62686
|
const UTF8_BOM_CHARACTER = "";
|
|
@@ -64792,7 +65009,16 @@ const getBrowserslistProtectionRequirement = (directory) => {
|
|
|
64792
65009
|
if (!queries) return void 0;
|
|
64793
65010
|
let requirement;
|
|
64794
65011
|
let hasUnsupportedTarget = false;
|
|
64795
|
-
|
|
65012
|
+
const previousIgnoreOldData = process.env.BROWSERSLIST_IGNORE_OLD_DATA;
|
|
65013
|
+
let browserTargets = [];
|
|
65014
|
+
try {
|
|
65015
|
+
process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true";
|
|
65016
|
+
browserTargets = (0, import_browserslist.default)(queries);
|
|
65017
|
+
} finally {
|
|
65018
|
+
if (previousIgnoreOldData === void 0) delete process.env.BROWSERSLIST_IGNORE_OLD_DATA;
|
|
65019
|
+
else process.env.BROWSERSLIST_IGNORE_OLD_DATA = previousIgnoreOldData;
|
|
65020
|
+
}
|
|
65021
|
+
for (const browserTarget of browserTargets) {
|
|
64796
65022
|
const browserRequirement = getBrowserProtectionRequirement(browserTarget);
|
|
64797
65023
|
if (browserRequirement === "unsupported") hasUnsupportedTarget = true;
|
|
64798
65024
|
if (browserRequirement === "noreferrer") requirement = "noreferrer";
|
|
@@ -64902,8 +65128,8 @@ const clearProjectCache = () => {
|
|
|
64902
65128
|
* framework-agnostic rules. Throws only when the directory has nothing
|
|
64903
65129
|
* to scan (no enclosing project and no source files of its own).
|
|
64904
65130
|
*/
|
|
64905
|
-
const discoverProjectWithoutPackageJson = (directory) => {
|
|
64906
|
-
const sourceFileCount = countSourceFiles(directory);
|
|
65131
|
+
const discoverProjectWithoutPackageJson = (directory, options) => {
|
|
65132
|
+
const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
|
|
64907
65133
|
const hasOwnTsConfig = NFS.existsSync(Path.join(directory, "tsconfig.json"));
|
|
64908
65134
|
const enclosingProjectRoot = findNearestAncestorPackageJson(directory);
|
|
64909
65135
|
const enclosingProject = enclosingProjectRoot !== null ? discoverProject(enclosingProjectRoot) : null;
|
|
@@ -64970,12 +65196,15 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
64970
65196
|
sourceFileCount
|
|
64971
65197
|
};
|
|
64972
65198
|
};
|
|
64973
|
-
const discoverProject = (directory) => {
|
|
65199
|
+
const discoverProject = (directory, options = {}) => {
|
|
64974
65200
|
const cached = cachedProjectInfos.get(directory);
|
|
64975
|
-
if (cached !== void 0) return cached
|
|
65201
|
+
if (cached !== void 0) return options.sourceFileCount === void 0 ? cached : {
|
|
65202
|
+
...cached,
|
|
65203
|
+
sourceFileCount: options.sourceFileCount
|
|
65204
|
+
};
|
|
64976
65205
|
const packageJsonPath = Path.join(directory, "package.json");
|
|
64977
65206
|
if (!isFile(packageJsonPath)) {
|
|
64978
|
-
const synthesized = discoverProjectWithoutPackageJson(directory);
|
|
65207
|
+
const synthesized = discoverProjectWithoutPackageJson(directory, options);
|
|
64979
65208
|
cachedProjectInfos.set(directory, synthesized);
|
|
64980
65209
|
return synthesized;
|
|
64981
65210
|
}
|
|
@@ -65038,7 +65267,7 @@ const discoverProject = (directory) => {
|
|
|
65038
65267
|
const zodVersion = zod.version;
|
|
65039
65268
|
const projectName = packageJson.name ?? Path.basename(directory);
|
|
65040
65269
|
const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
|
|
65041
|
-
const sourceFileCount = countSourceFiles(directory);
|
|
65270
|
+
const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
|
|
65042
65271
|
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
|
|
65043
65272
|
const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
65044
65273
|
rootDirectory: directory,
|
|
@@ -66394,7 +66623,8 @@ const readSystemFacts$1 = () => ({
|
|
|
66394
66623
|
/**
|
|
66395
66624
|
* Auto lint-worker count: the smaller of the (cgroup-CPU-aware) core count and
|
|
66396
66625
|
* the number of `PER_WORKER_MEM_BUDGET_BYTES` workers that fit in available
|
|
66397
|
-
* memory,
|
|
66626
|
+
* memory, and the measured automatic parallel-efficiency ceiling, then clamped
|
|
66627
|
+
* to `[MIN, HARD_MAX]` by `resolveScanConcurrency`.
|
|
66398
66628
|
*
|
|
66399
66629
|
* `os.availableParallelism()` already respects cgroup CPU quotas, so the core
|
|
66400
66630
|
* term needs no help. Available memory is `os.totalmem()` floored by the cgroup
|
|
@@ -66410,7 +66640,7 @@ const readSystemFacts$1 = () => ({
|
|
|
66410
66640
|
const resolveAutoScanConcurrency = (facts = readSystemFacts$1()) => {
|
|
66411
66641
|
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
66412
66642
|
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / PER_WORKER_MEM_BUDGET_BYTES);
|
|
66413
|
-
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
66643
|
+
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers, 10));
|
|
66414
66644
|
};
|
|
66415
66645
|
const resolveLintBatchOrdering = () => {
|
|
66416
66646
|
return process.env["REACT_DOCTOR_LINT_BATCH_ORDERING"]?.trim().toLowerCase() === "arrival" ? "arrival" : "cost";
|
|
@@ -66423,24 +66653,22 @@ const resolveLintBatchOrdering = () => {
|
|
|
66423
66653
|
*/
|
|
66424
66654
|
var OxlintSpawnTimeoutMs = class extends Reference("react-doctor/OxlintSpawnTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_OXLINT_SPAWN_TIMEOUT_MS", OXLINT_SPAWN_TIMEOUT_MS) }) {};
|
|
66425
66655
|
/**
|
|
66426
|
-
* Effect-side cap on the lint phase.
|
|
66427
|
-
*
|
|
66656
|
+
* Optional Effect-side cap on the lint phase. Unbounded unless explicitly
|
|
66657
|
+
* configured through the env var or a test layer.
|
|
66428
66658
|
* Tests override via `Layer.succeed(LintPhaseTimeoutMs, ...)`.
|
|
66429
66659
|
*/
|
|
66430
|
-
var LintPhaseTimeoutMs = class extends Reference("react-doctor/LintPhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_LINT_PHASE_TIMEOUT_MS",
|
|
66660
|
+
var LintPhaseTimeoutMs = class extends Reference("react-doctor/LintPhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_LINT_PHASE_TIMEOUT_MS", null) }) {};
|
|
66431
66661
|
/**
|
|
66432
|
-
* Effect-side cap on the dead-code phase
|
|
66433
|
-
*
|
|
66434
|
-
* type-heavy projects; tests override via
|
|
66662
|
+
* Optional Effect-side cap on the dead-code phase. Unbounded unless explicitly
|
|
66663
|
+
* configured through the env var or a test layer. Tests override via
|
|
66435
66664
|
* `Layer.succeed(DeadCodePhaseTimeoutMs, ...)`.
|
|
66436
66665
|
*/
|
|
66437
|
-
var DeadCodePhaseTimeoutMs = class extends Reference("react-doctor/DeadCodePhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_DEAD_CODE_PHASE_TIMEOUT_MS",
|
|
66666
|
+
var DeadCodePhaseTimeoutMs = class extends Reference("react-doctor/DeadCodePhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_DEAD_CODE_PHASE_TIMEOUT_MS", null) }) {};
|
|
66438
66667
|
/**
|
|
66439
|
-
*
|
|
66440
|
-
*
|
|
66441
|
-
* large repos; tests override via `Layer.succeed(ScanDeadlineMs, ...)`.
|
|
66668
|
+
* Optional overall scan deadline. Unbounded unless explicitly configured
|
|
66669
|
+
* through the env var or a test layer.
|
|
66442
66670
|
*/
|
|
66443
|
-
var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SCAN_DEADLINE_MS",
|
|
66671
|
+
var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SCAN_DEADLINE_MS", null) }) {};
|
|
66444
66672
|
/**
|
|
66445
66673
|
* Wall-clock budget for the supply-chain check when it runs on a background
|
|
66446
66674
|
* fiber overlapping the lint pass. Reads from the env var on startup so the
|
|
@@ -66513,14 +66741,14 @@ var DeadCodeOverlap = class extends Reference("react-doctor/DeadCodeOverlap", {
|
|
|
66513
66741
|
/**
|
|
66514
66742
|
* How the full-scan lint pass plans its file batches. `"cost"` (the default)
|
|
66515
66743
|
* builds size-balanced LPT batches (`planLintBatches`): the same mandatory
|
|
66516
|
-
* batch count as greedy chunking
|
|
66517
|
-
*
|
|
66744
|
+
* batch count as greedy chunking, but every batch gets an even share of files
|
|
66745
|
+
* AND bytes, so no full chunk is a straggler while
|
|
66518
66746
|
* the remainder-batch worker idles — and the heavy files are SPREAD across
|
|
66519
66747
|
* batches, the precondition the old sort-desc-then-chunk-100 `cost` mode
|
|
66520
66748
|
* lacked (it packed the heaviest files into one wave-1 straggler batch,
|
|
66521
66749
|
* measurably regressing size-skewed repos, which is why it never earned the
|
|
66522
66750
|
* default). `"arrival"` (`REACT_DOCTOR_LINT_BATCH_ORDERING=arrival`) is the
|
|
66523
|
-
* rollback hatch to plain greedy
|
|
66751
|
+
* rollback hatch to plain greedy fixed-size chunking in discovery order. Tests
|
|
66524
66752
|
* override via `Layer.succeed(LintBatchOrdering, ...)`. Diff / staged scans
|
|
66525
66753
|
* never reach this — they pass user-scoped `includePaths` that skip discovery
|
|
66526
66754
|
* and stay in arrival order; only the full-scan branch reads it.
|
|
@@ -67010,6 +67238,10 @@ const dedupeRelatedDiagnostics = (diagnostics) => {
|
|
|
67010
67238
|
}
|
|
67011
67239
|
return uniqueDiagnostics;
|
|
67012
67240
|
};
|
|
67241
|
+
const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
67242
|
+
const relativePath = Path.relative(parentAbsolutePath, childAbsolutePath);
|
|
67243
|
+
return Boolean(relativePath) && !relativePath.startsWith("..") && !Path.isAbsolute(relativePath);
|
|
67244
|
+
};
|
|
67013
67245
|
const compareStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
67014
67246
|
const sortDiagnosticsStable = (diagnostics) => [...diagnostics].sort((left, right) => compareStrings(left.filePath, right.filePath) || left.line - right.line || left.column - right.column || compareStrings(left.plugin, right.plugin) || compareStrings(left.rule, right.rule) || compareStrings(left.severity, right.severity) || compareStrings(left.message, right.message));
|
|
67015
67247
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
@@ -68586,7 +68818,7 @@ const readScannedFile = (candidate) => {
|
|
|
68586
68818
|
return null;
|
|
68587
68819
|
}
|
|
68588
68820
|
};
|
|
68589
|
-
function* collectSecurityScanFiles(rootDirectory) {
|
|
68821
|
+
function* collectSecurityScanFiles(rootDirectory, excludedDirectories = /* @__PURE__ */ new Set()) {
|
|
68590
68822
|
const priorityCandidates = [];
|
|
68591
68823
|
const artifactCandidates = [];
|
|
68592
68824
|
const otherCandidates = [];
|
|
@@ -68601,7 +68833,7 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
68601
68833
|
for (const entry of readDirectoryEntries(current.absolutePath)) {
|
|
68602
68834
|
const absolutePath = Path.join(current.absolutePath, entry.name);
|
|
68603
68835
|
if (entry.isDirectory()) {
|
|
68604
|
-
if (!SKIPPED_DIRECTORY_NAMES.has(entry.name)) stack.push({
|
|
68836
|
+
if (!SKIPPED_DIRECTORY_NAMES.has(entry.name) && !excludedDirectories.has(Path.resolve(absolutePath))) stack.push({
|
|
68605
68837
|
absolutePath,
|
|
68606
68838
|
depth: current.depth + 1
|
|
68607
68839
|
});
|
|
@@ -68782,10 +69014,8 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
|
|
|
68782
69014
|
}
|
|
68783
69015
|
return true;
|
|
68784
69016
|
};
|
|
69017
|
+
const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
|
|
68785
69018
|
const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
|
|
68786
|
-
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
68787
|
-
setImmediate(resolve);
|
|
68788
|
-
});
|
|
68789
69019
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
68790
69020
|
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
68791
69021
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
@@ -68838,19 +69068,35 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
68838
69068
|
};
|
|
68839
69069
|
};
|
|
68840
69070
|
const checkSecurityScanCooperative = async (rootDirectory, options = {}) => {
|
|
69071
|
+
const throwIfScanAborted = () => {
|
|
69072
|
+
options.signal?.throwIfAborted();
|
|
69073
|
+
};
|
|
69074
|
+
const didReachDeadline = () => {
|
|
69075
|
+
const hasDeadlineElapsed = options.deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(options.deadlineEpochMs) === 0;
|
|
69076
|
+
if (hasDeadlineElapsed) options.onDeadlineExceeded?.();
|
|
69077
|
+
return hasDeadlineElapsed;
|
|
69078
|
+
};
|
|
69079
|
+
throwIfScanAborted();
|
|
68841
69080
|
const session = createSecurityScanSession(rootDirectory, options);
|
|
68842
69081
|
if (session === null) return [];
|
|
69082
|
+
if (didReachDeadline()) return [];
|
|
68843
69083
|
let sliceStartedAt = performance.now();
|
|
68844
|
-
for (const file of collectSecurityScanFiles(rootDirectory)) {
|
|
69084
|
+
for (const file of collectSecurityScanFiles(rootDirectory, options.excludedDirectories)) {
|
|
69085
|
+
throwIfScanAborted();
|
|
69086
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68845
69087
|
if (file === null) {
|
|
68846
69088
|
if (performance.now() - sliceStartedAt >= 12) {
|
|
68847
69089
|
await yieldToEventLoop();
|
|
69090
|
+
throwIfScanAborted();
|
|
69091
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68848
69092
|
sliceStartedAt = performance.now();
|
|
68849
69093
|
}
|
|
68850
69094
|
continue;
|
|
68851
69095
|
}
|
|
68852
69096
|
for (const _ruleStep of session.scanFileByRule(file)) if (performance.now() - sliceStartedAt >= 12) {
|
|
68853
69097
|
await yieldToEventLoop();
|
|
69098
|
+
throwIfScanAborted();
|
|
69099
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68854
69100
|
sliceStartedAt = performance.now();
|
|
68855
69101
|
}
|
|
68856
69102
|
}
|
|
@@ -69764,7 +70010,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
|
|
|
69764
70010
|
return true;
|
|
69765
70011
|
};
|
|
69766
70012
|
const filterDiagnosticsForSurface = (diagnostics, surface, config) => diagnostics.filter((diagnostic) => isDiagnosticOnSurface(diagnostic, surface, config));
|
|
69767
|
-
const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
|
|
69768
70013
|
/**
|
|
69769
70014
|
* Budget for the dead-code phase, scaled to the work. deslop's graph build is
|
|
69770
70015
|
* CPU-bound and roughly linear in file count, so a fixed 120s cap is too tight
|
|
@@ -69772,25 +70017,28 @@ const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs
|
|
|
69772
70017
|
* tipped over by any concurrent load — silently dropping every dead-code
|
|
69773
70018
|
* finding. Scaling the budget with file count (and inversely with the core
|
|
69774
70019
|
* share when overlapped) lets the pass complete, while the ceiling still
|
|
69775
|
-
* reclaims a genuinely wedged worker.
|
|
69776
|
-
* and the Effect-side phase backstop that sits a margin above it.
|
|
70020
|
+
* reclaims a genuinely wedged worker.
|
|
69777
70021
|
*/
|
|
69778
70022
|
const resolveDeadCodeTimeout = (input) => {
|
|
69779
70023
|
const coreShareFactor = Math.max(1, input.fullConcurrency / Math.max(1, input.deadCodeConcurrency));
|
|
69780
|
-
|
|
69781
|
-
return {
|
|
69782
|
-
workerTimeoutMs,
|
|
69783
|
-
phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
|
|
69784
|
-
};
|
|
70024
|
+
return { workerTimeoutMs: Math.min(DEAD_CODE_TIMEOUT_CEILING_MS, Math.max(DEAD_CODE_WORKER_TIMEOUT_MS, Math.ceil(input.sourceFileCount * 30 * coreShareFactor))) };
|
|
69785
70025
|
};
|
|
69786
|
-
const resolveLintIncludePaths = (rootDirectory, userConfig) => {
|
|
70026
|
+
const resolveLintIncludePaths = (rootDirectory, userConfig, sourceFiles) => {
|
|
69787
70027
|
if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
|
|
69788
70028
|
const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
|
|
69789
|
-
return listSourceFiles(rootDirectory).filter((filePath) => {
|
|
70029
|
+
return (sourceFiles ?? listSourceFiles(rootDirectory)).filter((filePath) => {
|
|
69790
70030
|
if (!isLintableSourceFile(filePath)) return false;
|
|
69791
70031
|
return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
|
|
69792
70032
|
});
|
|
69793
70033
|
};
|
|
70034
|
+
const filterPathsOutsideDirectories = (input) => {
|
|
70035
|
+
const excludedPrefixes = input.excludedDirectories.map((excludedDirectory) => Path.resolve(excludedDirectory)).filter((excludedDirectory) => isPathInsideDirectory(excludedDirectory, input.rootDirectory)).map((excludedDirectory) => Path.relative(input.rootDirectory, excludedDirectory).replaceAll("\\", "/")).sort((left, right) => left.length - right.length).filter((candidatePrefix, index, prefixes) => !prefixes.slice(0, index).some((prefix) => candidatePrefix.startsWith(`${prefix}/`)));
|
|
70036
|
+
if (excludedPrefixes.length === 0) return [...input.relativePaths];
|
|
70037
|
+
return input.relativePaths.filter((relativePath) => {
|
|
70038
|
+
const normalizedRelativePath = relativePath.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
70039
|
+
return !excludedPrefixes.some((excludedPrefix) => normalizedRelativePath === excludedPrefix || normalizedRelativePath.startsWith(`${excludedPrefix}/`));
|
|
70040
|
+
});
|
|
70041
|
+
};
|
|
69794
70042
|
var Config = class Config extends Service()("react-doctor/Config") {
|
|
69795
70043
|
static layerNode = effect(Config, gen(function* () {
|
|
69796
70044
|
const cache = yield* make$3({
|
|
@@ -69852,6 +70100,7 @@ var Files = class Files extends Service()("react-doctor/Files") {
|
|
|
69852
70100
|
static layerNode = succeed$3(Files, Files.of({
|
|
69853
70101
|
readLines: (input) => sync(() => createNodeReadFileLinesSync(input.rootDirectory)(input.filePath)),
|
|
69854
70102
|
listSourceFiles: (rootDirectory) => sync(() => listSourceFiles(rootDirectory)),
|
|
70103
|
+
listSourceFilesCooperative: (input) => promise(() => listSourceFilesCooperative(input.rootDirectory, input.signal)),
|
|
69855
70104
|
isFile: (filePath) => sync(() => isFile(filePath)),
|
|
69856
70105
|
isDirectory: (filePath) => sync(() => isDirectory(filePath))
|
|
69857
70106
|
}));
|
|
@@ -69878,6 +70127,16 @@ var Files = class Files extends Service()("react-doctor/Files") {
|
|
|
69878
70127
|
}
|
|
69879
70128
|
return files;
|
|
69880
70129
|
}),
|
|
70130
|
+
listSourceFilesCooperative: (input) => sync(() => {
|
|
70131
|
+
const rootDirectory = input.rootDirectory;
|
|
70132
|
+
const prefix = rootDirectory.endsWith("/") ? rootDirectory : `${rootDirectory}/`;
|
|
70133
|
+
const files = [];
|
|
70134
|
+
for (const absolute of tree.keys()) {
|
|
70135
|
+
if (!absolute.startsWith(prefix)) continue;
|
|
70136
|
+
files.push(absolute.slice(prefix.length));
|
|
70137
|
+
}
|
|
70138
|
+
return files;
|
|
70139
|
+
}),
|
|
69881
70140
|
isFile: (filePath) => sync(() => tree.has(filePath)),
|
|
69882
70141
|
isDirectory: (filePath) => sync(() => {
|
|
69883
70142
|
const prefix = filePath.endsWith("/") ? filePath : `${filePath}/`;
|
|
@@ -70453,7 +70712,7 @@ const batchIncludePaths = (baseArgs, includePaths) => {
|
|
|
70453
70712
|
for (const filePath of includePaths) {
|
|
70454
70713
|
const entryLength = filePath.length + 1;
|
|
70455
70714
|
const exceedsArgLength = currentBatch.length > 0 && currentBatchLength + entryLength > 24e3;
|
|
70456
|
-
const exceedsFileCount = currentBatch.length >=
|
|
70715
|
+
const exceedsFileCount = currentBatch.length >= 200;
|
|
70457
70716
|
if (exceedsArgLength || exceedsFileCount) {
|
|
70458
70717
|
batches.push(currentBatch);
|
|
70459
70718
|
currentBatch = [];
|
|
@@ -70800,7 +71059,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
70800
71059
|
}
|
|
70801
71060
|
return enabled;
|
|
70802
71061
|
};
|
|
70803
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, runtimeGlobals, unpluginAutoImportGlobalScopes, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
71062
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, runtimeGlobals, unpluginAutoImportGlobalScopes, serverAuthFunctionNames, projectIndexModuleSources, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
70804
71063
|
const hasIncludedTags = includedTags.size > 0;
|
|
70805
71064
|
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
70806
71065
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
@@ -70864,7 +71123,8 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
70864
71123
|
}))
|
|
70865
71124
|
} : {},
|
|
70866
71125
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
70867
|
-
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
71126
|
+
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {},
|
|
71127
|
+
...projectIndexModuleSources !== void 0 ? { projectIndexModuleSources: [...projectIndexModuleSources] } : {}
|
|
70868
71128
|
} },
|
|
70869
71129
|
rules: {
|
|
70870
71130
|
...reactCompilerRules,
|
|
@@ -72349,6 +72609,12 @@ const buildProfiledNodeArguments = (input) => [
|
|
|
72349
72609
|
...input.heapProfileDirectory ? ["--heap-prof", `--heap-prof-dir=${input.heapProfileDirectory}`] : [],
|
|
72350
72610
|
...input.argumentsList
|
|
72351
72611
|
];
|
|
72612
|
+
const lowerChildProcessPriority = (processId) => {
|
|
72613
|
+
if (processId === void 0) return;
|
|
72614
|
+
try {
|
|
72615
|
+
OS.setPriority(processId, OS.constants.priority.PRIORITY_BELOW_NORMAL);
|
|
72616
|
+
} catch {}
|
|
72617
|
+
};
|
|
72352
72618
|
const SANITIZED_ENV = buildOxlintChildEnv(process.env);
|
|
72353
72619
|
/**
|
|
72354
72620
|
* Spawn one oxlint subprocess with hard ceilings on wall time and
|
|
@@ -72387,6 +72653,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
72387
72653
|
"pipe"
|
|
72388
72654
|
]
|
|
72389
72655
|
});
|
|
72656
|
+
lowerChildProcessPriority(child.pid);
|
|
72390
72657
|
const onAbort = () => {
|
|
72391
72658
|
child.kill("SIGKILL");
|
|
72392
72659
|
reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
|
|
@@ -72509,7 +72776,7 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
72509
72776
|
* loop with a slimmer config in that case.
|
|
72510
72777
|
*/
|
|
72511
72778
|
const spawnLintBatches = async (input) => {
|
|
72512
|
-
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth =
|
|
72779
|
+
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 9, signal, deadlineEpochMs } = input;
|
|
72513
72780
|
const resolveSourcePath = (filePath) => {
|
|
72514
72781
|
const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
|
|
72515
72782
|
return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
|
|
@@ -72517,6 +72784,12 @@ const spawnLintBatches = async (input) => {
|
|
|
72517
72784
|
const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
|
|
72518
72785
|
let rescueDeadlineEpochMs;
|
|
72519
72786
|
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
|
|
72787
|
+
const resolveSpawnTimeoutMs = () => {
|
|
72788
|
+
const deadlineBudgets = [deadlineEpochMs, rescueDeadlineEpochMs].filter((deadline) => deadline !== void 0).map(remainingDeadlineBudgetMs);
|
|
72789
|
+
if (deadlineBudgets.length === 0) return spawnTimeoutMs;
|
|
72790
|
+
const remainingDeadlineMs = Math.min(...deadlineBudgets);
|
|
72791
|
+
return spawnTimeoutMs === void 0 ? remainingDeadlineMs : Math.min(spawnTimeoutMs, remainingDeadlineMs);
|
|
72792
|
+
};
|
|
72520
72793
|
const runBatchPass = async (concurrency, passBatches, passOnFileProgress) => {
|
|
72521
72794
|
const totalFileCount = passBatches.reduce((sum, batch) => sum + batch.length, 0);
|
|
72522
72795
|
const allDiagnostics = [];
|
|
@@ -72534,12 +72807,13 @@ const spawnLintBatches = async (input) => {
|
|
|
72534
72807
|
const batchArgs = [...baseArgs, ...batch];
|
|
72535
72808
|
try {
|
|
72536
72809
|
const spawnBatch = () => {
|
|
72537
|
-
|
|
72810
|
+
const effectiveSpawnTimeoutMs = resolveSpawnTimeoutMs();
|
|
72811
|
+
if (effectiveSpawnTimeoutMs === 0) {
|
|
72538
72812
|
deadlineSkippedFiles.push(...batch);
|
|
72539
72813
|
batchState.deadlineSkippedFileCount += batch.length;
|
|
72540
72814
|
return Promise.resolve(null);
|
|
72541
72815
|
}
|
|
72542
|
-
return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath,
|
|
72816
|
+
return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, effectiveSpawnTimeoutMs, outputMaxBytes, signal, () => {
|
|
72543
72817
|
if (batchState.didStart) return;
|
|
72544
72818
|
batchState.didStart = true;
|
|
72545
72819
|
startedFileCount += batchState.initialFileCount;
|
|
@@ -72694,11 +72968,36 @@ const validateRuleRegistration = () => {
|
|
|
72694
72968
|
].filter((entry) => entry !== null).join("; ");
|
|
72695
72969
|
console.warn(`[react-doctor] rule-registration drift: ${detail}`);
|
|
72696
72970
|
};
|
|
72971
|
+
const PROJECT_INDEX_MODULE_SOURCES = [
|
|
72972
|
+
"next/og",
|
|
72973
|
+
"@vercel/og",
|
|
72974
|
+
"satori",
|
|
72975
|
+
"remotion"
|
|
72976
|
+
];
|
|
72977
|
+
const collectProjectIndexModuleSources = async (rootDirectory, candidateFiles) => {
|
|
72978
|
+
const foundModuleSources = /* @__PURE__ */ new Set();
|
|
72979
|
+
let sliceStartedAt = performance.now();
|
|
72980
|
+
for (const candidateFile of candidateFiles) {
|
|
72981
|
+
let sourceBuffer;
|
|
72982
|
+
try {
|
|
72983
|
+
sourceBuffer = NFS.readFileSync(Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile));
|
|
72984
|
+
} catch {
|
|
72985
|
+
continue;
|
|
72986
|
+
}
|
|
72987
|
+
for (const moduleSource of PROJECT_INDEX_MODULE_SOURCES) if (sourceBuffer.includes(`"${moduleSource}"`) || sourceBuffer.includes(`'${moduleSource}'`)) foundModuleSources.add(moduleSource);
|
|
72988
|
+
if (foundModuleSources.size === PROJECT_INDEX_MODULE_SOURCES.length) break;
|
|
72989
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
72990
|
+
await yieldToEventLoop();
|
|
72991
|
+
sliceStartedAt = performance.now();
|
|
72992
|
+
}
|
|
72993
|
+
}
|
|
72994
|
+
return [...foundModuleSources].sort();
|
|
72995
|
+
};
|
|
72697
72996
|
/**
|
|
72698
72997
|
* Balanced LPT (longest-processing-time-first) lint batch planner. Where
|
|
72699
|
-
* `batchIncludePaths` greedily fills
|
|
72700
|
-
* remainder batch
|
|
72701
|
-
*
|
|
72998
|
+
* `batchIncludePaths` greedily fills fixed-size batches and leaves a small
|
|
72999
|
+
* remainder batch, so the parallel pool's wall clock is set by whichever
|
|
73000
|
+
* full chunk happened to collect the most work while
|
|
72702
73001
|
* the remainder's worker idles), this planner keeps the SAME mandatory batch
|
|
72703
73002
|
* count — `ceil(files / OXLINT_MAX_FILES_PER_BATCH)`, the JS-plugin
|
|
72704
73003
|
* perf-cliff / native-binding SIGABRT guard — and assigns files largest-first,
|
|
@@ -72727,7 +73026,7 @@ const validateRuleRegistration = () => {
|
|
|
72727
73026
|
*/
|
|
72728
73027
|
const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
|
|
72729
73028
|
if (files.length === 0) return [];
|
|
72730
|
-
const batchCount = Math.ceil(files.length /
|
|
73029
|
+
const batchCount = Math.ceil(files.length / 200);
|
|
72731
73030
|
const maxFilesPerBatch = Math.ceil(files.length / batchCount);
|
|
72732
73031
|
const baseArgsLengthChars = estimateArgsLength(baseArgs);
|
|
72733
73032
|
const descendingSizeIndexes = [...files.keys()].sort((leftIndex, rightIndex) => (sizeByFile.get(files[rightIndex]) ?? 0) - (sizeByFile.get(files[leftIndex]) ?? 0));
|
|
@@ -73256,6 +73555,7 @@ const runOxlint = async (options) => {
|
|
|
73256
73555
|
await yieldToEventLoop();
|
|
73257
73556
|
const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
|
|
73258
73557
|
const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
|
|
73558
|
+
const projectIndexModuleSources = includePaths === void 0 && options.deadlineEpochMs === void 0 ? await collectProjectIndexModuleSources(rootDirectory, candidateFiles) : void 0;
|
|
73259
73559
|
unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
|
|
73260
73560
|
rootDirectory,
|
|
73261
73561
|
candidateFiles
|
|
@@ -73278,6 +73578,7 @@ const runOxlint = async (options) => {
|
|
|
73278
73578
|
runtimeGlobals,
|
|
73279
73579
|
unpluginAutoImportGlobalScopes,
|
|
73280
73580
|
serverAuthFunctionNames,
|
|
73581
|
+
projectIndexModuleSources,
|
|
73281
73582
|
severityControls,
|
|
73282
73583
|
userPlugins,
|
|
73283
73584
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
@@ -73745,10 +74046,10 @@ const translateProjectInfoError = (cause, directory) => {
|
|
|
73745
74046
|
}) });
|
|
73746
74047
|
};
|
|
73747
74048
|
var Project = class Project extends Service()("react-doctor/Project") {
|
|
73748
|
-
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (
|
|
74049
|
+
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (input) {
|
|
73749
74050
|
return yield* try_({
|
|
73750
|
-
try: () => discoverProject(directory),
|
|
73751
|
-
catch: (cause) => translateProjectInfoError(cause, directory)
|
|
74051
|
+
try: () => discoverProject(input.directory, { sourceFileCount: input.sourceFileCount }),
|
|
74052
|
+
catch: (cause) => translateProjectInfoError(cause, input.directory)
|
|
73752
74053
|
});
|
|
73753
74054
|
}) }));
|
|
73754
74055
|
static layerOf = (projectInfo) => succeed$3(Project, Project.of({ discover: () => succeed$2(projectInfo) }));
|
|
@@ -74333,9 +74634,10 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
74333
74634
|
* outage.
|
|
74334
74635
|
*/
|
|
74335
74636
|
var SupplyChain = class SupplyChain extends Service()("react-doctor/SupplyChain") {
|
|
74336
|
-
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (
|
|
74337
|
-
|
|
74338
|
-
|
|
74637
|
+
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (configuredTimeoutMs) => checkSupplyChain({
|
|
74638
|
+
rootDirectory: input.rootDirectory,
|
|
74639
|
+
userConfig: input.userConfig,
|
|
74640
|
+
totalTimeoutMs: input.timeoutMs ?? configuredTimeoutMs
|
|
74339
74641
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), withSpan("SupplyChain.run"))) }));
|
|
74340
74642
|
static layerOf = (diagnostics) => succeed$3(SupplyChain, SupplyChain.of({ run: () => fromIterable$1(diagnostics) }));
|
|
74341
74643
|
};
|
|
@@ -74451,8 +74753,28 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74451
74753
|
const partialFailuresRef = yield* LintPartialFailures;
|
|
74452
74754
|
const resolvedConfig = yield* configService.resolve(input.directory);
|
|
74453
74755
|
const scanDirectory = resolvedConfig.resolvedDirectory;
|
|
74454
|
-
const
|
|
74756
|
+
const excludedProjectDirectories = (input.excludedProjectDirectories ?? []).map((excludedDirectory) => Path.resolve(excludedDirectory)).filter((excludedDirectory) => isPathInsideDirectory(excludedDirectory, scanDirectory));
|
|
74757
|
+
const excludedProjectRelativePaths = excludedProjectDirectories.map((excludedDirectory) => Path.relative(scanDirectory, excludedDirectory).replaceAll("\\", "/"));
|
|
74758
|
+
const isExcludedProjectDiagnostic = (diagnostic) => {
|
|
74759
|
+
const relativeFilePath = toNormalizedRelativePath(diagnostic.filePath, scanDirectory);
|
|
74760
|
+
return excludedProjectRelativePaths.some((excludedRelativePath) => relativeFilePath === excludedRelativePath || relativeFilePath.startsWith(`${excludedRelativePath}/`));
|
|
74761
|
+
};
|
|
74762
|
+
const precomputedSourceFiles = input.suppressScanSummary === true || excludedProjectDirectories.length > 0 ? yield* filesService.listSourceFilesCooperative({
|
|
74763
|
+
rootDirectory: scanDirectory,
|
|
74764
|
+
signal: input.signal
|
|
74765
|
+
}) : null;
|
|
74766
|
+
const includedPrecomputedSourceFiles = precomputedSourceFiles !== null && excludedProjectDirectories.length > 0 ? filterPathsOutsideDirectories({
|
|
74767
|
+
rootDirectory: scanDirectory,
|
|
74768
|
+
relativePaths: precomputedSourceFiles,
|
|
74769
|
+
excludedDirectories: excludedProjectDirectories
|
|
74770
|
+
}) : precomputedSourceFiles;
|
|
74771
|
+
const sourceFileCount = excludedProjectDirectories.length > 0 ? includedPrecomputedSourceFiles?.length : input.precomputedSourceFileCount ?? includedPrecomputedSourceFiles?.length;
|
|
74772
|
+
const project = yield* projectService.discover({
|
|
74773
|
+
directory: scanDirectory,
|
|
74774
|
+
sourceFileCount
|
|
74775
|
+
});
|
|
74455
74776
|
if (!isAnalyzableProject(project)) return yield* new ReactDoctorError({ reason: new NoReactDependency({ directory: scanDirectory }) });
|
|
74777
|
+
const deadCodeSourceFileCount = input.retainExcludedProjectDeadCodeDiagnostics === true && precomputedSourceFiles !== null ? precomputedSourceFiles.length : project.sourceFileCount;
|
|
74456
74778
|
const [repo, sha, defaultBranch] = yield* all([
|
|
74457
74779
|
gitService.githubRepo(scanDirectory).pipe(orElseSucceed(() => null)),
|
|
74458
74780
|
gitService.headSha(scanDirectory).pipe(orElseSucceed(() => null)),
|
|
@@ -74463,8 +74785,13 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74463
74785
|
directory: scanDirectory,
|
|
74464
74786
|
repo
|
|
74465
74787
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
74466
|
-
|
|
74467
|
-
|
|
74788
|
+
let lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, includedPrecomputedSourceFiles ?? void 0);
|
|
74789
|
+
if (excludedProjectDirectories.length > 0) lintIncludePaths = filterPathsOutsideDirectories({
|
|
74790
|
+
rootDirectory: scanDirectory,
|
|
74791
|
+
relativePaths: lintIncludePaths ?? includedPrecomputedSourceFiles ?? (yield* filesService.listSourceFiles(scanDirectory)),
|
|
74792
|
+
excludedDirectories: excludedProjectDirectories
|
|
74793
|
+
});
|
|
74794
|
+
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? includedPrecomputedSourceFiles ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
74468
74795
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
74469
74796
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
74470
74797
|
yield* beforeLint(project, lintIncludePaths ?? void 0);
|
|
@@ -74487,17 +74814,31 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74487
74814
|
...checkReactNativeProject(scanDirectory, project)
|
|
74488
74815
|
])));
|
|
74489
74816
|
const securityScanFailedRef = yield* make$13(false);
|
|
74490
|
-
|
|
74817
|
+
let didSecurityScanReachDeadline = false;
|
|
74818
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise((signal) => checkSecurityScanCooperative(scanDirectory, {
|
|
74491
74819
|
project,
|
|
74492
74820
|
ignoredTags: input.ignoredTags,
|
|
74493
74821
|
includedTags: input.includedTags,
|
|
74494
|
-
includeTagDefaults: input.includeTagDefaults
|
|
74822
|
+
includeTagDefaults: input.includeTagDefaults,
|
|
74823
|
+
excludedDirectories: new Set(excludedProjectDirectories),
|
|
74824
|
+
deadlineEpochMs: input.deadlineEpochMs,
|
|
74825
|
+
signal,
|
|
74826
|
+
onDeadlineExceeded: () => {
|
|
74827
|
+
didSecurityScanReachDeadline = true;
|
|
74828
|
+
}
|
|
74495
74829
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
74830
|
+
const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
|
|
74831
|
+
const capOptionalToDeadline = (phaseTimeoutMs) => {
|
|
74832
|
+
if (input.deadlineEpochMs === void 0) return phaseTimeoutMs;
|
|
74833
|
+
const remainingBudgetMs = remainingDeadlineBudgetMs(input.deadlineEpochMs);
|
|
74834
|
+
return phaseTimeoutMs === null ? remainingBudgetMs : Math.min(phaseTimeoutMs, remainingBudgetMs);
|
|
74835
|
+
};
|
|
74496
74836
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
74497
|
-
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
74837
|
+
const supplyChainOverlapTimeout = capToDeadline(yield* SupplyChainOverlapTimeoutMs);
|
|
74498
74838
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
74499
74839
|
rootDirectory: scanDirectory,
|
|
74500
|
-
userConfig: resolvedConfig.config
|
|
74840
|
+
userConfig: resolvedConfig.config,
|
|
74841
|
+
timeoutMs: supplyChainOverlapTimeout
|
|
74501
74842
|
}))).pipe(map$3((diagnostics) => ({
|
|
74502
74843
|
diagnostics,
|
|
74503
74844
|
timedOut: false
|
|
@@ -74521,46 +74862,49 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74521
74862
|
const scanConcurrency = resolveScanConcurrency(yield* OxlintConcurrency);
|
|
74522
74863
|
const lintPhaseTimeoutMs = yield* LintPhaseTimeoutMs;
|
|
74523
74864
|
const deadCodePhaseTimeoutMs = yield* DeadCodePhaseTimeoutMs;
|
|
74524
|
-
const resolveDeadCodePhaseTimeoutMs = (scaledPhaseTimeoutMs) => deadCodePhaseTimeoutMs === 15e4 ? scaledPhaseTimeoutMs : deadCodePhaseTimeoutMs;
|
|
74525
74865
|
const workerCountSuffix = scanConcurrency > 1 ? ` ${highlighter.dim(`[~${scanConcurrency} workers]`)}` : "";
|
|
74526
|
-
const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
|
|
74527
74866
|
const shouldRunDeadCode = input.runDeadCode && !isDiffMode && (showWarnings || deadCodeMaySurfaceWhenWarningsHidden(resolvedConfig.config));
|
|
74528
74867
|
const deadCodeOverlapMode = yield* DeadCodeOverlap;
|
|
74529
74868
|
const shouldOverlapDeadCode = shouldRunDeadCode && deadCodeOverlapMode === "on";
|
|
74530
74869
|
const deadCodeParseConcurrency = shouldOverlapDeadCode ? Math.max(1, Math.floor(scanConcurrency * DEAD_CODE_OVERLAP_PARSE_SHARE)) : void 0;
|
|
74531
74870
|
const lintConcurrency = deadCodeParseConcurrency === void 0 ? scanConcurrency : Math.max(1, scanConcurrency - deadCodeParseConcurrency);
|
|
74532
|
-
const buildCollectDeadCode = (deadCodeTimeout) =>
|
|
74533
|
-
|
|
74534
|
-
|
|
74535
|
-
|
|
74536
|
-
|
|
74537
|
-
|
|
74538
|
-
|
|
74539
|
-
|
|
74540
|
-
|
|
74541
|
-
|
|
74542
|
-
|
|
74543
|
-
|
|
74544
|
-
|
|
74545
|
-
|
|
74546
|
-
|
|
74547
|
-
|
|
74548
|
-
|
|
74549
|
-
|
|
74550
|
-
|
|
74551
|
-
|
|
74552
|
-
|
|
74553
|
-
|
|
74554
|
-
|
|
74555
|
-
|
|
74871
|
+
const buildCollectDeadCode = (deadCodeTimeout) => {
|
|
74872
|
+
const collectDeadCode = runCollect(applyPerElementPipeline(deadCodeService.run({
|
|
74873
|
+
rootDirectory: scanDirectory,
|
|
74874
|
+
parseConcurrency: deadCodeParseConcurrency,
|
|
74875
|
+
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
|
|
74876
|
+
onCacheOutcome: (didHitCache) => {
|
|
74877
|
+
deadCodeCacheHit = didHitCache;
|
|
74878
|
+
},
|
|
74879
|
+
onSummaryCacheStats: (stats) => {
|
|
74880
|
+
deadCodeSummaryCacheHits = stats.hits;
|
|
74881
|
+
deadCodeSummaryCacheMisses = stats.misses;
|
|
74882
|
+
}
|
|
74883
|
+
}).pipe(filter((diagnostic) => input.retainExcludedProjectDeadCodeDiagnostics === true || !isExcludedProjectDiagnostic(diagnostic)), catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
74884
|
+
yield* set(deadCodeFailure, {
|
|
74885
|
+
didFail: true,
|
|
74886
|
+
reason: error.message
|
|
74887
|
+
});
|
|
74888
|
+
return empty$4;
|
|
74889
|
+
}))))));
|
|
74890
|
+
const phaseTimeoutMs = deadCodeTimeout.phaseTimeoutMs;
|
|
74891
|
+
if (phaseTimeoutMs === null) return collectDeadCode;
|
|
74892
|
+
return collectDeadCode.pipe(timeoutOption(phaseTimeoutMs), flatMap$2(match$3({
|
|
74893
|
+
onNone: () => set(deadCodeFailure, {
|
|
74894
|
+
didFail: true,
|
|
74895
|
+
reason: `Dead-code analysis exceeded ${Math.round(phaseTimeoutMs / MILLISECONDS_PER_SECOND)}s and was skipped.`
|
|
74896
|
+
}).pipe(as([])),
|
|
74897
|
+
onSome: succeed$2
|
|
74898
|
+
})));
|
|
74899
|
+
};
|
|
74556
74900
|
const overlapDeadCodeTimeout = resolveDeadCodeTimeout({
|
|
74557
|
-
sourceFileCount:
|
|
74901
|
+
sourceFileCount: deadCodeSourceFileCount,
|
|
74558
74902
|
deadCodeConcurrency: deadCodeParseConcurrency ?? scanConcurrency,
|
|
74559
74903
|
fullConcurrency: scanConcurrency
|
|
74560
74904
|
});
|
|
74561
74905
|
const deadCodeFiber = shouldOverlapDeadCode ? yield* forkChild(buildCollectDeadCode({
|
|
74562
74906
|
workerTimeoutMs: overlapDeadCodeTimeout.workerTimeoutMs,
|
|
74563
|
-
phaseTimeoutMs:
|
|
74907
|
+
phaseTimeoutMs: capOptionalToDeadline(deadCodePhaseTimeoutMs)
|
|
74564
74908
|
})) : null;
|
|
74565
74909
|
const scanProgress = yield* progressService.start("Scanning...");
|
|
74566
74910
|
const scanStartTime = Date.now();
|
|
@@ -74611,7 +74955,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74611
74955
|
});
|
|
74612
74956
|
return empty$4;
|
|
74613
74957
|
}))));
|
|
74614
|
-
const
|
|
74958
|
+
const collectLintDiagnostics = runCollect(filterPerElementPipeline(shouldOverlapDeadCode ? baseLintStream.pipe(provideService(OxlintConcurrency, lintConcurrency)) : baseLintStream));
|
|
74959
|
+
const lintCollected = dedupeRelatedDiagnostics(yield* lintPhaseTimeoutMs === null ? collectLintDiagnostics : collectLintDiagnostics.pipe(timeoutOption(lintPhaseTimeoutMs), flatMap$2(match$3({
|
|
74615
74960
|
onNone: () => set(lintFailure, {
|
|
74616
74961
|
didFail: true,
|
|
74617
74962
|
reason: `Lint analysis exceeded ${lintPhaseTimeoutMs / MILLISECONDS_PER_SECOND}s and was skipped.`,
|
|
@@ -74641,13 +74986,13 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74641
74986
|
} else {
|
|
74642
74987
|
yield* scanProgress.update(`Scanned ${scannedFilesLabel}, analyzing dead code...`);
|
|
74643
74988
|
const sequentialDeadCodeTimeout = resolveDeadCodeTimeout({
|
|
74644
|
-
sourceFileCount: totalFileCount,
|
|
74989
|
+
sourceFileCount: input.retainExcludedProjectDeadCodeDiagnostics === true ? deadCodeSourceFileCount : totalFileCount,
|
|
74645
74990
|
deadCodeConcurrency: scanConcurrency,
|
|
74646
74991
|
fullConcurrency: scanConcurrency
|
|
74647
74992
|
});
|
|
74648
74993
|
deadCodeCollected = deadCodeFiber !== null ? yield* join(deadCodeFiber) : yield* buildCollectDeadCode({
|
|
74649
74994
|
workerTimeoutMs: sequentialDeadCodeTimeout.workerTimeoutMs,
|
|
74650
|
-
phaseTimeoutMs:
|
|
74995
|
+
phaseTimeoutMs: capOptionalToDeadline(deadCodePhaseTimeoutMs)
|
|
74651
74996
|
});
|
|
74652
74997
|
}
|
|
74653
74998
|
const deadCodeFailureState = lintFailureState.didFail ? {
|
|
@@ -74691,7 +75036,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74691
75036
|
metadata: scoreMetadata
|
|
74692
75037
|
});
|
|
74693
75038
|
const lintPartialFailures = yield* get$2(partialFailuresRef);
|
|
74694
|
-
const
|
|
75039
|
+
const didSecurityScanFail = yield* get$2(securityScanFailedRef);
|
|
75040
|
+
const securityScanFailed = didSecurityScanFail || didSecurityScanReachDeadline;
|
|
75041
|
+
let securityScanFailureReason = null;
|
|
75042
|
+
if (didSecurityScanReachDeadline) securityScanFailureReason = "Security scan reached the max scan duration; findings collected before the deadline were preserved.";
|
|
75043
|
+
else if (didSecurityScanFail) securityScanFailureReason = "Security scan failed and was skipped.";
|
|
74695
75044
|
return {
|
|
74696
75045
|
project,
|
|
74697
75046
|
userConfig: resolvedConfig.config,
|
|
@@ -74714,6 +75063,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74714
75063
|
scanConcurrency,
|
|
74715
75064
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
74716
75065
|
securityScanFailed,
|
|
75066
|
+
securityScanFailureReason,
|
|
74717
75067
|
lintCacheHitFileCount,
|
|
74718
75068
|
lintCacheTotalFileCount,
|
|
74719
75069
|
lintSidecarReplayedFileCount,
|
|
@@ -74729,7 +75079,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74729
75079
|
"inspect.runDeadCode": input.runDeadCode,
|
|
74730
75080
|
"inspect.isCi": input.isCi,
|
|
74731
75081
|
"inspect.scoreSurface": input.scoreSurface ?? "score"
|
|
74732
|
-
} }), (scanProgram) => flatMap$2(ScanDeadlineMs, (scanDeadlineMs) =>
|
|
75082
|
+
} }), (scanProgram) => flatMap$2(ScanDeadlineMs, (scanDeadlineMs) => {
|
|
75083
|
+
if (scanDeadlineMs === null) return scanProgram;
|
|
75084
|
+
return scanProgram.pipe(timeout(scanDeadlineMs), catchTag$1("TimeoutError", () => new ReactDoctorError({ reason: new ScanDeadlineExceeded({ detail: `${scanDeadlineMs / MILLISECONDS_PER_SECOND}s elapsed` }) })));
|
|
75085
|
+
}));
|
|
74733
75086
|
const parseNodeVersion = (versionString) => {
|
|
74734
75087
|
const [major = 0, minor = 0, patch = 0] = versionString.replace(/^v/, "").trim().split(".").map(Number);
|
|
74735
75088
|
return {
|
|
@@ -74830,16 +75183,6 @@ const resolveNodeForOxlint = () => {
|
|
|
74830
75183
|
});
|
|
74831
75184
|
});
|
|
74832
75185
|
/**
|
|
74833
|
-
* Zip-Slip defense: relative paths come from git (`diff --name-only`), which
|
|
74834
|
-
* normalizes during ordinary adds, but a crafted index/pack/symlinked tree can
|
|
74835
|
-
* smuggle `..` segments that escape the temp root. Resolve against the temp dir
|
|
74836
|
-
* and reject anything that lands outside before writing.
|
|
74837
|
-
*/
|
|
74838
|
-
const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
74839
|
-
const relative = path.relative(parentAbsolutePath, childAbsolutePath);
|
|
74840
|
-
return Boolean(relative) && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
74841
|
-
};
|
|
74842
|
-
/**
|
|
74843
75186
|
* Writes a set of source files (supplied by `readContent` — e.g.
|
|
74844
75187
|
* `git show <ref>:<path>` for a baseline tree, or `git show :<path>` for the
|
|
74845
75188
|
* index) into a temp tree that mirrors the project layout, copying the
|
|
@@ -76767,8 +77110,11 @@ const METRIC = {
|
|
|
76767
77110
|
scanPhaseDuration: "scan.phase_duration",
|
|
76768
77111
|
scanFiles: "scan.files",
|
|
76769
77112
|
scanScore: "scan.score",
|
|
77113
|
+
scanScoreRetry: "scan.score_retry",
|
|
76770
77114
|
scanClean: "scan.clean",
|
|
76771
77115
|
scanCheckSkipped: "scan.check_skipped",
|
|
77116
|
+
scanProjectSkipped: "scan.project_skipped",
|
|
77117
|
+
scanWorkspaceDeadCodeShared: "scan.workspace_deadcode_shared",
|
|
76772
77118
|
scanNoReactDetected: "scan.no_react_detected",
|
|
76773
77119
|
baselineDegraded: "baseline.degraded",
|
|
76774
77120
|
ruleFired: "rule.fired",
|
|
@@ -76795,9 +77141,13 @@ const METRIC = {
|
|
|
76795
77141
|
lspScanCompleted: "lsp.scan.completed",
|
|
76796
77142
|
lspScanDuration: "lsp.scan.duration",
|
|
76797
77143
|
lspScanDiagnostics: "lsp.scan.diagnostics",
|
|
76798
|
-
tuiActionMenuOpened: "tui.action_menu_opened",
|
|
76799
77144
|
tuiCompactReportShown: "tui.compact_report_shown",
|
|
76800
77145
|
tuiFindingNavigated: "tui.finding_navigated",
|
|
77146
|
+
tuiIssueStreamShown: "tui.issue_stream_shown",
|
|
77147
|
+
tuiProjectPathContextShown: "tui.project_path_context_shown",
|
|
77148
|
+
tuiReportActionSelected: "tui.report_action_selected",
|
|
77149
|
+
tuiCancelled: "tui.cancelled",
|
|
77150
|
+
tuiScanInlineShown: "tui.scan_inline_shown",
|
|
76801
77151
|
tuiStackedReportCapped: "tui.stacked_report_capped",
|
|
76802
77152
|
aiTrainingWarningShown: "ai.training.warning_shown",
|
|
76803
77153
|
jsonOutUsed: "json.out_used"
|
|
@@ -77100,5 +77450,5 @@ const startLanguageServer = () => {
|
|
|
77100
77450
|
};
|
|
77101
77451
|
//#endregion
|
|
77102
77452
|
export { startLanguageServer };
|
|
77103
|
-
!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]="
|
|
77104
|
-
//# debugId=
|
|
77453
|
+
!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]="987837fa-d5be-5f58-a2e6-feaeda00b877")}catch(e){}}();
|
|
77454
|
+
//# debugId=987837fa-d5be-5f58-a2e6-feaeda00b877
|