react-doctor 0.5.8-dev.c2ce298 → 0.5.8-dev.e2393c4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +14 -1
- package/README.md +9 -3
- package/dist/cli.js +9326 -1434
- package/dist/index.d.ts +11 -2
- package/dist/index.js +260 -69
- package/dist/lsp.js +204 -70
- package/package.json +9 -7
package/dist/index.d.ts
CHANGED
|
@@ -9271,6 +9271,15 @@ interface ReactDoctorConfig {
|
|
|
9271
9271
|
* suppresses regardless of sibling content.
|
|
9272
9272
|
*/
|
|
9273
9273
|
rawTextWrapperComponents?: string[];
|
|
9274
|
+
/**
|
|
9275
|
+
* Capitalized identifiers that exist at runtime but aren't imported in
|
|
9276
|
+
* the file that uses them — react-live's `<LiveProvider scope={...}>`,
|
|
9277
|
+
* Storybook globals, MDX live blocks, or an ambient `declare global` in a
|
|
9278
|
+
* separate `.d.ts`. The single-file `jsx-no-undef` rule can't see those
|
|
9279
|
+
* bindings and would report `<DatePicker />` as an undefined JSX component.
|
|
9280
|
+
* List the injected names here and `jsx-no-undef` treats them as known.
|
|
9281
|
+
*/
|
|
9282
|
+
runtimeGlobals?: string[];
|
|
9274
9283
|
/**
|
|
9275
9284
|
* Project-level allowlist of function names that the
|
|
9276
9285
|
* `server-auth-actions` rule treats as an auth check at the top of
|
|
@@ -9726,7 +9735,7 @@ interface InspectResult {
|
|
|
9726
9735
|
* Per-file lint cache outcome: files served from cache, and total files
|
|
9727
9736
|
* considered. Both absent when the cache was off or bypassed (audit mode,
|
|
9728
9737
|
* adopted `extends`, user plugins). The CLI projects these onto the Sentry
|
|
9729
|
-
* wide event as `
|
|
9738
|
+
* wide event as `lint.cacheHitRatio`.
|
|
9730
9739
|
*/
|
|
9731
9740
|
lintCacheHitFileCount?: number | null;
|
|
9732
9741
|
lintCacheTotalFileCount?: number | null;
|
|
@@ -10123,7 +10132,7 @@ declare const summarizeDiagnostics: (diagnostics: Diagnostic[], worstScore?: num
|
|
|
10123
10132
|
* untouched so the loader sees the same plain object either way.
|
|
10124
10133
|
*/
|
|
10125
10134
|
declare const defineConfig: (config: ReactDoctorConfig) => ReactDoctorConfig; //#endregion
|
|
10126
|
-
//#region src/utils/
|
|
10135
|
+
//#region src/utils/detect-ai-training-environment.d.ts
|
|
10127
10136
|
//#endregion
|
|
10128
10137
|
//#region ../api/dist/index.d.ts
|
|
10129
10138
|
//#region src/diagnose.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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]="1e049c6a-27f7-5c62-8be8-57ce0b987f6f")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as NFS from "node:fs";
|
|
@@ -5996,7 +5996,7 @@ const composePassthrough = /* @__PURE__ */ dual(2, (left, right) => (input) => {
|
|
|
5996
5996
|
* @since 2.0.0
|
|
5997
5997
|
*/
|
|
5998
5998
|
const Scheduler = /* @__PURE__ */ Reference("effect/Scheduler", { defaultValue: () => new MixedScheduler() });
|
|
5999
|
-
const setImmediate = "setImmediate" in globalThis ? (f) => {
|
|
5999
|
+
const setImmediate$1 = "setImmediate" in globalThis ? (f) => {
|
|
6000
6000
|
const timer = globalThis.setImmediate(f);
|
|
6001
6001
|
return () => globalThis.clearImmediate(timer);
|
|
6002
6002
|
} : (f) => {
|
|
@@ -6040,7 +6040,7 @@ var PriorityBuckets = class {
|
|
|
6040
6040
|
var MixedScheduler = class {
|
|
6041
6041
|
executionMode;
|
|
6042
6042
|
setImmediate;
|
|
6043
|
-
constructor(executionMode = "async", setImmediateFn = setImmediate) {
|
|
6043
|
+
constructor(executionMode = "async", setImmediateFn = setImmediate$1) {
|
|
6044
6044
|
this.executionMode = executionMode;
|
|
6045
6045
|
this.setImmediate = setImmediateFn;
|
|
6046
6046
|
}
|
|
@@ -6065,7 +6065,7 @@ var MixedSchedulerDispatcher = class {
|
|
|
6065
6065
|
tasks = /* @__PURE__ */ new PriorityBuckets();
|
|
6066
6066
|
running = void 0;
|
|
6067
6067
|
setImmediate;
|
|
6068
|
-
constructor(setImmediateFn = setImmediate) {
|
|
6068
|
+
constructor(setImmediateFn = setImmediate$1) {
|
|
6069
6069
|
this.setImmediate = setImmediateFn;
|
|
6070
6070
|
}
|
|
6071
6071
|
/**
|
|
@@ -33694,6 +33694,7 @@ const MILLISECONDS_PER_SECOND = 1e3;
|
|
|
33694
33694
|
const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
33695
33695
|
const FETCH_TIMEOUT_MS = 1e4;
|
|
33696
33696
|
const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
|
|
33697
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
|
|
33697
33698
|
const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
|
|
33698
33699
|
const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
|
|
33699
33700
|
const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
|
|
@@ -33751,6 +33752,7 @@ const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
|
33751
33752
|
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
33752
33753
|
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
33753
33754
|
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
33755
|
+
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
33754
33756
|
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
33755
33757
|
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
33756
33758
|
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
@@ -34997,6 +34999,7 @@ const collectStringSet = (values) => {
|
|
|
34997
34999
|
if (!Array.isArray(values)) return /* @__PURE__ */ new Set();
|
|
34998
35000
|
return new Set(values.filter((value) => typeof value === "string"));
|
|
34999
35001
|
};
|
|
35002
|
+
const JSX_NO_UNDEF_IDENTIFIER_PATTERN = /^`([^`]+)`/;
|
|
35000
35003
|
/**
|
|
35001
35004
|
* Pre-compiles every stateful filter and returns a single
|
|
35002
35005
|
* `apply(diagnostic)` closure that runs (in order):
|
|
@@ -35030,8 +35033,10 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
35030
35033
|
const compiledOverrides = compileIgnoreOverrides(userConfig);
|
|
35031
35034
|
const textComponentNames = collectStringSet(userConfig?.textComponents);
|
|
35032
35035
|
const rawTextWrapperComponentNames = collectStringSet(userConfig?.rawTextWrapperComponents);
|
|
35036
|
+
const runtimeGlobalNames = collectStringSet(userConfig?.runtimeGlobals);
|
|
35033
35037
|
const hasTextComponents = textComponentNames.size > 0;
|
|
35034
35038
|
const hasRawTextWrappers = rawTextWrapperComponentNames.size > 0;
|
|
35039
|
+
const hasRuntimeGlobals = runtimeGlobalNames.size > 0;
|
|
35035
35040
|
const fileLinesCache = /* @__PURE__ */ new Map();
|
|
35036
35041
|
const fileContextCache = /* @__PURE__ */ new Map();
|
|
35037
35042
|
const libraryFileCache = /* @__PURE__ */ new Map();
|
|
@@ -35083,6 +35088,12 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
35083
35088
|
if (hasRawTextWrappers && isInsideStringOnlyWrapper(lines, diagnostic.line, diagnostic.column, rawTextWrapperComponentNames)) return true;
|
|
35084
35089
|
return false;
|
|
35085
35090
|
};
|
|
35091
|
+
const isJsxNoUndefSuppressedByConfig = (diagnostic) => {
|
|
35092
|
+
if (!hasRuntimeGlobals) return false;
|
|
35093
|
+
if (diagnostic.rule !== "jsx-no-undef") return false;
|
|
35094
|
+
const identifierMatch = JSX_NO_UNDEF_IDENTIFIER_PATTERN.exec(diagnostic.message);
|
|
35095
|
+
return identifierMatch !== null && runtimeGlobalNames.has(identifierMatch[1]);
|
|
35096
|
+
};
|
|
35086
35097
|
return { apply: (diagnostic) => {
|
|
35087
35098
|
if (shouldAutoSuppress(diagnostic)) return null;
|
|
35088
35099
|
let current = diagnostic;
|
|
@@ -35107,6 +35118,7 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
35107
35118
|
if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
|
|
35108
35119
|
if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return null;
|
|
35109
35120
|
if (isRnRawTextSuppressedByConfig(current)) return null;
|
|
35121
|
+
if (isJsxNoUndefSuppressedByConfig(current)) return null;
|
|
35110
35122
|
}
|
|
35111
35123
|
if (respectInlineDisables && current.line > 0) {
|
|
35112
35124
|
const lines = getFileLines(current.filePath);
|
|
@@ -35368,7 +35380,7 @@ const resolveScanConcurrency = (requested) => {
|
|
|
35368
35380
|
if (!Number.isFinite(requested) || requested < 1) return 1;
|
|
35369
35381
|
return Math.min(Math.floor(requested), 32);
|
|
35370
35382
|
};
|
|
35371
|
-
const readSystemFacts = () => ({
|
|
35383
|
+
const readSystemFacts$1 = () => ({
|
|
35372
35384
|
availableCores: os.availableParallelism(),
|
|
35373
35385
|
totalMemoryBytes: os.totalmem(),
|
|
35374
35386
|
cgroupMemoryLimitBytes: readCgroupMemoryLimitBytes()
|
|
@@ -35389,7 +35401,7 @@ const readSystemFacts = () => ({
|
|
|
35389
35401
|
* `facts` is injectable so tests exercise core-bound, memory-bound, cgroup-
|
|
35390
35402
|
* limited, and ceiling cases without mocking `os` or the filesystem.
|
|
35391
35403
|
*/
|
|
35392
|
-
const resolveAutoScanConcurrency = (facts = readSystemFacts()) => {
|
|
35404
|
+
const resolveAutoScanConcurrency = (facts = readSystemFacts$1()) => {
|
|
35393
35405
|
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
35394
35406
|
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / PER_WORKER_MEM_BUDGET_BYTES);
|
|
35395
35407
|
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
@@ -35580,6 +35592,13 @@ const BOOLEAN_FIELD_NAMES = [
|
|
|
35580
35592
|
"adoptExistingLintConfig"
|
|
35581
35593
|
];
|
|
35582
35594
|
const STRING_FIELD_NAMES = ["rootDir"];
|
|
35595
|
+
const STRING_ARRAY_FIELD_NAMES = [
|
|
35596
|
+
"projects",
|
|
35597
|
+
"textComponents",
|
|
35598
|
+
"rawTextWrapperComponents",
|
|
35599
|
+
"runtimeGlobals",
|
|
35600
|
+
"serverAuthFunctionNames"
|
|
35601
|
+
];
|
|
35583
35602
|
const SURFACE_CONTROL_FIELD_NAMES = [
|
|
35584
35603
|
"includeTags",
|
|
35585
35604
|
"excludeTags",
|
|
@@ -35681,6 +35700,7 @@ const validateConfigTypes = (config) => {
|
|
|
35681
35700
|
const validated = { ...config };
|
|
35682
35701
|
for (const fieldName of BOOLEAN_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => coerceMaybeBooleanString(fieldName, value));
|
|
35683
35702
|
for (const fieldName of STRING_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateString(fieldName, value));
|
|
35703
|
+
for (const fieldName of STRING_ARRAY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateStringArrayField(fieldName, value));
|
|
35684
35704
|
applyFieldValidator(config, validated, "surfaces", validateSurfacesField);
|
|
35685
35705
|
for (const fieldName of SEVERITY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateSeverityMap(fieldName, value, fieldName === "categories"));
|
|
35686
35706
|
applyFieldValidator(config, validated, "plugins", (value) => validateStringArrayField("plugins", value));
|
|
@@ -36915,7 +36935,10 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledBy)
|
|
|
36915
36935
|
}
|
|
36916
36936
|
return true;
|
|
36917
36937
|
};
|
|
36918
|
-
const
|
|
36938
|
+
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
36939
|
+
setImmediate(resolve);
|
|
36940
|
+
});
|
|
36941
|
+
const createSecurityScanSession = (rootDirectory, options) => {
|
|
36919
36942
|
const capabilities = options.project ? buildCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
36920
36943
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
36921
36944
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
@@ -36930,7 +36953,7 @@ const checkSecurityScan = (rootDirectory, options = {}) => {
|
|
|
36930
36953
|
committedFilesOnly: rule.committedFilesOnly === true
|
|
36931
36954
|
}];
|
|
36932
36955
|
});
|
|
36933
|
-
if (enabledScanRules.length === 0) return
|
|
36956
|
+
if (enabledScanRules.length === 0) return null;
|
|
36934
36957
|
const diagnostics = [];
|
|
36935
36958
|
const seen = /* @__PURE__ */ new Set();
|
|
36936
36959
|
const gitIgnoredCache = /* @__PURE__ */ new Map();
|
|
@@ -36942,15 +36965,34 @@ const checkSecurityScan = (rootDirectory, options = {}) => {
|
|
|
36942
36965
|
}
|
|
36943
36966
|
return status === true;
|
|
36944
36967
|
};
|
|
36945
|
-
|
|
36946
|
-
|
|
36947
|
-
|
|
36948
|
-
|
|
36949
|
-
|
|
36950
|
-
|
|
36951
|
-
|
|
36968
|
+
const scanFile = (file) => {
|
|
36969
|
+
for (const { entry, scan, committedFilesOnly } of enabledScanRules) for (const finding of scan(file)) {
|
|
36970
|
+
if (committedFilesOnly && isFileGitIgnored(file)) continue;
|
|
36971
|
+
const diagnostic = buildSecurityScanDiagnostic(finding, entry, file.relativePath);
|
|
36972
|
+
const key = `${diagnostic.rule}:${diagnostic.filePath}:${diagnostic.line}:${diagnostic.column}:${diagnostic.message}`;
|
|
36973
|
+
if (seen.has(key)) continue;
|
|
36974
|
+
seen.add(key);
|
|
36975
|
+
diagnostics.push(diagnostic);
|
|
36976
|
+
}
|
|
36977
|
+
};
|
|
36978
|
+
return {
|
|
36979
|
+
scanFile,
|
|
36980
|
+
diagnostics
|
|
36981
|
+
};
|
|
36982
|
+
};
|
|
36983
|
+
const checkSecurityScanCooperative = async (rootDirectory, options = {}) => {
|
|
36984
|
+
const session = createSecurityScanSession(rootDirectory, options);
|
|
36985
|
+
if (session === null) return [];
|
|
36986
|
+
let filesSinceYield = 0;
|
|
36987
|
+
for (const file of collectSecurityScanFiles(rootDirectory)) {
|
|
36988
|
+
session.scanFile(file);
|
|
36989
|
+
filesSinceYield += 1;
|
|
36990
|
+
if (filesSinceYield >= 16) {
|
|
36991
|
+
filesSinceYield = 0;
|
|
36992
|
+
await yieldToEventLoop();
|
|
36993
|
+
}
|
|
36952
36994
|
}
|
|
36953
|
-
return diagnostics;
|
|
36995
|
+
return session.diagnostics;
|
|
36954
36996
|
};
|
|
36955
36997
|
var import_picocolors = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
36956
36998
|
let p = process || {}, argv = p.argv || [], env = p.env || {};
|
|
@@ -37167,6 +37209,74 @@ const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
|
37167
37209
|
return [...seen].filter((pattern) => pattern.length > 0);
|
|
37168
37210
|
};
|
|
37169
37211
|
const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
|
|
37212
|
+
const readSystemFacts = () => ({
|
|
37213
|
+
availableCores: os.availableParallelism(),
|
|
37214
|
+
totalMemoryBytes: os.totalmem(),
|
|
37215
|
+
cgroupMemoryLimitBytes: readCgroupMemoryLimitBytes()
|
|
37216
|
+
});
|
|
37217
|
+
/**
|
|
37218
|
+
* How many real deslop dead-code child processes may run at once, across the
|
|
37219
|
+
* concurrent per-project `runInspect` fibers of one CLI run. The cap is the
|
|
37220
|
+
* smaller of the core count and the number of `DEAD_CODE_WORKER_MEM_BUDGET_BYTES`
|
|
37221
|
+
* workers that fit in available memory, floored at 1.
|
|
37222
|
+
*
|
|
37223
|
+
* On a roomy dev box / CI runner this resolves high enough that every
|
|
37224
|
+
* concurrently-scanned project still spawns its own worker (no serialization vs
|
|
37225
|
+
* the prior uncapped behavior); on a memory-constrained runner it collapses
|
|
37226
|
+
* toward 1, so the `withDeadCodeWorkerSlot` semaphore serializes the spawns
|
|
37227
|
+
* instead of oversubscribing memory with N simultaneous children — the global
|
|
37228
|
+
* cap the per-project spawn path lacked.
|
|
37229
|
+
*
|
|
37230
|
+
* Mirrors `resolveAutoScanConcurrency` (lint), but budgets memory per the
|
|
37231
|
+
* heavier dead-code worker. `facts` is injectable for tests.
|
|
37232
|
+
*/
|
|
37233
|
+
const resolveDeadCodeConcurrency = (facts = readSystemFacts()) => {
|
|
37234
|
+
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
37235
|
+
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / DEAD_CODE_WORKER_MEM_BUDGET_BYTES);
|
|
37236
|
+
return Math.max(1, Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
37237
|
+
};
|
|
37238
|
+
let availableSlots = -1;
|
|
37239
|
+
const waiters = [];
|
|
37240
|
+
const releaseSlot = () => {
|
|
37241
|
+
const nextWaiter = waiters.shift();
|
|
37242
|
+
if (nextWaiter !== void 0) nextWaiter();
|
|
37243
|
+
else availableSlots += 1;
|
|
37244
|
+
};
|
|
37245
|
+
/**
|
|
37246
|
+
* Runs `task` once a dead-code worker slot is free, releasing the slot when the
|
|
37247
|
+
* task settles (success or failure). With a high cap (roomy machine) every
|
|
37248
|
+
* caller proceeds immediately; with a low cap (constrained runner) callers
|
|
37249
|
+
* queue and run as slots free.
|
|
37250
|
+
*
|
|
37251
|
+
* `abortSignal` short-circuits the WAIT: if it's already aborted, or fires while
|
|
37252
|
+
* this caller is queued, the call rejects without acquiring a slot or running
|
|
37253
|
+
* `task` — so a cancelled scan (e.g. lint failed) doesn't sit in the queue and
|
|
37254
|
+
* then spawn a child only to tear it down. A queued caller that aborts removes
|
|
37255
|
+
* its own waiter so a later release never hands a slot to a dead request.
|
|
37256
|
+
*/
|
|
37257
|
+
const withDeadCodeWorkerSlot = async (task, abortSignal) => {
|
|
37258
|
+
if (abortSignal?.aborted) throw new Error("Dead-code worker aborted.");
|
|
37259
|
+
if (availableSlots < 0) availableSlots = resolveDeadCodeConcurrency();
|
|
37260
|
+
if (availableSlots > 0) availableSlots -= 1;
|
|
37261
|
+
else await new Promise((resolve, reject) => {
|
|
37262
|
+
const waiter = () => {
|
|
37263
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
37264
|
+
resolve();
|
|
37265
|
+
};
|
|
37266
|
+
const onAbort = () => {
|
|
37267
|
+
const queuedIndex = waiters.indexOf(waiter);
|
|
37268
|
+
if (queuedIndex !== -1) waiters.splice(queuedIndex, 1);
|
|
37269
|
+
reject(/* @__PURE__ */ new Error("Dead-code worker aborted."));
|
|
37270
|
+
};
|
|
37271
|
+
waiters.push(waiter);
|
|
37272
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
37273
|
+
});
|
|
37274
|
+
try {
|
|
37275
|
+
return await task();
|
|
37276
|
+
} finally {
|
|
37277
|
+
releaseSlot();
|
|
37278
|
+
}
|
|
37279
|
+
};
|
|
37170
37280
|
/**
|
|
37171
37281
|
* Resolves a path to its canonical, symlink-free form, falling back to
|
|
37172
37282
|
* the input when it cannot be realpath'd (broken symlink, permission
|
|
@@ -37191,6 +37301,11 @@ const toCanonicalPath = (filePath) => {
|
|
|
37191
37301
|
};
|
|
37192
37302
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
37193
37303
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
37304
|
+
const REACT_DOCTOR_TOOLCHAIN_PACKAGES = new Set([
|
|
37305
|
+
"react-doctor",
|
|
37306
|
+
"eslint-plugin-react-doctor",
|
|
37307
|
+
"oxlint-plugin-react-doctor"
|
|
37308
|
+
]);
|
|
37194
37309
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
37195
37310
|
const inputChunks = [];
|
|
37196
37311
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -37457,14 +37572,17 @@ const checkDeadCode = async (options) => {
|
|
|
37457
37572
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
37458
37573
|
const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
|
|
37459
37574
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37460
|
-
const
|
|
37461
|
-
|
|
37462
|
-
|
|
37463
|
-
|
|
37464
|
-
|
|
37465
|
-
|
|
37466
|
-
|
|
37467
|
-
|
|
37575
|
+
const spawnAndRun = () => {
|
|
37576
|
+
return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
37577
|
+
rootDirectory,
|
|
37578
|
+
entryPatterns,
|
|
37579
|
+
tsConfigPath: resolveTsConfigPath(rootDirectory),
|
|
37580
|
+
ignorePatterns,
|
|
37581
|
+
deslopJsModuleSpecifier: options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js"),
|
|
37582
|
+
parseConcurrency: options.parseConcurrency
|
|
37583
|
+
}), options.workerTimeoutMs ?? 12e4, options.abortSignal);
|
|
37584
|
+
};
|
|
37585
|
+
const result = parseDeadCodeWorkerResult(options.createWorker === void 0 ? await withDeadCodeWorkerSlot(spawnAndRun, options.abortSignal) : await spawnAndRun());
|
|
37468
37586
|
const toRelative = (filePath) => toRelativeFilePath(rootDirectory, filePath);
|
|
37469
37587
|
const diagnostics = [];
|
|
37470
37588
|
for (const unusedFile of result.unusedFiles) diagnostics.push({
|
|
@@ -37493,6 +37611,7 @@ const checkDeadCode = async (options) => {
|
|
|
37493
37611
|
});
|
|
37494
37612
|
}
|
|
37495
37613
|
for (const unusedDependency of result.unusedDependencies) {
|
|
37614
|
+
if (REACT_DOCTOR_TOOLCHAIN_PACKAGES.has(unusedDependency.name)) continue;
|
|
37496
37615
|
const label = unusedDependency.isDevDependency ? "devDependency" : "dependency";
|
|
37497
37616
|
diagnostics.push({
|
|
37498
37617
|
filePath: "package.json",
|
|
@@ -37865,43 +37984,46 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37865
37984
|
* reason: GitInvocationFailed })` so the rest of the codebase
|
|
37866
37985
|
* sees a single failure channel.
|
|
37867
37986
|
*/
|
|
37868
|
-
const runCommand = (input) =>
|
|
37869
|
-
const
|
|
37870
|
-
cwd: input.directory,
|
|
37871
|
-
env: input.env,
|
|
37872
|
-
extendEnv: true
|
|
37873
|
-
}));
|
|
37874
|
-
const maxStdoutBytes = input.maxStdoutBytes;
|
|
37875
|
-
const stdoutByteCount = yield* make$13(0);
|
|
37876
|
-
const [stdout, stderr, status] = yield* all([
|
|
37877
|
-
mkString(decodeText(maxStdoutBytes === void 0 ? handle.stdout : handle.stdout.pipe(tap((chunk) => updateAndGet(stdoutByteCount, (total) => total + chunk.length).pipe(flatMap$2((total) => total > maxStdoutBytes ? fail$4(new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
37878
|
-
args: [...input.args],
|
|
37879
|
-
directory: input.directory,
|
|
37880
|
-
cause: /* @__PURE__ */ new Error(`git stdout exceeded ${maxStdoutBytes} bytes`)
|
|
37881
|
-
}) })) : void_)))))),
|
|
37882
|
-
mkString(decodeText(handle.stderr)),
|
|
37883
|
-
handle.exitCode
|
|
37884
|
-
], { concurrency: 3 });
|
|
37885
|
-
return {
|
|
37886
|
-
status,
|
|
37887
|
-
stdout,
|
|
37888
|
-
stderr
|
|
37889
|
-
};
|
|
37890
|
-
})).pipe(catchTag$1("PlatformError", (cause) => {
|
|
37891
|
-
if (input.command !== "git") return succeed$2({
|
|
37987
|
+
const runCommand = (input) => {
|
|
37988
|
+
const foldSpawnFailure = (cause) => input.command !== "git" ? succeed$2({
|
|
37892
37989
|
status: 127,
|
|
37893
37990
|
stdout: "",
|
|
37894
37991
|
stderr: String(cause)
|
|
37895
|
-
})
|
|
37896
|
-
return new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
37992
|
+
}) : fail$4(new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
37897
37993
|
args: [...input.args],
|
|
37898
37994
|
directory: input.directory,
|
|
37899
37995
|
cause
|
|
37900
|
-
}) });
|
|
37901
|
-
|
|
37902
|
-
|
|
37903
|
-
|
|
37904
|
-
|
|
37996
|
+
}) }));
|
|
37997
|
+
return scoped(gen(function* () {
|
|
37998
|
+
if (!isDirectory(input.directory)) return yield* foldSpawnFailure(`spawn ENOTDIR (cwd is not a directory: ${input.directory})`);
|
|
37999
|
+
const argvLengthChars = input.command.length + 1 + input.args.reduce((total, arg) => total + arg.length + 1, 0);
|
|
38000
|
+
if (argvLengthChars > 24e3) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${SPAWN_ARGS_MAX_LENGTH_CHARS})`);
|
|
38001
|
+
const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
|
|
38002
|
+
cwd: input.directory,
|
|
38003
|
+
env: input.env,
|
|
38004
|
+
extendEnv: true
|
|
38005
|
+
}));
|
|
38006
|
+
const maxStdoutBytes = input.maxStdoutBytes;
|
|
38007
|
+
const stdoutByteCount = yield* make$13(0);
|
|
38008
|
+
const [stdout, stderr, status] = yield* all([
|
|
38009
|
+
mkString(decodeText(maxStdoutBytes === void 0 ? handle.stdout : handle.stdout.pipe(tap((chunk) => updateAndGet(stdoutByteCount, (total) => total + chunk.length).pipe(flatMap$2((total) => total > maxStdoutBytes ? fail$4(new ReactDoctorError({ reason: new GitInvocationFailed({
|
|
38010
|
+
args: [...input.args],
|
|
38011
|
+
directory: input.directory,
|
|
38012
|
+
cause: /* @__PURE__ */ new Error(`git stdout exceeded ${maxStdoutBytes} bytes`)
|
|
38013
|
+
}) })) : void_)))))),
|
|
38014
|
+
mkString(decodeText(handle.stderr)),
|
|
38015
|
+
handle.exitCode
|
|
38016
|
+
], { concurrency: 3 });
|
|
38017
|
+
return {
|
|
38018
|
+
status,
|
|
38019
|
+
stdout,
|
|
38020
|
+
stderr
|
|
38021
|
+
};
|
|
38022
|
+
})).pipe(catchTag$1("PlatformError", foldSpawnFailure), withSpan("git.exec", { attributes: {
|
|
38023
|
+
"git.command": input.command,
|
|
38024
|
+
"git.subcommand": input.args[0] ?? ""
|
|
38025
|
+
} }));
|
|
38026
|
+
};
|
|
37905
38027
|
const runGit = (directory, args) => runCommand({
|
|
37906
38028
|
command: "git",
|
|
37907
38029
|
args,
|
|
@@ -37934,7 +38056,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37934
38056
|
"rev-parse",
|
|
37935
38057
|
"--verify",
|
|
37936
38058
|
branch
|
|
37937
|
-
]).pipe(map$3((result) => result.status === 0));
|
|
38059
|
+
]).pipe(map$3((result) => result.status === 0), catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(false) : fail$4(error)));
|
|
37938
38060
|
const headSha = (directory) => runGit(directory, ["rev-parse", "HEAD"]).pipe(map$3((result) => result.status === 0 ? trimOrNull(result.stdout) : null));
|
|
37939
38061
|
const mergeBase = (input) => isSafeGitRevision(input.ref) ? runGit(input.directory, [
|
|
37940
38062
|
"merge-base",
|
|
@@ -38148,7 +38270,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38148
38270
|
]);
|
|
38149
38271
|
if (result.status !== 0) return null;
|
|
38150
38272
|
return parseChangedLineRanges(result.stdout);
|
|
38151
|
-
}).pipe(withSpan("Git.changedLineRanges"))
|
|
38273
|
+
}).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
|
|
38152
38274
|
});
|
|
38153
38275
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
38154
38276
|
/**
|
|
@@ -39223,11 +39345,12 @@ const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
|
39223
39345
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
39224
39346
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
39225
39347
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
39348
|
+
const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
|
|
39226
39349
|
const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
|
|
39227
|
-
const buildReactCompilerMessage = (reasonSummary) => {
|
|
39350
|
+
const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
|
|
39228
39351
|
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
39229
|
-
if (!normalizedSummary) return
|
|
39230
|
-
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${
|
|
39352
|
+
if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
|
|
39353
|
+
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
|
|
39231
39354
|
};
|
|
39232
39355
|
const PLUGIN_CATEGORY_MAP = {
|
|
39233
39356
|
react: "Bugs",
|
|
@@ -39276,7 +39399,7 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
39276
39399
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
39277
39400
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
39278
39401
|
return {
|
|
39279
|
-
message: buildReactCompilerMessage(reasonSummary.trim()),
|
|
39402
|
+
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
39280
39403
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
39281
39404
|
};
|
|
39282
39405
|
}
|
|
@@ -40625,7 +40748,10 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
40625
40748
|
* diagnostics).
|
|
40626
40749
|
* 2. beforeLint hook (e.g. CLI renders the project-detection block)
|
|
40627
40750
|
* 3. environment checks (reduced-motion + pnpm hardening +
|
|
40628
|
-
* expo/react-native
|
|
40751
|
+
* expo/react-native), collected synchronously. The heavier
|
|
40752
|
+
* content-regex security scan is forked instead (like supply-chain
|
|
40753
|
+
* below) and joined before the concat, so its CPU overlaps lint
|
|
40754
|
+
* rather than blocking the event loop before it.
|
|
40629
40755
|
* 4. The supply-chain check (Socket.dev) is forked onto a background
|
|
40630
40756
|
* fiber so its ~100% network-bound time overlaps the ~100%
|
|
40631
40757
|
* CPU/subprocess-bound lint pass below, collapsing two serial
|
|
@@ -40645,7 +40771,7 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
40645
40771
|
* order, so terminal output is identical either way; supply-chain
|
|
40646
40772
|
* rides alongside without a spinner.
|
|
40647
40773
|
* 6. Join the supply-chain fiber, then assemble the diagnostics in a
|
|
40648
|
-
* FIXED order (env, supply-chain, lint, dead-code) so the output is
|
|
40774
|
+
* FIXED order (env, security-scan, supply-chain, lint, dead-code) so the output is
|
|
40649
40775
|
* byte-identical regardless of which fiber settled first. The
|
|
40650
40776
|
* viewer-permission fiber is joined later, during score-metadata
|
|
40651
40777
|
* assembly (it feeds score metadata, not diagnostics). The per-element
|
|
@@ -40706,12 +40832,12 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40706
40832
|
...checkPnpmHardening(scanDirectory),
|
|
40707
40833
|
...checkReactServerComponentsAdvisory(scanDirectory, project),
|
|
40708
40834
|
...checkExpoProject(scanDirectory, project),
|
|
40709
|
-
...checkReactNativeProject(scanDirectory, project)
|
|
40710
|
-
...checkSecurityScan(scanDirectory, {
|
|
40711
|
-
project,
|
|
40712
|
-
ignoredTags: input.ignoredTags
|
|
40713
|
-
})
|
|
40835
|
+
...checkReactNativeProject(scanDirectory, project)
|
|
40714
40836
|
])));
|
|
40837
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(promise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
40838
|
+
project,
|
|
40839
|
+
ignoredTags: input.ignoredTags
|
|
40840
|
+
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)))))).pipe(withSpan("SecurityScan.run")));
|
|
40715
40841
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
40716
40842
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
40717
40843
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
@@ -40847,9 +40973,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40847
40973
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
40848
40974
|
const supplyChainResult = yield* join(supplyChainFiber);
|
|
40849
40975
|
const supplyChainCollected = supplyChainResult.diagnostics;
|
|
40976
|
+
const securityScanCollected = yield* join(securityScanFiber);
|
|
40850
40977
|
yield* reporterService.finalize;
|
|
40851
40978
|
const finalDiagnostics = sortDiagnosticsStable(assignFixGroups([
|
|
40852
40979
|
...envCollected,
|
|
40980
|
+
...securityScanCollected,
|
|
40853
40981
|
...supplyChainCollected,
|
|
40854
40982
|
...lintCollected,
|
|
40855
40983
|
...deadCodeCollected
|
|
@@ -41301,6 +41429,61 @@ const clearAutoSuppressionCaches = () => {};
|
|
|
41301
41429
|
* untouched so the loader sees the same plain object either way.
|
|
41302
41430
|
*/
|
|
41303
41431
|
const defineConfig = (config) => config;
|
|
41432
|
+
const AI_TRAINING_ENV_VARS = [
|
|
41433
|
+
["HF_DATASETS_CACHE", "huggingface"],
|
|
41434
|
+
["HF_HOME", "huggingface"],
|
|
41435
|
+
["HUGGINGFACE_HUB_CACHE", "huggingface"],
|
|
41436
|
+
["SPACE_ID", "huggingface-spaces"],
|
|
41437
|
+
["CUDA_VISIBLE_DEVICES", "cuda"],
|
|
41438
|
+
["NVIDIA_VISIBLE_DEVICES", "nvidia"],
|
|
41439
|
+
["ROCR_VISIBLE_DEVICES", "rocm"],
|
|
41440
|
+
["TPU_NAME", "google-tpu"],
|
|
41441
|
+
["WANDB_RUN_ID", "wandb"],
|
|
41442
|
+
["WANDB_SWEEP_ID", "wandb"],
|
|
41443
|
+
["MLFLOW_RUN_ID", "mlflow"],
|
|
41444
|
+
["MLFLOW_TRACKING_URI", "mlflow"],
|
|
41445
|
+
["COMET_EXPERIMENT_KEY", "comet"],
|
|
41446
|
+
["NEPTUNE_RUN_ID", "neptune"],
|
|
41447
|
+
["CLEARML_TASK_ID", "clearml"],
|
|
41448
|
+
["DVC_STAGE", "dvc"],
|
|
41449
|
+
["RAY_WORKER_PROCESS", "ray"],
|
|
41450
|
+
["RAY_ADDRESS", "ray"],
|
|
41451
|
+
["MUJOCO_GL", "mujoco"],
|
|
41452
|
+
["MUJOCO_PATH", "mujoco"],
|
|
41453
|
+
["GYM_DISABLE_ENV_CHECKER", "gymnasium"],
|
|
41454
|
+
["SM_TRAINING_ENV", "sagemaker"],
|
|
41455
|
+
["TRAINING_JOB_ARN", "sagemaker"],
|
|
41456
|
+
["SAGEMAKER_BASE_DIR", "sagemaker"],
|
|
41457
|
+
["AZUREML_RUN_ID", "azure-ml"],
|
|
41458
|
+
["AZURE_ML_MODEL_DIR", "azure-ml"],
|
|
41459
|
+
["CLOUD_ML_PROJECT_ID", "vertex-ai"],
|
|
41460
|
+
["VERTEX_AI_LOG_LEVEL", "vertex-ai"],
|
|
41461
|
+
["DET_MASTER", "determined-ai"],
|
|
41462
|
+
["LIGHTNING_USER_ID", "lightning-ai"],
|
|
41463
|
+
["FLYTE_INTERNAL_EXECUTION_ID", "flyte"],
|
|
41464
|
+
["ARGO_WORKFLOW_NAME", "argo-workflows"],
|
|
41465
|
+
["KFP_POD_NAME", "kubeflow-pipelines"],
|
|
41466
|
+
["KAGGLE_KERNEL_RUN_TYPE", "kaggle"],
|
|
41467
|
+
["COLAB_BACKEND_VERSION", "google-colab"],
|
|
41468
|
+
["DATABRICKS_RUNTIME_VERSION", "databricks"],
|
|
41469
|
+
["DAYTONA_WS_ID", "daytona"],
|
|
41470
|
+
["DAYTONA_WS_NAME", "daytona"],
|
|
41471
|
+
["E2B_SANDBOX_ID", "e2b"],
|
|
41472
|
+
["MODAL_FUNCTION_ID", "modal"],
|
|
41473
|
+
["MODAL_TASK_ID", "modal"],
|
|
41474
|
+
["RUNPOD_POD_ID", "runpod"],
|
|
41475
|
+
["REPLICATE_USERNAME", "replicate"],
|
|
41476
|
+
["VAST_CONTAINERLABEL", "vast-ai"],
|
|
41477
|
+
["HARBOR_URL", "harbor"],
|
|
41478
|
+
["HARBOR_HOSTNAME", "harbor"],
|
|
41479
|
+
["SWE_BENCH_TASK", "swe-bench"],
|
|
41480
|
+
["SWEBENCH_TASK", "swe-bench"],
|
|
41481
|
+
["SWE_AGENT_MODEL", "swe-agent"]
|
|
41482
|
+
];
|
|
41483
|
+
const detectAiTrainingEnvironment = () => {
|
|
41484
|
+
for (const [envVar, label] of AI_TRAINING_ENV_VARS) if (process.env[envVar]) return label;
|
|
41485
|
+
return null;
|
|
41486
|
+
};
|
|
41304
41487
|
const unionValues = (baseValues, overrideValues) => [...new Set([...baseValues, ...overrideValues])];
|
|
41305
41488
|
const mergeIgnores = (baseIgnore, overrideIgnore) => {
|
|
41306
41489
|
const mergedIgnore = {
|
|
@@ -41345,6 +41528,12 @@ const mergeReactDoctorConfigs = (baseConfig, overrideConfig) => {
|
|
|
41345
41528
|
};
|
|
41346
41529
|
//#endregion
|
|
41347
41530
|
//#region ../api/dist/index.js
|
|
41531
|
+
let didWarnAiTraining = false;
|
|
41532
|
+
const warnIfAiTrainingEnvironment = () => {
|
|
41533
|
+
if (didWarnAiTraining || detectAiTrainingEnvironment() === null) return;
|
|
41534
|
+
didWarnAiTraining = true;
|
|
41535
|
+
console.warn("[react-doctor] Use in an AI or ML pipeline requires written permission under the react-doctor license. Contact founders@million.dev to request access.");
|
|
41536
|
+
};
|
|
41348
41537
|
const buildDiagnoseLayer = (config, configOverrideTarget) => {
|
|
41349
41538
|
const configLayer = configOverrideTarget === void 0 ? Config.layerNode : Config.layerOf({
|
|
41350
41539
|
config,
|
|
@@ -41382,6 +41571,7 @@ const outputToDiagnoseResult = (output, elapsedMilliseconds) => {
|
|
|
41382
41571
|
};
|
|
41383
41572
|
};
|
|
41384
41573
|
const diagnoseDirectory = async (directory, options) => {
|
|
41574
|
+
warnIfAiTrainingEnvironment();
|
|
41385
41575
|
const startTime = globalThis.performance.now();
|
|
41386
41576
|
const scanTarget = await resolveScanTarget(directory);
|
|
41387
41577
|
return outputToDiagnoseResult(await runPromise(restoreLegacyThrow(buildInspectProgram(scanTarget, options).pipe(provide(buildDiagnoseLayer(scanTarget.userConfig)), provide(layerOtlp)))), globalThis.performance.now() - startTime);
|
|
@@ -41428,6 +41618,7 @@ const diagnoseProject = async (projectDefinition, baseOptions, batchConfig) => {
|
|
|
41428
41618
|
}
|
|
41429
41619
|
};
|
|
41430
41620
|
const diagnoseProjectBatch = async (input) => {
|
|
41621
|
+
warnIfAiTrainingEnvironment();
|
|
41431
41622
|
const startTime = globalThis.performance.now();
|
|
41432
41623
|
const { projects, concurrency, config: batchConfig, ...baseOptions } = input;
|
|
41433
41624
|
const projectResults = await mapWithConcurrency(projects, concurrency ?? 4, (projectDefinition) => diagnoseProject(projectDefinition, baseOptions, batchConfig));
|
|
@@ -41472,4 +41663,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
41472
41663
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
41473
41664
|
|
|
41474
41665
|
//# sourceMappingURL=index.js.map
|
|
41475
|
-
//# debugId=
|
|
41666
|
+
//# debugId=1e049c6a-27f7-5c62-8be8-57ce0b987f6f
|