react-doctor 0.9.3 → 0.9.4-dev.212b8b4
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 +1368 -684
- package/dist/index.d.ts +10 -2
- package/dist/index.js +721 -371
- package/dist/lsp.js +773 -344
- package/dist/run-scan-app-C8iWVgvR.js +2326 -0
- package/package.json +7 -6
- 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
|
/**
|
|
@@ -7275,6 +7275,16 @@ const catchTag$2 = /* @__PURE__ */ dual((args) => isEffect$1(args[0]), (self, k,
|
|
|
7275
7275
|
return catchIf$2(self, Array.isArray(k) ? (e) => hasProperty(e, "_tag") && k.includes(e._tag) : isTagged(k), f, orElse);
|
|
7276
7276
|
});
|
|
7277
7277
|
/** @internal */
|
|
7278
|
+
const catchReasons$1 = /* @__PURE__ */ dual((args) => isEffect$1(args[0]), (self, errorTag, cases, orElse) => {
|
|
7279
|
+
let keys;
|
|
7280
|
+
return catchIf$2(self, (e) => isTagged(e, errorTag) && hasProperty(e, "reason") && hasProperty(e.reason, "_tag") && isString(e.reason._tag), (e) => {
|
|
7281
|
+
const reason = e.reason;
|
|
7282
|
+
keys ??= Object.keys(cases);
|
|
7283
|
+
if (keys.includes(reason._tag)) return internalCall(() => cases[reason._tag](reason, e));
|
|
7284
|
+
return orElse ? internalCall(() => orElse(reason, e)) : fail$7(e);
|
|
7285
|
+
});
|
|
7286
|
+
});
|
|
7287
|
+
/** @internal */
|
|
7278
7288
|
const mapError = /* @__PURE__ */ dual(2, (self, f) => catch_$2(self, (error) => failSync(() => f(error))));
|
|
7279
7289
|
const mapBoth = /* @__PURE__ */ dual(2, (self, options) => matchEffect$2(self, {
|
|
7280
7290
|
onFailure: (e) => failSync(() => options.onFailure(e)),
|
|
@@ -12184,6 +12194,42 @@ const catch_$1 = catch_$2;
|
|
|
12184
12194
|
*/
|
|
12185
12195
|
const catchTag$1 = catchTag$2;
|
|
12186
12196
|
/**
|
|
12197
|
+
* Catches multiple reasons within a tagged error using an object of handlers.
|
|
12198
|
+
*
|
|
12199
|
+
* **Example** (Handling multiple error reasons)
|
|
12200
|
+
*
|
|
12201
|
+
* ```ts
|
|
12202
|
+
* import { Data, Effect } from "effect"
|
|
12203
|
+
*
|
|
12204
|
+
* class RateLimitError extends Data.TaggedError("RateLimitError")<{
|
|
12205
|
+
* retryAfter: number
|
|
12206
|
+
* }> {}
|
|
12207
|
+
*
|
|
12208
|
+
* class QuotaExceededError extends Data.TaggedError("QuotaExceededError")<{
|
|
12209
|
+
* limit: number
|
|
12210
|
+
* }> {}
|
|
12211
|
+
*
|
|
12212
|
+
* class AiError extends Data.TaggedError("AiError")<{
|
|
12213
|
+
* reason: RateLimitError | QuotaExceededError
|
|
12214
|
+
* }> {}
|
|
12215
|
+
*
|
|
12216
|
+
* declare const program: Effect.Effect<string, AiError>
|
|
12217
|
+
*
|
|
12218
|
+
* const handled = program.pipe(
|
|
12219
|
+
* Effect.catchReasons("AiError", {
|
|
12220
|
+
* RateLimitError: (reason) =>
|
|
12221
|
+
* Effect.succeed(`Retry after ${reason.retryAfter}s`),
|
|
12222
|
+
* QuotaExceededError: (reason) =>
|
|
12223
|
+
* Effect.succeed(`Quota exceeded: ${reason.limit}`)
|
|
12224
|
+
* })
|
|
12225
|
+
* )
|
|
12226
|
+
* ```
|
|
12227
|
+
*
|
|
12228
|
+
* @category error handling
|
|
12229
|
+
* @since 4.0.0
|
|
12230
|
+
*/
|
|
12231
|
+
const catchReasons = catchReasons$1;
|
|
12232
|
+
/**
|
|
12187
12233
|
* Handles both recoverable and unrecoverable errors by providing a recovery
|
|
12188
12234
|
* effect.
|
|
12189
12235
|
*
|
|
@@ -15586,7 +15632,7 @@ function transformOptional(f) {
|
|
|
15586
15632
|
*/
|
|
15587
15633
|
function withDefault$1(defaultValue) {
|
|
15588
15634
|
return new Getter((o) => {
|
|
15589
|
-
const filtered = filter(o, isNotUndefined);
|
|
15635
|
+
const filtered = filter$1(o, isNotUndefined);
|
|
15590
15636
|
return isSome(filtered) ? succeed$2(filtered) : mapEager(defaultValue, some);
|
|
15591
15637
|
});
|
|
15592
15638
|
}
|
|
@@ -19434,6 +19480,10 @@ var JsonReportProjectEntryV3 = class extends Class("JsonReportProjectEntryV3")({
|
|
|
19434
19480
|
scannedFileCount: optional(Number$1),
|
|
19435
19481
|
elapsedMilliseconds: Number$1
|
|
19436
19482
|
}) {};
|
|
19483
|
+
var JsonReportSkippedProject = class extends Class("JsonReportSkippedProject")({
|
|
19484
|
+
directory: String$1,
|
|
19485
|
+
reason: Literal("max-duration")
|
|
19486
|
+
}) {};
|
|
19437
19487
|
/** Original full, diff, and staged report contract. */
|
|
19438
19488
|
var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
19439
19489
|
schemaVersion: Literal(1),
|
|
@@ -19462,6 +19512,7 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
19462
19512
|
reactDetected: optional(Boolean$1),
|
|
19463
19513
|
diff: NullOr(JsonReportDiffInfo),
|
|
19464
19514
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19515
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19465
19516
|
diagnostics: ArraySchema(Diagnostic),
|
|
19466
19517
|
summary: JsonReportSummary,
|
|
19467
19518
|
elapsedMilliseconds: Number$1,
|
|
@@ -19490,6 +19541,7 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
19490
19541
|
diff: NullOr(JsonReportDiffInfo),
|
|
19491
19542
|
baseline: JsonReportBaseline,
|
|
19492
19543
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19544
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19493
19545
|
diagnostics: ArraySchema(Diagnostic),
|
|
19494
19546
|
summary: JsonReportSummary,
|
|
19495
19547
|
elapsedMilliseconds: Number$1,
|
|
@@ -19506,6 +19558,7 @@ var JsonReportV3 = class extends Class("JsonReportV3")({
|
|
|
19506
19558
|
diff: NullOr(JsonReportDiffInfo),
|
|
19507
19559
|
baseline: optional(JsonReportBaseline),
|
|
19508
19560
|
projects: ArraySchema(JsonReportProjectEntryV3),
|
|
19561
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19509
19562
|
diagnostics: ArraySchema(JsonReportDiagnosticV3),
|
|
19510
19563
|
summary: JsonReportSummary,
|
|
19511
19564
|
elapsedMilliseconds: Number$1,
|
|
@@ -53488,6 +53541,47 @@ const flattenArray = (self) => transformPull$1(self, (pull) => {
|
|
|
53488
53541
|
}));
|
|
53489
53542
|
});
|
|
53490
53543
|
/**
|
|
53544
|
+
* Filters arrays of elements emitted by a channel, applying the filter
|
|
53545
|
+
* to each element within the arrays and only emitting non-empty filtered arrays.
|
|
53546
|
+
*
|
|
53547
|
+
* **Example** (Filtering array output)
|
|
53548
|
+
*
|
|
53549
|
+
* ```ts
|
|
53550
|
+
* import { Array, Channel } from "effect"
|
|
53551
|
+
*
|
|
53552
|
+
* const nonEmptyArrayPredicate = Array.isReadonlyArrayNonEmpty
|
|
53553
|
+
*
|
|
53554
|
+
* // Create a channel that outputs arrays of mixed data
|
|
53555
|
+
* const arrayChannel = Channel.fromIterable([
|
|
53556
|
+
* Array.make(1, 2, 3, 4, 5),
|
|
53557
|
+
* Array.make(6, 7, 8, 9, 10),
|
|
53558
|
+
* Array.make(11, 12, 13, 14, 15)
|
|
53559
|
+
* ]).pipe(Channel.filter(nonEmptyArrayPredicate))
|
|
53560
|
+
*
|
|
53561
|
+
* // Filter arrays to keep only even numbers
|
|
53562
|
+
* const evenArraysChannel = Channel.filterArray(arrayChannel, (n) => n % 2 === 0)
|
|
53563
|
+
* // Outputs: [2, 4], [6, 8, 10], [12, 14]
|
|
53564
|
+
* // Note: Only non-empty filtered arrays are emitted
|
|
53565
|
+
*
|
|
53566
|
+
* // Arrays that would become empty after filtering are discarded entirely
|
|
53567
|
+
* const oddChannel = Channel.fromIterable([
|
|
53568
|
+
* Array.make(1, 3, 5),
|
|
53569
|
+
* Array.make(2, 4),
|
|
53570
|
+
* Array.make(7, 9)
|
|
53571
|
+
* ]).pipe(Channel.filter(nonEmptyArrayPredicate))
|
|
53572
|
+
* const filteredOddChannel = Channel.filterArray(oddChannel, (n) => n % 2 === 0)
|
|
53573
|
+
* // Outputs: [2, 4] (the arrays [1,3,5] and [7,9] are discarded)
|
|
53574
|
+
* ```
|
|
53575
|
+
*
|
|
53576
|
+
* @category filtering
|
|
53577
|
+
* @since 4.0.0
|
|
53578
|
+
*/
|
|
53579
|
+
const filterArray = /* @__PURE__ */ dual(2, (self, predicate) => transformPull$1(self, (pull) => succeed$2(flatMap$2(pull, function loop(arr) {
|
|
53580
|
+
const passes = [];
|
|
53581
|
+
for (let i = 0; i < arr.length; i++) if (predicate(arr[i])) passes.push(arr[i]);
|
|
53582
|
+
return isReadonlyArrayNonEmpty(passes) ? succeed$2(passes) : flatMap$2(pull, loop);
|
|
53583
|
+
}))));
|
|
53584
|
+
/**
|
|
53491
53585
|
* Filters and maps each element inside emitted non-empty arrays using a
|
|
53492
53586
|
* `Filter`.
|
|
53493
53587
|
*
|
|
@@ -55125,6 +55219,30 @@ const concat = /* @__PURE__ */ dual(2, (self, that) => flatten(fromArray([self,
|
|
|
55125
55219
|
*/
|
|
55126
55220
|
const merge$1 = /* @__PURE__ */ dual((args) => isStream(args[0]) && isStream(args[1]), (self, that, options) => fromChannel(merge$2(toChannel(self), toChannel(that), options)));
|
|
55127
55221
|
/**
|
|
55222
|
+
* Filters a stream to the elements that satisfy a predicate.
|
|
55223
|
+
*
|
|
55224
|
+
* **Example** (Filtering stream values)
|
|
55225
|
+
*
|
|
55226
|
+
* ```ts
|
|
55227
|
+
* import { Console, Effect, Stream } from "effect"
|
|
55228
|
+
*
|
|
55229
|
+
* const program = Effect.gen(function*() {
|
|
55230
|
+
* const stream = Stream.make(1, 2, 3, 4).pipe(
|
|
55231
|
+
* Stream.filter((n) => n % 2 === 0)
|
|
55232
|
+
* )
|
|
55233
|
+
* const values = yield* Stream.runCollect(stream)
|
|
55234
|
+
* yield* Console.log(values)
|
|
55235
|
+
* })
|
|
55236
|
+
*
|
|
55237
|
+
* Effect.runPromise(program)
|
|
55238
|
+
* // Output: [ 2, 4 ]
|
|
55239
|
+
* ```
|
|
55240
|
+
*
|
|
55241
|
+
* @category filtering
|
|
55242
|
+
* @since 2.0.0
|
|
55243
|
+
*/
|
|
55244
|
+
const filter = /* @__PURE__ */ dual(2, (self, predicate) => fromChannel(filterArray(toChannel(self), predicate)));
|
|
55245
|
+
/**
|
|
55128
55246
|
* Filters and maps stream elements in one pass using a `Filter`.
|
|
55129
55247
|
*
|
|
55130
55248
|
* @category filtering
|
|
@@ -61908,6 +62026,7 @@ const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
|
61908
62026
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
61909
62027
|
const MINIFIED_SNIFF_BYTES = 65536;
|
|
61910
62028
|
const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
62029
|
+
const GIT_CHECK_ATTR_MAX_BUFFER_BYTES = GIT_LS_FILES_MAX_BUFFER_BYTES;
|
|
61911
62030
|
const SCANNED_DOT_DIRECTORIES = new Set([".dumi", ".storybook"]);
|
|
61912
62031
|
const IGNORED_DIRECTORIES = new Set([
|
|
61913
62032
|
".angular",
|
|
@@ -62216,13 +62335,9 @@ const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
|
|
|
62216
62335
|
const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
|
|
62217
62336
|
const ABORT_EXIT_CODES = new Set([134, 3221226505]);
|
|
62218
62337
|
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
62338
|
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
62223
62339
|
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
62224
62340
|
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
62225
|
-
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
62226
62341
|
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
62227
62342
|
const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
|
|
62228
62343
|
const REACT_SERVER_DOM_PACKAGES = [
|
|
@@ -62269,7 +62384,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
62269
62384
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
62270
62385
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
62271
62386
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
62272
|
-
const CORE_PACKAGE_VERSION = "0.9.
|
|
62387
|
+
const CORE_PACKAGE_VERSION = "0.9.4";
|
|
62273
62388
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
62274
62389
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
62275
62390
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -62282,17 +62397,20 @@ const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
|
62282
62397
|
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
62283
62398
|
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
62284
62399
|
"EACCES",
|
|
62400
|
+
"EBUSY",
|
|
62285
62401
|
"EPERM",
|
|
62286
62402
|
"ENOENT",
|
|
62287
62403
|
"ENOTDIR",
|
|
62288
62404
|
"EINVAL",
|
|
62289
62405
|
"ELOOP",
|
|
62290
|
-
"ENAMETOOLONG"
|
|
62406
|
+
"ENAMETOOLONG",
|
|
62407
|
+
"ETIMEDOUT",
|
|
62408
|
+
"UNKNOWN"
|
|
62291
62409
|
]);
|
|
62292
62410
|
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
62293
62411
|
const readDirectoryEntries = (directoryPath) => {
|
|
62294
62412
|
try {
|
|
62295
|
-
return
|
|
62413
|
+
return fs.readdirSync(directoryPath, { withFileTypes: true });
|
|
62296
62414
|
} catch (error) {
|
|
62297
62415
|
if (isIgnorableReaddirError(error)) return [];
|
|
62298
62416
|
throw error;
|
|
@@ -62300,14 +62418,14 @@ const readDirectoryEntries = (directoryPath) => {
|
|
|
62300
62418
|
};
|
|
62301
62419
|
const isFile = (filePath) => {
|
|
62302
62420
|
try {
|
|
62303
|
-
return
|
|
62421
|
+
return fs.statSync(filePath).isFile();
|
|
62304
62422
|
} catch {
|
|
62305
62423
|
return false;
|
|
62306
62424
|
}
|
|
62307
62425
|
};
|
|
62308
62426
|
const isDirectory = (directoryPath) => {
|
|
62309
62427
|
try {
|
|
62310
|
-
return
|
|
62428
|
+
return fs.statSync(directoryPath).isDirectory();
|
|
62311
62429
|
} catch {
|
|
62312
62430
|
return false;
|
|
62313
62431
|
}
|
|
@@ -62317,6 +62435,66 @@ const isPlainObject = (value) => {
|
|
|
62317
62435
|
const prototype = Object.getPrototypeOf(value);
|
|
62318
62436
|
return prototype === null || prototype === Object.prototype;
|
|
62319
62437
|
};
|
|
62438
|
+
const LINGUIST_ATTRIBUTES = ["linguist-generated", "linguist-vendored"];
|
|
62439
|
+
const DISABLED_ATTRIBUTE_VALUES = new Set([
|
|
62440
|
+
"unspecified",
|
|
62441
|
+
"unset",
|
|
62442
|
+
"false",
|
|
62443
|
+
"0",
|
|
62444
|
+
"off",
|
|
62445
|
+
"no"
|
|
62446
|
+
]);
|
|
62447
|
+
const buildInput = (relativePaths) => `${relativePaths.join("\0")}\0`;
|
|
62448
|
+
const parseIgnoredPaths = (output) => {
|
|
62449
|
+
const ignoredPaths = /* @__PURE__ */ new Set();
|
|
62450
|
+
const fields = output.split("\0");
|
|
62451
|
+
for (let fieldIndex = 0; fieldIndex + 2 < fields.length; fieldIndex += 3) {
|
|
62452
|
+
const filePath = fields[fieldIndex];
|
|
62453
|
+
const value = fields[fieldIndex + 2]?.toLowerCase();
|
|
62454
|
+
if (filePath && value && !DISABLED_ATTRIBUTE_VALUES.has(value)) ignoredPaths.add(filePath);
|
|
62455
|
+
}
|
|
62456
|
+
return ignoredPaths;
|
|
62457
|
+
};
|
|
62458
|
+
const collectGitLinguistIgnoredPaths = (rootDirectory, relativePaths) => {
|
|
62459
|
+
if (relativePaths.length === 0) return /* @__PURE__ */ new Set();
|
|
62460
|
+
const result = spawnSync("git", [
|
|
62461
|
+
"check-attr",
|
|
62462
|
+
"-z",
|
|
62463
|
+
"--stdin",
|
|
62464
|
+
...LINGUIST_ATTRIBUTES
|
|
62465
|
+
], {
|
|
62466
|
+
cwd: rootDirectory,
|
|
62467
|
+
encoding: "utf-8",
|
|
62468
|
+
input: buildInput(relativePaths),
|
|
62469
|
+
maxBuffer: GIT_CHECK_ATTR_MAX_BUFFER_BYTES
|
|
62470
|
+
});
|
|
62471
|
+
if (result.error || result.status !== 0) return /* @__PURE__ */ new Set();
|
|
62472
|
+
return parseIgnoredPaths(result.stdout);
|
|
62473
|
+
};
|
|
62474
|
+
const collectGitLinguistIgnoredPathsCooperative = (rootDirectory, relativePaths, signal) => {
|
|
62475
|
+
if (relativePaths.length === 0) return Promise.resolve(/* @__PURE__ */ new Set());
|
|
62476
|
+
return new Promise((resolve, reject) => {
|
|
62477
|
+
signal?.throwIfAborted();
|
|
62478
|
+
execFile("git", [
|
|
62479
|
+
"check-attr",
|
|
62480
|
+
"-z",
|
|
62481
|
+
"--stdin",
|
|
62482
|
+
...LINGUIST_ATTRIBUTES
|
|
62483
|
+
], {
|
|
62484
|
+
cwd: rootDirectory,
|
|
62485
|
+
encoding: "utf-8",
|
|
62486
|
+
killSignal: "SIGKILL",
|
|
62487
|
+
maxBuffer: GIT_CHECK_ATTR_MAX_BUFFER_BYTES,
|
|
62488
|
+
signal
|
|
62489
|
+
}, (error, stdout) => {
|
|
62490
|
+
if (signal?.aborted) {
|
|
62491
|
+
reject(signal.reason);
|
|
62492
|
+
return;
|
|
62493
|
+
}
|
|
62494
|
+
resolve(error ? /* @__PURE__ */ new Set() : parseIgnoredPaths(stdout));
|
|
62495
|
+
}).stdin?.end(buildInput(relativePaths));
|
|
62496
|
+
});
|
|
62497
|
+
};
|
|
62320
62498
|
const lastSourceMappingUrl = (fileContent) => {
|
|
62321
62499
|
const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
|
|
62322
62500
|
return lastReference ? lastReference[1] : null;
|
|
@@ -62421,6 +62599,9 @@ function* walkSourceTreeFiles(rootDirectory) {
|
|
|
62421
62599
|
}
|
|
62422
62600
|
}
|
|
62423
62601
|
}
|
|
62602
|
+
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
62603
|
+
setImmediate(resolve);
|
|
62604
|
+
});
|
|
62424
62605
|
const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
62425
62606
|
const entries = [];
|
|
62426
62607
|
for (const relativePath of relativePaths) {
|
|
@@ -62434,23 +62615,55 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
|
62434
62615
|
}
|
|
62435
62616
|
return entries;
|
|
62436
62617
|
};
|
|
62437
|
-
const
|
|
62618
|
+
const collectSizedSourceFilesCooperative = async (rootDirectory, relativePaths, signal) => {
|
|
62619
|
+
const entries = [];
|
|
62620
|
+
let sliceStartedAt = performance.now();
|
|
62621
|
+
for (const relativePath of relativePaths) {
|
|
62622
|
+
signal?.throwIfAborted();
|
|
62623
|
+
const absolutePath = Path.resolve(rootDirectory, relativePath);
|
|
62624
|
+
const sizeBytes = statSourceFileSize(absolutePath);
|
|
62625
|
+
if (!isLargeMinifiedFile(absolutePath, sizeBytes)) entries.push({
|
|
62626
|
+
path: relativePath,
|
|
62627
|
+
sizeBytes: sizeBytes ?? 0
|
|
62628
|
+
});
|
|
62629
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
62630
|
+
await yieldToEventLoop();
|
|
62631
|
+
sliceStartedAt = performance.now();
|
|
62632
|
+
}
|
|
62633
|
+
}
|
|
62634
|
+
return entries;
|
|
62635
|
+
};
|
|
62636
|
+
const parseGitSourceFilePaths = (output) => {
|
|
62637
|
+
const trackedPaths = /* @__PURE__ */ new Set();
|
|
62638
|
+
const untrackedPaths = [];
|
|
62639
|
+
for (const entry of output.split("\0")) {
|
|
62640
|
+
if (entry.length === 0) continue;
|
|
62641
|
+
const trackedPath = /^[0-7]{6} [0-9a-f]+ [0-3]\t([\s\S]+)$/.exec(entry)?.[1];
|
|
62642
|
+
if (trackedPath === void 0) untrackedPaths.push(entry);
|
|
62643
|
+
else trackedPaths.add(trackedPath);
|
|
62644
|
+
}
|
|
62645
|
+
return {
|
|
62646
|
+
trackedPaths: [...trackedPaths],
|
|
62647
|
+
untrackedPaths
|
|
62648
|
+
};
|
|
62649
|
+
};
|
|
62650
|
+
const listGitSourceFilePaths = (rootDirectory) => {
|
|
62438
62651
|
const result = spawnSync("git", [
|
|
62439
62652
|
"ls-files",
|
|
62440
62653
|
"-z",
|
|
62441
|
-
|
|
62654
|
+
"--stage",
|
|
62655
|
+
"--others",
|
|
62656
|
+
"--exclude-standard"
|
|
62442
62657
|
], {
|
|
62443
62658
|
cwd: rootDirectory,
|
|
62444
62659
|
encoding: "utf-8",
|
|
62445
62660
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
62446
62661
|
});
|
|
62447
62662
|
if (result.error || result.status !== 0) return null;
|
|
62448
|
-
return result.stdout
|
|
62663
|
+
return parseGitSourceFilePaths(result.stdout);
|
|
62449
62664
|
};
|
|
62450
|
-
const
|
|
62451
|
-
const trackedPaths =
|
|
62452
|
-
const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
|
|
62453
|
-
if (trackedPaths === null || untrackedPaths === null) return null;
|
|
62665
|
+
const collectGitCandidateSourceFilePaths = (rootDirectory, paths) => {
|
|
62666
|
+
const { trackedPaths, untrackedPaths } = paths;
|
|
62454
62667
|
const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
|
|
62455
62668
|
trackedPaths: new Set(trackedPaths),
|
|
62456
62669
|
untrackedPaths,
|
|
@@ -62458,12 +62671,65 @@ const listSourceFilesViaGit = (rootDirectory) => {
|
|
|
62458
62671
|
});
|
|
62459
62672
|
return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
|
|
62460
62673
|
};
|
|
62674
|
+
const filterGitSourceFilePaths = (rootDirectory, paths) => {
|
|
62675
|
+
const candidatePaths = collectGitCandidateSourceFilePaths(rootDirectory, paths);
|
|
62676
|
+
const linguistIgnoredPaths = collectGitLinguistIgnoredPaths(rootDirectory, candidatePaths);
|
|
62677
|
+
return candidatePaths.filter((filePath) => !linguistIgnoredPaths.has(filePath));
|
|
62678
|
+
};
|
|
62679
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
62680
|
+
const paths = listGitSourceFilePaths(rootDirectory);
|
|
62681
|
+
return paths === null ? null : filterGitSourceFilePaths(rootDirectory, paths);
|
|
62682
|
+
};
|
|
62683
|
+
const listSourceFilesViaGitCooperative = async (rootDirectory, signal) => {
|
|
62684
|
+
const paths = await new Promise((resolve, reject) => {
|
|
62685
|
+
signal?.throwIfAborted();
|
|
62686
|
+
execFile("git", [
|
|
62687
|
+
"ls-files",
|
|
62688
|
+
"-z",
|
|
62689
|
+
"--stage",
|
|
62690
|
+
"--others",
|
|
62691
|
+
"--exclude-standard"
|
|
62692
|
+
], {
|
|
62693
|
+
cwd: rootDirectory,
|
|
62694
|
+
encoding: "utf-8",
|
|
62695
|
+
killSignal: "SIGKILL",
|
|
62696
|
+
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,
|
|
62697
|
+
signal
|
|
62698
|
+
}, (error, stdout) => {
|
|
62699
|
+
if (signal?.aborted) {
|
|
62700
|
+
reject(signal.reason);
|
|
62701
|
+
return;
|
|
62702
|
+
}
|
|
62703
|
+
resolve(error ? null : parseGitSourceFilePaths(stdout));
|
|
62704
|
+
});
|
|
62705
|
+
});
|
|
62706
|
+
if (paths === null) return null;
|
|
62707
|
+
const candidatePaths = collectGitCandidateSourceFilePaths(rootDirectory, paths);
|
|
62708
|
+
const linguistIgnoredPaths = await collectGitLinguistIgnoredPathsCooperative(rootDirectory, candidatePaths, signal);
|
|
62709
|
+
return candidatePaths.filter((filePath) => !linguistIgnoredPaths.has(filePath));
|
|
62710
|
+
};
|
|
62461
62711
|
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
62462
62712
|
const filePaths = [];
|
|
62463
62713
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
62464
62714
|
return filePaths;
|
|
62465
62715
|
};
|
|
62466
|
-
const
|
|
62716
|
+
const listSourceFilesViaFilesystemCooperative = async (rootDirectory, signal) => {
|
|
62717
|
+
const filePaths = [];
|
|
62718
|
+
let sliceStartedAt = performance.now();
|
|
62719
|
+
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
62720
|
+
signal?.throwIfAborted();
|
|
62721
|
+
if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
62722
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
62723
|
+
await yieldToEventLoop();
|
|
62724
|
+
sliceStartedAt = performance.now();
|
|
62725
|
+
}
|
|
62726
|
+
}
|
|
62727
|
+
return filePaths;
|
|
62728
|
+
};
|
|
62729
|
+
const listSourceFilePaths = (rootDirectory) => (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort();
|
|
62730
|
+
const listSourceFilePathsCooperative = async (rootDirectory, signal) => (await listSourceFilesViaGitCooperative(rootDirectory, signal) ?? await listSourceFilesViaFilesystemCooperative(rootDirectory, signal)).sort();
|
|
62731
|
+
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, listSourceFilePaths(rootDirectory));
|
|
62732
|
+
const listSourceFilesCooperative = async (rootDirectory, signal) => (await collectSizedSourceFilesCooperative(rootDirectory, await listSourceFilePathsCooperative(rootDirectory, signal), signal)).map((entry) => entry.path);
|
|
62467
62733
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
62468
62734
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
62469
62735
|
const UTF8_BOM_CHARACTER = "";
|
|
@@ -62589,7 +62855,12 @@ const mergeCompilerOptions = (inherited, current) => {
|
|
|
62589
62855
|
};
|
|
62590
62856
|
};
|
|
62591
62857
|
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
62592
|
-
|
|
62858
|
+
let realPath;
|
|
62859
|
+
try {
|
|
62860
|
+
realPath = NFS.realpathSync.native(tsConfigPath);
|
|
62861
|
+
} catch {
|
|
62862
|
+
return null;
|
|
62863
|
+
}
|
|
62593
62864
|
if (visitedPaths.has(realPath)) return null;
|
|
62594
62865
|
const tsConfig = readTsConfig(realPath);
|
|
62595
62866
|
if (!tsConfig) return null;
|
|
@@ -63117,27 +63388,30 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
|
|
|
63117
63388
|
}
|
|
63118
63389
|
return null;
|
|
63119
63390
|
};
|
|
63120
|
-
const configExpressionMayDefineProperty = (expression, propertyName, analysis) => {
|
|
63391
|
+
const configExpressionMayDefineProperty = (expression, propertyName, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
|
|
63121
63392
|
let resolvedExpression = expression;
|
|
63122
63393
|
while (ts.isParenthesizedExpression(resolvedExpression) || ts.isAsExpression(resolvedExpression) || ts.isTypeAssertionExpression(resolvedExpression) || ts.isSatisfiesExpression(resolvedExpression) || ts.isNonNullExpression(resolvedExpression)) resolvedExpression = resolvedExpression.expression;
|
|
63394
|
+
if (visitedExpressions.has(resolvedExpression)) return true;
|
|
63395
|
+
const nextVisitedExpressions = new Set(visitedExpressions);
|
|
63396
|
+
nextVisitedExpressions.add(resolvedExpression);
|
|
63123
63397
|
if (ts.isIdentifier(resolvedExpression)) {
|
|
63124
63398
|
if (analysis.localBindings.has(resolvedExpression.text)) {
|
|
63125
63399
|
const localReference = analysis.localBindings.get(resolvedExpression.text);
|
|
63126
|
-
return localReference?.expression ? configExpressionMayDefineProperty(localReference.expression, propertyName, localReference.analysis) : true;
|
|
63400
|
+
return localReference?.expression ? configExpressionMayDefineProperty(localReference.expression, propertyName, localReference.analysis, nextVisitedExpressions) : true;
|
|
63127
63401
|
}
|
|
63128
63402
|
const scopedBinding = getScopedConfigBinding(resolvedExpression);
|
|
63129
|
-
if (scopedBinding.wasFound) return scopedBinding.initializer ? configExpressionMayDefineProperty(scopedBinding.initializer, propertyName, analysis) : true;
|
|
63403
|
+
if (scopedBinding.wasFound) return scopedBinding.initializer ? configExpressionMayDefineProperty(scopedBinding.initializer, propertyName, analysis, nextVisitedExpressions) : true;
|
|
63130
63404
|
const topLevelBinding = getTopLevelBinding(analysis.sourceFile, resolvedExpression.text);
|
|
63131
|
-
return topLevelBinding && ts.isExpression(topLevelBinding) ? configExpressionMayDefineProperty(topLevelBinding, propertyName, analysis) : true;
|
|
63405
|
+
return topLevelBinding && ts.isExpression(topLevelBinding) ? configExpressionMayDefineProperty(topLevelBinding, propertyName, analysis, nextVisitedExpressions) : true;
|
|
63132
63406
|
}
|
|
63133
63407
|
if (ts.isConditionalExpression(resolvedExpression)) {
|
|
63134
|
-
if (isStaticallyTruthyConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis);
|
|
63135
|
-
if (isStaticallyDisabledConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis);
|
|
63136
|
-
return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis) || configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis);
|
|
63408
|
+
if (isStaticallyTruthyConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis, nextVisitedExpressions);
|
|
63409
|
+
if (isStaticallyDisabledConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis, nextVisitedExpressions);
|
|
63410
|
+
return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis, nextVisitedExpressions) || configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis, nextVisitedExpressions);
|
|
63137
63411
|
}
|
|
63138
63412
|
if (!ts.isObjectLiteralExpression(resolvedExpression)) return true;
|
|
63139
63413
|
return resolvedExpression.properties.some((property) => {
|
|
63140
|
-
if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
|
|
63414
|
+
if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis, nextVisitedExpressions);
|
|
63141
63415
|
if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
|
|
63142
63416
|
const staticPropertyName = getStaticPropertyName$2(property.name);
|
|
63143
63417
|
return staticPropertyName === null || staticPropertyName === propertyName;
|
|
@@ -63213,7 +63487,13 @@ const analyzeConfigModuleExport = (filePath, exportName, allowCompilerTransform,
|
|
|
63213
63487
|
if (visitedModules.has(moduleVisitKey)) return false;
|
|
63214
63488
|
const nextVisitedModules = new Set(visitedModules);
|
|
63215
63489
|
nextVisitedModules.add(moduleVisitKey);
|
|
63216
|
-
|
|
63490
|
+
let sourceText;
|
|
63491
|
+
try {
|
|
63492
|
+
sourceText = NFS.readFileSync(filePath, "utf-8");
|
|
63493
|
+
} catch {
|
|
63494
|
+
return false;
|
|
63495
|
+
}
|
|
63496
|
+
return analyzeConfigSourceFileExport(parseConfigSourceFile(filePath, sourceText), filePath, exportName, allowCompilerTransform, importDepth, nextVisitedModules, argumentsList, argumentAnalysis);
|
|
63217
63497
|
};
|
|
63218
63498
|
const analyzeConfigSourceFileExport = (sourceFile, filePath, exportName, allowCompilerTransform, importDepth, visitedModules, argumentsList = [], argumentAnalysis) => {
|
|
63219
63499
|
const analysis = {
|
|
@@ -64041,13 +64321,7 @@ const hasReactDependency = (packageJson) => {
|
|
|
64041
64321
|
};
|
|
64042
64322
|
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
64043
64323
|
};
|
|
64044
|
-
const getPreactVersion = (packageJson) =>
|
|
64045
|
-
return {
|
|
64046
|
-
...packageJson.peerDependencies,
|
|
64047
|
-
...packageJson.dependencies,
|
|
64048
|
-
...packageJson.devDependencies
|
|
64049
|
-
}.preact ?? null;
|
|
64050
|
-
};
|
|
64324
|
+
const getPreactVersion = (packageJson) => getDependencySpec(packageJson, "preact");
|
|
64051
64325
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, sourceDirectory = rootDirectory, sourcePackageJson = rootPackageJson, version }) => {
|
|
64052
64326
|
if (version === null || !isCatalogReference(version)) return version;
|
|
64053
64327
|
const catalogName = extractCatalogName(version);
|
|
@@ -64792,7 +65066,16 @@ const getBrowserslistProtectionRequirement = (directory) => {
|
|
|
64792
65066
|
if (!queries) return void 0;
|
|
64793
65067
|
let requirement;
|
|
64794
65068
|
let hasUnsupportedTarget = false;
|
|
64795
|
-
|
|
65069
|
+
const previousIgnoreOldData = process.env.BROWSERSLIST_IGNORE_OLD_DATA;
|
|
65070
|
+
let browserTargets = [];
|
|
65071
|
+
try {
|
|
65072
|
+
process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true";
|
|
65073
|
+
browserTargets = (0, import_browserslist.default)(queries);
|
|
65074
|
+
} finally {
|
|
65075
|
+
if (previousIgnoreOldData === void 0) delete process.env.BROWSERSLIST_IGNORE_OLD_DATA;
|
|
65076
|
+
else process.env.BROWSERSLIST_IGNORE_OLD_DATA = previousIgnoreOldData;
|
|
65077
|
+
}
|
|
65078
|
+
for (const browserTarget of browserTargets) {
|
|
64796
65079
|
const browserRequirement = getBrowserProtectionRequirement(browserTarget);
|
|
64797
65080
|
if (browserRequirement === "unsupported") hasUnsupportedTarget = true;
|
|
64798
65081
|
if (browserRequirement === "noreferrer") requirement = "noreferrer";
|
|
@@ -64902,9 +65185,9 @@ const clearProjectCache = () => {
|
|
|
64902
65185
|
* framework-agnostic rules. Throws only when the directory has nothing
|
|
64903
65186
|
* to scan (no enclosing project and no source files of its own).
|
|
64904
65187
|
*/
|
|
64905
|
-
const discoverProjectWithoutPackageJson = (directory) => {
|
|
64906
|
-
const sourceFileCount = countSourceFiles(directory);
|
|
64907
|
-
const hasOwnTsConfig =
|
|
65188
|
+
const discoverProjectWithoutPackageJson = (directory, options) => {
|
|
65189
|
+
const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
|
|
65190
|
+
const hasOwnTsConfig = isFile(Path.join(directory, "tsconfig.json"));
|
|
64908
65191
|
const enclosingProjectRoot = findNearestAncestorPackageJson(directory);
|
|
64909
65192
|
const enclosingProject = enclosingProjectRoot !== null ? discoverProject(enclosingProjectRoot) : null;
|
|
64910
65193
|
if (enclosingProject !== null) return {
|
|
@@ -64970,12 +65253,15 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
64970
65253
|
sourceFileCount
|
|
64971
65254
|
};
|
|
64972
65255
|
};
|
|
64973
|
-
const discoverProject = (directory) => {
|
|
65256
|
+
const discoverProject = (directory, options = {}) => {
|
|
64974
65257
|
const cached = cachedProjectInfos.get(directory);
|
|
64975
|
-
if (cached !== void 0) return cached
|
|
65258
|
+
if (cached !== void 0) return options.sourceFileCount === void 0 ? cached : {
|
|
65259
|
+
...cached,
|
|
65260
|
+
sourceFileCount: options.sourceFileCount
|
|
65261
|
+
};
|
|
64976
65262
|
const packageJsonPath = Path.join(directory, "package.json");
|
|
64977
65263
|
if (!isFile(packageJsonPath)) {
|
|
64978
|
-
const synthesized = discoverProjectWithoutPackageJson(directory);
|
|
65264
|
+
const synthesized = discoverProjectWithoutPackageJson(directory, options);
|
|
64979
65265
|
cachedProjectInfos.set(directory, synthesized);
|
|
64980
65266
|
return synthesized;
|
|
64981
65267
|
}
|
|
@@ -65037,8 +65323,8 @@ const discoverProject = (directory) => {
|
|
|
65037
65323
|
const tailwindVersion = tailwindcss.version;
|
|
65038
65324
|
const zodVersion = zod.version;
|
|
65039
65325
|
const projectName = packageJson.name ?? Path.basename(directory);
|
|
65040
|
-
const hasTypeScript =
|
|
65041
|
-
const sourceFileCount = countSourceFiles(directory);
|
|
65326
|
+
const hasTypeScript = isFile(Path.join(directory, "tsconfig.json"));
|
|
65327
|
+
const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
|
|
65042
65328
|
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
|
|
65043
65329
|
const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
65044
65330
|
rootDirectory: directory,
|
|
@@ -65167,134 +65453,6 @@ const discoverProject = (directory) => {
|
|
|
65167
65453
|
* single source file has nothing to analyze.
|
|
65168
65454
|
*/
|
|
65169
65455
|
const isAnalyzableProject = (project) => project.reactVersion !== null || project.preactVersion !== null || project.sourceFileCount > 0;
|
|
65170
|
-
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
65171
|
-
var InvalidGlobPatternError = class extends Error {
|
|
65172
|
-
pattern;
|
|
65173
|
-
reason;
|
|
65174
|
-
constructor(pattern, reason) {
|
|
65175
|
-
super(`Invalid glob pattern ${JSON.stringify(pattern)}: ${reason}`);
|
|
65176
|
-
this.name = "InvalidGlobPatternError";
|
|
65177
|
-
this.pattern = pattern;
|
|
65178
|
-
this.reason = reason;
|
|
65179
|
-
}
|
|
65180
|
-
};
|
|
65181
|
-
const assertGlobPattern = (condition, pattern, reason) => {
|
|
65182
|
-
if (!condition) throw new InvalidGlobPatternError(pattern, reason);
|
|
65183
|
-
};
|
|
65184
|
-
const countGlobWildcards = (pattern) => (pattern.match(/[*?]/g) ?? []).length;
|
|
65185
|
-
const normalizeGlobPattern = (pattern) => pattern.replace(/\\/g, "/").replace(/^\//, "");
|
|
65186
|
-
const PICOMATCH_OPTIONS = {
|
|
65187
|
-
dot: true,
|
|
65188
|
-
strictSlashes: false,
|
|
65189
|
-
windows: false
|
|
65190
|
-
};
|
|
65191
|
-
const compileGlobPattern = (rawPattern) => {
|
|
65192
|
-
assertGlobPattern(typeof rawPattern === "string" && rawPattern.length > 0, String(rawPattern), "pattern must be a non-empty string.");
|
|
65193
|
-
assertGlobPattern(rawPattern.length <= MAX_GLOB_PATTERN_LENGTH_CHARS, rawPattern, `pattern length ${rawPattern.length} exceeds the maximum of ${MAX_GLOB_PATTERN_LENGTH_CHARS} characters.`);
|
|
65194
|
-
const wildcardCount = countGlobWildcards(rawPattern);
|
|
65195
|
-
assertGlobPattern(wildcardCount <= 24, rawPattern, `pattern uses ${wildcardCount} wildcards (\`*\` / \`?\`), exceeding the maximum of 24. This guards against catastrophic backtracking from pathological patterns; split the pattern into multiple smaller entries.`);
|
|
65196
|
-
try {
|
|
65197
|
-
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
65198
|
-
} catch (caughtError) {
|
|
65199
|
-
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
65200
|
-
}
|
|
65201
|
-
};
|
|
65202
|
-
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
65203
|
-
const compiled = [];
|
|
65204
|
-
for (const pattern of patterns) try {
|
|
65205
|
-
compiled.push(compileGlobPattern(pattern));
|
|
65206
|
-
} catch (caughtError) {
|
|
65207
|
-
if (!(caughtError instanceof InvalidGlobPatternError)) throw caughtError;
|
|
65208
|
-
onInvalid(caughtError);
|
|
65209
|
-
}
|
|
65210
|
-
return compiled;
|
|
65211
|
-
};
|
|
65212
|
-
const toRelativePath = (filePath, rootDirectory) => {
|
|
65213
|
-
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
65214
|
-
const normalizedRoot = rootDirectory.replace(/\\/g, "/").replace(/\/$/, "") + "/";
|
|
65215
|
-
if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
|
|
65216
|
-
return normalizedFilePath.replace(/^\.\//, "");
|
|
65217
|
-
};
|
|
65218
|
-
const warnConfigIssue = (message) => {
|
|
65219
|
-
process.stderr.write(`[react-doctor] ${message}\n`);
|
|
65220
|
-
};
|
|
65221
|
-
const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
65222
|
-
const collectStringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
65223
|
-
const validateOverrideEntry = (entry, index) => {
|
|
65224
|
-
if (!isPlainObject(entry)) {
|
|
65225
|
-
warnConfigIssue(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
|
|
65226
|
-
return null;
|
|
65227
|
-
}
|
|
65228
|
-
if (!isStringArray(entry.files)) {
|
|
65229
|
-
warnConfigIssue(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
|
|
65230
|
-
return null;
|
|
65231
|
-
}
|
|
65232
|
-
if (entry.rules !== void 0 && !isStringArray(entry.rules)) {
|
|
65233
|
-
warnConfigIssue(`ignore.overrides[${index}].rules must be an array of "plugin/rule" strings or omitted; treating as missing (override would suppress every rule for the matched files).`);
|
|
65234
|
-
return { files: entry.files };
|
|
65235
|
-
}
|
|
65236
|
-
return entry.rules === void 0 ? { files: entry.files } : {
|
|
65237
|
-
files: entry.files,
|
|
65238
|
-
rules: entry.rules
|
|
65239
|
-
};
|
|
65240
|
-
};
|
|
65241
|
-
const compileIgnoreOverrides = (userConfig) => {
|
|
65242
|
-
const overrides = userConfig?.ignore?.overrides;
|
|
65243
|
-
if (overrides === void 0) return [];
|
|
65244
|
-
if (!Array.isArray(overrides)) {
|
|
65245
|
-
warnConfigIssue(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
|
|
65246
|
-
return [];
|
|
65247
|
-
}
|
|
65248
|
-
return overrides.flatMap((entry, index) => {
|
|
65249
|
-
const validated = validateOverrideEntry(entry, index);
|
|
65250
|
-
if (!validated) return [];
|
|
65251
|
-
const filePatterns = compileGlobPatternsLenient(collectStringList(validated.files), (error) => warnConfigIssue(`ignore.overrides[${index}]: ${error.message}`));
|
|
65252
|
-
if (filePatterns.length === 0) return [];
|
|
65253
|
-
return [{
|
|
65254
|
-
filePatterns,
|
|
65255
|
-
ruleIds: new Set(collectStringList(validated.rules))
|
|
65256
|
-
}];
|
|
65257
|
-
});
|
|
65258
|
-
};
|
|
65259
|
-
const isDiagnosticIgnoredByOverrides = (diagnostic, rootDirectory, overrides) => {
|
|
65260
|
-
if (overrides.length === 0) return false;
|
|
65261
|
-
const relativeFilePath = toRelativePath(diagnostic.filePath, rootDirectory);
|
|
65262
|
-
const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
65263
|
-
return overrides.some((override) => override.filePatterns.some((pattern) => pattern.test(relativeFilePath)) && (override.ruleIds.size === 0 || override.ruleIds.has(ruleIdentifier)));
|
|
65264
|
-
};
|
|
65265
|
-
const SEVERITY_FOR_OVERRIDE = {
|
|
65266
|
-
error: "error",
|
|
65267
|
-
warn: "warning"
|
|
65268
|
-
};
|
|
65269
|
-
const restampSeverity = (diagnostic, override) => {
|
|
65270
|
-
const targetSeverity = SEVERITY_FOR_OVERRIDE[override];
|
|
65271
|
-
if (diagnostic.severity === targetSeverity) return diagnostic;
|
|
65272
|
-
return {
|
|
65273
|
-
...diagnostic,
|
|
65274
|
-
severity: targetSeverity
|
|
65275
|
-
};
|
|
65276
|
-
};
|
|
65277
|
-
/**
|
|
65278
|
-
* Assembles the internal `RuleSeverityControls` shape from a user
|
|
65279
|
-
* config's top-level `rules` and `categories` fields — the
|
|
65280
|
-
* ESLint / oxlint-shaped severity surface.
|
|
65281
|
-
*
|
|
65282
|
-
* Returns `undefined` when neither field is present so the common
|
|
65283
|
-
* path (no severity config at all) stays allocation-free for
|
|
65284
|
-
* downstream consumers.
|
|
65285
|
-
*/
|
|
65286
|
-
const buildRuleSeverityControls = (config) => {
|
|
65287
|
-
if (!config) return void 0;
|
|
65288
|
-
if (config.rules === void 0 && config.categories === void 0 && config.buckets === void 0) return;
|
|
65289
|
-
return {
|
|
65290
|
-
...config.rules !== void 0 ? { rules: config.rules } : {},
|
|
65291
|
-
...config.categories !== void 0 ? { categories: config.categories } : {},
|
|
65292
|
-
...config.buckets !== void 0 ? { buckets: config.buckets } : {}
|
|
65293
|
-
};
|
|
65294
|
-
};
|
|
65295
|
-
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
65296
|
-
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
65297
|
-
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
65298
65456
|
const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
65299
65457
|
"effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
|
|
65300
65458
|
"effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
|
|
@@ -65433,6 +65591,139 @@ const getEquivalentRuleKeys = (ruleKey) => {
|
|
|
65433
65591
|
const nativeRuleKey = canonicalizeRuleKey(ruleKey);
|
|
65434
65592
|
return [nativeRuleKey, ...getLegacyRuleKeysForNative(nativeRuleKey)];
|
|
65435
65593
|
};
|
|
65594
|
+
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
65595
|
+
var InvalidGlobPatternError = class extends Error {
|
|
65596
|
+
pattern;
|
|
65597
|
+
reason;
|
|
65598
|
+
constructor(pattern, reason) {
|
|
65599
|
+
super(`Invalid glob pattern ${JSON.stringify(pattern)}: ${reason}`);
|
|
65600
|
+
this.name = "InvalidGlobPatternError";
|
|
65601
|
+
this.pattern = pattern;
|
|
65602
|
+
this.reason = reason;
|
|
65603
|
+
}
|
|
65604
|
+
};
|
|
65605
|
+
const assertGlobPattern = (condition, pattern, reason) => {
|
|
65606
|
+
if (!condition) throw new InvalidGlobPatternError(pattern, reason);
|
|
65607
|
+
};
|
|
65608
|
+
const countGlobWildcards = (pattern) => (pattern.match(/[*?]/g) ?? []).length;
|
|
65609
|
+
const normalizeGlobPattern = (pattern) => pattern.replace(/\\/g, "/").replace(/^\//, "");
|
|
65610
|
+
const PICOMATCH_OPTIONS = {
|
|
65611
|
+
dot: true,
|
|
65612
|
+
strictSlashes: false,
|
|
65613
|
+
windows: false
|
|
65614
|
+
};
|
|
65615
|
+
const compileGlobPattern = (rawPattern) => {
|
|
65616
|
+
assertGlobPattern(typeof rawPattern === "string" && rawPattern.length > 0, String(rawPattern), "pattern must be a non-empty string.");
|
|
65617
|
+
assertGlobPattern(rawPattern.length <= MAX_GLOB_PATTERN_LENGTH_CHARS, rawPattern, `pattern length ${rawPattern.length} exceeds the maximum of ${MAX_GLOB_PATTERN_LENGTH_CHARS} characters.`);
|
|
65618
|
+
const wildcardCount = countGlobWildcards(rawPattern);
|
|
65619
|
+
assertGlobPattern(wildcardCount <= 24, rawPattern, `pattern uses ${wildcardCount} wildcards (\`*\` / \`?\`), exceeding the maximum of 24. This guards against catastrophic backtracking from pathological patterns; split the pattern into multiple smaller entries.`);
|
|
65620
|
+
try {
|
|
65621
|
+
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
65622
|
+
} catch (caughtError) {
|
|
65623
|
+
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
65624
|
+
}
|
|
65625
|
+
};
|
|
65626
|
+
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
65627
|
+
const compiled = [];
|
|
65628
|
+
for (const pattern of patterns) try {
|
|
65629
|
+
compiled.push(compileGlobPattern(pattern));
|
|
65630
|
+
} catch (caughtError) {
|
|
65631
|
+
if (!(caughtError instanceof InvalidGlobPatternError)) throw caughtError;
|
|
65632
|
+
onInvalid(caughtError);
|
|
65633
|
+
}
|
|
65634
|
+
return compiled;
|
|
65635
|
+
};
|
|
65636
|
+
const toRelativePath = (filePath, rootDirectory) => {
|
|
65637
|
+
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
65638
|
+
const normalizedRoot = rootDirectory.replace(/\\/g, "/").replace(/\/$/, "") + "/";
|
|
65639
|
+
if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
|
|
65640
|
+
return normalizedFilePath.replace(/^\.\//, "");
|
|
65641
|
+
};
|
|
65642
|
+
const warnConfigIssue = (message) => {
|
|
65643
|
+
process.stderr.write(`[react-doctor] ${message}\n`);
|
|
65644
|
+
};
|
|
65645
|
+
const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
65646
|
+
const collectStringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
65647
|
+
const hasMatchingRuleOverride = (ruleIds, ruleIdentifier) => {
|
|
65648
|
+
if (ruleIds.size === 0) return true;
|
|
65649
|
+
for (const ruleId of ruleIds) if (isSameRuleKey(ruleId, ruleIdentifier)) return true;
|
|
65650
|
+
return false;
|
|
65651
|
+
};
|
|
65652
|
+
const validateOverrideEntry = (entry, index) => {
|
|
65653
|
+
if (!isPlainObject(entry)) {
|
|
65654
|
+
warnConfigIssue(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
|
|
65655
|
+
return null;
|
|
65656
|
+
}
|
|
65657
|
+
if (!isStringArray(entry.files)) {
|
|
65658
|
+
warnConfigIssue(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
|
|
65659
|
+
return null;
|
|
65660
|
+
}
|
|
65661
|
+
if (entry.rules !== void 0 && !isStringArray(entry.rules)) {
|
|
65662
|
+
warnConfigIssue(`ignore.overrides[${index}].rules must be an array of "plugin/rule" strings or omitted; treating as missing (override would suppress every rule for the matched files).`);
|
|
65663
|
+
return { files: entry.files };
|
|
65664
|
+
}
|
|
65665
|
+
return entry.rules === void 0 ? { files: entry.files } : {
|
|
65666
|
+
files: entry.files,
|
|
65667
|
+
rules: entry.rules
|
|
65668
|
+
};
|
|
65669
|
+
};
|
|
65670
|
+
const compileIgnoreOverrides = (userConfig) => {
|
|
65671
|
+
const overrides = userConfig?.ignore?.overrides;
|
|
65672
|
+
if (overrides === void 0) return [];
|
|
65673
|
+
if (!Array.isArray(overrides)) {
|
|
65674
|
+
warnConfigIssue(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
|
|
65675
|
+
return [];
|
|
65676
|
+
}
|
|
65677
|
+
return overrides.flatMap((entry, index) => {
|
|
65678
|
+
const validated = validateOverrideEntry(entry, index);
|
|
65679
|
+
if (!validated) return [];
|
|
65680
|
+
const filePatterns = compileGlobPatternsLenient(collectStringList(validated.files), (error) => warnConfigIssue(`ignore.overrides[${index}]: ${error.message}`));
|
|
65681
|
+
if (filePatterns.length === 0) return [];
|
|
65682
|
+
return [{
|
|
65683
|
+
filePatterns,
|
|
65684
|
+
ruleIds: new Set(collectStringList(validated.rules))
|
|
65685
|
+
}];
|
|
65686
|
+
});
|
|
65687
|
+
};
|
|
65688
|
+
const isDiagnosticIgnoredByOverrides = (diagnostic, rootDirectory, overrides) => {
|
|
65689
|
+
if (overrides.length === 0) return false;
|
|
65690
|
+
const relativeFilePath = toRelativePath(diagnostic.filePath, rootDirectory);
|
|
65691
|
+
const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
65692
|
+
return overrides.some((override) => override.filePatterns.some((pattern) => pattern.test(relativeFilePath)) && hasMatchingRuleOverride(override.ruleIds, ruleIdentifier));
|
|
65693
|
+
};
|
|
65694
|
+
const SEVERITY_FOR_OVERRIDE = {
|
|
65695
|
+
error: "error",
|
|
65696
|
+
warn: "warning"
|
|
65697
|
+
};
|
|
65698
|
+
const restampSeverity = (diagnostic, override) => {
|
|
65699
|
+
const targetSeverity = SEVERITY_FOR_OVERRIDE[override];
|
|
65700
|
+
if (diagnostic.severity === targetSeverity) return diagnostic;
|
|
65701
|
+
return {
|
|
65702
|
+
...diagnostic,
|
|
65703
|
+
severity: targetSeverity
|
|
65704
|
+
};
|
|
65705
|
+
};
|
|
65706
|
+
/**
|
|
65707
|
+
* Assembles the internal `RuleSeverityControls` shape from a user
|
|
65708
|
+
* config's top-level `rules` and `categories` fields — the
|
|
65709
|
+
* ESLint / oxlint-shaped severity surface.
|
|
65710
|
+
*
|
|
65711
|
+
* Returns `undefined` when neither field is present so the common
|
|
65712
|
+
* path (no severity config at all) stays allocation-free for
|
|
65713
|
+
* downstream consumers.
|
|
65714
|
+
*/
|
|
65715
|
+
const buildRuleSeverityControls = (config) => {
|
|
65716
|
+
if (!config) return void 0;
|
|
65717
|
+
if (config.rules === void 0 && config.categories === void 0 && config.buckets === void 0) return;
|
|
65718
|
+
return {
|
|
65719
|
+
...config.rules !== void 0 ? { rules: config.rules } : {},
|
|
65720
|
+
...config.categories !== void 0 ? { categories: config.categories } : {},
|
|
65721
|
+
...config.buckets !== void 0 ? { buckets: config.buckets } : {}
|
|
65722
|
+
};
|
|
65723
|
+
};
|
|
65724
|
+
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
65725
|
+
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
65726
|
+
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
65436
65727
|
const stripDescriptionTail = (ruleList) => {
|
|
65437
65728
|
const descriptionMatch = ruleList.match(/(?:^|\s)--\s/);
|
|
65438
65729
|
if (!descriptionMatch || descriptionMatch.index === void 0) return ruleList;
|
|
@@ -65845,6 +66136,10 @@ const classifyByDirectoryCohort = (packageDirectory) => {
|
|
|
65845
66136
|
current = parent;
|
|
65846
66137
|
}
|
|
65847
66138
|
};
|
|
66139
|
+
const clearPackageRoleCache = () => {
|
|
66140
|
+
cachedRoleByPackageDirectory.clear();
|
|
66141
|
+
cachedPackageDirectoryByFilename.clear();
|
|
66142
|
+
};
|
|
65848
66143
|
const classifyPackageRole = (filename) => {
|
|
65849
66144
|
if (!filename) return "unknown";
|
|
65850
66145
|
const packageDirectory = findNearestPackageDirectory(filename);
|
|
@@ -66079,12 +66374,8 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
66079
66374
|
if (rule.tags.includes("migration-hint")) return false;
|
|
66080
66375
|
return getFileContext(diagnostic.filePath) !== "production";
|
|
66081
66376
|
};
|
|
66082
|
-
const
|
|
66083
|
-
for (const
|
|
66084
|
-
return false;
|
|
66085
|
-
};
|
|
66086
|
-
const isAppOnlyRule = (ruleIdentifier) => {
|
|
66087
|
-
for (const appOnlyRuleKey of APP_ONLY_RULE_KEYS) if (isSameRuleKey(appOnlyRuleKey, ruleIdentifier)) return true;
|
|
66377
|
+
const matchesRuleKey = (ruleIdentifier, candidates) => {
|
|
66378
|
+
for (const candidate of candidates) if (isSameRuleKey(candidate, ruleIdentifier)) return true;
|
|
66088
66379
|
return false;
|
|
66089
66380
|
};
|
|
66090
66381
|
const isRnRawTextSuppressedByConfig = (diagnostic) => {
|
|
@@ -66126,12 +66417,13 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
66126
66417
|
if (explicitSeverityOverride === "off") return suppress(current, "config");
|
|
66127
66418
|
if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
|
|
66128
66419
|
}
|
|
66420
|
+
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
66129
66421
|
if (explicitRuleOverride === void 0) {
|
|
66130
|
-
if (
|
|
66422
|
+
if (matchesRuleKey(ruleIdentifier, APP_ONLY_RULE_KEYS) && isLibraryFile(current.filePath)) return null;
|
|
66131
66423
|
}
|
|
66132
66424
|
if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
|
|
66133
66425
|
if (userConfig) {
|
|
66134
|
-
if (
|
|
66426
|
+
if (matchesRuleKey(ruleIdentifier, ignoredRules)) return suppress(current, "config");
|
|
66135
66427
|
if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
|
|
66136
66428
|
if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
|
|
66137
66429
|
if (isRnRawTextSuppressedByConfig(current)) return null;
|
|
@@ -66140,7 +66432,6 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
66140
66432
|
if (respectInlineDisables && current.line > 0) {
|
|
66141
66433
|
const lines = getFileLines(current.filePath);
|
|
66142
66434
|
if (lines) {
|
|
66143
|
-
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
66144
66435
|
const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
|
|
66145
66436
|
if (evaluation.isSuppressed) return suppress(current, evaluation.isForeignDirective ? "foreign-inline" : "inline");
|
|
66146
66437
|
if (evaluation.nearMissHint) current = {
|
|
@@ -66394,7 +66685,8 @@ const readSystemFacts$1 = () => ({
|
|
|
66394
66685
|
/**
|
|
66395
66686
|
* Auto lint-worker count: the smaller of the (cgroup-CPU-aware) core count and
|
|
66396
66687
|
* the number of `PER_WORKER_MEM_BUDGET_BYTES` workers that fit in available
|
|
66397
|
-
* memory,
|
|
66688
|
+
* memory, and the measured automatic parallel-efficiency ceiling, then clamped
|
|
66689
|
+
* to `[MIN, HARD_MAX]` by `resolveScanConcurrency`.
|
|
66398
66690
|
*
|
|
66399
66691
|
* `os.availableParallelism()` already respects cgroup CPU quotas, so the core
|
|
66400
66692
|
* term needs no help. Available memory is `os.totalmem()` floored by the cgroup
|
|
@@ -66410,7 +66702,7 @@ const readSystemFacts$1 = () => ({
|
|
|
66410
66702
|
const resolveAutoScanConcurrency = (facts = readSystemFacts$1()) => {
|
|
66411
66703
|
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
66412
66704
|
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / PER_WORKER_MEM_BUDGET_BYTES);
|
|
66413
|
-
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
66705
|
+
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers, 10));
|
|
66414
66706
|
};
|
|
66415
66707
|
const resolveLintBatchOrdering = () => {
|
|
66416
66708
|
return process.env["REACT_DOCTOR_LINT_BATCH_ORDERING"]?.trim().toLowerCase() === "arrival" ? "arrival" : "cost";
|
|
@@ -66423,24 +66715,22 @@ const resolveLintBatchOrdering = () => {
|
|
|
66423
66715
|
*/
|
|
66424
66716
|
var OxlintSpawnTimeoutMs = class extends Reference("react-doctor/OxlintSpawnTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_OXLINT_SPAWN_TIMEOUT_MS", OXLINT_SPAWN_TIMEOUT_MS) }) {};
|
|
66425
66717
|
/**
|
|
66426
|
-
* Effect-side cap on the lint phase.
|
|
66427
|
-
*
|
|
66718
|
+
* Optional Effect-side cap on the lint phase. Unbounded unless explicitly
|
|
66719
|
+
* configured through the env var or a test layer.
|
|
66428
66720
|
* Tests override via `Layer.succeed(LintPhaseTimeoutMs, ...)`.
|
|
66429
66721
|
*/
|
|
66430
|
-
var LintPhaseTimeoutMs = class extends Reference("react-doctor/LintPhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_LINT_PHASE_TIMEOUT_MS",
|
|
66722
|
+
var LintPhaseTimeoutMs = class extends Reference("react-doctor/LintPhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_LINT_PHASE_TIMEOUT_MS", null) }) {};
|
|
66431
66723
|
/**
|
|
66432
|
-
* Effect-side cap on the dead-code phase
|
|
66433
|
-
*
|
|
66434
|
-
* type-heavy projects; tests override via
|
|
66724
|
+
* Optional Effect-side cap on the dead-code phase. Unbounded unless explicitly
|
|
66725
|
+
* configured through the env var or a test layer. Tests override via
|
|
66435
66726
|
* `Layer.succeed(DeadCodePhaseTimeoutMs, ...)`.
|
|
66436
66727
|
*/
|
|
66437
|
-
var DeadCodePhaseTimeoutMs = class extends Reference("react-doctor/DeadCodePhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_DEAD_CODE_PHASE_TIMEOUT_MS",
|
|
66728
|
+
var DeadCodePhaseTimeoutMs = class extends Reference("react-doctor/DeadCodePhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_DEAD_CODE_PHASE_TIMEOUT_MS", null) }) {};
|
|
66438
66729
|
/**
|
|
66439
|
-
*
|
|
66440
|
-
*
|
|
66441
|
-
* large repos; tests override via `Layer.succeed(ScanDeadlineMs, ...)`.
|
|
66730
|
+
* Optional overall scan deadline. Unbounded unless explicitly configured
|
|
66731
|
+
* through the env var or a test layer.
|
|
66442
66732
|
*/
|
|
66443
|
-
var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SCAN_DEADLINE_MS",
|
|
66733
|
+
var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SCAN_DEADLINE_MS", null) }) {};
|
|
66444
66734
|
/**
|
|
66445
66735
|
* Wall-clock budget for the supply-chain check when it runs on a background
|
|
66446
66736
|
* fiber overlapping the lint pass. Reads from the env var on startup so the
|
|
@@ -66513,14 +66803,14 @@ var DeadCodeOverlap = class extends Reference("react-doctor/DeadCodeOverlap", {
|
|
|
66513
66803
|
/**
|
|
66514
66804
|
* How the full-scan lint pass plans its file batches. `"cost"` (the default)
|
|
66515
66805
|
* builds size-balanced LPT batches (`planLintBatches`): the same mandatory
|
|
66516
|
-
* batch count as greedy chunking
|
|
66517
|
-
*
|
|
66806
|
+
* batch count as greedy chunking, but every batch gets an even share of files
|
|
66807
|
+
* AND bytes, so no full chunk is a straggler while
|
|
66518
66808
|
* the remainder-batch worker idles — and the heavy files are SPREAD across
|
|
66519
66809
|
* batches, the precondition the old sort-desc-then-chunk-100 `cost` mode
|
|
66520
66810
|
* lacked (it packed the heaviest files into one wave-1 straggler batch,
|
|
66521
66811
|
* measurably regressing size-skewed repos, which is why it never earned the
|
|
66522
66812
|
* default). `"arrival"` (`REACT_DOCTOR_LINT_BATCH_ORDERING=arrival`) is the
|
|
66523
|
-
* rollback hatch to plain greedy
|
|
66813
|
+
* rollback hatch to plain greedy fixed-size chunking in discovery order. Tests
|
|
66524
66814
|
* override via `Layer.succeed(LintBatchOrdering, ...)`. Diff / staged scans
|
|
66525
66815
|
* never reach this — they pass user-scoped `includePaths` that skip discovery
|
|
66526
66816
|
* and stay in arrival order; only the full-scan branch reads it.
|
|
@@ -66615,6 +66905,7 @@ const DEFAULT_SURFACE_EXCLUDED_TAGS = {
|
|
|
66615
66905
|
score: ["design"],
|
|
66616
66906
|
ciFailure: ["design"]
|
|
66617
66907
|
};
|
|
66908
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66618
66909
|
const VALID_RULE_SEVERITIES = [
|
|
66619
66910
|
"error",
|
|
66620
66911
|
"warn",
|
|
@@ -66657,7 +66948,6 @@ const SURFACE_CONTROL_FIELD_NAMES = [
|
|
|
66657
66948
|
];
|
|
66658
66949
|
const isIncludedFileContext = (value) => VALID_INCLUDED_FILE_CONTEXTS.some((fileContext) => fileContext === value);
|
|
66659
66950
|
const SEVERITY_FIELD_NAMES = ["rules", "categories"];
|
|
66660
|
-
const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66661
66951
|
const formatType = (value) => typeof value === "string" ? `"${value}"` : typeof value;
|
|
66662
66952
|
const isRuleSeverity = (value) => typeof value === "string" && VALID_RULE_SEVERITIES.includes(value);
|
|
66663
66953
|
const coerceMaybeBooleanString = (fieldName, value) => {
|
|
@@ -66684,8 +66974,45 @@ const validateStringArrayField = (fieldName, value) => {
|
|
|
66684
66974
|
return false;
|
|
66685
66975
|
});
|
|
66686
66976
|
};
|
|
66977
|
+
const validateIgnoreOverride = (rawOverride, index) => {
|
|
66978
|
+
const fieldName = `ignore.overrides[${index}]`;
|
|
66979
|
+
if (!isRecord(rawOverride)) {
|
|
66980
|
+
warnConfigIssue(`config field "${fieldName}" must be an object (got ${typeof rawOverride}); ignoring this override.`);
|
|
66981
|
+
return;
|
|
66982
|
+
}
|
|
66983
|
+
const files = validateStringArrayField(`${fieldName}.files`, rawOverride.files);
|
|
66984
|
+
if (files === void 0) return void 0;
|
|
66985
|
+
const validatedOverride = { files };
|
|
66986
|
+
if (rawOverride.rules !== void 0) {
|
|
66987
|
+
const rules = validateStringArrayField(`${fieldName}.rules`, rawOverride.rules);
|
|
66988
|
+
if (rules !== void 0) validatedOverride.rules = rules;
|
|
66989
|
+
}
|
|
66990
|
+
return validatedOverride;
|
|
66991
|
+
};
|
|
66992
|
+
const validateIgnoreField = (rawIgnore) => {
|
|
66993
|
+
if (!isRecord(rawIgnore)) {
|
|
66994
|
+
warnConfigIssue(`config field "ignore" must be an object (got ${typeof rawIgnore}); ignoring this field.`);
|
|
66995
|
+
return;
|
|
66996
|
+
}
|
|
66997
|
+
const validatedIgnore = {};
|
|
66998
|
+
for (const fieldName of [
|
|
66999
|
+
"rules",
|
|
67000
|
+
"files",
|
|
67001
|
+
"tags"
|
|
67002
|
+
]) {
|
|
67003
|
+
if (rawIgnore[fieldName] === void 0) continue;
|
|
67004
|
+
const validatedValues = validateStringArrayField(`ignore.${fieldName}`, rawIgnore[fieldName]);
|
|
67005
|
+
if (validatedValues !== void 0) validatedIgnore[fieldName] = validatedValues;
|
|
67006
|
+
}
|
|
67007
|
+
if (rawIgnore.overrides !== void 0) if (!Array.isArray(rawIgnore.overrides)) warnConfigIssue(`config field "ignore.overrides" must be an array (got ${typeof rawIgnore.overrides}); ignoring this field.`);
|
|
67008
|
+
else validatedIgnore.overrides = rawIgnore.overrides.flatMap((rawOverride, index) => {
|
|
67009
|
+
const validatedOverride = validateIgnoreOverride(rawOverride, index);
|
|
67010
|
+
return validatedOverride ? [validatedOverride] : [];
|
|
67011
|
+
});
|
|
67012
|
+
return validatedIgnore;
|
|
67013
|
+
};
|
|
66687
67014
|
const validateSurfaceControls = (surface, rawControls) => {
|
|
66688
|
-
if (!
|
|
67015
|
+
if (!isRecord(rawControls)) {
|
|
66689
67016
|
warnConfigIssue(`config field "surfaces.${surface}" must be an object (got ${typeof rawControls}); ignoring this surface.`);
|
|
66690
67017
|
return;
|
|
66691
67018
|
}
|
|
@@ -66709,7 +67036,7 @@ const validateSurfaceControls = (surface, rawControls) => {
|
|
|
66709
67036
|
return validatedSurfaceControls;
|
|
66710
67037
|
};
|
|
66711
67038
|
const validateSurfacesField = (rawSurfaces) => {
|
|
66712
|
-
if (!
|
|
67039
|
+
if (!isRecord(rawSurfaces)) {
|
|
66713
67040
|
warnConfigIssue(`config field "surfaces" must be an object (got ${typeof rawSurfaces}); ignoring this field.`);
|
|
66714
67041
|
return;
|
|
66715
67042
|
}
|
|
@@ -66725,7 +67052,7 @@ const validateSurfacesField = (rawSurfaces) => {
|
|
|
66725
67052
|
return validated;
|
|
66726
67053
|
};
|
|
66727
67054
|
const validateSeverityMap = (fieldName, rawMap, keysAreCategories = false) => {
|
|
66728
|
-
if (!
|
|
67055
|
+
if (!isRecord(rawMap)) {
|
|
66729
67056
|
warnConfigIssue(`config field "${fieldName}" must be an object (got ${typeof rawMap}); ignoring this field.`);
|
|
66730
67057
|
return;
|
|
66731
67058
|
}
|
|
@@ -66759,6 +67086,7 @@ const validateConfigTypes = (config) => {
|
|
|
66759
67086
|
for (const fieldName of BOOLEAN_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => coerceMaybeBooleanString(fieldName, value));
|
|
66760
67087
|
for (const fieldName of STRING_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateString(fieldName, value));
|
|
66761
67088
|
for (const fieldName of STRING_ARRAY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateStringArrayField(fieldName, value));
|
|
67089
|
+
applyFieldValidator(config, validated, "ignore", validateIgnoreField);
|
|
66762
67090
|
applyFieldValidator(config, validated, "surfaces", validateSurfacesField);
|
|
66763
67091
|
for (const fieldName of SEVERITY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateSeverityMap(fieldName, value, fieldName === "categories"));
|
|
66764
67092
|
applyFieldValidator(config, validated, "plugins", (value) => validateStringArrayField("plugins", value));
|
|
@@ -67010,6 +67338,10 @@ const dedupeRelatedDiagnostics = (diagnostics) => {
|
|
|
67010
67338
|
}
|
|
67011
67339
|
return uniqueDiagnostics;
|
|
67012
67340
|
};
|
|
67341
|
+
const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
67342
|
+
const relativePath = Path.relative(parentAbsolutePath, childAbsolutePath);
|
|
67343
|
+
return Boolean(relativePath) && !relativePath.startsWith("..") && !Path.isAbsolute(relativePath);
|
|
67344
|
+
};
|
|
67013
67345
|
const compareStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
67014
67346
|
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
67347
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
@@ -68371,7 +68703,7 @@ const collectScriptMotionEvidence = (sourceFile, typeChecker, program) => {
|
|
|
68371
68703
|
if (calleeEvidence.isReducedMotionHook && isExpressionValueConsumed(node)) evidence.hasReducedMotionHandling = true;
|
|
68372
68704
|
}
|
|
68373
68705
|
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
68374
|
-
const tagEvidence = ts.
|
|
68706
|
+
const tagEvidence = ts.isIdentifier(node.tagName) || ts.isPropertyAccessExpression(node.tagName) ? resolveMotionExpressionEvidence(node.tagName, typeChecker, program) : EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
68375
68707
|
if (tagEvidence.isMotionComponent || tagEvidence.isMotionComponentFactory) evidence.hasMotionUse = true;
|
|
68376
68708
|
if (tagEvidence.isMotionConfig && jsxElementHasReducedMotionConfiguration(node.attributes, typeChecker)) evidence.hasReducedMotionHandling = true;
|
|
68377
68709
|
}
|
|
@@ -68586,7 +68918,7 @@ const readScannedFile = (candidate) => {
|
|
|
68586
68918
|
return null;
|
|
68587
68919
|
}
|
|
68588
68920
|
};
|
|
68589
|
-
function* collectSecurityScanFiles(rootDirectory) {
|
|
68921
|
+
function* collectSecurityScanFiles(rootDirectory, excludedDirectories = /* @__PURE__ */ new Set()) {
|
|
68590
68922
|
const priorityCandidates = [];
|
|
68591
68923
|
const artifactCandidates = [];
|
|
68592
68924
|
const otherCandidates = [];
|
|
@@ -68601,7 +68933,7 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
68601
68933
|
for (const entry of readDirectoryEntries(current.absolutePath)) {
|
|
68602
68934
|
const absolutePath = Path.join(current.absolutePath, entry.name);
|
|
68603
68935
|
if (entry.isDirectory()) {
|
|
68604
|
-
if (!SKIPPED_DIRECTORY_NAMES.has(entry.name)) stack.push({
|
|
68936
|
+
if (!SKIPPED_DIRECTORY_NAMES.has(entry.name) && !excludedDirectories.has(Path.resolve(absolutePath))) stack.push({
|
|
68605
68937
|
absolutePath,
|
|
68606
68938
|
depth: current.depth + 1
|
|
68607
68939
|
});
|
|
@@ -68782,10 +69114,8 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
|
|
|
68782
69114
|
}
|
|
68783
69115
|
return true;
|
|
68784
69116
|
};
|
|
69117
|
+
const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
|
|
68785
69118
|
const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
|
|
68786
|
-
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
68787
|
-
setImmediate(resolve);
|
|
68788
|
-
});
|
|
68789
69119
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
68790
69120
|
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
68791
69121
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
@@ -68838,19 +69168,35 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
68838
69168
|
};
|
|
68839
69169
|
};
|
|
68840
69170
|
const checkSecurityScanCooperative = async (rootDirectory, options = {}) => {
|
|
69171
|
+
const throwIfScanAborted = () => {
|
|
69172
|
+
options.signal?.throwIfAborted();
|
|
69173
|
+
};
|
|
69174
|
+
const didReachDeadline = () => {
|
|
69175
|
+
const hasDeadlineElapsed = options.deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(options.deadlineEpochMs) === 0;
|
|
69176
|
+
if (hasDeadlineElapsed) options.onDeadlineExceeded?.();
|
|
69177
|
+
return hasDeadlineElapsed;
|
|
69178
|
+
};
|
|
69179
|
+
throwIfScanAborted();
|
|
68841
69180
|
const session = createSecurityScanSession(rootDirectory, options);
|
|
68842
69181
|
if (session === null) return [];
|
|
69182
|
+
if (didReachDeadline()) return [];
|
|
68843
69183
|
let sliceStartedAt = performance.now();
|
|
68844
|
-
for (const file of collectSecurityScanFiles(rootDirectory)) {
|
|
69184
|
+
for (const file of collectSecurityScanFiles(rootDirectory, options.excludedDirectories)) {
|
|
69185
|
+
throwIfScanAborted();
|
|
69186
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68845
69187
|
if (file === null) {
|
|
68846
69188
|
if (performance.now() - sliceStartedAt >= 12) {
|
|
68847
69189
|
await yieldToEventLoop();
|
|
69190
|
+
throwIfScanAborted();
|
|
69191
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68848
69192
|
sliceStartedAt = performance.now();
|
|
68849
69193
|
}
|
|
68850
69194
|
continue;
|
|
68851
69195
|
}
|
|
68852
69196
|
for (const _ruleStep of session.scanFileByRule(file)) if (performance.now() - sliceStartedAt >= 12) {
|
|
68853
69197
|
await yieldToEventLoop();
|
|
69198
|
+
throwIfScanAborted();
|
|
69199
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68854
69200
|
sliceStartedAt = performance.now();
|
|
68855
69201
|
}
|
|
68856
69202
|
}
|
|
@@ -69013,25 +69359,18 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
69013
69359
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
69014
69360
|
return patterns;
|
|
69015
69361
|
};
|
|
69016
|
-
const
|
|
69017
|
-
const KNIP_JSON_FILENAME = "knip.json";
|
|
69018
|
-
const readJsonFileSafe = (filePath) => {
|
|
69019
|
-
let rawContents;
|
|
69020
|
-
try {
|
|
69021
|
-
rawContents = fs.readFileSync(filePath, "utf-8");
|
|
69022
|
-
} catch {
|
|
69023
|
-
return null;
|
|
69024
|
-
}
|
|
69362
|
+
const failOpenReadJson = (filePath, fallback) => {
|
|
69025
69363
|
try {
|
|
69026
|
-
return JSON.parse(
|
|
69364
|
+
return JSON.parse(NFS.readFileSync(filePath, "utf8"));
|
|
69027
69365
|
} catch {
|
|
69028
|
-
return
|
|
69366
|
+
return fallback;
|
|
69029
69367
|
}
|
|
69030
69368
|
};
|
|
69369
|
+
const KNIP_JSON_FILENAME = "knip.json";
|
|
69031
69370
|
const readKnipConfig = (rootDirectory) => {
|
|
69032
|
-
const knipJson =
|
|
69371
|
+
const knipJson = failOpenReadJson(path.join(rootDirectory, KNIP_JSON_FILENAME), null);
|
|
69033
69372
|
if (isRecord(knipJson)) return knipJson;
|
|
69034
|
-
const packageJson =
|
|
69373
|
+
const packageJson = failOpenReadJson(path.join(rootDirectory, "package.json"), null);
|
|
69035
69374
|
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
69036
69375
|
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
69037
69376
|
};
|
|
@@ -69079,13 +69418,6 @@ const atomicWriteJson = (filePath, value) => {
|
|
|
69079
69418
|
return;
|
|
69080
69419
|
}
|
|
69081
69420
|
};
|
|
69082
|
-
const failOpenReadJson = (filePath, fallback) => {
|
|
69083
|
-
try {
|
|
69084
|
-
return JSON.parse(NFS.readFileSync(filePath, "utf8"));
|
|
69085
|
-
} catch {
|
|
69086
|
-
return fallback;
|
|
69087
|
-
}
|
|
69088
|
-
};
|
|
69089
69421
|
const hashFileContents = (filePath) => {
|
|
69090
69422
|
try {
|
|
69091
69423
|
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
@@ -69764,7 +70096,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
|
|
|
69764
70096
|
return true;
|
|
69765
70097
|
};
|
|
69766
70098
|
const filterDiagnosticsForSurface = (diagnostics, surface, config) => diagnostics.filter((diagnostic) => isDiagnosticOnSurface(diagnostic, surface, config));
|
|
69767
|
-
const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
|
|
69768
70099
|
/**
|
|
69769
70100
|
* Budget for the dead-code phase, scaled to the work. deslop's graph build is
|
|
69770
70101
|
* CPU-bound and roughly linear in file count, so a fixed 120s cap is too tight
|
|
@@ -69772,25 +70103,28 @@ const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs
|
|
|
69772
70103
|
* tipped over by any concurrent load — silently dropping every dead-code
|
|
69773
70104
|
* finding. Scaling the budget with file count (and inversely with the core
|
|
69774
70105
|
* 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.
|
|
70106
|
+
* reclaims a genuinely wedged worker.
|
|
69777
70107
|
*/
|
|
69778
70108
|
const resolveDeadCodeTimeout = (input) => {
|
|
69779
70109
|
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
|
-
};
|
|
70110
|
+
return { workerTimeoutMs: Math.min(DEAD_CODE_TIMEOUT_CEILING_MS, Math.max(DEAD_CODE_WORKER_TIMEOUT_MS, Math.ceil(input.sourceFileCount * 30 * coreShareFactor))) };
|
|
69785
70111
|
};
|
|
69786
|
-
const resolveLintIncludePaths = (rootDirectory, userConfig) => {
|
|
70112
|
+
const resolveLintIncludePaths = (rootDirectory, userConfig, sourceFiles) => {
|
|
69787
70113
|
if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
|
|
69788
70114
|
const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
|
|
69789
|
-
return listSourceFiles(rootDirectory).filter((filePath) => {
|
|
70115
|
+
return (sourceFiles ?? listSourceFiles(rootDirectory)).filter((filePath) => {
|
|
69790
70116
|
if (!isLintableSourceFile(filePath)) return false;
|
|
69791
70117
|
return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
|
|
69792
70118
|
});
|
|
69793
70119
|
};
|
|
70120
|
+
const filterPathsOutsideDirectories = (input) => {
|
|
70121
|
+
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}/`)));
|
|
70122
|
+
if (excludedPrefixes.length === 0) return [...input.relativePaths];
|
|
70123
|
+
return input.relativePaths.filter((relativePath) => {
|
|
70124
|
+
const normalizedRelativePath = relativePath.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
70125
|
+
return !excludedPrefixes.some((excludedPrefix) => normalizedRelativePath === excludedPrefix || normalizedRelativePath.startsWith(`${excludedPrefix}/`));
|
|
70126
|
+
});
|
|
70127
|
+
};
|
|
69794
70128
|
var Config = class Config extends Service()("react-doctor/Config") {
|
|
69795
70129
|
static layerNode = effect(Config, gen(function* () {
|
|
69796
70130
|
const cache = yield* make$3({
|
|
@@ -69852,6 +70186,7 @@ var Files = class Files extends Service()("react-doctor/Files") {
|
|
|
69852
70186
|
static layerNode = succeed$3(Files, Files.of({
|
|
69853
70187
|
readLines: (input) => sync(() => createNodeReadFileLinesSync(input.rootDirectory)(input.filePath)),
|
|
69854
70188
|
listSourceFiles: (rootDirectory) => sync(() => listSourceFiles(rootDirectory)),
|
|
70189
|
+
listSourceFilesCooperative: (input) => promise(() => listSourceFilesCooperative(input.rootDirectory, input.signal)),
|
|
69855
70190
|
isFile: (filePath) => sync(() => isFile(filePath)),
|
|
69856
70191
|
isDirectory: (filePath) => sync(() => isDirectory(filePath))
|
|
69857
70192
|
}));
|
|
@@ -69878,6 +70213,16 @@ var Files = class Files extends Service()("react-doctor/Files") {
|
|
|
69878
70213
|
}
|
|
69879
70214
|
return files;
|
|
69880
70215
|
}),
|
|
70216
|
+
listSourceFilesCooperative: (input) => sync(() => {
|
|
70217
|
+
const rootDirectory = input.rootDirectory;
|
|
70218
|
+
const prefix = rootDirectory.endsWith("/") ? rootDirectory : `${rootDirectory}/`;
|
|
70219
|
+
const files = [];
|
|
70220
|
+
for (const absolute of tree.keys()) {
|
|
70221
|
+
if (!absolute.startsWith(prefix)) continue;
|
|
70222
|
+
files.push(absolute.slice(prefix.length));
|
|
70223
|
+
}
|
|
70224
|
+
return files;
|
|
70225
|
+
}),
|
|
69881
70226
|
isFile: (filePath) => sync(() => tree.has(filePath)),
|
|
69882
70227
|
isDirectory: (filePath) => sync(() => {
|
|
69883
70228
|
const prefix = filePath.endsWith("/") ? filePath : `${filePath}/`;
|
|
@@ -70342,7 +70687,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
70342
70687
|
changedFiles: yield* mergeUntracked(directory, splitNullSeparated(diff.stdout), includeUntracked),
|
|
70343
70688
|
isCurrentChanges: false
|
|
70344
70689
|
};
|
|
70345
|
-
}).pipe(withSpan("Git.diffSelection")),
|
|
70690
|
+
}).pipe(catchReasons("ReactDoctorError", { GitInvocationFailed: () => succeed$2(null) }, (_reason, error) => fail$4(error)), withSpan("Git.diffSelection")),
|
|
70346
70691
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
70347
70692
|
"diff",
|
|
70348
70693
|
"--no-ext-diff",
|
|
@@ -70453,7 +70798,7 @@ const batchIncludePaths = (baseArgs, includePaths) => {
|
|
|
70453
70798
|
for (const filePath of includePaths) {
|
|
70454
70799
|
const entryLength = filePath.length + 1;
|
|
70455
70800
|
const exceedsArgLength = currentBatch.length > 0 && currentBatchLength + entryLength > 24e3;
|
|
70456
|
-
const exceedsFileCount = currentBatch.length >=
|
|
70801
|
+
const exceedsFileCount = currentBatch.length >= 200;
|
|
70457
70802
|
if (exceedsArgLength || exceedsFileCount) {
|
|
70458
70803
|
batches.push(currentBatch);
|
|
70459
70804
|
currentBatch = [];
|
|
@@ -70800,7 +71145,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
70800
71145
|
}
|
|
70801
71146
|
return enabled;
|
|
70802
71147
|
};
|
|
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 }) => {
|
|
71148
|
+
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
71149
|
const hasIncludedTags = includedTags.size > 0;
|
|
70805
71150
|
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
70806
71151
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
@@ -70864,7 +71209,8 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
70864
71209
|
}))
|
|
70865
71210
|
} : {},
|
|
70866
71211
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
70867
|
-
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
71212
|
+
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {},
|
|
71213
|
+
...projectIndexModuleSources !== void 0 ? { projectIndexModuleSources: [...projectIndexModuleSources] } : {}
|
|
70868
71214
|
} },
|
|
70869
71215
|
rules: {
|
|
70870
71216
|
...reactCompilerRules,
|
|
@@ -71113,11 +71459,17 @@ const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }
|
|
|
71113
71459
|
return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
|
|
71114
71460
|
};
|
|
71115
71461
|
const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
|
|
71462
|
+
const decodeDiagnostic = (raw) => {
|
|
71463
|
+
const diagnostic = validateDiagnostic$1(raw);
|
|
71464
|
+
return {
|
|
71465
|
+
...diagnostic,
|
|
71466
|
+
relatedLocations: diagnostic.relatedLocations?.map((location) => ({ ...location }))
|
|
71467
|
+
};
|
|
71468
|
+
};
|
|
71116
71469
|
const decodeFileDiagnostics = (raw) => {
|
|
71117
71470
|
if (!Array.isArray(raw)) return null;
|
|
71118
71471
|
try {
|
|
71119
|
-
|
|
71120
|
-
return raw;
|
|
71472
|
+
return raw.map((entry) => decodeDiagnostic(entry));
|
|
71121
71473
|
} catch {
|
|
71122
71474
|
return null;
|
|
71123
71475
|
}
|
|
@@ -72349,6 +72701,12 @@ const buildProfiledNodeArguments = (input) => [
|
|
|
72349
72701
|
...input.heapProfileDirectory ? ["--heap-prof", `--heap-prof-dir=${input.heapProfileDirectory}`] : [],
|
|
72350
72702
|
...input.argumentsList
|
|
72351
72703
|
];
|
|
72704
|
+
const lowerChildProcessPriority = (processId) => {
|
|
72705
|
+
if (processId === void 0) return;
|
|
72706
|
+
try {
|
|
72707
|
+
OS.setPriority(processId, OS.constants.priority.PRIORITY_BELOW_NORMAL);
|
|
72708
|
+
} catch {}
|
|
72709
|
+
};
|
|
72352
72710
|
const SANITIZED_ENV = buildOxlintChildEnv(process.env);
|
|
72353
72711
|
/**
|
|
72354
72712
|
* Spawn one oxlint subprocess with hard ceilings on wall time and
|
|
@@ -72387,6 +72745,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
72387
72745
|
"pipe"
|
|
72388
72746
|
]
|
|
72389
72747
|
});
|
|
72748
|
+
lowerChildProcessPriority(child.pid);
|
|
72390
72749
|
const onAbort = () => {
|
|
72391
72750
|
child.kill("SIGKILL");
|
|
72392
72751
|
reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
|
|
@@ -72509,7 +72868,7 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
72509
72868
|
* loop with a slimmer config in that case.
|
|
72510
72869
|
*/
|
|
72511
72870
|
const spawnLintBatches = async (input) => {
|
|
72512
|
-
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth =
|
|
72871
|
+
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 9, signal, deadlineEpochMs } = input;
|
|
72513
72872
|
const resolveSourcePath = (filePath) => {
|
|
72514
72873
|
const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
|
|
72515
72874
|
return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
|
|
@@ -72517,6 +72876,12 @@ const spawnLintBatches = async (input) => {
|
|
|
72517
72876
|
const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
|
|
72518
72877
|
let rescueDeadlineEpochMs;
|
|
72519
72878
|
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
|
|
72879
|
+
const resolveSpawnTimeoutMs = () => {
|
|
72880
|
+
const deadlineBudgets = [deadlineEpochMs, rescueDeadlineEpochMs].filter((deadline) => deadline !== void 0).map(remainingDeadlineBudgetMs);
|
|
72881
|
+
if (deadlineBudgets.length === 0) return spawnTimeoutMs;
|
|
72882
|
+
const remainingDeadlineMs = Math.min(...deadlineBudgets);
|
|
72883
|
+
return spawnTimeoutMs === void 0 ? remainingDeadlineMs : Math.min(spawnTimeoutMs, remainingDeadlineMs);
|
|
72884
|
+
};
|
|
72520
72885
|
const runBatchPass = async (concurrency, passBatches, passOnFileProgress) => {
|
|
72521
72886
|
const totalFileCount = passBatches.reduce((sum, batch) => sum + batch.length, 0);
|
|
72522
72887
|
const allDiagnostics = [];
|
|
@@ -72534,12 +72899,13 @@ const spawnLintBatches = async (input) => {
|
|
|
72534
72899
|
const batchArgs = [...baseArgs, ...batch];
|
|
72535
72900
|
try {
|
|
72536
72901
|
const spawnBatch = () => {
|
|
72537
|
-
|
|
72902
|
+
const effectiveSpawnTimeoutMs = resolveSpawnTimeoutMs();
|
|
72903
|
+
if (effectiveSpawnTimeoutMs === 0) {
|
|
72538
72904
|
deadlineSkippedFiles.push(...batch);
|
|
72539
72905
|
batchState.deadlineSkippedFileCount += batch.length;
|
|
72540
72906
|
return Promise.resolve(null);
|
|
72541
72907
|
}
|
|
72542
|
-
return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath,
|
|
72908
|
+
return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, effectiveSpawnTimeoutMs, outputMaxBytes, signal, () => {
|
|
72543
72909
|
if (batchState.didStart) return;
|
|
72544
72910
|
batchState.didStart = true;
|
|
72545
72911
|
startedFileCount += batchState.initialFileCount;
|
|
@@ -72694,11 +73060,36 @@ const validateRuleRegistration = () => {
|
|
|
72694
73060
|
].filter((entry) => entry !== null).join("; ");
|
|
72695
73061
|
console.warn(`[react-doctor] rule-registration drift: ${detail}`);
|
|
72696
73062
|
};
|
|
73063
|
+
const PROJECT_INDEX_MODULE_SOURCES = [
|
|
73064
|
+
"next/og",
|
|
73065
|
+
"@vercel/og",
|
|
73066
|
+
"satori",
|
|
73067
|
+
"remotion"
|
|
73068
|
+
];
|
|
73069
|
+
const collectProjectIndexModuleSources = async (rootDirectory, candidateFiles) => {
|
|
73070
|
+
const foundModuleSources = /* @__PURE__ */ new Set();
|
|
73071
|
+
let sliceStartedAt = performance.now();
|
|
73072
|
+
for (const candidateFile of candidateFiles) {
|
|
73073
|
+
let sourceBuffer;
|
|
73074
|
+
try {
|
|
73075
|
+
sourceBuffer = NFS.readFileSync(Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile));
|
|
73076
|
+
} catch {
|
|
73077
|
+
continue;
|
|
73078
|
+
}
|
|
73079
|
+
for (const moduleSource of PROJECT_INDEX_MODULE_SOURCES) if (sourceBuffer.includes(`"${moduleSource}"`) || sourceBuffer.includes(`'${moduleSource}'`)) foundModuleSources.add(moduleSource);
|
|
73080
|
+
if (foundModuleSources.size === PROJECT_INDEX_MODULE_SOURCES.length) break;
|
|
73081
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
73082
|
+
await yieldToEventLoop();
|
|
73083
|
+
sliceStartedAt = performance.now();
|
|
73084
|
+
}
|
|
73085
|
+
}
|
|
73086
|
+
return [...foundModuleSources].sort();
|
|
73087
|
+
};
|
|
72697
73088
|
/**
|
|
72698
73089
|
* Balanced LPT (longest-processing-time-first) lint batch planner. Where
|
|
72699
|
-
* `batchIncludePaths` greedily fills
|
|
72700
|
-
* remainder batch
|
|
72701
|
-
*
|
|
73090
|
+
* `batchIncludePaths` greedily fills fixed-size batches and leaves a small
|
|
73091
|
+
* remainder batch, so the parallel pool's wall clock is set by whichever
|
|
73092
|
+
* full chunk happened to collect the most work while
|
|
72702
73093
|
* the remainder's worker idles), this planner keeps the SAME mandatory batch
|
|
72703
73094
|
* count — `ceil(files / OXLINT_MAX_FILES_PER_BATCH)`, the JS-plugin
|
|
72704
73095
|
* perf-cliff / native-binding SIGABRT guard — and assigns files largest-first,
|
|
@@ -72727,7 +73118,7 @@ const validateRuleRegistration = () => {
|
|
|
72727
73118
|
*/
|
|
72728
73119
|
const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
|
|
72729
73120
|
if (files.length === 0) return [];
|
|
72730
|
-
const batchCount = Math.ceil(files.length /
|
|
73121
|
+
const batchCount = Math.ceil(files.length / 200);
|
|
72731
73122
|
const maxFilesPerBatch = Math.ceil(files.length / batchCount);
|
|
72732
73123
|
const baseArgsLengthChars = estimateArgsLength(baseArgs);
|
|
72733
73124
|
const descendingSizeIndexes = [...files.keys()].sort((leftIndex, rightIndex) => (sizeByFile.get(files[rightIndex]) ?? 0) - (sizeByFile.get(files[leftIndex]) ?? 0));
|
|
@@ -73256,6 +73647,7 @@ const runOxlint = async (options) => {
|
|
|
73256
73647
|
await yieldToEventLoop();
|
|
73257
73648
|
const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
|
|
73258
73649
|
const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
|
|
73650
|
+
const projectIndexModuleSources = includePaths === void 0 && options.deadlineEpochMs === void 0 ? await collectProjectIndexModuleSources(rootDirectory, candidateFiles) : void 0;
|
|
73259
73651
|
unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
|
|
73260
73652
|
rootDirectory,
|
|
73261
73653
|
candidateFiles
|
|
@@ -73278,6 +73670,7 @@ const runOxlint = async (options) => {
|
|
|
73278
73670
|
runtimeGlobals,
|
|
73279
73671
|
unpluginAutoImportGlobalScopes,
|
|
73280
73672
|
serverAuthFunctionNames,
|
|
73673
|
+
projectIndexModuleSources,
|
|
73281
73674
|
severityControls,
|
|
73282
73675
|
userPlugins,
|
|
73283
73676
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
@@ -73745,10 +74138,10 @@ const translateProjectInfoError = (cause, directory) => {
|
|
|
73745
74138
|
}) });
|
|
73746
74139
|
};
|
|
73747
74140
|
var Project = class Project extends Service()("react-doctor/Project") {
|
|
73748
|
-
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (
|
|
74141
|
+
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (input) {
|
|
73749
74142
|
return yield* try_({
|
|
73750
|
-
try: () => discoverProject(directory),
|
|
73751
|
-
catch: (cause) => translateProjectInfoError(cause, directory)
|
|
74143
|
+
try: () => discoverProject(input.directory, { sourceFileCount: input.sourceFileCount }),
|
|
74144
|
+
catch: (cause) => translateProjectInfoError(cause, input.directory)
|
|
73752
74145
|
});
|
|
73753
74146
|
}) }));
|
|
73754
74147
|
static layerOf = (projectInfo) => succeed$3(Project, Project.of({ discover: () => succeed$2(projectInfo) }));
|
|
@@ -74333,9 +74726,10 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
74333
74726
|
* outage.
|
|
74334
74727
|
*/
|
|
74335
74728
|
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
|
-
|
|
74729
|
+
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (configuredTimeoutMs) => checkSupplyChain({
|
|
74730
|
+
rootDirectory: input.rootDirectory,
|
|
74731
|
+
userConfig: input.userConfig,
|
|
74732
|
+
totalTimeoutMs: input.timeoutMs ?? configuredTimeoutMs
|
|
74339
74733
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), withSpan("SupplyChain.run"))) }));
|
|
74340
74734
|
static layerOf = (diagnostics) => succeed$3(SupplyChain, SupplyChain.of({ run: () => fromIterable$1(diagnostics) }));
|
|
74341
74735
|
};
|
|
@@ -74370,10 +74764,6 @@ const NO_HOOKS = {
|
|
|
74370
74764
|
beforeLint: () => void_,
|
|
74371
74765
|
afterLint: () => void_
|
|
74372
74766
|
};
|
|
74373
|
-
const filterMapNullable = (transform) => fromPredicateOption((value) => {
|
|
74374
|
-
const result = transform(value);
|
|
74375
|
-
return result === null ? none() : some(result);
|
|
74376
|
-
});
|
|
74377
74767
|
const fileReader = (filesService, rootDirectory) => (filePath) => {
|
|
74378
74768
|
const lines = runSync(filesService.readLines({
|
|
74379
74769
|
filePath,
|
|
@@ -74397,7 +74787,7 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
74397
74787
|
* The GitHub viewer-permission lookup is forked onto a background
|
|
74398
74788
|
* fiber here and joined late (it feeds score metadata, not
|
|
74399
74789
|
* diagnostics).
|
|
74400
|
-
* 2. beforeLint hook (e.g. CLI
|
|
74790
|
+
* 2. beforeLint hook (e.g. CLI records project telemetry)
|
|
74401
74791
|
* 3. environment checks (reduced-motion + pnpm hardening +
|
|
74402
74792
|
* expo/react-native), collected synchronously. The heavier
|
|
74403
74793
|
* content-regex security scan is forked instead (like supply-chain
|
|
@@ -74410,13 +74800,11 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
74410
74800
|
* `SupplyChainOverlapTimeoutMs` (measured from fork) so a hung
|
|
74411
74801
|
* socket can't drag out its join; on timeout it fails open to no
|
|
74412
74802
|
* diagnostics — the same outcome class as a Socket outage.
|
|
74413
|
-
* 5. Linter.run runs; DeadCode.run
|
|
74414
|
-
*
|
|
74415
|
-
*
|
|
74416
|
-
*
|
|
74417
|
-
*
|
|
74418
|
-
* fiber is joined (or interrupted, SIGKILLing its worker, on lint
|
|
74419
|
-
* failure) before diagnostics are concatenated. The afterLint hook
|
|
74803
|
+
* 5. Linter.run runs; DeadCode.run forks only when
|
|
74804
|
+
* REACT_DOCTOR_DEAD_CODE_OVERLAP=on. The default "auto" and explicit
|
|
74805
|
+
* "off" paths stay sequential. The fiber is joined (or interrupted,
|
|
74806
|
+
* SIGKILLing its worker, on lint failure) before diagnostics are
|
|
74807
|
+
* concatenated. The afterLint hook
|
|
74420
74808
|
* fires between lint and dead-code. Progress spinner labels AND the
|
|
74421
74809
|
* final diagnostic / score order stay independent of execution
|
|
74422
74810
|
* order, so terminal output is identical either way; supply-chain
|
|
@@ -74451,8 +74839,28 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74451
74839
|
const partialFailuresRef = yield* LintPartialFailures;
|
|
74452
74840
|
const resolvedConfig = yield* configService.resolve(input.directory);
|
|
74453
74841
|
const scanDirectory = resolvedConfig.resolvedDirectory;
|
|
74454
|
-
const
|
|
74842
|
+
const excludedProjectDirectories = (input.excludedProjectDirectories ?? []).map((excludedDirectory) => Path.resolve(excludedDirectory)).filter((excludedDirectory) => isPathInsideDirectory(excludedDirectory, scanDirectory));
|
|
74843
|
+
const excludedProjectRelativePaths = excludedProjectDirectories.map((excludedDirectory) => Path.relative(scanDirectory, excludedDirectory).replaceAll("\\", "/"));
|
|
74844
|
+
const isExcludedProjectDiagnostic = (diagnostic) => {
|
|
74845
|
+
const relativeFilePath = toNormalizedRelativePath(diagnostic.filePath, scanDirectory);
|
|
74846
|
+
return excludedProjectRelativePaths.some((excludedRelativePath) => relativeFilePath === excludedRelativePath || relativeFilePath.startsWith(`${excludedRelativePath}/`));
|
|
74847
|
+
};
|
|
74848
|
+
const precomputedSourceFiles = input.suppressScanSummary === true || excludedProjectDirectories.length > 0 ? yield* filesService.listSourceFilesCooperative({
|
|
74849
|
+
rootDirectory: scanDirectory,
|
|
74850
|
+
signal: input.signal
|
|
74851
|
+
}) : null;
|
|
74852
|
+
const includedPrecomputedSourceFiles = precomputedSourceFiles !== null && excludedProjectDirectories.length > 0 ? filterPathsOutsideDirectories({
|
|
74853
|
+
rootDirectory: scanDirectory,
|
|
74854
|
+
relativePaths: precomputedSourceFiles,
|
|
74855
|
+
excludedDirectories: excludedProjectDirectories
|
|
74856
|
+
}) : precomputedSourceFiles;
|
|
74857
|
+
const sourceFileCount = excludedProjectDirectories.length > 0 ? includedPrecomputedSourceFiles?.length : input.precomputedSourceFileCount ?? includedPrecomputedSourceFiles?.length;
|
|
74858
|
+
const project = yield* projectService.discover({
|
|
74859
|
+
directory: scanDirectory,
|
|
74860
|
+
sourceFileCount
|
|
74861
|
+
});
|
|
74455
74862
|
if (!isAnalyzableProject(project)) return yield* new ReactDoctorError({ reason: new NoReactDependency({ directory: scanDirectory }) });
|
|
74863
|
+
const deadCodeSourceFileCount = input.retainExcludedProjectDeadCodeDiagnostics === true && precomputedSourceFiles !== null ? precomputedSourceFiles.length : project.sourceFileCount;
|
|
74456
74864
|
const [repo, sha, defaultBranch] = yield* all([
|
|
74457
74865
|
gitService.githubRepo(scanDirectory).pipe(orElseSucceed(() => null)),
|
|
74458
74866
|
gitService.headSha(scanDirectory).pipe(orElseSucceed(() => null)),
|
|
@@ -74463,11 +74871,16 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74463
74871
|
directory: scanDirectory,
|
|
74464
74872
|
repo
|
|
74465
74873
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
74466
|
-
|
|
74467
|
-
|
|
74874
|
+
let lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, includedPrecomputedSourceFiles ?? void 0);
|
|
74875
|
+
if (excludedProjectDirectories.length > 0) lintIncludePaths = filterPathsOutsideDirectories({
|
|
74876
|
+
rootDirectory: scanDirectory,
|
|
74877
|
+
relativePaths: lintIncludePaths ?? includedPrecomputedSourceFiles ?? (yield* filesService.listSourceFiles(scanDirectory)),
|
|
74878
|
+
excludedDirectories: excludedProjectDirectories
|
|
74879
|
+
});
|
|
74880
|
+
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? includedPrecomputedSourceFiles ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
74468
74881
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
74469
74882
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
74470
|
-
yield* beforeLint(project
|
|
74883
|
+
yield* beforeLint(project);
|
|
74471
74884
|
const isDiffMode = input.includePaths.length > 0;
|
|
74472
74885
|
const showWarnings = input.warnings ?? resolvedConfig.config?.warnings ?? true;
|
|
74473
74886
|
const transform = buildDiagnosticPipeline({
|
|
@@ -74477,7 +74890,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74477
74890
|
respectInlineDisables: input.respectInlineDisables,
|
|
74478
74891
|
showWarnings
|
|
74479
74892
|
});
|
|
74480
|
-
const filterPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(
|
|
74893
|
+
const filterPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(fromPredicateOption((diagnostic) => {
|
|
74894
|
+
const filteredDiagnostic = transform.apply(diagnostic);
|
|
74895
|
+
return filteredDiagnostic === null ? none() : some(filteredDiagnostic);
|
|
74896
|
+
})));
|
|
74481
74897
|
const applyPerElementPipeline = (rawStream) => filterPerElementPipeline(rawStream).pipe(tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
74482
74898
|
const envCollected = yield* runCollect(applyPerElementPipeline(fromIterable$1(isDiffMode ? [] : [
|
|
74483
74899
|
...checkReducedMotion(scanDirectory),
|
|
@@ -74487,17 +74903,31 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74487
74903
|
...checkReactNativeProject(scanDirectory, project)
|
|
74488
74904
|
])));
|
|
74489
74905
|
const securityScanFailedRef = yield* make$13(false);
|
|
74490
|
-
|
|
74906
|
+
let didSecurityScanReachDeadline = false;
|
|
74907
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise((signal) => checkSecurityScanCooperative(scanDirectory, {
|
|
74491
74908
|
project,
|
|
74492
74909
|
ignoredTags: input.ignoredTags,
|
|
74493
74910
|
includedTags: input.includedTags,
|
|
74494
|
-
includeTagDefaults: input.includeTagDefaults
|
|
74911
|
+
includeTagDefaults: input.includeTagDefaults,
|
|
74912
|
+
excludedDirectories: new Set(excludedProjectDirectories),
|
|
74913
|
+
deadlineEpochMs: input.deadlineEpochMs,
|
|
74914
|
+
signal,
|
|
74915
|
+
onDeadlineExceeded: () => {
|
|
74916
|
+
didSecurityScanReachDeadline = true;
|
|
74917
|
+
}
|
|
74495
74918
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
74919
|
+
const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
|
|
74920
|
+
const capOptionalToDeadline = (phaseTimeoutMs) => {
|
|
74921
|
+
if (input.deadlineEpochMs === void 0) return phaseTimeoutMs;
|
|
74922
|
+
const remainingBudgetMs = remainingDeadlineBudgetMs(input.deadlineEpochMs);
|
|
74923
|
+
return phaseTimeoutMs === null ? remainingBudgetMs : Math.min(phaseTimeoutMs, remainingBudgetMs);
|
|
74924
|
+
};
|
|
74496
74925
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
74497
|
-
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
74926
|
+
const supplyChainOverlapTimeout = capToDeadline(yield* SupplyChainOverlapTimeoutMs);
|
|
74498
74927
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
74499
74928
|
rootDirectory: scanDirectory,
|
|
74500
|
-
userConfig: resolvedConfig.config
|
|
74929
|
+
userConfig: resolvedConfig.config,
|
|
74930
|
+
timeoutMs: supplyChainOverlapTimeout
|
|
74501
74931
|
}))).pipe(map$3((diagnostics) => ({
|
|
74502
74932
|
diagnostics,
|
|
74503
74933
|
timedOut: false
|
|
@@ -74521,46 +74951,49 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74521
74951
|
const scanConcurrency = resolveScanConcurrency(yield* OxlintConcurrency);
|
|
74522
74952
|
const lintPhaseTimeoutMs = yield* LintPhaseTimeoutMs;
|
|
74523
74953
|
const deadCodePhaseTimeoutMs = yield* DeadCodePhaseTimeoutMs;
|
|
74524
|
-
const resolveDeadCodePhaseTimeoutMs = (scaledPhaseTimeoutMs) => deadCodePhaseTimeoutMs === 15e4 ? scaledPhaseTimeoutMs : deadCodePhaseTimeoutMs;
|
|
74525
74954
|
const workerCountSuffix = scanConcurrency > 1 ? ` ${highlighter.dim(`[~${scanConcurrency} workers]`)}` : "";
|
|
74526
|
-
const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
|
|
74527
74955
|
const shouldRunDeadCode = input.runDeadCode && !isDiffMode && (showWarnings || deadCodeMaySurfaceWhenWarningsHidden(resolvedConfig.config));
|
|
74528
74956
|
const deadCodeOverlapMode = yield* DeadCodeOverlap;
|
|
74529
74957
|
const shouldOverlapDeadCode = shouldRunDeadCode && deadCodeOverlapMode === "on";
|
|
74530
74958
|
const deadCodeParseConcurrency = shouldOverlapDeadCode ? Math.max(1, Math.floor(scanConcurrency * DEAD_CODE_OVERLAP_PARSE_SHARE)) : void 0;
|
|
74531
74959
|
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
|
-
|
|
74960
|
+
const buildCollectDeadCode = (deadCodeTimeout) => {
|
|
74961
|
+
const collectDeadCode = runCollect(applyPerElementPipeline(deadCodeService.run({
|
|
74962
|
+
rootDirectory: scanDirectory,
|
|
74963
|
+
parseConcurrency: deadCodeParseConcurrency,
|
|
74964
|
+
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
|
|
74965
|
+
onCacheOutcome: (didHitCache) => {
|
|
74966
|
+
deadCodeCacheHit = didHitCache;
|
|
74967
|
+
},
|
|
74968
|
+
onSummaryCacheStats: (stats) => {
|
|
74969
|
+
deadCodeSummaryCacheHits = stats.hits;
|
|
74970
|
+
deadCodeSummaryCacheMisses = stats.misses;
|
|
74971
|
+
}
|
|
74972
|
+
}).pipe(filter((diagnostic) => input.retainExcludedProjectDeadCodeDiagnostics === true || !isExcludedProjectDiagnostic(diagnostic)), catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
74973
|
+
yield* set(deadCodeFailure, {
|
|
74974
|
+
didFail: true,
|
|
74975
|
+
reason: error.message
|
|
74976
|
+
});
|
|
74977
|
+
return empty$4;
|
|
74978
|
+
}))))));
|
|
74979
|
+
const phaseTimeoutMs = deadCodeTimeout.phaseTimeoutMs;
|
|
74980
|
+
if (phaseTimeoutMs === null) return collectDeadCode;
|
|
74981
|
+
return collectDeadCode.pipe(timeoutOption(phaseTimeoutMs), flatMap$2(match$3({
|
|
74982
|
+
onNone: () => set(deadCodeFailure, {
|
|
74983
|
+
didFail: true,
|
|
74984
|
+
reason: `Dead-code analysis exceeded ${Math.round(phaseTimeoutMs / MILLISECONDS_PER_SECOND)}s and was skipped.`
|
|
74985
|
+
}).pipe(as([])),
|
|
74986
|
+
onSome: succeed$2
|
|
74987
|
+
})));
|
|
74988
|
+
};
|
|
74556
74989
|
const overlapDeadCodeTimeout = resolveDeadCodeTimeout({
|
|
74557
|
-
sourceFileCount:
|
|
74990
|
+
sourceFileCount: deadCodeSourceFileCount,
|
|
74558
74991
|
deadCodeConcurrency: deadCodeParseConcurrency ?? scanConcurrency,
|
|
74559
74992
|
fullConcurrency: scanConcurrency
|
|
74560
74993
|
});
|
|
74561
74994
|
const deadCodeFiber = shouldOverlapDeadCode ? yield* forkChild(buildCollectDeadCode({
|
|
74562
74995
|
workerTimeoutMs: overlapDeadCodeTimeout.workerTimeoutMs,
|
|
74563
|
-
phaseTimeoutMs:
|
|
74996
|
+
phaseTimeoutMs: capOptionalToDeadline(deadCodePhaseTimeoutMs)
|
|
74564
74997
|
})) : null;
|
|
74565
74998
|
const scanProgress = yield* progressService.start("Scanning...");
|
|
74566
74999
|
const scanStartTime = Date.now();
|
|
@@ -74611,7 +75044,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74611
75044
|
});
|
|
74612
75045
|
return empty$4;
|
|
74613
75046
|
}))));
|
|
74614
|
-
const
|
|
75047
|
+
const collectLintDiagnostics = runCollect(filterPerElementPipeline(shouldOverlapDeadCode ? baseLintStream.pipe(provideService(OxlintConcurrency, lintConcurrency)) : baseLintStream));
|
|
75048
|
+
const lintCollected = dedupeRelatedDiagnostics(yield* lintPhaseTimeoutMs === null ? collectLintDiagnostics : collectLintDiagnostics.pipe(timeoutOption(lintPhaseTimeoutMs), flatMap$2(match$3({
|
|
74615
75049
|
onNone: () => set(lintFailure, {
|
|
74616
75050
|
didFail: true,
|
|
74617
75051
|
reason: `Lint analysis exceeded ${lintPhaseTimeoutMs / MILLISECONDS_PER_SECOND}s and was skipped.`,
|
|
@@ -74641,13 +75075,13 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74641
75075
|
} else {
|
|
74642
75076
|
yield* scanProgress.update(`Scanned ${scannedFilesLabel}, analyzing dead code...`);
|
|
74643
75077
|
const sequentialDeadCodeTimeout = resolveDeadCodeTimeout({
|
|
74644
|
-
sourceFileCount: totalFileCount,
|
|
75078
|
+
sourceFileCount: input.retainExcludedProjectDeadCodeDiagnostics === true ? deadCodeSourceFileCount : totalFileCount,
|
|
74645
75079
|
deadCodeConcurrency: scanConcurrency,
|
|
74646
75080
|
fullConcurrency: scanConcurrency
|
|
74647
75081
|
});
|
|
74648
75082
|
deadCodeCollected = deadCodeFiber !== null ? yield* join(deadCodeFiber) : yield* buildCollectDeadCode({
|
|
74649
75083
|
workerTimeoutMs: sequentialDeadCodeTimeout.workerTimeoutMs,
|
|
74650
|
-
phaseTimeoutMs:
|
|
75084
|
+
phaseTimeoutMs: capOptionalToDeadline(deadCodePhaseTimeoutMs)
|
|
74651
75085
|
});
|
|
74652
75086
|
}
|
|
74653
75087
|
const deadCodeFailureState = lintFailureState.didFail ? {
|
|
@@ -74691,7 +75125,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74691
75125
|
metadata: scoreMetadata
|
|
74692
75126
|
});
|
|
74693
75127
|
const lintPartialFailures = yield* get$2(partialFailuresRef);
|
|
74694
|
-
const
|
|
75128
|
+
const didSecurityScanFail = yield* get$2(securityScanFailedRef);
|
|
75129
|
+
const securityScanFailed = didSecurityScanFail || didSecurityScanReachDeadline;
|
|
75130
|
+
let securityScanFailureReason = null;
|
|
75131
|
+
if (didSecurityScanReachDeadline) securityScanFailureReason = "Security scan reached the max scan duration; findings collected before the deadline were preserved.";
|
|
75132
|
+
else if (didSecurityScanFail) securityScanFailureReason = "Security scan failed and was skipped.";
|
|
74695
75133
|
return {
|
|
74696
75134
|
project,
|
|
74697
75135
|
userConfig: resolvedConfig.config,
|
|
@@ -74714,6 +75152,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74714
75152
|
scanConcurrency,
|
|
74715
75153
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
74716
75154
|
securityScanFailed,
|
|
75155
|
+
securityScanFailureReason,
|
|
74717
75156
|
lintCacheHitFileCount,
|
|
74718
75157
|
lintCacheTotalFileCount,
|
|
74719
75158
|
lintSidecarReplayedFileCount,
|
|
@@ -74729,7 +75168,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74729
75168
|
"inspect.runDeadCode": input.runDeadCode,
|
|
74730
75169
|
"inspect.isCi": input.isCi,
|
|
74731
75170
|
"inspect.scoreSurface": input.scoreSurface ?? "score"
|
|
74732
|
-
} }), (scanProgram) => flatMap$2(ScanDeadlineMs, (scanDeadlineMs) =>
|
|
75171
|
+
} }), (scanProgram) => flatMap$2(ScanDeadlineMs, (scanDeadlineMs) => {
|
|
75172
|
+
if (scanDeadlineMs === null) return scanProgram;
|
|
75173
|
+
return scanProgram.pipe(timeout(scanDeadlineMs), catchTag$1("TimeoutError", () => new ReactDoctorError({ reason: new ScanDeadlineExceeded({ detail: `${scanDeadlineMs / MILLISECONDS_PER_SECOND}s elapsed` }) })));
|
|
75174
|
+
}));
|
|
74733
75175
|
const parseNodeVersion = (versionString) => {
|
|
74734
75176
|
const [major = 0, minor = 0, patch = 0] = versionString.replace(/^v/, "").trim().split(".").map(Number);
|
|
74735
75177
|
return {
|
|
@@ -74830,16 +75272,6 @@ const resolveNodeForOxlint = () => {
|
|
|
74830
75272
|
});
|
|
74831
75273
|
});
|
|
74832
75274
|
/**
|
|
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
75275
|
* Writes a set of source files (supplied by `readContent` — e.g.
|
|
74844
75276
|
* `git show <ref>:<path>` for a baseline tree, or `git show :<path>` for the
|
|
74845
75277
|
* index) into a temp tree that mirrors the project layout, copying the
|
|
@@ -74875,7 +75307,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
74875
75307
|
const sourcePath = path.join(input.directory, subdirectory, configFilename);
|
|
74876
75308
|
const targetPath = path.resolve(resolvedTempDirectory, subdirectory, configFilename);
|
|
74877
75309
|
if (!isPathInsideDirectory(targetPath, resolvedTempDirectory)) continue;
|
|
74878
|
-
if (
|
|
75310
|
+
if (isFile(sourcePath) && !fs.existsSync(targetPath)) {
|
|
74879
75311
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
74880
75312
|
fs.cpSync(sourcePath, targetPath);
|
|
74881
75313
|
}
|
|
@@ -75016,14 +75448,6 @@ const runEditorScan = async (input) => {
|
|
|
75016
75448
|
error: messageFromUnknown(error)
|
|
75017
75449
|
};
|
|
75018
75450
|
};
|
|
75019
|
-
/**
|
|
75020
|
-
* Back-compat alias: the streaming pipeline holds its caches in
|
|
75021
|
-
* per-pipeline closures that are garbage-collected when the pipeline
|
|
75022
|
-
* goes out of scope, so there is nothing to clear at module scope. The
|
|
75023
|
-
* public CLI's `clearCaches()` still calls this for symmetry with the
|
|
75024
|
-
* other `clear*` helpers.
|
|
75025
|
-
*/
|
|
75026
|
-
const clearAutoSuppressionCaches = () => {};
|
|
75027
75451
|
const lookupOwnRule = (rule) => Object.hasOwn(REACT_DOCTOR_RULE_REGISTRY, rule) ? REACT_DOCTOR_RULE_REGISTRY[rule] : void 0;
|
|
75028
75452
|
/**
|
|
75029
75453
|
* Returns presentation metadata for `<plugin>/<rule>`, or `null` when the
|
|
@@ -75063,7 +75487,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
75063
75487
|
/** Display name used in client-facing messages and progress titles. */
|
|
75064
75488
|
const SERVER_DISPLAY_NAME = "React Doctor";
|
|
75065
75489
|
/** Server version reported in `serverInfo`; injected at build, `dev` from source. */
|
|
75066
|
-
const SERVER_VERSION = "0.9.
|
|
75490
|
+
const SERVER_VERSION = "0.9.4";
|
|
75067
75491
|
/** `Diagnostic.source` shown next to every published diagnostic. */
|
|
75068
75492
|
const DIAGNOSTIC_SOURCE = "react-doctor";
|
|
75069
75493
|
/**
|
|
@@ -75691,10 +76115,7 @@ const createProjectGraph = (options) => {
|
|
|
75691
76115
|
for (const root of roots) try {
|
|
75692
76116
|
for (const workspacePackage of discoverReactSubprojects(root)) {
|
|
75693
76117
|
const directory = normalizeDirectory(workspacePackage.directory);
|
|
75694
|
-
if (!seen.has(directory)) seen.set(directory, {
|
|
75695
|
-
directory,
|
|
75696
|
-
name: workspacePackage.name
|
|
75697
|
-
});
|
|
76118
|
+
if (!seen.has(directory)) seen.set(directory, { directory });
|
|
75698
76119
|
}
|
|
75699
76120
|
} catch (error) {
|
|
75700
76121
|
logger.warn(`Project discovery failed for ${root}: ${messageFromUnknown(error)}`);
|
|
@@ -75719,8 +76140,8 @@ const createProjectGraph = (options) => {
|
|
|
75719
76140
|
clearProjectCache();
|
|
75720
76141
|
clearConfigCache();
|
|
75721
76142
|
clearPackageJsonCache();
|
|
76143
|
+
clearPackageRoleCache();
|
|
75722
76144
|
clearIgnorePatternsCache();
|
|
75723
|
-
clearAutoSuppressionCaches();
|
|
75724
76145
|
clearMinifiedFileCache();
|
|
75725
76146
|
projects = null;
|
|
75726
76147
|
}
|
|
@@ -76116,11 +76537,9 @@ const createScheduler = (options) => {
|
|
|
76116
76537
|
timers.clear();
|
|
76117
76538
|
queue.length = 0;
|
|
76118
76539
|
};
|
|
76119
|
-
const pendingCount = () => queue.length + running + timers.size;
|
|
76120
76540
|
return {
|
|
76121
76541
|
enqueue,
|
|
76122
76542
|
cancelProject,
|
|
76123
|
-
pendingCount,
|
|
76124
76543
|
dispose
|
|
76125
76544
|
};
|
|
76126
76545
|
};
|
|
@@ -76767,8 +77186,11 @@ const METRIC = {
|
|
|
76767
77186
|
scanPhaseDuration: "scan.phase_duration",
|
|
76768
77187
|
scanFiles: "scan.files",
|
|
76769
77188
|
scanScore: "scan.score",
|
|
77189
|
+
scanScoreRetry: "scan.score_retry",
|
|
76770
77190
|
scanClean: "scan.clean",
|
|
76771
77191
|
scanCheckSkipped: "scan.check_skipped",
|
|
77192
|
+
scanProjectSkipped: "scan.project_skipped",
|
|
77193
|
+
scanWorkspaceDeadCodeShared: "scan.workspace_deadcode_shared",
|
|
76772
77194
|
scanNoReactDetected: "scan.no_react_detected",
|
|
76773
77195
|
baselineDegraded: "baseline.degraded",
|
|
76774
77196
|
ruleFired: "rule.fired",
|
|
@@ -76795,9 +77217,14 @@ const METRIC = {
|
|
|
76795
77217
|
lspScanCompleted: "lsp.scan.completed",
|
|
76796
77218
|
lspScanDuration: "lsp.scan.duration",
|
|
76797
77219
|
lspScanDiagnostics: "lsp.scan.diagnostics",
|
|
76798
|
-
tuiActionMenuOpened: "tui.action_menu_opened",
|
|
76799
77220
|
tuiCompactReportShown: "tui.compact_report_shown",
|
|
76800
77221
|
tuiFindingNavigated: "tui.finding_navigated",
|
|
77222
|
+
tuiIssueStreamShown: "tui.issue_stream_shown",
|
|
77223
|
+
tuiProjectPathContextShown: "tui.project_path_context_shown",
|
|
77224
|
+
tuiProjectSelectInlineShown: "tui.project_select_inline_shown",
|
|
77225
|
+
tuiReportActionSelected: "tui.report_action_selected",
|
|
77226
|
+
tuiCancelled: "tui.cancelled",
|
|
77227
|
+
tuiScanInlineShown: "tui.scan_inline_shown",
|
|
76801
77228
|
tuiStackedReportCapped: "tui.stacked_report_capped",
|
|
76802
77229
|
aiTrainingWarningShown: "ai.training.warning_shown",
|
|
76803
77230
|
jsonOutUsed: "json.out_used"
|
|
@@ -76812,6 +77239,9 @@ const METRIC = {
|
|
|
76812
77239
|
*/
|
|
76813
77240
|
const toCategoryKey = (category) => category.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
76814
77241
|
//#endregion
|
|
77242
|
+
//#region src/cli/utils/is-env-flag-enabled.ts
|
|
77243
|
+
const isEnvFlagEnabled = (value) => value === "1" || value?.toLowerCase() === "true";
|
|
77244
|
+
//#endregion
|
|
76815
77245
|
//#region src/cli/utils/anonymize-text.ts
|
|
76816
77246
|
/**
|
|
76817
77247
|
* Free-text fields can carry both a home-directory path (the OS username) and a
|
|
@@ -76972,7 +77402,6 @@ const resolveTracesSampleRate = () => {
|
|
|
76972
77402
|
* session.
|
|
76973
77403
|
*/
|
|
76974
77404
|
let lspTracesSampleRate = 0;
|
|
76975
|
-
const isEnvFlagEnabled = (value) => value === "1" || value?.toLowerCase() === "true";
|
|
76976
77405
|
const nodeMajorVersion = () => Number.parseInt(process.versions.node.split(".", 1)[0] ?? "", 10) || 0;
|
|
76977
77406
|
const shouldEnableLspTelemetry = () => {
|
|
76978
77407
|
if (isEnvFlagEnabled(process.env.REACT_DOCTOR_NO_TELEMETRY)) return false;
|
|
@@ -77100,5 +77529,5 @@ const startLanguageServer = () => {
|
|
|
77100
77529
|
};
|
|
77101
77530
|
//#endregion
|
|
77102
77531
|
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=
|
|
77532
|
+
!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]="2d26cd21-f7f6-5e65-9c29-fabf32208583")}catch(e){}}();
|
|
77533
|
+
//# debugId=2d26cd21-f7f6-5e65-9c29-fabf32208583
|