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/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8d6e3c06-44f8-589f-8e07-aaa4704b6112")}catch(e){}}();
|
|
3
3
|
import { i as __toESM$1, r as __require, t as __commonJSMin$1 } from "./chunk-ChKA3wi6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, REACT_DOCTOR_RULE_REGISTRY, REACT_DOCTOR_SCAN_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor/core";
|
|
6
6
|
import * as Crypto from "node:crypto";
|
|
7
7
|
import crypto, { createHash } from "node:crypto";
|
|
8
|
-
import * as NFS from "node:fs";
|
|
9
|
-
import fs from "node:fs";
|
|
10
8
|
import * as Path from "node:path";
|
|
11
9
|
import path from "node:path";
|
|
10
|
+
import * as NFS from "node:fs";
|
|
11
|
+
import fs from "node:fs";
|
|
12
12
|
import * as NodeChildProcess from "node:child_process";
|
|
13
|
-
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
13
|
+
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
14
14
|
import { ResolverFactory } from "oxc-resolver";
|
|
15
15
|
import ts from "typescript";
|
|
16
16
|
import * as NodeUrl from "node:url";
|
|
@@ -3621,7 +3621,7 @@ const flatMap$5 = /* @__PURE__ */ dual(2, (self, f) => isNone(self) ? none() : f
|
|
|
3621
3621
|
* @category filtering
|
|
3622
3622
|
* @since 2.0.0
|
|
3623
3623
|
*/
|
|
3624
|
-
const filter = /* @__PURE__ */ dual(2, (self, predicate) => isNone(self) ? none() : predicate(self.value) ? some(self.value) : none());
|
|
3624
|
+
const filter$1 = /* @__PURE__ */ dual(2, (self, predicate) => isNone(self) ? none() : predicate(self.value) ? some(self.value) : none());
|
|
3625
3625
|
//#endregion
|
|
3626
3626
|
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.70/node_modules/effect/dist/Result.js
|
|
3627
3627
|
/**
|
|
@@ -15556,7 +15556,7 @@ function transformOptional(f) {
|
|
|
15556
15556
|
*/
|
|
15557
15557
|
function withDefault$1(defaultValue) {
|
|
15558
15558
|
return new Getter((o) => {
|
|
15559
|
-
const filtered = filter(o, isNotUndefined);
|
|
15559
|
+
const filtered = filter$1(o, isNotUndefined);
|
|
15560
15560
|
return isSome(filtered) ? succeed$2(filtered) : mapEager(defaultValue, some);
|
|
15561
15561
|
});
|
|
15562
15562
|
}
|
|
@@ -19404,6 +19404,10 @@ var JsonReportProjectEntryV3 = class extends Class("JsonReportProjectEntryV3")({
|
|
|
19404
19404
|
scannedFileCount: optional(Number$1),
|
|
19405
19405
|
elapsedMilliseconds: Number$1
|
|
19406
19406
|
}) {};
|
|
19407
|
+
var JsonReportSkippedProject = class extends Class("JsonReportSkippedProject")({
|
|
19408
|
+
directory: String$1,
|
|
19409
|
+
reason: Literal("max-duration")
|
|
19410
|
+
}) {};
|
|
19407
19411
|
/** Original full, diff, and staged report contract. */
|
|
19408
19412
|
var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
19409
19413
|
schemaVersion: Literal(1),
|
|
@@ -19432,6 +19436,7 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
19432
19436
|
reactDetected: optional(Boolean$1),
|
|
19433
19437
|
diff: NullOr(JsonReportDiffInfo),
|
|
19434
19438
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19439
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19435
19440
|
diagnostics: ArraySchema(Diagnostic),
|
|
19436
19441
|
summary: JsonReportSummary,
|
|
19437
19442
|
elapsedMilliseconds: Number$1,
|
|
@@ -19460,6 +19465,7 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
19460
19465
|
diff: NullOr(JsonReportDiffInfo),
|
|
19461
19466
|
baseline: JsonReportBaseline,
|
|
19462
19467
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19468
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19463
19469
|
diagnostics: ArraySchema(Diagnostic),
|
|
19464
19470
|
summary: JsonReportSummary,
|
|
19465
19471
|
elapsedMilliseconds: Number$1,
|
|
@@ -19476,6 +19482,7 @@ var JsonReportV3 = class extends Class("JsonReportV3")({
|
|
|
19476
19482
|
diff: NullOr(JsonReportDiffInfo),
|
|
19477
19483
|
baseline: optional(JsonReportBaseline),
|
|
19478
19484
|
projects: ArraySchema(JsonReportProjectEntryV3),
|
|
19485
|
+
skippedProjects: optional(ArraySchema(JsonReportSkippedProject)),
|
|
19479
19486
|
diagnostics: ArraySchema(JsonReportDiagnosticV3),
|
|
19480
19487
|
summary: JsonReportSummary,
|
|
19481
19488
|
elapsedMilliseconds: Number$1,
|
|
@@ -53458,6 +53465,47 @@ const flattenArray = (self) => transformPull$1(self, (pull) => {
|
|
|
53458
53465
|
}));
|
|
53459
53466
|
});
|
|
53460
53467
|
/**
|
|
53468
|
+
* Filters arrays of elements emitted by a channel, applying the filter
|
|
53469
|
+
* to each element within the arrays and only emitting non-empty filtered arrays.
|
|
53470
|
+
*
|
|
53471
|
+
* **Example** (Filtering array output)
|
|
53472
|
+
*
|
|
53473
|
+
* ```ts
|
|
53474
|
+
* import { Array, Channel } from "effect"
|
|
53475
|
+
*
|
|
53476
|
+
* const nonEmptyArrayPredicate = Array.isReadonlyArrayNonEmpty
|
|
53477
|
+
*
|
|
53478
|
+
* // Create a channel that outputs arrays of mixed data
|
|
53479
|
+
* const arrayChannel = Channel.fromIterable([
|
|
53480
|
+
* Array.make(1, 2, 3, 4, 5),
|
|
53481
|
+
* Array.make(6, 7, 8, 9, 10),
|
|
53482
|
+
* Array.make(11, 12, 13, 14, 15)
|
|
53483
|
+
* ]).pipe(Channel.filter(nonEmptyArrayPredicate))
|
|
53484
|
+
*
|
|
53485
|
+
* // Filter arrays to keep only even numbers
|
|
53486
|
+
* const evenArraysChannel = Channel.filterArray(arrayChannel, (n) => n % 2 === 0)
|
|
53487
|
+
* // Outputs: [2, 4], [6, 8, 10], [12, 14]
|
|
53488
|
+
* // Note: Only non-empty filtered arrays are emitted
|
|
53489
|
+
*
|
|
53490
|
+
* // Arrays that would become empty after filtering are discarded entirely
|
|
53491
|
+
* const oddChannel = Channel.fromIterable([
|
|
53492
|
+
* Array.make(1, 3, 5),
|
|
53493
|
+
* Array.make(2, 4),
|
|
53494
|
+
* Array.make(7, 9)
|
|
53495
|
+
* ]).pipe(Channel.filter(nonEmptyArrayPredicate))
|
|
53496
|
+
* const filteredOddChannel = Channel.filterArray(oddChannel, (n) => n % 2 === 0)
|
|
53497
|
+
* // Outputs: [2, 4] (the arrays [1,3,5] and [7,9] are discarded)
|
|
53498
|
+
* ```
|
|
53499
|
+
*
|
|
53500
|
+
* @category filtering
|
|
53501
|
+
* @since 4.0.0
|
|
53502
|
+
*/
|
|
53503
|
+
const filterArray = /* @__PURE__ */ dual(2, (self, predicate) => transformPull$1(self, (pull) => succeed$2(flatMap$2(pull, function loop(arr) {
|
|
53504
|
+
const passes = [];
|
|
53505
|
+
for (let i = 0; i < arr.length; i++) if (predicate(arr[i])) passes.push(arr[i]);
|
|
53506
|
+
return isReadonlyArrayNonEmpty(passes) ? succeed$2(passes) : flatMap$2(pull, loop);
|
|
53507
|
+
}))));
|
|
53508
|
+
/**
|
|
53461
53509
|
* Filters and maps each element inside emitted non-empty arrays using a
|
|
53462
53510
|
* `Filter`.
|
|
53463
53511
|
*
|
|
@@ -55095,6 +55143,30 @@ const concat = /* @__PURE__ */ dual(2, (self, that) => flatten(fromArray([self,
|
|
|
55095
55143
|
*/
|
|
55096
55144
|
const merge$1 = /* @__PURE__ */ dual((args) => isStream(args[0]) && isStream(args[1]), (self, that, options) => fromChannel(merge$2(toChannel(self), toChannel(that), options)));
|
|
55097
55145
|
/**
|
|
55146
|
+
* Filters a stream to the elements that satisfy a predicate.
|
|
55147
|
+
*
|
|
55148
|
+
* **Example** (Filtering stream values)
|
|
55149
|
+
*
|
|
55150
|
+
* ```ts
|
|
55151
|
+
* import { Console, Effect, Stream } from "effect"
|
|
55152
|
+
*
|
|
55153
|
+
* const program = Effect.gen(function*() {
|
|
55154
|
+
* const stream = Stream.make(1, 2, 3, 4).pipe(
|
|
55155
|
+
* Stream.filter((n) => n % 2 === 0)
|
|
55156
|
+
* )
|
|
55157
|
+
* const values = yield* Stream.runCollect(stream)
|
|
55158
|
+
* yield* Console.log(values)
|
|
55159
|
+
* })
|
|
55160
|
+
*
|
|
55161
|
+
* Effect.runPromise(program)
|
|
55162
|
+
* // Output: [ 2, 4 ]
|
|
55163
|
+
* ```
|
|
55164
|
+
*
|
|
55165
|
+
* @category filtering
|
|
55166
|
+
* @since 2.0.0
|
|
55167
|
+
*/
|
|
55168
|
+
const filter = /* @__PURE__ */ dual(2, (self, predicate) => fromChannel(filterArray(toChannel(self), predicate)));
|
|
55169
|
+
/**
|
|
55098
55170
|
* Filters and maps stream elements in one pass using a `Filter`.
|
|
55099
55171
|
*
|
|
55100
55172
|
* @category filtering
|
|
@@ -61878,6 +61950,7 @@ const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
|
61878
61950
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
61879
61951
|
const MINIFIED_SNIFF_BYTES = 65536;
|
|
61880
61952
|
const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
61953
|
+
const GIT_CHECK_ATTR_MAX_BUFFER_BYTES = GIT_LS_FILES_MAX_BUFFER_BYTES;
|
|
61881
61954
|
const SCANNED_DOT_DIRECTORIES = new Set([".dumi", ".storybook"]);
|
|
61882
61955
|
const IGNORED_DIRECTORIES = new Set([
|
|
61883
61956
|
".angular",
|
|
@@ -62163,13 +62236,9 @@ const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
|
|
|
62163
62236
|
const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
|
|
62164
62237
|
const ABORT_EXIT_CODES = new Set([134, 3221226505]);
|
|
62165
62238
|
const OXLINT_OOM_RESCUE_BUDGET_MS = 6e4;
|
|
62166
|
-
const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
62167
|
-
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
62168
|
-
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
62169
62239
|
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
62170
62240
|
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
62171
62241
|
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
62172
|
-
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
62173
62242
|
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
62174
62243
|
const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
|
|
62175
62244
|
const REACT_SERVER_DOM_PACKAGES = [
|
|
@@ -62216,7 +62285,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
62216
62285
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
62217
62286
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
62218
62287
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
62219
|
-
const CORE_PACKAGE_VERSION = "0.9.
|
|
62288
|
+
const CORE_PACKAGE_VERSION = "0.9.4";
|
|
62220
62289
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
62221
62290
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
62222
62291
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -62229,17 +62298,20 @@ const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
|
62229
62298
|
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
62230
62299
|
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
62231
62300
|
"EACCES",
|
|
62301
|
+
"EBUSY",
|
|
62232
62302
|
"EPERM",
|
|
62233
62303
|
"ENOENT",
|
|
62234
62304
|
"ENOTDIR",
|
|
62235
62305
|
"EINVAL",
|
|
62236
62306
|
"ELOOP",
|
|
62237
|
-
"ENAMETOOLONG"
|
|
62307
|
+
"ENAMETOOLONG",
|
|
62308
|
+
"ETIMEDOUT",
|
|
62309
|
+
"UNKNOWN"
|
|
62238
62310
|
]);
|
|
62239
62311
|
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
62240
62312
|
const readDirectoryEntries = (directoryPath) => {
|
|
62241
62313
|
try {
|
|
62242
|
-
return
|
|
62314
|
+
return fs.readdirSync(directoryPath, { withFileTypes: true });
|
|
62243
62315
|
} catch (error) {
|
|
62244
62316
|
if (isIgnorableReaddirError(error)) return [];
|
|
62245
62317
|
throw error;
|
|
@@ -62247,14 +62319,14 @@ const readDirectoryEntries = (directoryPath) => {
|
|
|
62247
62319
|
};
|
|
62248
62320
|
const isFile = (filePath) => {
|
|
62249
62321
|
try {
|
|
62250
|
-
return
|
|
62322
|
+
return fs.statSync(filePath).isFile();
|
|
62251
62323
|
} catch {
|
|
62252
62324
|
return false;
|
|
62253
62325
|
}
|
|
62254
62326
|
};
|
|
62255
62327
|
const isDirectory = (directoryPath) => {
|
|
62256
62328
|
try {
|
|
62257
|
-
return
|
|
62329
|
+
return fs.statSync(directoryPath).isDirectory();
|
|
62258
62330
|
} catch {
|
|
62259
62331
|
return false;
|
|
62260
62332
|
}
|
|
@@ -62264,6 +62336,66 @@ const isPlainObject = (value) => {
|
|
|
62264
62336
|
const prototype = Object.getPrototypeOf(value);
|
|
62265
62337
|
return prototype === null || prototype === Object.prototype;
|
|
62266
62338
|
};
|
|
62339
|
+
const LINGUIST_ATTRIBUTES = ["linguist-generated", "linguist-vendored"];
|
|
62340
|
+
const DISABLED_ATTRIBUTE_VALUES = new Set([
|
|
62341
|
+
"unspecified",
|
|
62342
|
+
"unset",
|
|
62343
|
+
"false",
|
|
62344
|
+
"0",
|
|
62345
|
+
"off",
|
|
62346
|
+
"no"
|
|
62347
|
+
]);
|
|
62348
|
+
const buildInput = (relativePaths) => `${relativePaths.join("\0")}\0`;
|
|
62349
|
+
const parseIgnoredPaths = (output) => {
|
|
62350
|
+
const ignoredPaths = /* @__PURE__ */ new Set();
|
|
62351
|
+
const fields = output.split("\0");
|
|
62352
|
+
for (let fieldIndex = 0; fieldIndex + 2 < fields.length; fieldIndex += 3) {
|
|
62353
|
+
const filePath = fields[fieldIndex];
|
|
62354
|
+
const value = fields[fieldIndex + 2]?.toLowerCase();
|
|
62355
|
+
if (filePath && value && !DISABLED_ATTRIBUTE_VALUES.has(value)) ignoredPaths.add(filePath);
|
|
62356
|
+
}
|
|
62357
|
+
return ignoredPaths;
|
|
62358
|
+
};
|
|
62359
|
+
const collectGitLinguistIgnoredPaths = (rootDirectory, relativePaths) => {
|
|
62360
|
+
if (relativePaths.length === 0) return /* @__PURE__ */ new Set();
|
|
62361
|
+
const result = spawnSync("git", [
|
|
62362
|
+
"check-attr",
|
|
62363
|
+
"-z",
|
|
62364
|
+
"--stdin",
|
|
62365
|
+
...LINGUIST_ATTRIBUTES
|
|
62366
|
+
], {
|
|
62367
|
+
cwd: rootDirectory,
|
|
62368
|
+
encoding: "utf-8",
|
|
62369
|
+
input: buildInput(relativePaths),
|
|
62370
|
+
maxBuffer: GIT_CHECK_ATTR_MAX_BUFFER_BYTES
|
|
62371
|
+
});
|
|
62372
|
+
if (result.error || result.status !== 0) return /* @__PURE__ */ new Set();
|
|
62373
|
+
return parseIgnoredPaths(result.stdout);
|
|
62374
|
+
};
|
|
62375
|
+
const collectGitLinguistIgnoredPathsCooperative = (rootDirectory, relativePaths, signal) => {
|
|
62376
|
+
if (relativePaths.length === 0) return Promise.resolve(/* @__PURE__ */ new Set());
|
|
62377
|
+
return new Promise((resolve, reject) => {
|
|
62378
|
+
signal?.throwIfAborted();
|
|
62379
|
+
execFile("git", [
|
|
62380
|
+
"check-attr",
|
|
62381
|
+
"-z",
|
|
62382
|
+
"--stdin",
|
|
62383
|
+
...LINGUIST_ATTRIBUTES
|
|
62384
|
+
], {
|
|
62385
|
+
cwd: rootDirectory,
|
|
62386
|
+
encoding: "utf-8",
|
|
62387
|
+
killSignal: "SIGKILL",
|
|
62388
|
+
maxBuffer: GIT_CHECK_ATTR_MAX_BUFFER_BYTES,
|
|
62389
|
+
signal
|
|
62390
|
+
}, (error, stdout) => {
|
|
62391
|
+
if (signal?.aborted) {
|
|
62392
|
+
reject(signal.reason);
|
|
62393
|
+
return;
|
|
62394
|
+
}
|
|
62395
|
+
resolve(error ? /* @__PURE__ */ new Set() : parseIgnoredPaths(stdout));
|
|
62396
|
+
}).stdin?.end(buildInput(relativePaths));
|
|
62397
|
+
});
|
|
62398
|
+
};
|
|
62267
62399
|
const lastSourceMappingUrl = (fileContent) => {
|
|
62268
62400
|
const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
|
|
62269
62401
|
return lastReference ? lastReference[1] : null;
|
|
@@ -62368,6 +62500,9 @@ function* walkSourceTreeFiles(rootDirectory) {
|
|
|
62368
62500
|
}
|
|
62369
62501
|
}
|
|
62370
62502
|
}
|
|
62503
|
+
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
62504
|
+
setImmediate(resolve);
|
|
62505
|
+
});
|
|
62371
62506
|
const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
62372
62507
|
const entries = [];
|
|
62373
62508
|
for (const relativePath of relativePaths) {
|
|
@@ -62381,23 +62516,55 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
|
62381
62516
|
}
|
|
62382
62517
|
return entries;
|
|
62383
62518
|
};
|
|
62384
|
-
const
|
|
62519
|
+
const collectSizedSourceFilesCooperative = async (rootDirectory, relativePaths, signal) => {
|
|
62520
|
+
const entries = [];
|
|
62521
|
+
let sliceStartedAt = performance.now();
|
|
62522
|
+
for (const relativePath of relativePaths) {
|
|
62523
|
+
signal?.throwIfAborted();
|
|
62524
|
+
const absolutePath = Path.resolve(rootDirectory, relativePath);
|
|
62525
|
+
const sizeBytes = statSourceFileSize(absolutePath);
|
|
62526
|
+
if (!isLargeMinifiedFile(absolutePath, sizeBytes)) entries.push({
|
|
62527
|
+
path: relativePath,
|
|
62528
|
+
sizeBytes: sizeBytes ?? 0
|
|
62529
|
+
});
|
|
62530
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
62531
|
+
await yieldToEventLoop();
|
|
62532
|
+
sliceStartedAt = performance.now();
|
|
62533
|
+
}
|
|
62534
|
+
}
|
|
62535
|
+
return entries;
|
|
62536
|
+
};
|
|
62537
|
+
const parseGitSourceFilePaths = (output) => {
|
|
62538
|
+
const trackedPaths = /* @__PURE__ */ new Set();
|
|
62539
|
+
const untrackedPaths = [];
|
|
62540
|
+
for (const entry of output.split("\0")) {
|
|
62541
|
+
if (entry.length === 0) continue;
|
|
62542
|
+
const trackedPath = /^[0-7]{6} [0-9a-f]+ [0-3]\t([\s\S]+)$/.exec(entry)?.[1];
|
|
62543
|
+
if (trackedPath === void 0) untrackedPaths.push(entry);
|
|
62544
|
+
else trackedPaths.add(trackedPath);
|
|
62545
|
+
}
|
|
62546
|
+
return {
|
|
62547
|
+
trackedPaths: [...trackedPaths],
|
|
62548
|
+
untrackedPaths
|
|
62549
|
+
};
|
|
62550
|
+
};
|
|
62551
|
+
const listGitSourceFilePaths = (rootDirectory) => {
|
|
62385
62552
|
const result = spawnSync("git", [
|
|
62386
62553
|
"ls-files",
|
|
62387
62554
|
"-z",
|
|
62388
|
-
|
|
62555
|
+
"--stage",
|
|
62556
|
+
"--others",
|
|
62557
|
+
"--exclude-standard"
|
|
62389
62558
|
], {
|
|
62390
62559
|
cwd: rootDirectory,
|
|
62391
62560
|
encoding: "utf-8",
|
|
62392
62561
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
62393
62562
|
});
|
|
62394
62563
|
if (result.error || result.status !== 0) return null;
|
|
62395
|
-
return result.stdout
|
|
62564
|
+
return parseGitSourceFilePaths(result.stdout);
|
|
62396
62565
|
};
|
|
62397
|
-
const
|
|
62398
|
-
const trackedPaths =
|
|
62399
|
-
const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
|
|
62400
|
-
if (trackedPaths === null || untrackedPaths === null) return null;
|
|
62566
|
+
const collectGitCandidateSourceFilePaths = (rootDirectory, paths) => {
|
|
62567
|
+
const { trackedPaths, untrackedPaths } = paths;
|
|
62401
62568
|
const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
|
|
62402
62569
|
trackedPaths: new Set(trackedPaths),
|
|
62403
62570
|
untrackedPaths,
|
|
@@ -62405,12 +62572,65 @@ const listSourceFilesViaGit = (rootDirectory) => {
|
|
|
62405
62572
|
});
|
|
62406
62573
|
return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
|
|
62407
62574
|
};
|
|
62575
|
+
const filterGitSourceFilePaths = (rootDirectory, paths) => {
|
|
62576
|
+
const candidatePaths = collectGitCandidateSourceFilePaths(rootDirectory, paths);
|
|
62577
|
+
const linguistIgnoredPaths = collectGitLinguistIgnoredPaths(rootDirectory, candidatePaths);
|
|
62578
|
+
return candidatePaths.filter((filePath) => !linguistIgnoredPaths.has(filePath));
|
|
62579
|
+
};
|
|
62580
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
62581
|
+
const paths = listGitSourceFilePaths(rootDirectory);
|
|
62582
|
+
return paths === null ? null : filterGitSourceFilePaths(rootDirectory, paths);
|
|
62583
|
+
};
|
|
62584
|
+
const listSourceFilesViaGitCooperative = async (rootDirectory, signal) => {
|
|
62585
|
+
const paths = await new Promise((resolve, reject) => {
|
|
62586
|
+
signal?.throwIfAborted();
|
|
62587
|
+
execFile("git", [
|
|
62588
|
+
"ls-files",
|
|
62589
|
+
"-z",
|
|
62590
|
+
"--stage",
|
|
62591
|
+
"--others",
|
|
62592
|
+
"--exclude-standard"
|
|
62593
|
+
], {
|
|
62594
|
+
cwd: rootDirectory,
|
|
62595
|
+
encoding: "utf-8",
|
|
62596
|
+
killSignal: "SIGKILL",
|
|
62597
|
+
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,
|
|
62598
|
+
signal
|
|
62599
|
+
}, (error, stdout) => {
|
|
62600
|
+
if (signal?.aborted) {
|
|
62601
|
+
reject(signal.reason);
|
|
62602
|
+
return;
|
|
62603
|
+
}
|
|
62604
|
+
resolve(error ? null : parseGitSourceFilePaths(stdout));
|
|
62605
|
+
});
|
|
62606
|
+
});
|
|
62607
|
+
if (paths === null) return null;
|
|
62608
|
+
const candidatePaths = collectGitCandidateSourceFilePaths(rootDirectory, paths);
|
|
62609
|
+
const linguistIgnoredPaths = await collectGitLinguistIgnoredPathsCooperative(rootDirectory, candidatePaths, signal);
|
|
62610
|
+
return candidatePaths.filter((filePath) => !linguistIgnoredPaths.has(filePath));
|
|
62611
|
+
};
|
|
62408
62612
|
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
62409
62613
|
const filePaths = [];
|
|
62410
62614
|
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
62411
62615
|
return filePaths;
|
|
62412
62616
|
};
|
|
62413
|
-
const
|
|
62617
|
+
const listSourceFilesViaFilesystemCooperative = async (rootDirectory, signal) => {
|
|
62618
|
+
const filePaths = [];
|
|
62619
|
+
let sliceStartedAt = performance.now();
|
|
62620
|
+
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
62621
|
+
signal?.throwIfAborted();
|
|
62622
|
+
if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
62623
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
62624
|
+
await yieldToEventLoop();
|
|
62625
|
+
sliceStartedAt = performance.now();
|
|
62626
|
+
}
|
|
62627
|
+
}
|
|
62628
|
+
return filePaths;
|
|
62629
|
+
};
|
|
62630
|
+
const listSourceFilePaths = (rootDirectory) => (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort();
|
|
62631
|
+
const listSourceFilePathsCooperative = async (rootDirectory, signal) => (await listSourceFilesViaGitCooperative(rootDirectory, signal) ?? await listSourceFilesViaFilesystemCooperative(rootDirectory, signal)).sort();
|
|
62632
|
+
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, listSourceFilePaths(rootDirectory));
|
|
62633
|
+
const listSourceFilesCooperative = async (rootDirectory, signal) => (await collectSizedSourceFilesCooperative(rootDirectory, await listSourceFilePathsCooperative(rootDirectory, signal), signal)).map((entry) => entry.path);
|
|
62414
62634
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
62415
62635
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
62416
62636
|
const UTF8_BOM_CHARACTER = "";
|
|
@@ -62536,7 +62756,12 @@ const mergeCompilerOptions = (inherited, current) => {
|
|
|
62536
62756
|
};
|
|
62537
62757
|
};
|
|
62538
62758
|
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
62539
|
-
|
|
62759
|
+
let realPath;
|
|
62760
|
+
try {
|
|
62761
|
+
realPath = NFS.realpathSync.native(tsConfigPath);
|
|
62762
|
+
} catch {
|
|
62763
|
+
return null;
|
|
62764
|
+
}
|
|
62540
62765
|
if (visitedPaths.has(realPath)) return null;
|
|
62541
62766
|
const tsConfig = readTsConfig(realPath);
|
|
62542
62767
|
if (!tsConfig) return null;
|
|
@@ -63064,27 +63289,30 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
|
|
|
63064
63289
|
}
|
|
63065
63290
|
return null;
|
|
63066
63291
|
};
|
|
63067
|
-
const configExpressionMayDefineProperty = (expression, propertyName, analysis) => {
|
|
63292
|
+
const configExpressionMayDefineProperty = (expression, propertyName, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
|
|
63068
63293
|
let resolvedExpression = expression;
|
|
63069
63294
|
while (ts.isParenthesizedExpression(resolvedExpression) || ts.isAsExpression(resolvedExpression) || ts.isTypeAssertionExpression(resolvedExpression) || ts.isSatisfiesExpression(resolvedExpression) || ts.isNonNullExpression(resolvedExpression)) resolvedExpression = resolvedExpression.expression;
|
|
63295
|
+
if (visitedExpressions.has(resolvedExpression)) return true;
|
|
63296
|
+
const nextVisitedExpressions = new Set(visitedExpressions);
|
|
63297
|
+
nextVisitedExpressions.add(resolvedExpression);
|
|
63070
63298
|
if (ts.isIdentifier(resolvedExpression)) {
|
|
63071
63299
|
if (analysis.localBindings.has(resolvedExpression.text)) {
|
|
63072
63300
|
const localReference = analysis.localBindings.get(resolvedExpression.text);
|
|
63073
|
-
return localReference?.expression ? configExpressionMayDefineProperty(localReference.expression, propertyName, localReference.analysis) : true;
|
|
63301
|
+
return localReference?.expression ? configExpressionMayDefineProperty(localReference.expression, propertyName, localReference.analysis, nextVisitedExpressions) : true;
|
|
63074
63302
|
}
|
|
63075
63303
|
const scopedBinding = getScopedConfigBinding(resolvedExpression);
|
|
63076
|
-
if (scopedBinding.wasFound) return scopedBinding.initializer ? configExpressionMayDefineProperty(scopedBinding.initializer, propertyName, analysis) : true;
|
|
63304
|
+
if (scopedBinding.wasFound) return scopedBinding.initializer ? configExpressionMayDefineProperty(scopedBinding.initializer, propertyName, analysis, nextVisitedExpressions) : true;
|
|
63077
63305
|
const topLevelBinding = getTopLevelBinding(analysis.sourceFile, resolvedExpression.text);
|
|
63078
|
-
return topLevelBinding && ts.isExpression(topLevelBinding) ? configExpressionMayDefineProperty(topLevelBinding, propertyName, analysis) : true;
|
|
63306
|
+
return topLevelBinding && ts.isExpression(topLevelBinding) ? configExpressionMayDefineProperty(topLevelBinding, propertyName, analysis, nextVisitedExpressions) : true;
|
|
63079
63307
|
}
|
|
63080
63308
|
if (ts.isConditionalExpression(resolvedExpression)) {
|
|
63081
|
-
if (isStaticallyTruthyConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis);
|
|
63082
|
-
if (isStaticallyDisabledConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis);
|
|
63083
|
-
return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis) || configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis);
|
|
63309
|
+
if (isStaticallyTruthyConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis, nextVisitedExpressions);
|
|
63310
|
+
if (isStaticallyDisabledConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis, nextVisitedExpressions);
|
|
63311
|
+
return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis, nextVisitedExpressions) || configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis, nextVisitedExpressions);
|
|
63084
63312
|
}
|
|
63085
63313
|
if (!ts.isObjectLiteralExpression(resolvedExpression)) return true;
|
|
63086
63314
|
return resolvedExpression.properties.some((property) => {
|
|
63087
|
-
if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
|
|
63315
|
+
if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis, nextVisitedExpressions);
|
|
63088
63316
|
if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
|
|
63089
63317
|
const staticPropertyName = getStaticPropertyName$2(property.name);
|
|
63090
63318
|
return staticPropertyName === null || staticPropertyName === propertyName;
|
|
@@ -63160,7 +63388,13 @@ const analyzeConfigModuleExport = (filePath, exportName, allowCompilerTransform,
|
|
|
63160
63388
|
if (visitedModules.has(moduleVisitKey)) return false;
|
|
63161
63389
|
const nextVisitedModules = new Set(visitedModules);
|
|
63162
63390
|
nextVisitedModules.add(moduleVisitKey);
|
|
63163
|
-
|
|
63391
|
+
let sourceText;
|
|
63392
|
+
try {
|
|
63393
|
+
sourceText = NFS.readFileSync(filePath, "utf-8");
|
|
63394
|
+
} catch {
|
|
63395
|
+
return false;
|
|
63396
|
+
}
|
|
63397
|
+
return analyzeConfigSourceFileExport(parseConfigSourceFile(filePath, sourceText), filePath, exportName, allowCompilerTransform, importDepth, nextVisitedModules, argumentsList, argumentAnalysis);
|
|
63164
63398
|
};
|
|
63165
63399
|
const analyzeConfigSourceFileExport = (sourceFile, filePath, exportName, allowCompilerTransform, importDepth, visitedModules, argumentsList = [], argumentAnalysis) => {
|
|
63166
63400
|
const analysis = {
|
|
@@ -63988,13 +64222,7 @@ const hasReactDependency = (packageJson) => {
|
|
|
63988
64222
|
};
|
|
63989
64223
|
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
63990
64224
|
};
|
|
63991
|
-
const getPreactVersion = (packageJson) =>
|
|
63992
|
-
return {
|
|
63993
|
-
...packageJson.peerDependencies,
|
|
63994
|
-
...packageJson.dependencies,
|
|
63995
|
-
...packageJson.devDependencies
|
|
63996
|
-
}.preact ?? null;
|
|
63997
|
-
};
|
|
64225
|
+
const getPreactVersion = (packageJson) => getDependencySpec(packageJson, "preact");
|
|
63998
64226
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, sourceDirectory = rootDirectory, sourcePackageJson = rootPackageJson, version }) => {
|
|
63999
64227
|
if (version === null || !isCatalogReference(version)) return version;
|
|
64000
64228
|
const catalogName = extractCatalogName(version);
|
|
@@ -64739,7 +64967,16 @@ const getBrowserslistProtectionRequirement = (directory) => {
|
|
|
64739
64967
|
if (!queries) return void 0;
|
|
64740
64968
|
let requirement;
|
|
64741
64969
|
let hasUnsupportedTarget = false;
|
|
64742
|
-
|
|
64970
|
+
const previousIgnoreOldData = process.env.BROWSERSLIST_IGNORE_OLD_DATA;
|
|
64971
|
+
let browserTargets = [];
|
|
64972
|
+
try {
|
|
64973
|
+
process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true";
|
|
64974
|
+
browserTargets = (0, import_browserslist.default)(queries);
|
|
64975
|
+
} finally {
|
|
64976
|
+
if (previousIgnoreOldData === void 0) delete process.env.BROWSERSLIST_IGNORE_OLD_DATA;
|
|
64977
|
+
else process.env.BROWSERSLIST_IGNORE_OLD_DATA = previousIgnoreOldData;
|
|
64978
|
+
}
|
|
64979
|
+
for (const browserTarget of browserTargets) {
|
|
64743
64980
|
const browserRequirement = getBrowserProtectionRequirement(browserTarget);
|
|
64744
64981
|
if (browserRequirement === "unsupported") hasUnsupportedTarget = true;
|
|
64745
64982
|
if (browserRequirement === "noreferrer") requirement = "noreferrer";
|
|
@@ -64849,9 +65086,9 @@ const clearProjectCache = () => {
|
|
|
64849
65086
|
* framework-agnostic rules. Throws only when the directory has nothing
|
|
64850
65087
|
* to scan (no enclosing project and no source files of its own).
|
|
64851
65088
|
*/
|
|
64852
|
-
const discoverProjectWithoutPackageJson = (directory) => {
|
|
64853
|
-
const sourceFileCount = countSourceFiles(directory);
|
|
64854
|
-
const hasOwnTsConfig =
|
|
65089
|
+
const discoverProjectWithoutPackageJson = (directory, options) => {
|
|
65090
|
+
const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
|
|
65091
|
+
const hasOwnTsConfig = isFile(Path.join(directory, "tsconfig.json"));
|
|
64855
65092
|
const enclosingProjectRoot = findNearestAncestorPackageJson(directory);
|
|
64856
65093
|
const enclosingProject = enclosingProjectRoot !== null ? discoverProject(enclosingProjectRoot) : null;
|
|
64857
65094
|
if (enclosingProject !== null) return {
|
|
@@ -64917,12 +65154,15 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
64917
65154
|
sourceFileCount
|
|
64918
65155
|
};
|
|
64919
65156
|
};
|
|
64920
|
-
const discoverProject = (directory) => {
|
|
65157
|
+
const discoverProject = (directory, options = {}) => {
|
|
64921
65158
|
const cached = cachedProjectInfos.get(directory);
|
|
64922
|
-
if (cached !== void 0) return cached
|
|
65159
|
+
if (cached !== void 0) return options.sourceFileCount === void 0 ? cached : {
|
|
65160
|
+
...cached,
|
|
65161
|
+
sourceFileCount: options.sourceFileCount
|
|
65162
|
+
};
|
|
64923
65163
|
const packageJsonPath = Path.join(directory, "package.json");
|
|
64924
65164
|
if (!isFile(packageJsonPath)) {
|
|
64925
|
-
const synthesized = discoverProjectWithoutPackageJson(directory);
|
|
65165
|
+
const synthesized = discoverProjectWithoutPackageJson(directory, options);
|
|
64926
65166
|
cachedProjectInfos.set(directory, synthesized);
|
|
64927
65167
|
return synthesized;
|
|
64928
65168
|
}
|
|
@@ -64984,8 +65224,8 @@ const discoverProject = (directory) => {
|
|
|
64984
65224
|
const tailwindVersion = tailwindcss.version;
|
|
64985
65225
|
const zodVersion = zod.version;
|
|
64986
65226
|
const projectName = packageJson.name ?? Path.basename(directory);
|
|
64987
|
-
const hasTypeScript =
|
|
64988
|
-
const sourceFileCount = countSourceFiles(directory);
|
|
65227
|
+
const hasTypeScript = isFile(Path.join(directory, "tsconfig.json"));
|
|
65228
|
+
const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
|
|
64989
65229
|
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
|
|
64990
65230
|
const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
64991
65231
|
rootDirectory: directory,
|
|
@@ -65114,134 +65354,6 @@ const discoverProject = (directory) => {
|
|
|
65114
65354
|
* single source file has nothing to analyze.
|
|
65115
65355
|
*/
|
|
65116
65356
|
const isAnalyzableProject = (project) => project.reactVersion !== null || project.preactVersion !== null || project.sourceFileCount > 0;
|
|
65117
|
-
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
65118
|
-
var InvalidGlobPatternError = class extends Error {
|
|
65119
|
-
pattern;
|
|
65120
|
-
reason;
|
|
65121
|
-
constructor(pattern, reason) {
|
|
65122
|
-
super(`Invalid glob pattern ${JSON.stringify(pattern)}: ${reason}`);
|
|
65123
|
-
this.name = "InvalidGlobPatternError";
|
|
65124
|
-
this.pattern = pattern;
|
|
65125
|
-
this.reason = reason;
|
|
65126
|
-
}
|
|
65127
|
-
};
|
|
65128
|
-
const assertGlobPattern = (condition, pattern, reason) => {
|
|
65129
|
-
if (!condition) throw new InvalidGlobPatternError(pattern, reason);
|
|
65130
|
-
};
|
|
65131
|
-
const countGlobWildcards = (pattern) => (pattern.match(/[*?]/g) ?? []).length;
|
|
65132
|
-
const normalizeGlobPattern = (pattern) => pattern.replace(/\\/g, "/").replace(/^\//, "");
|
|
65133
|
-
const PICOMATCH_OPTIONS = {
|
|
65134
|
-
dot: true,
|
|
65135
|
-
strictSlashes: false,
|
|
65136
|
-
windows: false
|
|
65137
|
-
};
|
|
65138
|
-
const compileGlobPattern = (rawPattern) => {
|
|
65139
|
-
assertGlobPattern(typeof rawPattern === "string" && rawPattern.length > 0, String(rawPattern), "pattern must be a non-empty string.");
|
|
65140
|
-
assertGlobPattern(rawPattern.length <= MAX_GLOB_PATTERN_LENGTH_CHARS, rawPattern, `pattern length ${rawPattern.length} exceeds the maximum of ${MAX_GLOB_PATTERN_LENGTH_CHARS} characters.`);
|
|
65141
|
-
const wildcardCount = countGlobWildcards(rawPattern);
|
|
65142
|
-
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.`);
|
|
65143
|
-
try {
|
|
65144
|
-
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
65145
|
-
} catch (caughtError) {
|
|
65146
|
-
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
65147
|
-
}
|
|
65148
|
-
};
|
|
65149
|
-
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
65150
|
-
const compiled = [];
|
|
65151
|
-
for (const pattern of patterns) try {
|
|
65152
|
-
compiled.push(compileGlobPattern(pattern));
|
|
65153
|
-
} catch (caughtError) {
|
|
65154
|
-
if (!(caughtError instanceof InvalidGlobPatternError)) throw caughtError;
|
|
65155
|
-
onInvalid(caughtError);
|
|
65156
|
-
}
|
|
65157
|
-
return compiled;
|
|
65158
|
-
};
|
|
65159
|
-
const toRelativePath = (filePath, rootDirectory) => {
|
|
65160
|
-
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
65161
|
-
const normalizedRoot = rootDirectory.replace(/\\/g, "/").replace(/\/$/, "") + "/";
|
|
65162
|
-
if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
|
|
65163
|
-
return normalizedFilePath.replace(/^\.\//, "");
|
|
65164
|
-
};
|
|
65165
|
-
const warnConfigIssue = (message) => {
|
|
65166
|
-
process.stderr.write(`[react-doctor] ${message}\n`);
|
|
65167
|
-
};
|
|
65168
|
-
const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
65169
|
-
const collectStringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
65170
|
-
const validateOverrideEntry = (entry, index) => {
|
|
65171
|
-
if (!isPlainObject(entry)) {
|
|
65172
|
-
warnConfigIssue(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
|
|
65173
|
-
return null;
|
|
65174
|
-
}
|
|
65175
|
-
if (!isStringArray(entry.files)) {
|
|
65176
|
-
warnConfigIssue(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
|
|
65177
|
-
return null;
|
|
65178
|
-
}
|
|
65179
|
-
if (entry.rules !== void 0 && !isStringArray(entry.rules)) {
|
|
65180
|
-
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).`);
|
|
65181
|
-
return { files: entry.files };
|
|
65182
|
-
}
|
|
65183
|
-
return entry.rules === void 0 ? { files: entry.files } : {
|
|
65184
|
-
files: entry.files,
|
|
65185
|
-
rules: entry.rules
|
|
65186
|
-
};
|
|
65187
|
-
};
|
|
65188
|
-
const compileIgnoreOverrides = (userConfig) => {
|
|
65189
|
-
const overrides = userConfig?.ignore?.overrides;
|
|
65190
|
-
if (overrides === void 0) return [];
|
|
65191
|
-
if (!Array.isArray(overrides)) {
|
|
65192
|
-
warnConfigIssue(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
|
|
65193
|
-
return [];
|
|
65194
|
-
}
|
|
65195
|
-
return overrides.flatMap((entry, index) => {
|
|
65196
|
-
const validated = validateOverrideEntry(entry, index);
|
|
65197
|
-
if (!validated) return [];
|
|
65198
|
-
const filePatterns = compileGlobPatternsLenient(collectStringList(validated.files), (error) => warnConfigIssue(`ignore.overrides[${index}]: ${error.message}`));
|
|
65199
|
-
if (filePatterns.length === 0) return [];
|
|
65200
|
-
return [{
|
|
65201
|
-
filePatterns,
|
|
65202
|
-
ruleIds: new Set(collectStringList(validated.rules))
|
|
65203
|
-
}];
|
|
65204
|
-
});
|
|
65205
|
-
};
|
|
65206
|
-
const isDiagnosticIgnoredByOverrides = (diagnostic, rootDirectory, overrides) => {
|
|
65207
|
-
if (overrides.length === 0) return false;
|
|
65208
|
-
const relativeFilePath = toRelativePath(diagnostic.filePath, rootDirectory);
|
|
65209
|
-
const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
65210
|
-
return overrides.some((override) => override.filePatterns.some((pattern) => pattern.test(relativeFilePath)) && (override.ruleIds.size === 0 || override.ruleIds.has(ruleIdentifier)));
|
|
65211
|
-
};
|
|
65212
|
-
const SEVERITY_FOR_OVERRIDE = {
|
|
65213
|
-
error: "error",
|
|
65214
|
-
warn: "warning"
|
|
65215
|
-
};
|
|
65216
|
-
const restampSeverity = (diagnostic, override) => {
|
|
65217
|
-
const targetSeverity = SEVERITY_FOR_OVERRIDE[override];
|
|
65218
|
-
if (diagnostic.severity === targetSeverity) return diagnostic;
|
|
65219
|
-
return {
|
|
65220
|
-
...diagnostic,
|
|
65221
|
-
severity: targetSeverity
|
|
65222
|
-
};
|
|
65223
|
-
};
|
|
65224
|
-
/**
|
|
65225
|
-
* Assembles the internal `RuleSeverityControls` shape from a user
|
|
65226
|
-
* config's top-level `rules` and `categories` fields — the
|
|
65227
|
-
* ESLint / oxlint-shaped severity surface.
|
|
65228
|
-
*
|
|
65229
|
-
* Returns `undefined` when neither field is present so the common
|
|
65230
|
-
* path (no severity config at all) stays allocation-free for
|
|
65231
|
-
* downstream consumers.
|
|
65232
|
-
*/
|
|
65233
|
-
const buildRuleSeverityControls = (config) => {
|
|
65234
|
-
if (!config) return void 0;
|
|
65235
|
-
if (config.rules === void 0 && config.categories === void 0 && config.buckets === void 0) return;
|
|
65236
|
-
return {
|
|
65237
|
-
...config.rules !== void 0 ? { rules: config.rules } : {},
|
|
65238
|
-
...config.categories !== void 0 ? { categories: config.categories } : {},
|
|
65239
|
-
...config.buckets !== void 0 ? { buckets: config.buckets } : {}
|
|
65240
|
-
};
|
|
65241
|
-
};
|
|
65242
|
-
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
65243
|
-
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
65244
|
-
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
65245
65357
|
const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
65246
65358
|
"effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
|
|
65247
65359
|
"effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
|
|
@@ -65380,6 +65492,139 @@ const getEquivalentRuleKeys = (ruleKey) => {
|
|
|
65380
65492
|
const nativeRuleKey = canonicalizeRuleKey(ruleKey);
|
|
65381
65493
|
return [nativeRuleKey, ...getLegacyRuleKeysForNative(nativeRuleKey)];
|
|
65382
65494
|
};
|
|
65495
|
+
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
65496
|
+
var InvalidGlobPatternError = class extends Error {
|
|
65497
|
+
pattern;
|
|
65498
|
+
reason;
|
|
65499
|
+
constructor(pattern, reason) {
|
|
65500
|
+
super(`Invalid glob pattern ${JSON.stringify(pattern)}: ${reason}`);
|
|
65501
|
+
this.name = "InvalidGlobPatternError";
|
|
65502
|
+
this.pattern = pattern;
|
|
65503
|
+
this.reason = reason;
|
|
65504
|
+
}
|
|
65505
|
+
};
|
|
65506
|
+
const assertGlobPattern = (condition, pattern, reason) => {
|
|
65507
|
+
if (!condition) throw new InvalidGlobPatternError(pattern, reason);
|
|
65508
|
+
};
|
|
65509
|
+
const countGlobWildcards = (pattern) => (pattern.match(/[*?]/g) ?? []).length;
|
|
65510
|
+
const normalizeGlobPattern = (pattern) => pattern.replace(/\\/g, "/").replace(/^\//, "");
|
|
65511
|
+
const PICOMATCH_OPTIONS = {
|
|
65512
|
+
dot: true,
|
|
65513
|
+
strictSlashes: false,
|
|
65514
|
+
windows: false
|
|
65515
|
+
};
|
|
65516
|
+
const compileGlobPattern = (rawPattern) => {
|
|
65517
|
+
assertGlobPattern(typeof rawPattern === "string" && rawPattern.length > 0, String(rawPattern), "pattern must be a non-empty string.");
|
|
65518
|
+
assertGlobPattern(rawPattern.length <= MAX_GLOB_PATTERN_LENGTH_CHARS, rawPattern, `pattern length ${rawPattern.length} exceeds the maximum of ${MAX_GLOB_PATTERN_LENGTH_CHARS} characters.`);
|
|
65519
|
+
const wildcardCount = countGlobWildcards(rawPattern);
|
|
65520
|
+
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.`);
|
|
65521
|
+
try {
|
|
65522
|
+
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
65523
|
+
} catch (caughtError) {
|
|
65524
|
+
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
65525
|
+
}
|
|
65526
|
+
};
|
|
65527
|
+
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
65528
|
+
const compiled = [];
|
|
65529
|
+
for (const pattern of patterns) try {
|
|
65530
|
+
compiled.push(compileGlobPattern(pattern));
|
|
65531
|
+
} catch (caughtError) {
|
|
65532
|
+
if (!(caughtError instanceof InvalidGlobPatternError)) throw caughtError;
|
|
65533
|
+
onInvalid(caughtError);
|
|
65534
|
+
}
|
|
65535
|
+
return compiled;
|
|
65536
|
+
};
|
|
65537
|
+
const toRelativePath = (filePath, rootDirectory) => {
|
|
65538
|
+
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
65539
|
+
const normalizedRoot = rootDirectory.replace(/\\/g, "/").replace(/\/$/, "") + "/";
|
|
65540
|
+
if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
|
|
65541
|
+
return normalizedFilePath.replace(/^\.\//, "");
|
|
65542
|
+
};
|
|
65543
|
+
const warnConfigIssue = (message) => {
|
|
65544
|
+
process.stderr.write(`[react-doctor] ${message}\n`);
|
|
65545
|
+
};
|
|
65546
|
+
const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
65547
|
+
const collectStringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
65548
|
+
const hasMatchingRuleOverride = (ruleIds, ruleIdentifier) => {
|
|
65549
|
+
if (ruleIds.size === 0) return true;
|
|
65550
|
+
for (const ruleId of ruleIds) if (isSameRuleKey(ruleId, ruleIdentifier)) return true;
|
|
65551
|
+
return false;
|
|
65552
|
+
};
|
|
65553
|
+
const validateOverrideEntry = (entry, index) => {
|
|
65554
|
+
if (!isPlainObject(entry)) {
|
|
65555
|
+
warnConfigIssue(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
|
|
65556
|
+
return null;
|
|
65557
|
+
}
|
|
65558
|
+
if (!isStringArray(entry.files)) {
|
|
65559
|
+
warnConfigIssue(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
|
|
65560
|
+
return null;
|
|
65561
|
+
}
|
|
65562
|
+
if (entry.rules !== void 0 && !isStringArray(entry.rules)) {
|
|
65563
|
+
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).`);
|
|
65564
|
+
return { files: entry.files };
|
|
65565
|
+
}
|
|
65566
|
+
return entry.rules === void 0 ? { files: entry.files } : {
|
|
65567
|
+
files: entry.files,
|
|
65568
|
+
rules: entry.rules
|
|
65569
|
+
};
|
|
65570
|
+
};
|
|
65571
|
+
const compileIgnoreOverrides = (userConfig) => {
|
|
65572
|
+
const overrides = userConfig?.ignore?.overrides;
|
|
65573
|
+
if (overrides === void 0) return [];
|
|
65574
|
+
if (!Array.isArray(overrides)) {
|
|
65575
|
+
warnConfigIssue(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
|
|
65576
|
+
return [];
|
|
65577
|
+
}
|
|
65578
|
+
return overrides.flatMap((entry, index) => {
|
|
65579
|
+
const validated = validateOverrideEntry(entry, index);
|
|
65580
|
+
if (!validated) return [];
|
|
65581
|
+
const filePatterns = compileGlobPatternsLenient(collectStringList(validated.files), (error) => warnConfigIssue(`ignore.overrides[${index}]: ${error.message}`));
|
|
65582
|
+
if (filePatterns.length === 0) return [];
|
|
65583
|
+
return [{
|
|
65584
|
+
filePatterns,
|
|
65585
|
+
ruleIds: new Set(collectStringList(validated.rules))
|
|
65586
|
+
}];
|
|
65587
|
+
});
|
|
65588
|
+
};
|
|
65589
|
+
const isDiagnosticIgnoredByOverrides = (diagnostic, rootDirectory, overrides) => {
|
|
65590
|
+
if (overrides.length === 0) return false;
|
|
65591
|
+
const relativeFilePath = toRelativePath(diagnostic.filePath, rootDirectory);
|
|
65592
|
+
const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
65593
|
+
return overrides.some((override) => override.filePatterns.some((pattern) => pattern.test(relativeFilePath)) && hasMatchingRuleOverride(override.ruleIds, ruleIdentifier));
|
|
65594
|
+
};
|
|
65595
|
+
const SEVERITY_FOR_OVERRIDE = {
|
|
65596
|
+
error: "error",
|
|
65597
|
+
warn: "warning"
|
|
65598
|
+
};
|
|
65599
|
+
const restampSeverity = (diagnostic, override) => {
|
|
65600
|
+
const targetSeverity = SEVERITY_FOR_OVERRIDE[override];
|
|
65601
|
+
if (diagnostic.severity === targetSeverity) return diagnostic;
|
|
65602
|
+
return {
|
|
65603
|
+
...diagnostic,
|
|
65604
|
+
severity: targetSeverity
|
|
65605
|
+
};
|
|
65606
|
+
};
|
|
65607
|
+
/**
|
|
65608
|
+
* Assembles the internal `RuleSeverityControls` shape from a user
|
|
65609
|
+
* config's top-level `rules` and `categories` fields — the
|
|
65610
|
+
* ESLint / oxlint-shaped severity surface.
|
|
65611
|
+
*
|
|
65612
|
+
* Returns `undefined` when neither field is present so the common
|
|
65613
|
+
* path (no severity config at all) stays allocation-free for
|
|
65614
|
+
* downstream consumers.
|
|
65615
|
+
*/
|
|
65616
|
+
const buildRuleSeverityControls = (config) => {
|
|
65617
|
+
if (!config) return void 0;
|
|
65618
|
+
if (config.rules === void 0 && config.categories === void 0 && config.buckets === void 0) return;
|
|
65619
|
+
return {
|
|
65620
|
+
...config.rules !== void 0 ? { rules: config.rules } : {},
|
|
65621
|
+
...config.categories !== void 0 ? { categories: config.categories } : {},
|
|
65622
|
+
...config.buckets !== void 0 ? { buckets: config.buckets } : {}
|
|
65623
|
+
};
|
|
65624
|
+
};
|
|
65625
|
+
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
65626
|
+
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
65627
|
+
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
65383
65628
|
const stripDescriptionTail = (ruleList) => {
|
|
65384
65629
|
const descriptionMatch = ruleList.match(/(?:^|\s)--\s/);
|
|
65385
65630
|
if (!descriptionMatch || descriptionMatch.index === void 0) return ruleList;
|
|
@@ -66030,12 +66275,8 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
66030
66275
|
if (rule.tags.includes("migration-hint")) return false;
|
|
66031
66276
|
return getFileContext(diagnostic.filePath) !== "production";
|
|
66032
66277
|
};
|
|
66033
|
-
const
|
|
66034
|
-
for (const
|
|
66035
|
-
return false;
|
|
66036
|
-
};
|
|
66037
|
-
const isAppOnlyRule = (ruleIdentifier) => {
|
|
66038
|
-
for (const appOnlyRuleKey of APP_ONLY_RULE_KEYS) if (isSameRuleKey(appOnlyRuleKey, ruleIdentifier)) return true;
|
|
66278
|
+
const matchesRuleKey = (ruleIdentifier, candidates) => {
|
|
66279
|
+
for (const candidate of candidates) if (isSameRuleKey(candidate, ruleIdentifier)) return true;
|
|
66039
66280
|
return false;
|
|
66040
66281
|
};
|
|
66041
66282
|
const isRnRawTextSuppressedByConfig = (diagnostic) => {
|
|
@@ -66077,12 +66318,13 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
66077
66318
|
if (explicitSeverityOverride === "off") return suppress(current, "config");
|
|
66078
66319
|
if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
|
|
66079
66320
|
}
|
|
66321
|
+
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
66080
66322
|
if (explicitRuleOverride === void 0) {
|
|
66081
|
-
if (
|
|
66323
|
+
if (matchesRuleKey(ruleIdentifier, APP_ONLY_RULE_KEYS) && isLibraryFile(current.filePath)) return null;
|
|
66082
66324
|
}
|
|
66083
66325
|
if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
|
|
66084
66326
|
if (userConfig) {
|
|
66085
|
-
if (
|
|
66327
|
+
if (matchesRuleKey(ruleIdentifier, ignoredRules)) return suppress(current, "config");
|
|
66086
66328
|
if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
|
|
66087
66329
|
if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
|
|
66088
66330
|
if (isRnRawTextSuppressedByConfig(current)) return null;
|
|
@@ -66091,7 +66333,6 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
66091
66333
|
if (respectInlineDisables && current.line > 0) {
|
|
66092
66334
|
const lines = getFileLines(current.filePath);
|
|
66093
66335
|
if (lines) {
|
|
66094
|
-
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
66095
66336
|
const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
|
|
66096
66337
|
if (evaluation.isSuppressed) return suppress(current, evaluation.isForeignDirective ? "foreign-inline" : "inline");
|
|
66097
66338
|
if (evaluation.nearMissHint) current = {
|
|
@@ -66367,7 +66608,8 @@ const readSystemFacts$1 = () => ({
|
|
|
66367
66608
|
/**
|
|
66368
66609
|
* Auto lint-worker count: the smaller of the (cgroup-CPU-aware) core count and
|
|
66369
66610
|
* the number of `PER_WORKER_MEM_BUDGET_BYTES` workers that fit in available
|
|
66370
|
-
* memory,
|
|
66611
|
+
* memory, and the measured automatic parallel-efficiency ceiling, then clamped
|
|
66612
|
+
* to `[MIN, HARD_MAX]` by `resolveScanConcurrency`.
|
|
66371
66613
|
*
|
|
66372
66614
|
* `os.availableParallelism()` already respects cgroup CPU quotas, so the core
|
|
66373
66615
|
* term needs no help. Available memory is `os.totalmem()` floored by the cgroup
|
|
@@ -66383,7 +66625,7 @@ const readSystemFacts$1 = () => ({
|
|
|
66383
66625
|
const resolveAutoScanConcurrency = (facts = readSystemFacts$1()) => {
|
|
66384
66626
|
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
66385
66627
|
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / PER_WORKER_MEM_BUDGET_BYTES);
|
|
66386
|
-
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
66628
|
+
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers, 10));
|
|
66387
66629
|
};
|
|
66388
66630
|
const resolveLintBatchOrdering = () => {
|
|
66389
66631
|
return process.env["REACT_DOCTOR_LINT_BATCH_ORDERING"]?.trim().toLowerCase() === "arrival" ? "arrival" : "cost";
|
|
@@ -66396,24 +66638,22 @@ const resolveLintBatchOrdering = () => {
|
|
|
66396
66638
|
*/
|
|
66397
66639
|
var OxlintSpawnTimeoutMs = class extends Reference("react-doctor/OxlintSpawnTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_OXLINT_SPAWN_TIMEOUT_MS", OXLINT_SPAWN_TIMEOUT_MS) }) {};
|
|
66398
66640
|
/**
|
|
66399
|
-
* Effect-side cap on the lint phase.
|
|
66400
|
-
*
|
|
66641
|
+
* Optional Effect-side cap on the lint phase. Unbounded unless explicitly
|
|
66642
|
+
* configured through the env var or a test layer.
|
|
66401
66643
|
* Tests override via `Layer.succeed(LintPhaseTimeoutMs, ...)`.
|
|
66402
66644
|
*/
|
|
66403
|
-
var LintPhaseTimeoutMs = class extends Reference("react-doctor/LintPhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_LINT_PHASE_TIMEOUT_MS",
|
|
66645
|
+
var LintPhaseTimeoutMs = class extends Reference("react-doctor/LintPhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_LINT_PHASE_TIMEOUT_MS", null) }) {};
|
|
66404
66646
|
/**
|
|
66405
|
-
* Effect-side cap on the dead-code phase
|
|
66406
|
-
*
|
|
66407
|
-
* type-heavy projects; tests override via
|
|
66647
|
+
* Optional Effect-side cap on the dead-code phase. Unbounded unless explicitly
|
|
66648
|
+
* configured through the env var or a test layer. Tests override via
|
|
66408
66649
|
* `Layer.succeed(DeadCodePhaseTimeoutMs, ...)`.
|
|
66409
66650
|
*/
|
|
66410
|
-
var DeadCodePhaseTimeoutMs = class extends Reference("react-doctor/DeadCodePhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_DEAD_CODE_PHASE_TIMEOUT_MS",
|
|
66651
|
+
var DeadCodePhaseTimeoutMs = class extends Reference("react-doctor/DeadCodePhaseTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_DEAD_CODE_PHASE_TIMEOUT_MS", null) }) {};
|
|
66411
66652
|
/**
|
|
66412
|
-
*
|
|
66413
|
-
*
|
|
66414
|
-
* large repos; tests override via `Layer.succeed(ScanDeadlineMs, ...)`.
|
|
66653
|
+
* Optional overall scan deadline. Unbounded unless explicitly configured
|
|
66654
|
+
* through the env var or a test layer.
|
|
66415
66655
|
*/
|
|
66416
|
-
var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SCAN_DEADLINE_MS",
|
|
66656
|
+
var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SCAN_DEADLINE_MS", null) }) {};
|
|
66417
66657
|
/**
|
|
66418
66658
|
* Wall-clock budget for the supply-chain check when it runs on a background
|
|
66419
66659
|
* fiber overlapping the lint pass. Reads from the env var on startup so the
|
|
@@ -66486,14 +66726,14 @@ var DeadCodeOverlap = class extends Reference("react-doctor/DeadCodeOverlap", {
|
|
|
66486
66726
|
/**
|
|
66487
66727
|
* How the full-scan lint pass plans its file batches. `"cost"` (the default)
|
|
66488
66728
|
* builds size-balanced LPT batches (`planLintBatches`): the same mandatory
|
|
66489
|
-
* batch count as greedy chunking
|
|
66490
|
-
*
|
|
66729
|
+
* batch count as greedy chunking, but every batch gets an even share of files
|
|
66730
|
+
* AND bytes, so no full chunk is a straggler while
|
|
66491
66731
|
* the remainder-batch worker idles — and the heavy files are SPREAD across
|
|
66492
66732
|
* batches, the precondition the old sort-desc-then-chunk-100 `cost` mode
|
|
66493
66733
|
* lacked (it packed the heaviest files into one wave-1 straggler batch,
|
|
66494
66734
|
* measurably regressing size-skewed repos, which is why it never earned the
|
|
66495
66735
|
* default). `"arrival"` (`REACT_DOCTOR_LINT_BATCH_ORDERING=arrival`) is the
|
|
66496
|
-
* rollback hatch to plain greedy
|
|
66736
|
+
* rollback hatch to plain greedy fixed-size chunking in discovery order. Tests
|
|
66497
66737
|
* override via `Layer.succeed(LintBatchOrdering, ...)`. Diff / staged scans
|
|
66498
66738
|
* never reach this — they pass user-scoped `includePaths` that skip discovery
|
|
66499
66739
|
* and stay in arrival order; only the full-scan branch reads it.
|
|
@@ -66588,6 +66828,7 @@ const DEFAULT_SURFACE_EXCLUDED_TAGS = {
|
|
|
66588
66828
|
score: ["design"],
|
|
66589
66829
|
ciFailure: ["design"]
|
|
66590
66830
|
};
|
|
66831
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66591
66832
|
const VALID_RULE_SEVERITIES = [
|
|
66592
66833
|
"error",
|
|
66593
66834
|
"warn",
|
|
@@ -66630,7 +66871,6 @@ const SURFACE_CONTROL_FIELD_NAMES = [
|
|
|
66630
66871
|
];
|
|
66631
66872
|
const isIncludedFileContext = (value) => VALID_INCLUDED_FILE_CONTEXTS.some((fileContext) => fileContext === value);
|
|
66632
66873
|
const SEVERITY_FIELD_NAMES = ["rules", "categories"];
|
|
66633
|
-
const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66634
66874
|
const formatType = (value) => typeof value === "string" ? `"${value}"` : typeof value;
|
|
66635
66875
|
const isRuleSeverity = (value) => typeof value === "string" && VALID_RULE_SEVERITIES.includes(value);
|
|
66636
66876
|
const coerceMaybeBooleanString = (fieldName, value) => {
|
|
@@ -66657,8 +66897,45 @@ const validateStringArrayField = (fieldName, value) => {
|
|
|
66657
66897
|
return false;
|
|
66658
66898
|
});
|
|
66659
66899
|
};
|
|
66900
|
+
const validateIgnoreOverride = (rawOverride, index) => {
|
|
66901
|
+
const fieldName = `ignore.overrides[${index}]`;
|
|
66902
|
+
if (!isRecord(rawOverride)) {
|
|
66903
|
+
warnConfigIssue(`config field "${fieldName}" must be an object (got ${typeof rawOverride}); ignoring this override.`);
|
|
66904
|
+
return;
|
|
66905
|
+
}
|
|
66906
|
+
const files = validateStringArrayField(`${fieldName}.files`, rawOverride.files);
|
|
66907
|
+
if (files === void 0) return void 0;
|
|
66908
|
+
const validatedOverride = { files };
|
|
66909
|
+
if (rawOverride.rules !== void 0) {
|
|
66910
|
+
const rules = validateStringArrayField(`${fieldName}.rules`, rawOverride.rules);
|
|
66911
|
+
if (rules !== void 0) validatedOverride.rules = rules;
|
|
66912
|
+
}
|
|
66913
|
+
return validatedOverride;
|
|
66914
|
+
};
|
|
66915
|
+
const validateIgnoreField = (rawIgnore) => {
|
|
66916
|
+
if (!isRecord(rawIgnore)) {
|
|
66917
|
+
warnConfigIssue(`config field "ignore" must be an object (got ${typeof rawIgnore}); ignoring this field.`);
|
|
66918
|
+
return;
|
|
66919
|
+
}
|
|
66920
|
+
const validatedIgnore = {};
|
|
66921
|
+
for (const fieldName of [
|
|
66922
|
+
"rules",
|
|
66923
|
+
"files",
|
|
66924
|
+
"tags"
|
|
66925
|
+
]) {
|
|
66926
|
+
if (rawIgnore[fieldName] === void 0) continue;
|
|
66927
|
+
const validatedValues = validateStringArrayField(`ignore.${fieldName}`, rawIgnore[fieldName]);
|
|
66928
|
+
if (validatedValues !== void 0) validatedIgnore[fieldName] = validatedValues;
|
|
66929
|
+
}
|
|
66930
|
+
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.`);
|
|
66931
|
+
else validatedIgnore.overrides = rawIgnore.overrides.flatMap((rawOverride, index) => {
|
|
66932
|
+
const validatedOverride = validateIgnoreOverride(rawOverride, index);
|
|
66933
|
+
return validatedOverride ? [validatedOverride] : [];
|
|
66934
|
+
});
|
|
66935
|
+
return validatedIgnore;
|
|
66936
|
+
};
|
|
66660
66937
|
const validateSurfaceControls = (surface, rawControls) => {
|
|
66661
|
-
if (!
|
|
66938
|
+
if (!isRecord(rawControls)) {
|
|
66662
66939
|
warnConfigIssue(`config field "surfaces.${surface}" must be an object (got ${typeof rawControls}); ignoring this surface.`);
|
|
66663
66940
|
return;
|
|
66664
66941
|
}
|
|
@@ -66682,7 +66959,7 @@ const validateSurfaceControls = (surface, rawControls) => {
|
|
|
66682
66959
|
return validatedSurfaceControls;
|
|
66683
66960
|
};
|
|
66684
66961
|
const validateSurfacesField = (rawSurfaces) => {
|
|
66685
|
-
if (!
|
|
66962
|
+
if (!isRecord(rawSurfaces)) {
|
|
66686
66963
|
warnConfigIssue(`config field "surfaces" must be an object (got ${typeof rawSurfaces}); ignoring this field.`);
|
|
66687
66964
|
return;
|
|
66688
66965
|
}
|
|
@@ -66698,7 +66975,7 @@ const validateSurfacesField = (rawSurfaces) => {
|
|
|
66698
66975
|
return validated;
|
|
66699
66976
|
};
|
|
66700
66977
|
const validateSeverityMap = (fieldName, rawMap, keysAreCategories = false) => {
|
|
66701
|
-
if (!
|
|
66978
|
+
if (!isRecord(rawMap)) {
|
|
66702
66979
|
warnConfigIssue(`config field "${fieldName}" must be an object (got ${typeof rawMap}); ignoring this field.`);
|
|
66703
66980
|
return;
|
|
66704
66981
|
}
|
|
@@ -66732,6 +67009,7 @@ const validateConfigTypes = (config) => {
|
|
|
66732
67009
|
for (const fieldName of BOOLEAN_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => coerceMaybeBooleanString(fieldName, value));
|
|
66733
67010
|
for (const fieldName of STRING_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateString(fieldName, value));
|
|
66734
67011
|
for (const fieldName of STRING_ARRAY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateStringArrayField(fieldName, value));
|
|
67012
|
+
applyFieldValidator(config, validated, "ignore", validateIgnoreField);
|
|
66735
67013
|
applyFieldValidator(config, validated, "surfaces", validateSurfacesField);
|
|
66736
67014
|
for (const fieldName of SEVERITY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateSeverityMap(fieldName, value, fieldName === "categories"));
|
|
66737
67015
|
applyFieldValidator(config, validated, "plugins", (value) => validateStringArrayField("plugins", value));
|
|
@@ -67031,6 +67309,10 @@ const dedupeRelatedDiagnostics = (diagnostics) => {
|
|
|
67031
67309
|
}
|
|
67032
67310
|
return uniqueDiagnostics;
|
|
67033
67311
|
};
|
|
67312
|
+
const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
67313
|
+
const relativePath = Path.relative(parentAbsolutePath, childAbsolutePath);
|
|
67314
|
+
return Boolean(relativePath) && !relativePath.startsWith("..") && !Path.isAbsolute(relativePath);
|
|
67315
|
+
};
|
|
67034
67316
|
const compareStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
67035
67317
|
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));
|
|
67036
67318
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
@@ -68392,7 +68674,7 @@ const collectScriptMotionEvidence = (sourceFile, typeChecker, program) => {
|
|
|
68392
68674
|
if (calleeEvidence.isReducedMotionHook && isExpressionValueConsumed(node)) evidence.hasReducedMotionHandling = true;
|
|
68393
68675
|
}
|
|
68394
68676
|
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
68395
|
-
const tagEvidence = ts.
|
|
68677
|
+
const tagEvidence = ts.isIdentifier(node.tagName) || ts.isPropertyAccessExpression(node.tagName) ? resolveMotionExpressionEvidence(node.tagName, typeChecker, program) : EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
68396
68678
|
if (tagEvidence.isMotionComponent || tagEvidence.isMotionComponentFactory) evidence.hasMotionUse = true;
|
|
68397
68679
|
if (tagEvidence.isMotionConfig && jsxElementHasReducedMotionConfiguration(node.attributes, typeChecker)) evidence.hasReducedMotionHandling = true;
|
|
68398
68680
|
}
|
|
@@ -68607,7 +68889,7 @@ const readScannedFile = (candidate) => {
|
|
|
68607
68889
|
return null;
|
|
68608
68890
|
}
|
|
68609
68891
|
};
|
|
68610
|
-
function* collectSecurityScanFiles(rootDirectory) {
|
|
68892
|
+
function* collectSecurityScanFiles(rootDirectory, excludedDirectories = /* @__PURE__ */ new Set()) {
|
|
68611
68893
|
const priorityCandidates = [];
|
|
68612
68894
|
const artifactCandidates = [];
|
|
68613
68895
|
const otherCandidates = [];
|
|
@@ -68622,7 +68904,7 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
68622
68904
|
for (const entry of readDirectoryEntries(current.absolutePath)) {
|
|
68623
68905
|
const absolutePath = Path.join(current.absolutePath, entry.name);
|
|
68624
68906
|
if (entry.isDirectory()) {
|
|
68625
|
-
if (!SKIPPED_DIRECTORY_NAMES.has(entry.name)) stack.push({
|
|
68907
|
+
if (!SKIPPED_DIRECTORY_NAMES.has(entry.name) && !excludedDirectories.has(Path.resolve(absolutePath))) stack.push({
|
|
68626
68908
|
absolutePath,
|
|
68627
68909
|
depth: current.depth + 1
|
|
68628
68910
|
});
|
|
@@ -68803,10 +69085,8 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
|
|
|
68803
69085
|
}
|
|
68804
69086
|
return true;
|
|
68805
69087
|
};
|
|
69088
|
+
const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
|
|
68806
69089
|
const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
|
|
68807
|
-
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
68808
|
-
setImmediate(resolve);
|
|
68809
|
-
});
|
|
68810
69090
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
68811
69091
|
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
68812
69092
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
@@ -68859,19 +69139,35 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
68859
69139
|
};
|
|
68860
69140
|
};
|
|
68861
69141
|
const checkSecurityScanCooperative = async (rootDirectory, options = {}) => {
|
|
69142
|
+
const throwIfScanAborted = () => {
|
|
69143
|
+
options.signal?.throwIfAborted();
|
|
69144
|
+
};
|
|
69145
|
+
const didReachDeadline = () => {
|
|
69146
|
+
const hasDeadlineElapsed = options.deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(options.deadlineEpochMs) === 0;
|
|
69147
|
+
if (hasDeadlineElapsed) options.onDeadlineExceeded?.();
|
|
69148
|
+
return hasDeadlineElapsed;
|
|
69149
|
+
};
|
|
69150
|
+
throwIfScanAborted();
|
|
68862
69151
|
const session = createSecurityScanSession(rootDirectory, options);
|
|
68863
69152
|
if (session === null) return [];
|
|
69153
|
+
if (didReachDeadline()) return [];
|
|
68864
69154
|
let sliceStartedAt = performance.now();
|
|
68865
|
-
for (const file of collectSecurityScanFiles(rootDirectory)) {
|
|
69155
|
+
for (const file of collectSecurityScanFiles(rootDirectory, options.excludedDirectories)) {
|
|
69156
|
+
throwIfScanAborted();
|
|
69157
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68866
69158
|
if (file === null) {
|
|
68867
69159
|
if (performance.now() - sliceStartedAt >= 12) {
|
|
68868
69160
|
await yieldToEventLoop();
|
|
69161
|
+
throwIfScanAborted();
|
|
69162
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68869
69163
|
sliceStartedAt = performance.now();
|
|
68870
69164
|
}
|
|
68871
69165
|
continue;
|
|
68872
69166
|
}
|
|
68873
69167
|
for (const _ruleStep of session.scanFileByRule(file)) if (performance.now() - sliceStartedAt >= 12) {
|
|
68874
69168
|
await yieldToEventLoop();
|
|
69169
|
+
throwIfScanAborted();
|
|
69170
|
+
if (didReachDeadline()) return session.diagnostics;
|
|
68875
69171
|
sliceStartedAt = performance.now();
|
|
68876
69172
|
}
|
|
68877
69173
|
}
|
|
@@ -69034,25 +69330,18 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
69034
69330
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
69035
69331
|
return patterns;
|
|
69036
69332
|
};
|
|
69037
|
-
const
|
|
69038
|
-
const KNIP_JSON_FILENAME = "knip.json";
|
|
69039
|
-
const readJsonFileSafe = (filePath) => {
|
|
69040
|
-
let rawContents;
|
|
69041
|
-
try {
|
|
69042
|
-
rawContents = fs.readFileSync(filePath, "utf-8");
|
|
69043
|
-
} catch {
|
|
69044
|
-
return null;
|
|
69045
|
-
}
|
|
69333
|
+
const failOpenReadJson = (filePath, fallback) => {
|
|
69046
69334
|
try {
|
|
69047
|
-
return JSON.parse(
|
|
69335
|
+
return JSON.parse(NFS.readFileSync(filePath, "utf8"));
|
|
69048
69336
|
} catch {
|
|
69049
|
-
return
|
|
69337
|
+
return fallback;
|
|
69050
69338
|
}
|
|
69051
69339
|
};
|
|
69340
|
+
const KNIP_JSON_FILENAME = "knip.json";
|
|
69052
69341
|
const readKnipConfig = (rootDirectory) => {
|
|
69053
|
-
const knipJson =
|
|
69342
|
+
const knipJson = failOpenReadJson(path.join(rootDirectory, KNIP_JSON_FILENAME), null);
|
|
69054
69343
|
if (isRecord(knipJson)) return knipJson;
|
|
69055
|
-
const packageJson =
|
|
69344
|
+
const packageJson = failOpenReadJson(path.join(rootDirectory, "package.json"), null);
|
|
69056
69345
|
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
69057
69346
|
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
69058
69347
|
};
|
|
@@ -69100,13 +69389,6 @@ const atomicWriteJson = (filePath, value) => {
|
|
|
69100
69389
|
return;
|
|
69101
69390
|
}
|
|
69102
69391
|
};
|
|
69103
|
-
const failOpenReadJson = (filePath, fallback) => {
|
|
69104
|
-
try {
|
|
69105
|
-
return JSON.parse(NFS.readFileSync(filePath, "utf8"));
|
|
69106
|
-
} catch {
|
|
69107
|
-
return fallback;
|
|
69108
|
-
}
|
|
69109
|
-
};
|
|
69110
69392
|
const hashFileContents = (filePath) => {
|
|
69111
69393
|
try {
|
|
69112
69394
|
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
@@ -69785,7 +70067,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
|
|
|
69785
70067
|
return true;
|
|
69786
70068
|
};
|
|
69787
70069
|
const filterDiagnosticsForSurface = (diagnostics, surface, config) => diagnostics.filter((diagnostic) => isDiagnosticOnSurface(diagnostic, surface, config));
|
|
69788
|
-
const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
|
|
69789
70070
|
/**
|
|
69790
70071
|
* Budget for the dead-code phase, scaled to the work. deslop's graph build is
|
|
69791
70072
|
* CPU-bound and roughly linear in file count, so a fixed 120s cap is too tight
|
|
@@ -69793,25 +70074,28 @@ const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs
|
|
|
69793
70074
|
* tipped over by any concurrent load — silently dropping every dead-code
|
|
69794
70075
|
* finding. Scaling the budget with file count (and inversely with the core
|
|
69795
70076
|
* share when overlapped) lets the pass complete, while the ceiling still
|
|
69796
|
-
* reclaims a genuinely wedged worker.
|
|
69797
|
-
* and the Effect-side phase backstop that sits a margin above it.
|
|
70077
|
+
* reclaims a genuinely wedged worker.
|
|
69798
70078
|
*/
|
|
69799
70079
|
const resolveDeadCodeTimeout = (input) => {
|
|
69800
70080
|
const coreShareFactor = Math.max(1, input.fullConcurrency / Math.max(1, input.deadCodeConcurrency));
|
|
69801
|
-
|
|
69802
|
-
return {
|
|
69803
|
-
workerTimeoutMs,
|
|
69804
|
-
phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
|
|
69805
|
-
};
|
|
70081
|
+
return { workerTimeoutMs: Math.min(DEAD_CODE_TIMEOUT_CEILING_MS, Math.max(DEAD_CODE_WORKER_TIMEOUT_MS, Math.ceil(input.sourceFileCount * 30 * coreShareFactor))) };
|
|
69806
70082
|
};
|
|
69807
|
-
const resolveLintIncludePaths = (rootDirectory, userConfig) => {
|
|
70083
|
+
const resolveLintIncludePaths = (rootDirectory, userConfig, sourceFiles) => {
|
|
69808
70084
|
if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
|
|
69809
70085
|
const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
|
|
69810
|
-
return listSourceFiles(rootDirectory).filter((filePath) => {
|
|
70086
|
+
return (sourceFiles ?? listSourceFiles(rootDirectory)).filter((filePath) => {
|
|
69811
70087
|
if (!isLintableSourceFile(filePath)) return false;
|
|
69812
70088
|
return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
|
|
69813
70089
|
});
|
|
69814
70090
|
};
|
|
70091
|
+
const filterPathsOutsideDirectories = (input) => {
|
|
70092
|
+
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}/`)));
|
|
70093
|
+
if (excludedPrefixes.length === 0) return [...input.relativePaths];
|
|
70094
|
+
return input.relativePaths.filter((relativePath) => {
|
|
70095
|
+
const normalizedRelativePath = relativePath.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
70096
|
+
return !excludedPrefixes.some((excludedPrefix) => normalizedRelativePath === excludedPrefix || normalizedRelativePath.startsWith(`${excludedPrefix}/`));
|
|
70097
|
+
});
|
|
70098
|
+
};
|
|
69815
70099
|
var Config = class Config extends Service()("react-doctor/Config") {
|
|
69816
70100
|
static layerNode = effect(Config, gen(function* () {
|
|
69817
70101
|
const cache = yield* make$3({
|
|
@@ -69873,6 +70157,7 @@ var Files = class Files extends Service()("react-doctor/Files") {
|
|
|
69873
70157
|
static layerNode = succeed$3(Files, Files.of({
|
|
69874
70158
|
readLines: (input) => sync(() => createNodeReadFileLinesSync(input.rootDirectory)(input.filePath)),
|
|
69875
70159
|
listSourceFiles: (rootDirectory) => sync(() => listSourceFiles(rootDirectory)),
|
|
70160
|
+
listSourceFilesCooperative: (input) => promise(() => listSourceFilesCooperative(input.rootDirectory, input.signal)),
|
|
69876
70161
|
isFile: (filePath) => sync(() => isFile(filePath)),
|
|
69877
70162
|
isDirectory: (filePath) => sync(() => isDirectory(filePath))
|
|
69878
70163
|
}));
|
|
@@ -69899,6 +70184,16 @@ var Files = class Files extends Service()("react-doctor/Files") {
|
|
|
69899
70184
|
}
|
|
69900
70185
|
return files;
|
|
69901
70186
|
}),
|
|
70187
|
+
listSourceFilesCooperative: (input) => sync(() => {
|
|
70188
|
+
const rootDirectory = input.rootDirectory;
|
|
70189
|
+
const prefix = rootDirectory.endsWith("/") ? rootDirectory : `${rootDirectory}/`;
|
|
70190
|
+
const files = [];
|
|
70191
|
+
for (const absolute of tree.keys()) {
|
|
70192
|
+
if (!absolute.startsWith(prefix)) continue;
|
|
70193
|
+
files.push(absolute.slice(prefix.length));
|
|
70194
|
+
}
|
|
70195
|
+
return files;
|
|
70196
|
+
}),
|
|
69902
70197
|
isFile: (filePath) => sync(() => tree.has(filePath)),
|
|
69903
70198
|
isDirectory: (filePath) => sync(() => {
|
|
69904
70199
|
const prefix = filePath.endsWith("/") ? filePath : `${filePath}/`;
|
|
@@ -70363,7 +70658,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
70363
70658
|
changedFiles: yield* mergeUntracked(directory, splitNullSeparated(diff.stdout), includeUntracked),
|
|
70364
70659
|
isCurrentChanges: false
|
|
70365
70660
|
};
|
|
70366
|
-
}).pipe(withSpan("Git.diffSelection")),
|
|
70661
|
+
}).pipe(catchReasons("ReactDoctorError", { GitInvocationFailed: () => succeed$2(null) }, (_reason, error) => fail$4(error)), withSpan("Git.diffSelection")),
|
|
70367
70662
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
70368
70663
|
"diff",
|
|
70369
70664
|
"--no-ext-diff",
|
|
@@ -70474,7 +70769,7 @@ const batchIncludePaths = (baseArgs, includePaths) => {
|
|
|
70474
70769
|
for (const filePath of includePaths) {
|
|
70475
70770
|
const entryLength = filePath.length + 1;
|
|
70476
70771
|
const exceedsArgLength = currentBatch.length > 0 && currentBatchLength + entryLength > 24e3;
|
|
70477
|
-
const exceedsFileCount = currentBatch.length >=
|
|
70772
|
+
const exceedsFileCount = currentBatch.length >= 200;
|
|
70478
70773
|
if (exceedsArgLength || exceedsFileCount) {
|
|
70479
70774
|
batches.push(currentBatch);
|
|
70480
70775
|
currentBatch = [];
|
|
@@ -70821,7 +71116,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
70821
71116
|
}
|
|
70822
71117
|
return enabled;
|
|
70823
71118
|
};
|
|
70824
|
-
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 }) => {
|
|
71119
|
+
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 }) => {
|
|
70825
71120
|
const hasIncludedTags = includedTags.size > 0;
|
|
70826
71121
|
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
70827
71122
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
@@ -70885,7 +71180,8 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
70885
71180
|
}))
|
|
70886
71181
|
} : {},
|
|
70887
71182
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
70888
|
-
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
71183
|
+
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {},
|
|
71184
|
+
...projectIndexModuleSources !== void 0 ? { projectIndexModuleSources: [...projectIndexModuleSources] } : {}
|
|
70889
71185
|
} },
|
|
70890
71186
|
rules: {
|
|
70891
71187
|
...reactCompilerRules,
|
|
@@ -71134,11 +71430,17 @@ const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }
|
|
|
71134
71430
|
return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
|
|
71135
71431
|
};
|
|
71136
71432
|
const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
|
|
71433
|
+
const decodeDiagnostic = (raw) => {
|
|
71434
|
+
const diagnostic = validateDiagnostic$1(raw);
|
|
71435
|
+
return {
|
|
71436
|
+
...diagnostic,
|
|
71437
|
+
relatedLocations: diagnostic.relatedLocations?.map((location) => ({ ...location }))
|
|
71438
|
+
};
|
|
71439
|
+
};
|
|
71137
71440
|
const decodeFileDiagnostics = (raw) => {
|
|
71138
71441
|
if (!Array.isArray(raw)) return null;
|
|
71139
71442
|
try {
|
|
71140
|
-
|
|
71141
|
-
return raw;
|
|
71443
|
+
return raw.map((entry) => decodeDiagnostic(entry));
|
|
71142
71444
|
} catch {
|
|
71143
71445
|
return null;
|
|
71144
71446
|
}
|
|
@@ -72370,6 +72672,12 @@ const buildProfiledNodeArguments = (input) => [
|
|
|
72370
72672
|
...input.heapProfileDirectory ? ["--heap-prof", `--heap-prof-dir=${input.heapProfileDirectory}`] : [],
|
|
72371
72673
|
...input.argumentsList
|
|
72372
72674
|
];
|
|
72675
|
+
const lowerChildProcessPriority = (processId) => {
|
|
72676
|
+
if (processId === void 0) return;
|
|
72677
|
+
try {
|
|
72678
|
+
OS.setPriority(processId, OS.constants.priority.PRIORITY_BELOW_NORMAL);
|
|
72679
|
+
} catch {}
|
|
72680
|
+
};
|
|
72373
72681
|
const SANITIZED_ENV = buildOxlintChildEnv(process.env);
|
|
72374
72682
|
/**
|
|
72375
72683
|
* Spawn one oxlint subprocess with hard ceilings on wall time and
|
|
@@ -72408,6 +72716,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
72408
72716
|
"pipe"
|
|
72409
72717
|
]
|
|
72410
72718
|
});
|
|
72719
|
+
lowerChildProcessPriority(child.pid);
|
|
72411
72720
|
const onAbort = () => {
|
|
72412
72721
|
child.kill("SIGKILL");
|
|
72413
72722
|
reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
|
|
@@ -72530,7 +72839,7 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
72530
72839
|
* loop with a slimmer config in that case.
|
|
72531
72840
|
*/
|
|
72532
72841
|
const spawnLintBatches = async (input) => {
|
|
72533
|
-
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth =
|
|
72842
|
+
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 9, signal, deadlineEpochMs } = input;
|
|
72534
72843
|
const resolveSourcePath = (filePath) => {
|
|
72535
72844
|
const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
|
|
72536
72845
|
return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
|
|
@@ -72538,6 +72847,12 @@ const spawnLintBatches = async (input) => {
|
|
|
72538
72847
|
const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
|
|
72539
72848
|
let rescueDeadlineEpochMs;
|
|
72540
72849
|
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
|
|
72850
|
+
const resolveSpawnTimeoutMs = () => {
|
|
72851
|
+
const deadlineBudgets = [deadlineEpochMs, rescueDeadlineEpochMs].filter((deadline) => deadline !== void 0).map(remainingDeadlineBudgetMs);
|
|
72852
|
+
if (deadlineBudgets.length === 0) return spawnTimeoutMs;
|
|
72853
|
+
const remainingDeadlineMs = Math.min(...deadlineBudgets);
|
|
72854
|
+
return spawnTimeoutMs === void 0 ? remainingDeadlineMs : Math.min(spawnTimeoutMs, remainingDeadlineMs);
|
|
72855
|
+
};
|
|
72541
72856
|
const runBatchPass = async (concurrency, passBatches, passOnFileProgress) => {
|
|
72542
72857
|
const totalFileCount = passBatches.reduce((sum, batch) => sum + batch.length, 0);
|
|
72543
72858
|
const allDiagnostics = [];
|
|
@@ -72555,12 +72870,13 @@ const spawnLintBatches = async (input) => {
|
|
|
72555
72870
|
const batchArgs = [...baseArgs, ...batch];
|
|
72556
72871
|
try {
|
|
72557
72872
|
const spawnBatch = () => {
|
|
72558
|
-
|
|
72873
|
+
const effectiveSpawnTimeoutMs = resolveSpawnTimeoutMs();
|
|
72874
|
+
if (effectiveSpawnTimeoutMs === 0) {
|
|
72559
72875
|
deadlineSkippedFiles.push(...batch);
|
|
72560
72876
|
batchState.deadlineSkippedFileCount += batch.length;
|
|
72561
72877
|
return Promise.resolve(null);
|
|
72562
72878
|
}
|
|
72563
|
-
return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath,
|
|
72879
|
+
return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, effectiveSpawnTimeoutMs, outputMaxBytes, signal, () => {
|
|
72564
72880
|
if (batchState.didStart) return;
|
|
72565
72881
|
batchState.didStart = true;
|
|
72566
72882
|
startedFileCount += batchState.initialFileCount;
|
|
@@ -72715,11 +73031,36 @@ const validateRuleRegistration = () => {
|
|
|
72715
73031
|
].filter((entry) => entry !== null).join("; ");
|
|
72716
73032
|
console.warn(`[react-doctor] rule-registration drift: ${detail}`);
|
|
72717
73033
|
};
|
|
73034
|
+
const PROJECT_INDEX_MODULE_SOURCES = [
|
|
73035
|
+
"next/og",
|
|
73036
|
+
"@vercel/og",
|
|
73037
|
+
"satori",
|
|
73038
|
+
"remotion"
|
|
73039
|
+
];
|
|
73040
|
+
const collectProjectIndexModuleSources = async (rootDirectory, candidateFiles) => {
|
|
73041
|
+
const foundModuleSources = /* @__PURE__ */ new Set();
|
|
73042
|
+
let sliceStartedAt = performance.now();
|
|
73043
|
+
for (const candidateFile of candidateFiles) {
|
|
73044
|
+
let sourceBuffer;
|
|
73045
|
+
try {
|
|
73046
|
+
sourceBuffer = NFS.readFileSync(Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile));
|
|
73047
|
+
} catch {
|
|
73048
|
+
continue;
|
|
73049
|
+
}
|
|
73050
|
+
for (const moduleSource of PROJECT_INDEX_MODULE_SOURCES) if (sourceBuffer.includes(`"${moduleSource}"`) || sourceBuffer.includes(`'${moduleSource}'`)) foundModuleSources.add(moduleSource);
|
|
73051
|
+
if (foundModuleSources.size === PROJECT_INDEX_MODULE_SOURCES.length) break;
|
|
73052
|
+
if (performance.now() - sliceStartedAt >= 12) {
|
|
73053
|
+
await yieldToEventLoop();
|
|
73054
|
+
sliceStartedAt = performance.now();
|
|
73055
|
+
}
|
|
73056
|
+
}
|
|
73057
|
+
return [...foundModuleSources].sort();
|
|
73058
|
+
};
|
|
72718
73059
|
/**
|
|
72719
73060
|
* Balanced LPT (longest-processing-time-first) lint batch planner. Where
|
|
72720
|
-
* `batchIncludePaths` greedily fills
|
|
72721
|
-
* remainder batch
|
|
72722
|
-
*
|
|
73061
|
+
* `batchIncludePaths` greedily fills fixed-size batches and leaves a small
|
|
73062
|
+
* remainder batch, so the parallel pool's wall clock is set by whichever
|
|
73063
|
+
* full chunk happened to collect the most work while
|
|
72723
73064
|
* the remainder's worker idles), this planner keeps the SAME mandatory batch
|
|
72724
73065
|
* count — `ceil(files / OXLINT_MAX_FILES_PER_BATCH)`, the JS-plugin
|
|
72725
73066
|
* perf-cliff / native-binding SIGABRT guard — and assigns files largest-first,
|
|
@@ -72748,7 +73089,7 @@ const validateRuleRegistration = () => {
|
|
|
72748
73089
|
*/
|
|
72749
73090
|
const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
|
|
72750
73091
|
if (files.length === 0) return [];
|
|
72751
|
-
const batchCount = Math.ceil(files.length /
|
|
73092
|
+
const batchCount = Math.ceil(files.length / 200);
|
|
72752
73093
|
const maxFilesPerBatch = Math.ceil(files.length / batchCount);
|
|
72753
73094
|
const baseArgsLengthChars = estimateArgsLength(baseArgs);
|
|
72754
73095
|
const descendingSizeIndexes = [...files.keys()].sort((leftIndex, rightIndex) => (sizeByFile.get(files[rightIndex]) ?? 0) - (sizeByFile.get(files[leftIndex]) ?? 0));
|
|
@@ -73277,6 +73618,7 @@ const runOxlint = async (options) => {
|
|
|
73277
73618
|
await yieldToEventLoop();
|
|
73278
73619
|
const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
|
|
73279
73620
|
const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
|
|
73621
|
+
const projectIndexModuleSources = includePaths === void 0 && options.deadlineEpochMs === void 0 ? await collectProjectIndexModuleSources(rootDirectory, candidateFiles) : void 0;
|
|
73280
73622
|
unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
|
|
73281
73623
|
rootDirectory,
|
|
73282
73624
|
candidateFiles
|
|
@@ -73299,6 +73641,7 @@ const runOxlint = async (options) => {
|
|
|
73299
73641
|
runtimeGlobals,
|
|
73300
73642
|
unpluginAutoImportGlobalScopes,
|
|
73301
73643
|
serverAuthFunctionNames,
|
|
73644
|
+
projectIndexModuleSources,
|
|
73302
73645
|
severityControls,
|
|
73303
73646
|
userPlugins,
|
|
73304
73647
|
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
@@ -73766,10 +74109,10 @@ const translateProjectInfoError = (cause, directory) => {
|
|
|
73766
74109
|
}) });
|
|
73767
74110
|
};
|
|
73768
74111
|
var Project = class Project extends Service()("react-doctor/Project") {
|
|
73769
|
-
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (
|
|
74112
|
+
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (input) {
|
|
73770
74113
|
return yield* try_({
|
|
73771
|
-
try: () => discoverProject(directory),
|
|
73772
|
-
catch: (cause) => translateProjectInfoError(cause, directory)
|
|
74114
|
+
try: () => discoverProject(input.directory, { sourceFileCount: input.sourceFileCount }),
|
|
74115
|
+
catch: (cause) => translateProjectInfoError(cause, input.directory)
|
|
73773
74116
|
});
|
|
73774
74117
|
}) }));
|
|
73775
74118
|
static layerOf = (projectInfo) => succeed$3(Project, Project.of({ discover: () => succeed$2(projectInfo) }));
|
|
@@ -74354,9 +74697,10 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
74354
74697
|
* outage.
|
|
74355
74698
|
*/
|
|
74356
74699
|
var SupplyChain = class SupplyChain extends Service()("react-doctor/SupplyChain") {
|
|
74357
|
-
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (
|
|
74358
|
-
|
|
74359
|
-
|
|
74700
|
+
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (configuredTimeoutMs) => checkSupplyChain({
|
|
74701
|
+
rootDirectory: input.rootDirectory,
|
|
74702
|
+
userConfig: input.userConfig,
|
|
74703
|
+
totalTimeoutMs: input.timeoutMs ?? configuredTimeoutMs
|
|
74360
74704
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), withSpan("SupplyChain.run"))) }));
|
|
74361
74705
|
static layerOf = (diagnostics) => succeed$3(SupplyChain, SupplyChain.of({ run: () => fromIterable$1(diagnostics) }));
|
|
74362
74706
|
};
|
|
@@ -74391,10 +74735,6 @@ const NO_HOOKS = {
|
|
|
74391
74735
|
beforeLint: () => void_,
|
|
74392
74736
|
afterLint: () => void_
|
|
74393
74737
|
};
|
|
74394
|
-
const filterMapNullable = (transform) => fromPredicateOption((value) => {
|
|
74395
|
-
const result = transform(value);
|
|
74396
|
-
return result === null ? none() : some(result);
|
|
74397
|
-
});
|
|
74398
74738
|
const fileReader = (filesService, rootDirectory) => (filePath) => {
|
|
74399
74739
|
const lines = runSync(filesService.readLines({
|
|
74400
74740
|
filePath,
|
|
@@ -74418,7 +74758,7 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
74418
74758
|
* The GitHub viewer-permission lookup is forked onto a background
|
|
74419
74759
|
* fiber here and joined late (it feeds score metadata, not
|
|
74420
74760
|
* diagnostics).
|
|
74421
|
-
* 2. beforeLint hook (e.g. CLI
|
|
74761
|
+
* 2. beforeLint hook (e.g. CLI records project telemetry)
|
|
74422
74762
|
* 3. environment checks (reduced-motion + pnpm hardening +
|
|
74423
74763
|
* expo/react-native), collected synchronously. The heavier
|
|
74424
74764
|
* content-regex security scan is forked instead (like supply-chain
|
|
@@ -74431,13 +74771,11 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
74431
74771
|
* `SupplyChainOverlapTimeoutMs` (measured from fork) so a hung
|
|
74432
74772
|
* socket can't drag out its join; on timeout it fails open to no
|
|
74433
74773
|
* diagnostics — the same outcome class as a Socket outage.
|
|
74434
|
-
* 5. Linter.run runs; DeadCode.run
|
|
74435
|
-
*
|
|
74436
|
-
*
|
|
74437
|
-
*
|
|
74438
|
-
*
|
|
74439
|
-
* fiber is joined (or interrupted, SIGKILLing its worker, on lint
|
|
74440
|
-
* failure) before diagnostics are concatenated. The afterLint hook
|
|
74774
|
+
* 5. Linter.run runs; DeadCode.run forks only when
|
|
74775
|
+
* REACT_DOCTOR_DEAD_CODE_OVERLAP=on. The default "auto" and explicit
|
|
74776
|
+
* "off" paths stay sequential. The fiber is joined (or interrupted,
|
|
74777
|
+
* SIGKILLing its worker, on lint failure) before diagnostics are
|
|
74778
|
+
* concatenated. The afterLint hook
|
|
74441
74779
|
* fires between lint and dead-code. Progress spinner labels AND the
|
|
74442
74780
|
* final diagnostic / score order stay independent of execution
|
|
74443
74781
|
* order, so terminal output is identical either way; supply-chain
|
|
@@ -74472,8 +74810,28 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74472
74810
|
const partialFailuresRef = yield* LintPartialFailures;
|
|
74473
74811
|
const resolvedConfig = yield* configService.resolve(input.directory);
|
|
74474
74812
|
const scanDirectory = resolvedConfig.resolvedDirectory;
|
|
74475
|
-
const
|
|
74813
|
+
const excludedProjectDirectories = (input.excludedProjectDirectories ?? []).map((excludedDirectory) => Path.resolve(excludedDirectory)).filter((excludedDirectory) => isPathInsideDirectory(excludedDirectory, scanDirectory));
|
|
74814
|
+
const excludedProjectRelativePaths = excludedProjectDirectories.map((excludedDirectory) => Path.relative(scanDirectory, excludedDirectory).replaceAll("\\", "/"));
|
|
74815
|
+
const isExcludedProjectDiagnostic = (diagnostic) => {
|
|
74816
|
+
const relativeFilePath = toNormalizedRelativePath(diagnostic.filePath, scanDirectory);
|
|
74817
|
+
return excludedProjectRelativePaths.some((excludedRelativePath) => relativeFilePath === excludedRelativePath || relativeFilePath.startsWith(`${excludedRelativePath}/`));
|
|
74818
|
+
};
|
|
74819
|
+
const precomputedSourceFiles = input.suppressScanSummary === true || excludedProjectDirectories.length > 0 ? yield* filesService.listSourceFilesCooperative({
|
|
74820
|
+
rootDirectory: scanDirectory,
|
|
74821
|
+
signal: input.signal
|
|
74822
|
+
}) : null;
|
|
74823
|
+
const includedPrecomputedSourceFiles = precomputedSourceFiles !== null && excludedProjectDirectories.length > 0 ? filterPathsOutsideDirectories({
|
|
74824
|
+
rootDirectory: scanDirectory,
|
|
74825
|
+
relativePaths: precomputedSourceFiles,
|
|
74826
|
+
excludedDirectories: excludedProjectDirectories
|
|
74827
|
+
}) : precomputedSourceFiles;
|
|
74828
|
+
const sourceFileCount = excludedProjectDirectories.length > 0 ? includedPrecomputedSourceFiles?.length : input.precomputedSourceFileCount ?? includedPrecomputedSourceFiles?.length;
|
|
74829
|
+
const project = yield* projectService.discover({
|
|
74830
|
+
directory: scanDirectory,
|
|
74831
|
+
sourceFileCount
|
|
74832
|
+
});
|
|
74476
74833
|
if (!isAnalyzableProject(project)) return yield* new ReactDoctorError({ reason: new NoReactDependency({ directory: scanDirectory }) });
|
|
74834
|
+
const deadCodeSourceFileCount = input.retainExcludedProjectDeadCodeDiagnostics === true && precomputedSourceFiles !== null ? precomputedSourceFiles.length : project.sourceFileCount;
|
|
74477
74835
|
const [repo, sha, defaultBranch] = yield* all([
|
|
74478
74836
|
gitService.githubRepo(scanDirectory).pipe(orElseSucceed(() => null)),
|
|
74479
74837
|
gitService.headSha(scanDirectory).pipe(orElseSucceed(() => null)),
|
|
@@ -74484,11 +74842,16 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74484
74842
|
directory: scanDirectory,
|
|
74485
74843
|
repo
|
|
74486
74844
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
74487
|
-
|
|
74488
|
-
|
|
74845
|
+
let lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, includedPrecomputedSourceFiles ?? void 0);
|
|
74846
|
+
if (excludedProjectDirectories.length > 0) lintIncludePaths = filterPathsOutsideDirectories({
|
|
74847
|
+
rootDirectory: scanDirectory,
|
|
74848
|
+
relativePaths: lintIncludePaths ?? includedPrecomputedSourceFiles ?? (yield* filesService.listSourceFiles(scanDirectory)),
|
|
74849
|
+
excludedDirectories: excludedProjectDirectories
|
|
74850
|
+
});
|
|
74851
|
+
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? includedPrecomputedSourceFiles ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
74489
74852
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
74490
74853
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
74491
|
-
yield* beforeLint(project
|
|
74854
|
+
yield* beforeLint(project);
|
|
74492
74855
|
const isDiffMode = input.includePaths.length > 0;
|
|
74493
74856
|
const showWarnings = input.warnings ?? resolvedConfig.config?.warnings ?? true;
|
|
74494
74857
|
const transform = buildDiagnosticPipeline({
|
|
@@ -74498,7 +74861,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74498
74861
|
respectInlineDisables: input.respectInlineDisables,
|
|
74499
74862
|
showWarnings
|
|
74500
74863
|
});
|
|
74501
|
-
const filterPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(
|
|
74864
|
+
const filterPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(fromPredicateOption((diagnostic) => {
|
|
74865
|
+
const filteredDiagnostic = transform.apply(diagnostic);
|
|
74866
|
+
return filteredDiagnostic === null ? none() : some(filteredDiagnostic);
|
|
74867
|
+
})));
|
|
74502
74868
|
const applyPerElementPipeline = (rawStream) => filterPerElementPipeline(rawStream).pipe(tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
74503
74869
|
const envCollected = yield* runCollect(applyPerElementPipeline(fromIterable$1(isDiffMode ? [] : [
|
|
74504
74870
|
...checkReducedMotion(scanDirectory),
|
|
@@ -74508,17 +74874,31 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74508
74874
|
...checkReactNativeProject(scanDirectory, project)
|
|
74509
74875
|
])));
|
|
74510
74876
|
const securityScanFailedRef = yield* make$13(false);
|
|
74511
|
-
|
|
74877
|
+
let didSecurityScanReachDeadline = false;
|
|
74878
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise((signal) => checkSecurityScanCooperative(scanDirectory, {
|
|
74512
74879
|
project,
|
|
74513
74880
|
ignoredTags: input.ignoredTags,
|
|
74514
74881
|
includedTags: input.includedTags,
|
|
74515
|
-
includeTagDefaults: input.includeTagDefaults
|
|
74882
|
+
includeTagDefaults: input.includeTagDefaults,
|
|
74883
|
+
excludedDirectories: new Set(excludedProjectDirectories),
|
|
74884
|
+
deadlineEpochMs: input.deadlineEpochMs,
|
|
74885
|
+
signal,
|
|
74886
|
+
onDeadlineExceeded: () => {
|
|
74887
|
+
didSecurityScanReachDeadline = true;
|
|
74888
|
+
}
|
|
74516
74889
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
74890
|
+
const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
|
|
74891
|
+
const capOptionalToDeadline = (phaseTimeoutMs) => {
|
|
74892
|
+
if (input.deadlineEpochMs === void 0) return phaseTimeoutMs;
|
|
74893
|
+
const remainingBudgetMs = remainingDeadlineBudgetMs(input.deadlineEpochMs);
|
|
74894
|
+
return phaseTimeoutMs === null ? remainingBudgetMs : Math.min(phaseTimeoutMs, remainingBudgetMs);
|
|
74895
|
+
};
|
|
74517
74896
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
74518
|
-
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
74897
|
+
const supplyChainOverlapTimeout = capToDeadline(yield* SupplyChainOverlapTimeoutMs);
|
|
74519
74898
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
74520
74899
|
rootDirectory: scanDirectory,
|
|
74521
|
-
userConfig: resolvedConfig.config
|
|
74900
|
+
userConfig: resolvedConfig.config,
|
|
74901
|
+
timeoutMs: supplyChainOverlapTimeout
|
|
74522
74902
|
}))).pipe(map$3((diagnostics) => ({
|
|
74523
74903
|
diagnostics,
|
|
74524
74904
|
timedOut: false
|
|
@@ -74542,46 +74922,49 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74542
74922
|
const scanConcurrency = resolveScanConcurrency(yield* OxlintConcurrency);
|
|
74543
74923
|
const lintPhaseTimeoutMs = yield* LintPhaseTimeoutMs;
|
|
74544
74924
|
const deadCodePhaseTimeoutMs = yield* DeadCodePhaseTimeoutMs;
|
|
74545
|
-
const resolveDeadCodePhaseTimeoutMs = (scaledPhaseTimeoutMs) => deadCodePhaseTimeoutMs === 15e4 ? scaledPhaseTimeoutMs : deadCodePhaseTimeoutMs;
|
|
74546
74925
|
const workerCountSuffix = scanConcurrency > 1 ? ` ${highlighter.dim(`[~${scanConcurrency} workers]`)}` : "";
|
|
74547
|
-
const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
|
|
74548
74926
|
const shouldRunDeadCode = input.runDeadCode && !isDiffMode && (showWarnings || deadCodeMaySurfaceWhenWarningsHidden(resolvedConfig.config));
|
|
74549
74927
|
const deadCodeOverlapMode = yield* DeadCodeOverlap;
|
|
74550
74928
|
const shouldOverlapDeadCode = shouldRunDeadCode && deadCodeOverlapMode === "on";
|
|
74551
74929
|
const deadCodeParseConcurrency = shouldOverlapDeadCode ? Math.max(1, Math.floor(scanConcurrency * DEAD_CODE_OVERLAP_PARSE_SHARE)) : void 0;
|
|
74552
74930
|
const lintConcurrency = deadCodeParseConcurrency === void 0 ? scanConcurrency : Math.max(1, scanConcurrency - deadCodeParseConcurrency);
|
|
74553
|
-
const buildCollectDeadCode = (deadCodeTimeout) =>
|
|
74554
|
-
|
|
74555
|
-
|
|
74556
|
-
|
|
74557
|
-
|
|
74558
|
-
|
|
74559
|
-
|
|
74560
|
-
|
|
74561
|
-
|
|
74562
|
-
|
|
74563
|
-
|
|
74564
|
-
|
|
74565
|
-
|
|
74566
|
-
|
|
74567
|
-
|
|
74568
|
-
|
|
74569
|
-
|
|
74570
|
-
|
|
74571
|
-
|
|
74572
|
-
|
|
74573
|
-
|
|
74574
|
-
|
|
74575
|
-
|
|
74576
|
-
|
|
74931
|
+
const buildCollectDeadCode = (deadCodeTimeout) => {
|
|
74932
|
+
const collectDeadCode = runCollect(applyPerElementPipeline(deadCodeService.run({
|
|
74933
|
+
rootDirectory: scanDirectory,
|
|
74934
|
+
parseConcurrency: deadCodeParseConcurrency,
|
|
74935
|
+
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs,
|
|
74936
|
+
onCacheOutcome: (didHitCache) => {
|
|
74937
|
+
deadCodeCacheHit = didHitCache;
|
|
74938
|
+
},
|
|
74939
|
+
onSummaryCacheStats: (stats) => {
|
|
74940
|
+
deadCodeSummaryCacheHits = stats.hits;
|
|
74941
|
+
deadCodeSummaryCacheMisses = stats.misses;
|
|
74942
|
+
}
|
|
74943
|
+
}).pipe(filter((diagnostic) => input.retainExcludedProjectDeadCodeDiagnostics === true || !isExcludedProjectDiagnostic(diagnostic)), catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
74944
|
+
yield* set(deadCodeFailure, {
|
|
74945
|
+
didFail: true,
|
|
74946
|
+
reason: error.message
|
|
74947
|
+
});
|
|
74948
|
+
return empty$4;
|
|
74949
|
+
}))))));
|
|
74950
|
+
const phaseTimeoutMs = deadCodeTimeout.phaseTimeoutMs;
|
|
74951
|
+
if (phaseTimeoutMs === null) return collectDeadCode;
|
|
74952
|
+
return collectDeadCode.pipe(timeoutOption(phaseTimeoutMs), flatMap$2(match$3({
|
|
74953
|
+
onNone: () => set(deadCodeFailure, {
|
|
74954
|
+
didFail: true,
|
|
74955
|
+
reason: `Dead-code analysis exceeded ${Math.round(phaseTimeoutMs / MILLISECONDS_PER_SECOND)}s and was skipped.`
|
|
74956
|
+
}).pipe(as([])),
|
|
74957
|
+
onSome: succeed$2
|
|
74958
|
+
})));
|
|
74959
|
+
};
|
|
74577
74960
|
const overlapDeadCodeTimeout = resolveDeadCodeTimeout({
|
|
74578
|
-
sourceFileCount:
|
|
74961
|
+
sourceFileCount: deadCodeSourceFileCount,
|
|
74579
74962
|
deadCodeConcurrency: deadCodeParseConcurrency ?? scanConcurrency,
|
|
74580
74963
|
fullConcurrency: scanConcurrency
|
|
74581
74964
|
});
|
|
74582
74965
|
const deadCodeFiber = shouldOverlapDeadCode ? yield* forkChild(buildCollectDeadCode({
|
|
74583
74966
|
workerTimeoutMs: overlapDeadCodeTimeout.workerTimeoutMs,
|
|
74584
|
-
phaseTimeoutMs:
|
|
74967
|
+
phaseTimeoutMs: capOptionalToDeadline(deadCodePhaseTimeoutMs)
|
|
74585
74968
|
})) : null;
|
|
74586
74969
|
const scanProgress = yield* progressService.start("Scanning...");
|
|
74587
74970
|
const scanStartTime = Date.now();
|
|
@@ -74632,7 +75015,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74632
75015
|
});
|
|
74633
75016
|
return empty$4;
|
|
74634
75017
|
}))));
|
|
74635
|
-
const
|
|
75018
|
+
const collectLintDiagnostics = runCollect(filterPerElementPipeline(shouldOverlapDeadCode ? baseLintStream.pipe(provideService(OxlintConcurrency, lintConcurrency)) : baseLintStream));
|
|
75019
|
+
const lintCollected = dedupeRelatedDiagnostics(yield* lintPhaseTimeoutMs === null ? collectLintDiagnostics : collectLintDiagnostics.pipe(timeoutOption(lintPhaseTimeoutMs), flatMap$2(match$3({
|
|
74636
75020
|
onNone: () => set(lintFailure, {
|
|
74637
75021
|
didFail: true,
|
|
74638
75022
|
reason: `Lint analysis exceeded ${lintPhaseTimeoutMs / MILLISECONDS_PER_SECOND}s and was skipped.`,
|
|
@@ -74662,13 +75046,13 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74662
75046
|
} else {
|
|
74663
75047
|
yield* scanProgress.update(`Scanned ${scannedFilesLabel}, analyzing dead code...`);
|
|
74664
75048
|
const sequentialDeadCodeTimeout = resolveDeadCodeTimeout({
|
|
74665
|
-
sourceFileCount: totalFileCount,
|
|
75049
|
+
sourceFileCount: input.retainExcludedProjectDeadCodeDiagnostics === true ? deadCodeSourceFileCount : totalFileCount,
|
|
74666
75050
|
deadCodeConcurrency: scanConcurrency,
|
|
74667
75051
|
fullConcurrency: scanConcurrency
|
|
74668
75052
|
});
|
|
74669
75053
|
deadCodeCollected = deadCodeFiber !== null ? yield* join(deadCodeFiber) : yield* buildCollectDeadCode({
|
|
74670
75054
|
workerTimeoutMs: sequentialDeadCodeTimeout.workerTimeoutMs,
|
|
74671
|
-
phaseTimeoutMs:
|
|
75055
|
+
phaseTimeoutMs: capOptionalToDeadline(deadCodePhaseTimeoutMs)
|
|
74672
75056
|
});
|
|
74673
75057
|
}
|
|
74674
75058
|
const deadCodeFailureState = lintFailureState.didFail ? {
|
|
@@ -74712,7 +75096,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74712
75096
|
metadata: scoreMetadata
|
|
74713
75097
|
});
|
|
74714
75098
|
const lintPartialFailures = yield* get$2(partialFailuresRef);
|
|
74715
|
-
const
|
|
75099
|
+
const didSecurityScanFail = yield* get$2(securityScanFailedRef);
|
|
75100
|
+
const securityScanFailed = didSecurityScanFail || didSecurityScanReachDeadline;
|
|
75101
|
+
let securityScanFailureReason = null;
|
|
75102
|
+
if (didSecurityScanReachDeadline) securityScanFailureReason = "Security scan reached the max scan duration; findings collected before the deadline were preserved.";
|
|
75103
|
+
else if (didSecurityScanFail) securityScanFailureReason = "Security scan failed and was skipped.";
|
|
74716
75104
|
return {
|
|
74717
75105
|
project,
|
|
74718
75106
|
userConfig: resolvedConfig.config,
|
|
@@ -74735,6 +75123,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74735
75123
|
scanConcurrency,
|
|
74736
75124
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
74737
75125
|
securityScanFailed,
|
|
75126
|
+
securityScanFailureReason,
|
|
74738
75127
|
lintCacheHitFileCount,
|
|
74739
75128
|
lintCacheTotalFileCount,
|
|
74740
75129
|
lintSidecarReplayedFileCount,
|
|
@@ -74750,7 +75139,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
74750
75139
|
"inspect.runDeadCode": input.runDeadCode,
|
|
74751
75140
|
"inspect.isCi": input.isCi,
|
|
74752
75141
|
"inspect.scoreSurface": input.scoreSurface ?? "score"
|
|
74753
|
-
} }), (scanProgram) => flatMap$2(ScanDeadlineMs, (scanDeadlineMs) =>
|
|
75142
|
+
} }), (scanProgram) => flatMap$2(ScanDeadlineMs, (scanDeadlineMs) => {
|
|
75143
|
+
if (scanDeadlineMs === null) return scanProgram;
|
|
75144
|
+
return scanProgram.pipe(timeout(scanDeadlineMs), catchTag$1("TimeoutError", () => new ReactDoctorError({ reason: new ScanDeadlineExceeded({ detail: `${scanDeadlineMs / MILLISECONDS_PER_SECOND}s elapsed` }) })));
|
|
75145
|
+
}));
|
|
74754
75146
|
const parseNodeVersion = (versionString) => {
|
|
74755
75147
|
const [major = 0, minor = 0, patch = 0] = versionString.replace(/^v/, "").trim().split(".").map(Number);
|
|
74756
75148
|
return {
|
|
@@ -74851,16 +75243,6 @@ const resolveNodeForOxlint = () => {
|
|
|
74851
75243
|
});
|
|
74852
75244
|
});
|
|
74853
75245
|
/**
|
|
74854
|
-
* Zip-Slip defense: relative paths come from git (`diff --name-only`), which
|
|
74855
|
-
* normalizes during ordinary adds, but a crafted index/pack/symlinked tree can
|
|
74856
|
-
* smuggle `..` segments that escape the temp root. Resolve against the temp dir
|
|
74857
|
-
* and reject anything that lands outside before writing.
|
|
74858
|
-
*/
|
|
74859
|
-
const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
74860
|
-
const relative = path.relative(parentAbsolutePath, childAbsolutePath);
|
|
74861
|
-
return Boolean(relative) && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
74862
|
-
};
|
|
74863
|
-
/**
|
|
74864
75246
|
* Writes a set of source files (supplied by `readContent` — e.g.
|
|
74865
75247
|
* `git show <ref>:<path>` for a baseline tree, or `git show :<path>` for the
|
|
74866
75248
|
* index) into a temp tree that mirrors the project layout, copying the
|
|
@@ -74896,7 +75278,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
74896
75278
|
const sourcePath = path.join(input.directory, subdirectory, configFilename);
|
|
74897
75279
|
const targetPath = path.resolve(resolvedTempDirectory, subdirectory, configFilename);
|
|
74898
75280
|
if (!isPathInsideDirectory(targetPath, resolvedTempDirectory)) continue;
|
|
74899
|
-
if (
|
|
75281
|
+
if (isFile(sourcePath) && !fs.existsSync(targetPath)) {
|
|
74900
75282
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
74901
75283
|
fs.cpSync(sourcePath, targetPath);
|
|
74902
75284
|
}
|
|
@@ -75135,6 +75517,7 @@ const buildJsonReport = (input) => {
|
|
|
75135
75517
|
directory: input.directory,
|
|
75136
75518
|
diff: toJsonDiff(input.diff),
|
|
75137
75519
|
projects,
|
|
75520
|
+
...input.skippedProjects && input.skippedProjects.length > 0 ? { skippedProjects: [...input.skippedProjects] } : {},
|
|
75138
75521
|
diagnostics: flattenedDiagnostics,
|
|
75139
75522
|
summary,
|
|
75140
75523
|
elapsedMilliseconds: input.totalElapsedMilliseconds,
|
|
@@ -75159,7 +75542,7 @@ const buildSkippedChecks = (input) => {
|
|
|
75159
75542
|
else if (input.lintPartialFailures.length > 0) skippedCheckReasons["lint:partial"] = input.lintPartialFailures.join("; ");
|
|
75160
75543
|
if (input.didDeadCodeFail && input.deadCodeFailureReason !== null) skippedCheckReasons["dead-code"] = input.deadCodeFailureReason;
|
|
75161
75544
|
if (input.supplyChainOverlapTimedOut) skippedCheckReasons["supply-chain"] = "Supply-chain analysis timed out and was skipped.";
|
|
75162
|
-
if (input.securityScanFailed) skippedCheckReasons["security-scan"] = "Security scan failed and was skipped.";
|
|
75545
|
+
if (input.securityScanFailed) skippedCheckReasons["security-scan"] = input.securityScanFailureReason ?? "Security scan failed and was skipped.";
|
|
75163
75546
|
return {
|
|
75164
75547
|
skippedChecks,
|
|
75165
75548
|
skippedCheckReasons
|
|
@@ -75194,14 +75577,6 @@ const getDiffInfo = (directory, explicitBaseBranch, includeUntracked) => runProm
|
|
|
75194
75577
|
};
|
|
75195
75578
|
}).pipe(provide(Git.layerNode)));
|
|
75196
75579
|
const filterSourceFiles = (filePaths) => filePaths.filter(isLintableSourceFile);
|
|
75197
|
-
/**
|
|
75198
|
-
* Back-compat alias: the streaming pipeline holds its caches in
|
|
75199
|
-
* per-pipeline closures that are garbage-collected when the pipeline
|
|
75200
|
-
* goes out of scope, so there is nothing to clear at module scope. The
|
|
75201
|
-
* public CLI's `clearCaches()` still calls this for symmetry with the
|
|
75202
|
-
* other `clear*` helpers.
|
|
75203
|
-
*/
|
|
75204
|
-
const clearAutoSuppressionCaches = () => {};
|
|
75205
75580
|
const createLintPhaseAbortError = () => new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) });
|
|
75206
75581
|
const createOxlintSpawnSlots = (concurrency) => createWorkerSlots({
|
|
75207
75582
|
slotCount: resolveScanConcurrency(concurrency),
|
|
@@ -75214,71 +75589,47 @@ const createOxlintSpawnSlots = (concurrency) => createWorkerSlots({
|
|
|
75214
75589
|
* untouched so the loader sees the same plain object either way.
|
|
75215
75590
|
*/
|
|
75216
75591
|
const defineConfig = (config) => config;
|
|
75217
|
-
const
|
|
75218
|
-
["HF_DATASETS_CACHE", "huggingface"],
|
|
75219
|
-
["HF_HOME", "huggingface"],
|
|
75220
|
-
["HUGGINGFACE_HUB_CACHE", "huggingface"],
|
|
75221
|
-
["SPACE_ID", "huggingface-spaces"],
|
|
75222
|
-
["CUDA_VISIBLE_DEVICES", "cuda"],
|
|
75223
|
-
["NVIDIA_VISIBLE_DEVICES", "nvidia"],
|
|
75224
|
-
["ROCR_VISIBLE_DEVICES", "rocm"],
|
|
75225
|
-
["TPU_NAME", "google-tpu"],
|
|
75592
|
+
const AI_TRAINING_BY_ENVIRONMENT_VARIABLE = [
|
|
75226
75593
|
["WANDB_RUN_ID", "wandb"],
|
|
75227
75594
|
["WANDB_SWEEP_ID", "wandb"],
|
|
75228
75595
|
["MLFLOW_RUN_ID", "mlflow"],
|
|
75229
|
-
["MLFLOW_TRACKING_URI", "mlflow"],
|
|
75230
75596
|
["COMET_EXPERIMENT_KEY", "comet"],
|
|
75231
75597
|
["NEPTUNE_RUN_ID", "neptune"],
|
|
75232
75598
|
["CLEARML_TASK_ID", "clearml"],
|
|
75233
75599
|
["DVC_STAGE", "dvc"],
|
|
75234
75600
|
["RAY_WORKER_PROCESS", "ray"],
|
|
75235
|
-
["RAY_ADDRESS", "ray"],
|
|
75236
|
-
["MUJOCO_GL", "mujoco"],
|
|
75237
|
-
["MUJOCO_PATH", "mujoco"],
|
|
75238
|
-
["GYM_DISABLE_ENV_CHECKER", "gymnasium"],
|
|
75239
75601
|
["SM_TRAINING_ENV", "sagemaker"],
|
|
75240
75602
|
["TRAINING_JOB_ARN", "sagemaker"],
|
|
75241
|
-
["SAGEMAKER_BASE_DIR", "sagemaker"],
|
|
75242
75603
|
["AZUREML_RUN_ID", "azure-ml"],
|
|
75243
|
-
["AZURE_ML_MODEL_DIR", "azure-ml"],
|
|
75244
|
-
["CLOUD_ML_PROJECT_ID", "vertex-ai"],
|
|
75245
|
-
["VERTEX_AI_LOG_LEVEL", "vertex-ai"],
|
|
75246
|
-
["DET_MASTER", "determined-ai"],
|
|
75247
|
-
["LIGHTNING_USER_ID", "lightning-ai"],
|
|
75248
75604
|
["FLYTE_INTERNAL_EXECUTION_ID", "flyte"],
|
|
75249
|
-
["ARGO_WORKFLOW_NAME", "argo-workflows"],
|
|
75250
75605
|
["KFP_POD_NAME", "kubeflow-pipelines"],
|
|
75251
75606
|
["KAGGLE_KERNEL_RUN_TYPE", "kaggle"],
|
|
75252
75607
|
["COLAB_BACKEND_VERSION", "google-colab"],
|
|
75253
|
-
["DATABRICKS_RUNTIME_VERSION", "databricks"],
|
|
75254
75608
|
["DAYTONA_WS_ID", "daytona"],
|
|
75255
|
-
["DAYTONA_WS_NAME", "daytona"],
|
|
75256
75609
|
["E2B_SANDBOX_ID", "e2b"],
|
|
75257
75610
|
["MODAL_FUNCTION_ID", "modal"],
|
|
75258
75611
|
["MODAL_TASK_ID", "modal"],
|
|
75259
75612
|
["RUNPOD_POD_ID", "runpod"],
|
|
75260
|
-
["REPLICATE_USERNAME", "replicate"],
|
|
75261
75613
|
["VAST_CONTAINERLABEL", "vast-ai"],
|
|
75262
|
-
["HARBOR_URL", "harbor"],
|
|
75263
|
-
["HARBOR_HOSTNAME", "harbor"],
|
|
75264
75614
|
["SWE_BENCH_TASK", "swe-bench"],
|
|
75265
75615
|
["SWEBENCH_TASK", "swe-bench"],
|
|
75266
75616
|
["SWE_AGENT_MODEL", "swe-agent"]
|
|
75267
75617
|
];
|
|
75268
|
-
const detectAiTrainingEnvironment = () => {
|
|
75269
|
-
for (const [
|
|
75618
|
+
const detectAiTrainingEnvironment = (environment = process.env) => {
|
|
75619
|
+
for (const [environmentVariable, label] of AI_TRAINING_BY_ENVIRONMENT_VARIABLE) if (environment[environmentVariable]?.trim()) return label;
|
|
75270
75620
|
return null;
|
|
75271
75621
|
};
|
|
75272
|
-
const
|
|
75622
|
+
const stringValues = (values) => Array.isArray(values) ? values.filter((value) => typeof value === "string") : [];
|
|
75623
|
+
const unionValues = (baseValues, overrideValues) => [...new Set([...stringValues(baseValues), ...stringValues(overrideValues)])];
|
|
75273
75624
|
const mergeIgnores = (baseIgnore, overrideIgnore) => {
|
|
75274
75625
|
const mergedIgnore = {
|
|
75275
75626
|
...baseIgnore,
|
|
75276
75627
|
...overrideIgnore
|
|
75277
75628
|
};
|
|
75278
|
-
if (baseIgnore.rules
|
|
75279
|
-
if (baseIgnore.files
|
|
75280
|
-
if (baseIgnore.tags
|
|
75281
|
-
if (baseIgnore.overrides
|
|
75629
|
+
if (baseIgnore.rules !== void 0 || overrideIgnore.rules !== void 0) mergedIgnore.rules = unionValues(baseIgnore.rules, overrideIgnore.rules);
|
|
75630
|
+
if (baseIgnore.files !== void 0 || overrideIgnore.files !== void 0) mergedIgnore.files = unionValues(baseIgnore.files, overrideIgnore.files);
|
|
75631
|
+
if (baseIgnore.tags !== void 0 || overrideIgnore.tags !== void 0) mergedIgnore.tags = unionValues(baseIgnore.tags, overrideIgnore.tags);
|
|
75632
|
+
if (baseIgnore.overrides !== void 0 || overrideIgnore.overrides !== void 0) mergedIgnore.overrides = [...Array.isArray(baseIgnore.overrides) ? baseIgnore.overrides : [], ...Array.isArray(overrideIgnore.overrides) ? overrideIgnore.overrides : []];
|
|
75282
75633
|
return mergedIgnore;
|
|
75283
75634
|
};
|
|
75284
75635
|
/**
|
|
@@ -75460,7 +75811,6 @@ const clearCaches = () => {
|
|
|
75460
75811
|
clearPackageJsonCache();
|
|
75461
75812
|
clearIgnorePatternsCache();
|
|
75462
75813
|
clearPackageRoleCache();
|
|
75463
|
-
clearAutoSuppressionCaches();
|
|
75464
75814
|
clearMinifiedFileCache();
|
|
75465
75815
|
};
|
|
75466
75816
|
const toJsonReport = (result, options) => buildJsonReport({
|
|
@@ -75487,4 +75837,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
75487
75837
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
75488
75838
|
|
|
75489
75839
|
//# sourceMappingURL=index.js.map
|
|
75490
|
-
//# debugId=
|
|
75840
|
+
//# debugId=8d6e3c06-44f8-589f-8e07-aaa4704b6112
|