react-doctor 0.5.8-dev.849580c → 0.5.8-dev.88a5c3c
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/README.md +9 -3
- package/dist/cli.js +9337 -1520
- package/dist/index.d.ts +21 -0
- package/dist/index.js +174 -89
- package/dist/lsp.js +180 -90
- package/package.json +6 -5
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
|
|
@@ -9377,6 +9386,10 @@ interface ReactDoctorConfig {
|
|
|
9377
9386
|
* { "categories": { "Maintainability": "off", "Performance": "warn" } }
|
|
9378
9387
|
* ```
|
|
9379
9388
|
*
|
|
9389
|
+
* A category severity re-stamps rules that are already enabled; it
|
|
9390
|
+
* never activates opt-out (`defaultEnabled: false`) rules — pin the
|
|
9391
|
+
* rule itself under `rules` to opt in.
|
|
9392
|
+
*
|
|
9380
9393
|
* To silence a whole tag-defined rule family (e.g. `"design"`,
|
|
9381
9394
|
* `"test-noise"`, `"migration-hint"`) that doesn't align with a
|
|
9382
9395
|
* single category, use `ignore.tags` instead.
|
|
@@ -10082,6 +10095,14 @@ interface BuildJsonReportInput {
|
|
|
10082
10095
|
fixedCount: number;
|
|
10083
10096
|
baseTotalCount: number;
|
|
10084
10097
|
};
|
|
10098
|
+
/**
|
|
10099
|
+
* True when a `changed` run was intended but its baseline delta couldn't be
|
|
10100
|
+
* computed (no merge base — usually a shallow CI checkout — or a failed
|
|
10101
|
+
* base/head lint), so `diagnostics` list every finding in the changed files
|
|
10102
|
+
* rather than only the introduced ones. Ignored when `baseline` is set: a
|
|
10103
|
+
* computed baseline (v2) wins, so callers pass at most one.
|
|
10104
|
+
*/
|
|
10105
|
+
baselineDegraded?: boolean;
|
|
10085
10106
|
}
|
|
10086
10107
|
declare const buildJsonReport: (input: BuildJsonReportInput) => JsonReport; //#endregion
|
|
10087
10108
|
//#region src/build-skipped-checks.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]="7cfd5199-4216-5c6e-8cf5-c9623c317a1e")}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";
|
|
@@ -7,7 +7,7 @@ import fs from "node:fs";
|
|
|
7
7
|
import * as Path from "node:path";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import * as NodeChildProcess from "node:child_process";
|
|
10
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
10
|
+
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
11
11
|
import * as ts from "typescript";
|
|
12
12
|
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
13
13
|
import * as OS from "node:os";
|
|
@@ -19364,6 +19364,15 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
19364
19364
|
ok: Boolean$1,
|
|
19365
19365
|
directory: String$1,
|
|
19366
19366
|
mode: JsonReportMode,
|
|
19367
|
+
/**
|
|
19368
|
+
* True when a `changed` (compare) run was intended but the base couldn't be
|
|
19369
|
+
* resolved — a shallow CI checkout with no merge base, or a failed base/head
|
|
19370
|
+
* lint. The report then lists every finding in the changed files (mode
|
|
19371
|
+
* downgrades to `diff`, the `baseline` block is dropped, the CI gate is
|
|
19372
|
+
* skipped) rather than only the ones the change introduced. Absent on a
|
|
19373
|
+
* successful `baseline` run (`schemaVersion: 2`) and on non-compare scopes.
|
|
19374
|
+
*/
|
|
19375
|
+
baselineDegraded: optional(Boolean$1),
|
|
19367
19376
|
diff: NullOr(JsonReportDiffInfo),
|
|
19368
19377
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19369
19378
|
diagnostics: ArraySchema(Diagnostic),
|
|
@@ -33695,6 +33704,9 @@ const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
|
33695
33704
|
const FETCH_TIMEOUT_MS = 1e4;
|
|
33696
33705
|
const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
|
|
33697
33706
|
const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
|
|
33707
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
|
|
33708
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
|
|
33709
|
+
const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
|
|
33698
33710
|
const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
|
|
33699
33711
|
const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
|
|
33700
33712
|
const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
|
|
@@ -34519,7 +34531,7 @@ const tokenizeRuleList = (ruleList) => {
|
|
|
34519
34531
|
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
34520
34532
|
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
34521
34533
|
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
34522
|
-
const buildHint = (tool, token, ruleId) => `oxlint matches plugin rules only by their full name, so \`${token}\` in your ${tool}-disable comment does not silence \`${ruleId}\` —
|
|
34534
|
+
const buildHint = (tool, token, ruleId) => `oxlint matches plugin rules only by their full name, so \`${token}\` in your ${tool}-disable comment does not silence \`${ruleId}\` — add \`${ruleId}\` to the comment (e.g. \`${token}, ${ruleId}\`).`;
|
|
34523
34535
|
const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
|
|
34524
34536
|
const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34525
34537
|
const candidates = [{
|
|
@@ -34999,6 +35011,7 @@ const collectStringSet = (values) => {
|
|
|
34999
35011
|
if (!Array.isArray(values)) return /* @__PURE__ */ new Set();
|
|
35000
35012
|
return new Set(values.filter((value) => typeof value === "string"));
|
|
35001
35013
|
};
|
|
35014
|
+
const JSX_NO_UNDEF_IDENTIFIER_PATTERN = /^`([^`]+)`/;
|
|
35002
35015
|
/**
|
|
35003
35016
|
* Pre-compiles every stateful filter and returns a single
|
|
35004
35017
|
* `apply(diagnostic)` closure that runs (in order):
|
|
@@ -35032,11 +35045,28 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
35032
35045
|
const compiledOverrides = compileIgnoreOverrides(userConfig);
|
|
35033
35046
|
const textComponentNames = collectStringSet(userConfig?.textComponents);
|
|
35034
35047
|
const rawTextWrapperComponentNames = collectStringSet(userConfig?.rawTextWrapperComponents);
|
|
35048
|
+
const runtimeGlobalNames = collectStringSet(userConfig?.runtimeGlobals);
|
|
35035
35049
|
const hasTextComponents = textComponentNames.size > 0;
|
|
35036
35050
|
const hasRawTextWrappers = rawTextWrapperComponentNames.size > 0;
|
|
35051
|
+
const hasRuntimeGlobals = runtimeGlobalNames.size > 0;
|
|
35037
35052
|
const fileLinesCache = /* @__PURE__ */ new Map();
|
|
35038
35053
|
const fileContextCache = /* @__PURE__ */ new Map();
|
|
35039
35054
|
const libraryFileCache = /* @__PURE__ */ new Map();
|
|
35055
|
+
const suppressions = /* @__PURE__ */ new Map();
|
|
35056
|
+
const suppress = (diagnostic, source) => {
|
|
35057
|
+
const { ruleKey } = getDiagnosticRuleIdentity(diagnostic);
|
|
35058
|
+
const suppressionKey = `${ruleKey}\u0000${source}`;
|
|
35059
|
+
const existing = suppressions.get(suppressionKey);
|
|
35060
|
+
suppressions.set(suppressionKey, existing ? {
|
|
35061
|
+
...existing,
|
|
35062
|
+
count: existing.count + 1
|
|
35063
|
+
} : {
|
|
35064
|
+
rule: ruleKey,
|
|
35065
|
+
source,
|
|
35066
|
+
count: 1
|
|
35067
|
+
});
|
|
35068
|
+
return null;
|
|
35069
|
+
};
|
|
35040
35070
|
const isLibraryFile = (filePath) => {
|
|
35041
35071
|
let cached = libraryFileCache.get(filePath);
|
|
35042
35072
|
if (cached === void 0) {
|
|
@@ -35085,50 +35115,60 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
35085
35115
|
if (hasRawTextWrappers && isInsideStringOnlyWrapper(lines, diagnostic.line, diagnostic.column, rawTextWrapperComponentNames)) return true;
|
|
35086
35116
|
return false;
|
|
35087
35117
|
};
|
|
35088
|
-
|
|
35089
|
-
if (
|
|
35090
|
-
|
|
35091
|
-
|
|
35092
|
-
|
|
35093
|
-
|
|
35094
|
-
|
|
35095
|
-
|
|
35096
|
-
|
|
35097
|
-
|
|
35098
|
-
|
|
35099
|
-
|
|
35100
|
-
if (
|
|
35101
|
-
|
|
35102
|
-
|
|
35103
|
-
|
|
35104
|
-
|
|
35105
|
-
|
|
35106
|
-
|
|
35107
|
-
|
|
35108
|
-
|
|
35109
|
-
if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
|
|
35110
|
-
if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return null;
|
|
35111
|
-
if (isRnRawTextSuppressedByConfig(current)) return null;
|
|
35112
|
-
}
|
|
35113
|
-
if (respectInlineDisables && current.line > 0) {
|
|
35114
|
-
const lines = getFileLines(current.filePath);
|
|
35115
|
-
if (lines) {
|
|
35116
|
-
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
35117
|
-
const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
|
|
35118
|
-
if (evaluation.isSuppressed) return null;
|
|
35119
|
-
if (evaluation.nearMissHint) current = {
|
|
35120
|
-
...current,
|
|
35121
|
-
suppressionHint: evaluation.nearMissHint
|
|
35122
|
-
};
|
|
35118
|
+
const isJsxNoUndefSuppressedByConfig = (diagnostic) => {
|
|
35119
|
+
if (!hasRuntimeGlobals) return false;
|
|
35120
|
+
if (diagnostic.rule !== "jsx-no-undef") return false;
|
|
35121
|
+
const identifierMatch = JSX_NO_UNDEF_IDENTIFIER_PATTERN.exec(diagnostic.message);
|
|
35122
|
+
return identifierMatch !== null && runtimeGlobalNames.has(identifierMatch[1]);
|
|
35123
|
+
};
|
|
35124
|
+
return {
|
|
35125
|
+
apply: (diagnostic) => {
|
|
35126
|
+
if (shouldAutoSuppress(diagnostic)) return null;
|
|
35127
|
+
let current = diagnostic;
|
|
35128
|
+
let explicitSeverityOverride;
|
|
35129
|
+
let explicitRuleOverride;
|
|
35130
|
+
if (severityControls) {
|
|
35131
|
+
const { ruleKey, category } = getDiagnosticRuleIdentity(current);
|
|
35132
|
+
explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
|
|
35133
|
+
explicitSeverityOverride = resolveRuleSeverityOverride({
|
|
35134
|
+
ruleKey,
|
|
35135
|
+
category
|
|
35136
|
+
}, severityControls);
|
|
35137
|
+
if (explicitSeverityOverride === "off") return suppress(current, "config");
|
|
35138
|
+
if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
|
|
35123
35139
|
}
|
|
35124
|
-
|
|
35125
|
-
|
|
35126
|
-
|
|
35127
|
-
|
|
35128
|
-
|
|
35129
|
-
|
|
35130
|
-
|
|
35131
|
-
|
|
35140
|
+
if (explicitRuleOverride === void 0) {
|
|
35141
|
+
if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
|
|
35142
|
+
}
|
|
35143
|
+
if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
|
|
35144
|
+
if (userConfig) {
|
|
35145
|
+
if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return suppress(current, "config");
|
|
35146
|
+
if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
|
|
35147
|
+
if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
|
|
35148
|
+
if (isRnRawTextSuppressedByConfig(current)) return null;
|
|
35149
|
+
if (isJsxNoUndefSuppressedByConfig(current)) return null;
|
|
35150
|
+
}
|
|
35151
|
+
if (respectInlineDisables && current.line > 0) {
|
|
35152
|
+
const lines = getFileLines(current.filePath);
|
|
35153
|
+
if (lines) {
|
|
35154
|
+
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
35155
|
+
const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
|
|
35156
|
+
if (evaluation.isSuppressed) return suppress(current, "inline");
|
|
35157
|
+
if (evaluation.nearMissHint) current = {
|
|
35158
|
+
...current,
|
|
35159
|
+
suppressionHint: evaluation.nearMissHint
|
|
35160
|
+
};
|
|
35161
|
+
}
|
|
35162
|
+
}
|
|
35163
|
+
const fileContext = getFileContext(current.filePath);
|
|
35164
|
+
if (fileContext !== "production") current = {
|
|
35165
|
+
...current,
|
|
35166
|
+
fileContext
|
|
35167
|
+
};
|
|
35168
|
+
return current;
|
|
35169
|
+
},
|
|
35170
|
+
summarizeSuppressions: () => [...suppressions.values()]
|
|
35171
|
+
};
|
|
35132
35172
|
};
|
|
35133
35173
|
const OxlintUnavailableKind = Literals(["binary-not-found", "native-binding-missing"]);
|
|
35134
35174
|
var OxlintUnavailable = class extends TaggedErrorClass()("OxlintUnavailable", {
|
|
@@ -35432,13 +35472,7 @@ var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { de
|
|
|
35432
35472
|
* without recompiling react-doctor. Tests override via
|
|
35433
35473
|
* `Layer.succeed(SupplyChainOverlapTimeoutMs, ...)`.
|
|
35434
35474
|
*/
|
|
35435
|
-
var SupplyChainOverlapTimeoutMs = class extends Reference("react-doctor/SupplyChainOverlapTimeoutMs", { defaultValue: () => {
|
|
35436
|
-
const raw = process.env["REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MS"];
|
|
35437
|
-
if (raw === void 0) return SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS;
|
|
35438
|
-
const parsed = Number(raw);
|
|
35439
|
-
if (!Number.isFinite(parsed) || parsed <= 0) return SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS;
|
|
35440
|
-
return parsed;
|
|
35441
|
-
} }) {};
|
|
35475
|
+
var SupplyChainOverlapTimeoutMs = class extends Reference("react-doctor/SupplyChainOverlapTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MS", SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS) }) {};
|
|
35442
35476
|
/**
|
|
35443
35477
|
* Hard cap on combined stdout+stderr bytes per oxlint batch. The
|
|
35444
35478
|
* subprocess gets SIGKILL'd if it produces more; the recovery path
|
|
@@ -35586,6 +35620,7 @@ const STRING_ARRAY_FIELD_NAMES = [
|
|
|
35586
35620
|
"projects",
|
|
35587
35621
|
"textComponents",
|
|
35588
35622
|
"rawTextWrapperComponents",
|
|
35623
|
+
"runtimeGlobals",
|
|
35589
35624
|
"serverAuthFunctionNames"
|
|
35590
35625
|
];
|
|
35591
35626
|
const SURFACE_CONTROL_FIELD_NAMES = [
|
|
@@ -37290,6 +37325,11 @@ const toCanonicalPath = (filePath) => {
|
|
|
37290
37325
|
};
|
|
37291
37326
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
37292
37327
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
37328
|
+
const REACT_DOCTOR_TOOLCHAIN_PACKAGES = new Set([
|
|
37329
|
+
"react-doctor",
|
|
37330
|
+
"eslint-plugin-react-doctor",
|
|
37331
|
+
"oxlint-plugin-react-doctor"
|
|
37332
|
+
]);
|
|
37293
37333
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
37294
37334
|
const inputChunks = [];
|
|
37295
37335
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -37595,6 +37635,7 @@ const checkDeadCode = async (options) => {
|
|
|
37595
37635
|
});
|
|
37596
37636
|
}
|
|
37597
37637
|
for (const unusedDependency of result.unusedDependencies) {
|
|
37638
|
+
if (REACT_DOCTOR_TOOLCHAIN_PACKAGES.has(unusedDependency.name)) continue;
|
|
37598
37639
|
const label = unusedDependency.isDevDependency ? "devDependency" : "dependency";
|
|
37599
37640
|
diagnostics.push({
|
|
37600
37641
|
filePath: "package.json",
|
|
@@ -37773,7 +37814,6 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
37773
37814
|
return yield* tryPromise({
|
|
37774
37815
|
try: (signal) => checkDeadCode({
|
|
37775
37816
|
rootDirectory: input.rootDirectory,
|
|
37776
|
-
userConfig: input.userConfig,
|
|
37777
37817
|
parseConcurrency: input.parseConcurrency,
|
|
37778
37818
|
workerTimeoutMs: input.workerTimeoutMs,
|
|
37779
37819
|
abortSignal: signal
|
|
@@ -37896,6 +37936,11 @@ const isSafeGitRevision = (candidate) => {
|
|
|
37896
37936
|
if (candidate.includes("..") || candidate.includes("@{")) return false;
|
|
37897
37937
|
return SAFE_GIT_REVISION_PATTERN.test(candidate);
|
|
37898
37938
|
};
|
|
37939
|
+
const resolveSpawnArgsLengthCap = () => {
|
|
37940
|
+
if (process.platform === "win32") return SPAWN_ARGS_MAX_LENGTH_CHARS;
|
|
37941
|
+
if (process.platform === "darwin") return SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN;
|
|
37942
|
+
return SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX;
|
|
37943
|
+
};
|
|
37899
37944
|
/**
|
|
37900
37945
|
* Splits a git revision range into its endpoints: three-dot `A...B`
|
|
37901
37946
|
* (symmetric, merge-base) or two-dot `A..B` (direct). Returns `null`
|
|
@@ -37980,7 +38025,8 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37980
38025
|
return scoped(gen(function* () {
|
|
37981
38026
|
if (!isDirectory(input.directory)) return yield* foldSpawnFailure(`spawn ENOTDIR (cwd is not a directory: ${input.directory})`);
|
|
37982
38027
|
const argvLengthChars = input.command.length + 1 + input.args.reduce((total, arg) => total + arg.length + 1, 0);
|
|
37983
|
-
|
|
38028
|
+
const spawnArgsLengthCap = resolveSpawnArgsLengthCap();
|
|
38029
|
+
if (argvLengthChars > spawnArgsLengthCap) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${spawnArgsLengthCap})`);
|
|
37984
38030
|
const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
|
|
37985
38031
|
cwd: input.directory,
|
|
37986
38032
|
env: input.env,
|
|
@@ -38149,6 +38195,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38149
38195
|
if (resolvedCurrentBranch === null && explicitBaseBranch === void 0) return null;
|
|
38150
38196
|
const baseBranch = explicitBaseBranch ?? (yield* defaultBranch(directory));
|
|
38151
38197
|
if (baseBranch === null) return null;
|
|
38198
|
+
if (!isSafeGitRevision(baseBranch)) return null;
|
|
38152
38199
|
if (explicitBaseBranch !== void 0) {
|
|
38153
38200
|
if (!(yield* branchExists(directory, explicitBaseBranch))) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchMissing({ branch: explicitBaseBranch }) }));
|
|
38154
38201
|
}
|
|
@@ -38499,7 +38546,7 @@ const normalizeConfigForHash = (config) => {
|
|
|
38499
38546
|
if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
|
|
38500
38547
|
return clone;
|
|
38501
38548
|
};
|
|
38502
|
-
const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("
|
|
38549
|
+
const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("\0").update(input.tsconfigContent ?? "").digest("hex");
|
|
38503
38550
|
/**
|
|
38504
38551
|
* Loads a plugin module via the local require resolver and extracts
|
|
38505
38552
|
* `(name, ruleNames)` from either `module.exports.meta + rules` or
|
|
@@ -38670,12 +38717,12 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
38670
38717
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
38671
38718
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
38672
38719
|
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledBy)) continue;
|
|
38673
|
-
const
|
|
38720
|
+
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
38721
|
+
if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
|
|
38722
|
+
const severity = resolveRuleSeverityOverride({
|
|
38674
38723
|
ruleKey: registryEntry.key,
|
|
38675
38724
|
category: rule.category
|
|
38676
|
-
}, severityControls);
|
|
38677
|
-
if (rule.defaultEnabled === false && explicitSeverity === void 0) continue;
|
|
38678
|
-
const severity = explicitSeverity ?? resolveCompilerCleanupBucketSeverity(registryEntry.key, severityControls) ?? rule.severity;
|
|
38725
|
+
}, severityControls) ?? resolveCompilerCleanupBucketSeverity(registryEntry.key, severityControls) ?? rule.severity;
|
|
38679
38726
|
if (severity === "off") continue;
|
|
38680
38727
|
enabledReactDoctorRules[registryEntry.key] = severity;
|
|
38681
38728
|
}
|
|
@@ -38777,24 +38824,38 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
38777
38824
|
updatedAtMs: Date.now(),
|
|
38778
38825
|
files: Object.fromEntries(cappedEntries)
|
|
38779
38826
|
};
|
|
38780
|
-
const keptHashes = Object.entries(rulesets).sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8).map(([hash]) => hash);
|
|
38781
|
-
const prunedRulesets = {};
|
|
38782
|
-
for (const hash of keptHashes) prunedRulesets[hash] = rulesets[hash];
|
|
38783
38827
|
atomicWriteJson(cacheFilePath, {
|
|
38784
38828
|
version: 1,
|
|
38785
|
-
rulesets:
|
|
38829
|
+
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
38786
38830
|
});
|
|
38787
38831
|
}
|
|
38788
38832
|
};
|
|
38789
38833
|
};
|
|
38790
38834
|
const bundledRequire = createRequire(import.meta.url);
|
|
38835
|
+
const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
|
|
38836
|
+
const resolveChildNodeVersion = (nodeBinaryPath) => {
|
|
38837
|
+
if (nodeBinaryPath === process.execPath) return process.version;
|
|
38838
|
+
const cachedVersion = childNodeVersionByBinaryPath.get(nodeBinaryPath);
|
|
38839
|
+
if (cachedVersion !== void 0) return cachedVersion;
|
|
38840
|
+
let version;
|
|
38841
|
+
try {
|
|
38842
|
+
version = execFileSync(nodeBinaryPath, ["--version"], {
|
|
38843
|
+
encoding: "utf8",
|
|
38844
|
+
timeout: NODE_VERSION_PROBE_TIMEOUT_MS
|
|
38845
|
+
}).trim();
|
|
38846
|
+
} catch {
|
|
38847
|
+
version = `unknown:${nodeBinaryPath}`;
|
|
38848
|
+
}
|
|
38849
|
+
childNodeVersionByBinaryPath.set(nodeBinaryPath, version);
|
|
38850
|
+
return version;
|
|
38851
|
+
};
|
|
38791
38852
|
const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
38792
38853
|
"oxlint/package.json",
|
|
38793
38854
|
"oxlint-plugin-react-doctor/package.json",
|
|
38794
38855
|
"eslint-plugin-react-hooks/package.json"
|
|
38795
38856
|
];
|
|
38796
|
-
const resolveOxlintToolchainVersions = () => {
|
|
38797
|
-
const versions = [`node=${
|
|
38857
|
+
const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
38858
|
+
const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
|
|
38798
38859
|
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
|
|
38799
38860
|
const packageJson = bundledRequire(specifier);
|
|
38800
38861
|
const version = typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
@@ -39328,11 +39389,12 @@ const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
|
39328
39389
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
39329
39390
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
39330
39391
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
39392
|
+
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`.";
|
|
39331
39393
|
const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
|
|
39332
|
-
const buildReactCompilerMessage = (reasonSummary) => {
|
|
39394
|
+
const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
|
|
39333
39395
|
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
39334
|
-
if (!normalizedSummary) return
|
|
39335
|
-
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${
|
|
39396
|
+
if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
|
|
39397
|
+
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
|
|
39336
39398
|
};
|
|
39337
39399
|
const PLUGIN_CATEGORY_MAP = {
|
|
39338
39400
|
react: "Bugs",
|
|
@@ -39381,7 +39443,7 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
39381
39443
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
39382
39444
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
39383
39445
|
return {
|
|
39384
|
-
message: buildReactCompilerMessage(reasonSummary.trim()),
|
|
39446
|
+
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
39385
39447
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
39386
39448
|
};
|
|
39387
39449
|
}
|
|
@@ -39649,21 +39711,27 @@ const spawnLintBatches = async (input) => {
|
|
|
39649
39711
|
const allDiagnostics = [];
|
|
39650
39712
|
const droppedFiles = [];
|
|
39651
39713
|
let firstDropReason = null;
|
|
39652
|
-
const
|
|
39653
|
-
const spawnLintBatch = async (batch, depth) => {
|
|
39714
|
+
const spawnLintBatch = async (batch, depth, splitBudget) => {
|
|
39654
39715
|
const batchArgs = [...baseArgs, ...batch];
|
|
39655
39716
|
try {
|
|
39656
39717
|
return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
|
|
39657
39718
|
} catch (error) {
|
|
39658
39719
|
if (!isSplittableReactDoctorError(error)) throw error;
|
|
39659
|
-
|
|
39660
|
-
|
|
39720
|
+
splitBudget.deadlineMs ??= Date.now() + splitTotalBudgetMs;
|
|
39721
|
+
const isBudgetElapsed = Date.now() >= splitBudget.deadlineMs;
|
|
39722
|
+
const isDepthCapReached = depth >= splitMaxDepth;
|
|
39723
|
+
if (batch.length <= 1 || isBudgetElapsed || isDepthCapReached) {
|
|
39661
39724
|
droppedFiles.push(...batch);
|
|
39662
|
-
if (firstDropReason === null)
|
|
39725
|
+
if (firstDropReason === null) {
|
|
39726
|
+
let limitHint = "";
|
|
39727
|
+
if (isDepthCapReached) limitHint = ` (split depth cap of ${splitMaxDepth} levels reached)`;
|
|
39728
|
+
else if (isBudgetElapsed) limitHint = ` (split budget of ${splitTotalBudgetMs / MILLISECONDS_PER_SECOND}s exhausted at depth ${depth})`;
|
|
39729
|
+
firstDropReason = batch.length > 1 ? `${error.message}${limitHint}` : error.message;
|
|
39730
|
+
}
|
|
39663
39731
|
return [];
|
|
39664
39732
|
}
|
|
39665
39733
|
const splitIndex = Math.ceil(batch.length / 2);
|
|
39666
|
-
return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1)];
|
|
39734
|
+
return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, splitBudget), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, splitBudget)];
|
|
39667
39735
|
}
|
|
39668
39736
|
};
|
|
39669
39737
|
let startedFileCount = 0;
|
|
@@ -39680,7 +39748,7 @@ const spawnLintBatches = async (input) => {
|
|
|
39680
39748
|
try {
|
|
39681
39749
|
const batchResults = await mapWithConcurrency(fileBatches, concurrency, async (batch) => {
|
|
39682
39750
|
startedFileCount += batch.length;
|
|
39683
|
-
const batchDiagnostics = await spawnLintBatch(batch, 0);
|
|
39751
|
+
const batchDiagnostics = await spawnLintBatch(batch, 0, { deadlineMs: null });
|
|
39684
39752
|
scannedFileCount += batch.length;
|
|
39685
39753
|
if (onFileProgress) {
|
|
39686
39754
|
displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
|
|
@@ -39754,7 +39822,14 @@ const resolveReactDoctorCacheDir = (projectDirectory) => {
|
|
|
39754
39822
|
if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
|
|
39755
39823
|
const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
|
|
39756
39824
|
if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
|
|
39757
|
-
return Path.join(os.tmpdir(),
|
|
39825
|
+
return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
|
|
39826
|
+
};
|
|
39827
|
+
const resolveUserCacheScope = () => {
|
|
39828
|
+
try {
|
|
39829
|
+
return String(process.getuid?.() ?? os.userInfo().username);
|
|
39830
|
+
} catch {
|
|
39831
|
+
return "shared";
|
|
39832
|
+
}
|
|
39758
39833
|
};
|
|
39759
39834
|
const sortSourceFilesByCost = (entries) => [...entries].sort((left, right) => right.sizeBytes - left.sizeBytes).map((entry) => entry.path);
|
|
39760
39835
|
/**
|
|
@@ -39922,7 +39997,7 @@ const runOxlint = async (options) => {
|
|
|
39922
39997
|
extendsPaths: [],
|
|
39923
39998
|
ruleSelection: "cacheable"
|
|
39924
39999
|
}),
|
|
39925
|
-
toolchainVersions: resolveOxlintToolchainVersions(),
|
|
40000
|
+
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
39926
40001
|
ignorePatterns: combinedPatterns,
|
|
39927
40002
|
tsconfigContent
|
|
39928
40003
|
});
|
|
@@ -39936,7 +40011,7 @@ const runOxlint = async (options) => {
|
|
|
39936
40011
|
missFiles.push(candidateFile);
|
|
39937
40012
|
continue;
|
|
39938
40013
|
}
|
|
39939
|
-
const cacheKey = `${candidateFile.replaceAll("\\", "/")}
|
|
40014
|
+
const cacheKey = `${candidateFile.replaceAll("\\", "/")}\u0000${contentHash}`;
|
|
39940
40015
|
cacheKeyByFile.set(candidateFile, cacheKey);
|
|
39941
40016
|
const cachedDiagnostics = cache.lookup(cacheKey);
|
|
39942
40017
|
if (cachedDiagnostics === null) missFiles.push(candidateFile);
|
|
@@ -40252,7 +40327,7 @@ const ScoreApiResponseSchema = Struct({
|
|
|
40252
40327
|
})))
|
|
40253
40328
|
});
|
|
40254
40329
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
40255
|
-
const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, ...rest }) => rest);
|
|
40330
|
+
const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
|
|
40256
40331
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
40257
40332
|
const describeFailure = (error) => {
|
|
40258
40333
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -40556,7 +40631,10 @@ const ALERT_SEVERITY_RANK = {
|
|
|
40556
40631
|
medium: 2,
|
|
40557
40632
|
low: 1
|
|
40558
40633
|
};
|
|
40559
|
-
const severityRank = (severity) =>
|
|
40634
|
+
const severityRank = (severity) => {
|
|
40635
|
+
const normalized = severity.toLowerCase();
|
|
40636
|
+
return Object.hasOwn(ALERT_SEVERITY_RANK, normalized) ? ALERT_SEVERITY_RANK[normalized] : 0;
|
|
40637
|
+
};
|
|
40560
40638
|
const displaySeverity = (severity) => {
|
|
40561
40639
|
const normalized = sanitizeTerminalText(severity.toLowerCase());
|
|
40562
40640
|
return normalized === "middle" ? "medium" : normalized;
|
|
@@ -40573,7 +40651,7 @@ const ALERT_TYPE_LABELS = {
|
|
|
40573
40651
|
typosquat: "possible typosquat"
|
|
40574
40652
|
};
|
|
40575
40653
|
const humanizeAlertType = (type) => type.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").toLowerCase().trim();
|
|
40576
|
-
const friendlyAlertType = (type) => ALERT_TYPE_LABELS[type]
|
|
40654
|
+
const friendlyAlertType = (type) => Object.hasOwn(ALERT_TYPE_LABELS, type) ? ALERT_TYPE_LABELS[type] : sanitizeTerminalText(humanizeAlertType(type));
|
|
40577
40655
|
const summarizeAlertNote = (note) => {
|
|
40578
40656
|
const collapsed = sanitizeTerminalText(note.replace(/\s+/g, " ").trim());
|
|
40579
40657
|
const firstSentence = collapsed.split(/(?<=\.)\s/)[0] || collapsed;
|
|
@@ -40668,7 +40746,10 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
40668
40746
|
* outage.
|
|
40669
40747
|
*/
|
|
40670
40748
|
var SupplyChain = class SupplyChain extends Service()("react-doctor/SupplyChain") {
|
|
40671
|
-
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(
|
|
40749
|
+
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (totalTimeoutMs) => checkSupplyChain({
|
|
40750
|
+
...input,
|
|
40751
|
+
totalTimeoutMs
|
|
40752
|
+
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), withSpan("SupplyChain.run"))) }));
|
|
40672
40753
|
static layerOf = (diagnostics) => succeed$3(SupplyChain, SupplyChain.of({ run: () => fromIterable$1(diagnostics) }));
|
|
40673
40754
|
};
|
|
40674
40755
|
const getObjectProperty = (value, propertyName) => {
|
|
@@ -40816,10 +40897,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40816
40897
|
...checkExpoProject(scanDirectory, project),
|
|
40817
40898
|
...checkReactNativeProject(scanDirectory, project)
|
|
40818
40899
|
])));
|
|
40819
|
-
const
|
|
40900
|
+
const securityScanFailedRef = yield* make$13(false);
|
|
40901
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
40820
40902
|
project,
|
|
40821
40903
|
ignoredTags: input.ignoredTags
|
|
40822
|
-
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)))))).pipe(withSpan("SecurityScan.run")));
|
|
40904
|
+
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
40823
40905
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
40824
40906
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
40825
40907
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
@@ -40857,7 +40939,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40857
40939
|
const lintConcurrency = deadCodeParseConcurrency === void 0 ? scanConcurrency : Math.max(1, scanConcurrency - deadCodeParseConcurrency);
|
|
40858
40940
|
const buildCollectDeadCode = (deadCodeTimeout) => runCollect(applyPerElementPipeline(deadCodeService.run({
|
|
40859
40941
|
rootDirectory: scanDirectory,
|
|
40860
|
-
userConfig: resolvedConfig.config,
|
|
40861
40942
|
parseConcurrency: deadCodeParseConcurrency,
|
|
40862
40943
|
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs
|
|
40863
40944
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
@@ -40985,6 +41066,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40985
41066
|
metadata: scoreMetadata
|
|
40986
41067
|
});
|
|
40987
41068
|
const lintPartialFailures = yield* get$2(partialFailuresRef);
|
|
41069
|
+
const securityScanFailed = yield* get$2(securityScanFailedRef);
|
|
40988
41070
|
return {
|
|
40989
41071
|
project,
|
|
40990
41072
|
userConfig: resolvedConfig.config,
|
|
@@ -41005,8 +41087,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41005
41087
|
scanElapsedMilliseconds,
|
|
41006
41088
|
scanConcurrency,
|
|
41007
41089
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
41090
|
+
securityScanFailed,
|
|
41008
41091
|
lintCacheHitFileCount,
|
|
41009
|
-
lintCacheTotalFileCount
|
|
41092
|
+
lintCacheTotalFileCount,
|
|
41093
|
+
suppressedRuleCounts: transform.summarizeSuppressions()
|
|
41010
41094
|
};
|
|
41011
41095
|
}).pipe(withSpan("runInspect", { attributes: {
|
|
41012
41096
|
"inspect.directory": input.directory,
|
|
@@ -41345,6 +41429,7 @@ const buildJsonReport = (input) => {
|
|
|
41345
41429
|
return {
|
|
41346
41430
|
schemaVersion: 1,
|
|
41347
41431
|
mode: input.mode,
|
|
41432
|
+
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
41348
41433
|
...shared
|
|
41349
41434
|
};
|
|
41350
41435
|
};
|
|
@@ -41645,4 +41730,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
41645
41730
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
41646
41731
|
|
|
41647
41732
|
//# sourceMappingURL=index.js.map
|
|
41648
|
-
//# debugId=
|
|
41733
|
+
//# debugId=7cfd5199-4216-5c6e-8cf5-c9623c317a1e
|