react-doctor 0.9.4-dev.da0647e → 0.9.5
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 +0 -1
- package/dist/cli.js +60 -166
- package/dist/{exit-gracefully-BN2OivAV.js → exit-gracefully-B18ck0kt.js} +384 -1015
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/lsp.js +5 -5
- package/dist/{run-scan-app-_1xMQtKK.js → run-scan-app-CjGdpTbP.js} +127 -45
- package/package.json +6 -6
|
@@ -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]="b58d69eb-938f-5abd-9831-40b3dfe65ff2")}catch(e){}}();
|
|
3
3
|
import { n as __require, r as __toESM$1, t as __commonJSMin$1 } from "./chunk-q7NCDQ7-.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as NodeChildProcess from "node:child_process";
|
|
@@ -15,7 +15,7 @@ import crypto, { createHash, randomUUID } from "node:crypto";
|
|
|
15
15
|
import { ResolverFactory } from "oxc-resolver";
|
|
16
16
|
import ts from "typescript";
|
|
17
17
|
import * as NodeUrl from "node:url";
|
|
18
|
-
import { fileURLToPath
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
19
19
|
import * as OS from "node:os";
|
|
20
20
|
import os, { tmpdir } from "node:os";
|
|
21
21
|
import { parseJSON5 } from "confbox";
|
|
@@ -28,9 +28,9 @@ import { performance as performance$1 } from "node:perf_hooks";
|
|
|
28
28
|
import { promisify, stripVTControlCharacters } from "node:util";
|
|
29
29
|
import tty from "node:tty";
|
|
30
30
|
import basePrompts from "prompts";
|
|
31
|
-
import { codeFrameColumns } from "@babel/code-frame";
|
|
32
|
-
import Conf from "conf";
|
|
33
31
|
import { detectInstalledSkillAgents, getSkillAgentTypes } from "agent-install";
|
|
32
|
+
import Conf from "conf";
|
|
33
|
+
import { codeFrameColumns } from "@babel/code-frame";
|
|
34
34
|
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.70/node_modules/effect/dist/Pipeable.js
|
|
35
35
|
/**
|
|
36
36
|
* The `Pipeable` module defines the shared interface and implementation helpers
|
|
@@ -62453,7 +62453,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
62453
62453
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
62454
62454
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
62455
62455
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
62456
|
-
const CORE_PACKAGE_VERSION = "0.9.
|
|
62456
|
+
const CORE_PACKAGE_VERSION = "0.9.5";
|
|
62457
62457
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
62458
62458
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
62459
62459
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -76357,8 +76357,7 @@ const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
|
|
|
76357
76357
|
const TUI_REPORT_COMPACT_MAX_ROWS = 23;
|
|
76358
76358
|
const TUI_REPORT_DETAIL_WIDTH_FRACTION = .6;
|
|
76359
76359
|
const CI_TRUST_COMPANIES = "PayPal, Rippling, and Alibaba";
|
|
76360
|
-
const
|
|
76361
|
-
const CATEGORY_COUNTUP_SETTLE_HOLD_MS = 1e3;
|
|
76360
|
+
const MINIMUM_VTE_VERSION_FOR_HYPERLINKS = 5e3;
|
|
76362
76361
|
const INTERNAL_ERROR_JSON_FALLBACK = "{\"schemaVersion\":3,\"version\":\"unknown\",\"ok\":false,\"directory\":\"\",\"mode\":\"full\",\"diff\":null,\"projects\":[],\"diagnostics\":[],\"summary\":{\"errorCount\":0,\"warningCount\":0,\"affectedFileCount\":0,\"totalDiagnosticCount\":0,\"score\":null,\"scoreLabel\":null},\"elapsedMilliseconds\":0,\"error\":{\"message\":\"Internal error\",\"name\":\"Error\",\"chain\":[]}}\n";
|
|
76363
76362
|
const SENTRY_FLUSH_TIMEOUT_MS = 2e3;
|
|
76364
76363
|
const NANOSECONDS_PER_SECOND = 1000000000n;
|
|
@@ -76412,7 +76411,7 @@ const METRIC = {
|
|
|
76412
76411
|
tuiFindingNavigated: "tui.finding_navigated",
|
|
76413
76412
|
tuiIssueStreamShown: "tui.issue_stream_shown",
|
|
76414
76413
|
tuiProjectPathContextShown: "tui.project_path_context_shown",
|
|
76415
|
-
|
|
76414
|
+
tuiProjectSelectShown: "tui.project_select_shown",
|
|
76416
76415
|
tuiReportActionSelected: "tui.report_action_selected",
|
|
76417
76416
|
tuiCancelled: "tui.cancelled",
|
|
76418
76417
|
tuiScanInlineShown: "tui.scan_inline_shown",
|
|
@@ -76461,7 +76460,7 @@ const makeNoopConsole = () => ({
|
|
|
76461
76460
|
});
|
|
76462
76461
|
//#endregion
|
|
76463
76462
|
//#region src/cli/utils/version.ts
|
|
76464
|
-
const VERSION = "0.9.
|
|
76463
|
+
const VERSION = "0.9.5";
|
|
76465
76464
|
//#endregion
|
|
76466
76465
|
//#region src/cli/utils/json-mode.ts
|
|
76467
76466
|
let context = null;
|
|
@@ -76922,13 +76921,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
76922
76921
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
76923
76922
|
* standard `SENTRY_RELEASE` override.
|
|
76924
76923
|
*/
|
|
76925
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.
|
|
76924
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.5`;
|
|
76926
76925
|
/**
|
|
76927
76926
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
76928
76927
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
76929
76928
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
76930
76929
|
*/
|
|
76931
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.
|
|
76930
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.5") ? "development" : "production");
|
|
76932
76931
|
/**
|
|
76933
76932
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
76934
76933
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -82449,88 +82448,68 @@ const printAgentGuidance = () => gen(function* () {
|
|
|
82449
82448
|
yield* log("");
|
|
82450
82449
|
});
|
|
82451
82450
|
//#endregion
|
|
82452
|
-
//#region src/cli/utils/
|
|
82453
|
-
const
|
|
82454
|
-
|
|
82455
|
-
|
|
82456
|
-
const
|
|
82457
|
-
|
|
82458
|
-
|
|
82459
|
-
const
|
|
82460
|
-
|
|
82461
|
-
const
|
|
82462
|
-
|
|
82463
|
-
|
|
82464
|
-
|
|
82465
|
-
|
|
82466
|
-
|
|
82467
|
-
|
|
82468
|
-
|
|
82469
|
-
|
|
82470
|
-
|
|
82471
|
-
|
|
82472
|
-
|
|
82473
|
-
|
|
82474
|
-
|
|
82451
|
+
//#region src/cli/utils/filter-diagnostics-by-categories.ts
|
|
82452
|
+
const filterDiagnosticsByCategories = (diagnostics, categories) => categories.size === 0 ? [...diagnostics] : diagnostics.filter((diagnostic) => categories.has(diagnostic.category));
|
|
82453
|
+
//#endregion
|
|
82454
|
+
//#region src/cli/utils/format-diagnostic-site.ts
|
|
82455
|
+
const formatDiagnosticSite = (site) => site.line > 0 ? `${site.filePath}:${site.line}` : site.filePath;
|
|
82456
|
+
//#endregion
|
|
82457
|
+
//#region src/cli/utils/format-rule-summary.ts
|
|
82458
|
+
const formatFileContextTag = (diagnostic) => diagnostic.fileContext ? ` (${diagnostic.fileContext} file)` : "";
|
|
82459
|
+
const formatRuleSummary = (ruleKey, ruleDiagnostics) => {
|
|
82460
|
+
const firstDiagnostic = ruleDiagnostics[0];
|
|
82461
|
+
if (firstDiagnostic === void 0) return "";
|
|
82462
|
+
const distinctMessages = [...new Set(ruleDiagnostics.map((diagnostic) => diagnostic.message))];
|
|
82463
|
+
const sections = [
|
|
82464
|
+
`Rule: ${ruleKey}`,
|
|
82465
|
+
`Severity: ${firstDiagnostic.severity}`,
|
|
82466
|
+
`Category: ${firstDiagnostic.category}`,
|
|
82467
|
+
`Count: ${ruleDiagnostics.length}`,
|
|
82468
|
+
"",
|
|
82469
|
+
distinctMessages.join("\n\n")
|
|
82470
|
+
];
|
|
82471
|
+
if (firstDiagnostic.help) sections.push("", `Suggestion: ${firstDiagnostic.help}`);
|
|
82472
|
+
if (firstDiagnostic.url) sections.push("", `Docs: ${firstDiagnostic.url}`);
|
|
82473
|
+
const fixRecipeLine = formatFixRecipeLine(firstDiagnostic);
|
|
82474
|
+
if (fixRecipeLine) sections.push("", fixRecipeLine);
|
|
82475
|
+
sections.push("", "Files:");
|
|
82476
|
+
for (const diagnostic of ruleDiagnostics) {
|
|
82477
|
+
sections.push(` ${formatDiagnosticSite(diagnostic)}${formatFileContextTag(diagnostic)}`);
|
|
82478
|
+
if (diagnostic.suppressionHint) sections.push(` ${diagnostic.suppressionHint}`);
|
|
82475
82479
|
}
|
|
82476
|
-
return `${
|
|
82477
|
-
};
|
|
82478
|
-
const boxText = (content, innerWidth) => {
|
|
82479
|
-
const horizontalRule = highlighter.dim("─".repeat(innerWidth + 2));
|
|
82480
|
-
const side = highlighter.dim("│");
|
|
82481
|
-
const body = content.split("\n").map((rawLine) => {
|
|
82482
|
-
const line = truncateToVisibleWidth(rawLine, innerWidth);
|
|
82483
|
-
return `${side} ${line}${" ".repeat(innerWidth - visibleWidth(line))} ${side}`;
|
|
82484
|
-
});
|
|
82485
|
-
return [
|
|
82486
|
-
`${highlighter.dim("┌")}${horizontalRule}${highlighter.dim("┐")}`,
|
|
82487
|
-
...body,
|
|
82488
|
-
`${highlighter.dim("└")}${horizontalRule}${highlighter.dim("┘")}`
|
|
82489
|
-
].join("\n");
|
|
82480
|
+
return `${sections.join("\n")}\n`;
|
|
82490
82481
|
};
|
|
82491
82482
|
//#endregion
|
|
82492
|
-
//#region src/cli/utils/
|
|
82493
|
-
|
|
82494
|
-
|
|
82495
|
-
* already absolute) to an absolute path. Shared by the code-frame reader and
|
|
82496
|
-
* the terminal hyperlink builder so both turn a relative path into the same
|
|
82497
|
-
* on-disk location.
|
|
82498
|
-
*/
|
|
82499
|
-
const resolveAbsolutePath = (filePath, rootDirectory) => Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory || ".", filePath);
|
|
82500
|
-
//#endregion
|
|
82501
|
-
//#region src/cli/utils/build-code-frame.ts
|
|
82502
|
-
/**
|
|
82503
|
-
* Renders a syntax-highlighted source excerpt around a diagnostic site
|
|
82504
|
-
* with a caret pointing at the offending column. Returns null when the
|
|
82505
|
-
* file can't be read (e.g. multi-project summaries where paths are
|
|
82506
|
-
* resolved against a different cwd), so callers can fall back to the
|
|
82507
|
-
* bare `file:line` reference instead of failing the whole render.
|
|
82508
|
-
*/
|
|
82509
|
-
const buildCodeFrame = (input) => {
|
|
82510
|
-
if (input.line <= 0) return null;
|
|
82511
|
-
const absolutePath = resolveAbsolutePath(input.filePath, input.rootDirectory);
|
|
82512
|
-
let source;
|
|
82483
|
+
//#region src/cli/utils/write-diagnostics-directory.ts
|
|
82484
|
+
const ruleDumpFileName = (ruleKey) => ruleKey.replace(/\//g, "--") + ".txt";
|
|
82485
|
+
const readPreviousRuleDumpFileNames = (directory) => {
|
|
82513
82486
|
try {
|
|
82514
|
-
|
|
82487
|
+
const previous = JSON.parse(NFS.readFileSync(Path.join(directory, "diagnostics.json"), "utf8"));
|
|
82488
|
+
return new Set(previous.filter((d) => typeof d?.plugin === "string" && typeof d?.rule === "string").map((d) => ruleDumpFileName(`${d.plugin}/${d.rule}`)));
|
|
82515
82489
|
} catch {
|
|
82516
|
-
return
|
|
82490
|
+
return /* @__PURE__ */ new Set();
|
|
82517
82491
|
}
|
|
82518
|
-
|
|
82519
|
-
|
|
82520
|
-
|
|
82521
|
-
|
|
82522
|
-
|
|
82523
|
-
|
|
82524
|
-
|
|
82525
|
-
|
|
82526
|
-
return codeFrameColumns(source, location, {
|
|
82527
|
-
highlightCode: true,
|
|
82528
|
-
linesAbove: 1,
|
|
82529
|
-
linesBelow: 1,
|
|
82530
|
-
...input.message ? { message: input.message } : {}
|
|
82531
|
-
});
|
|
82492
|
+
};
|
|
82493
|
+
const writeDiagnosticsDirectory = (diagnostics, outputDirectory) => {
|
|
82494
|
+
const directory = outputDirectory ? Path.resolve(outputDirectory) : Path.join(tmpdir(), `react-doctor-${randomUUID()}`);
|
|
82495
|
+
if (outputDirectory) for (const fileName of readPreviousRuleDumpFileNames(directory)) NFS.rmSync(Path.join(directory, fileName), { force: true });
|
|
82496
|
+
NFS.mkdirSync(directory, { recursive: true });
|
|
82497
|
+
for (const [ruleKey, ruleDiagnostics] of buildSortedRuleGroups(diagnostics)) NFS.writeFileSync(Path.join(directory, ruleDumpFileName(ruleKey)), formatRuleSummary(ruleKey, ruleDiagnostics));
|
|
82498
|
+
NFS.writeFileSync(Path.join(directory, "diagnostics.json"), JSON.stringify(diagnostics));
|
|
82499
|
+
return directory;
|
|
82532
82500
|
};
|
|
82533
82501
|
//#endregion
|
|
82502
|
+
//#region src/cli/utils/print-diagnostics-dump.ts
|
|
82503
|
+
const printDiagnosticsDump = (diagnostics, outputDirectory, verbose, stream = "stdout") => gen(function* () {
|
|
82504
|
+
const writtenDirectory = yield* try_({
|
|
82505
|
+
try: () => writeDiagnosticsDirectory(diagnostics, outputDirectory),
|
|
82506
|
+
catch: (cause) => cause
|
|
82507
|
+
}).pipe(orElseSucceed(() => null));
|
|
82508
|
+
if (writtenDirectory === null || !verbose && !outputDirectory) return;
|
|
82509
|
+
const pathLine = highlighter.gray(` Full diagnostics written to ${writtenDirectory}`);
|
|
82510
|
+
yield* stream === "stderr" || Boolean(outputDirectory) && isJsonModeActive() ? sync(() => process.stderr.write(`${pathLine}\n`)) : log(pathLine);
|
|
82511
|
+
});
|
|
82512
|
+
//#endregion
|
|
82534
82513
|
//#region src/cli/utils/resolve-measure-width.ts
|
|
82535
82514
|
const resolveClampedWidth = (input) => {
|
|
82536
82515
|
const terminalColumns = process.stdout.columns;
|
|
@@ -82544,20 +82523,6 @@ const resolveMeasureWidth = (reservedColumns = 0) => resolveClampedWidth({
|
|
|
82544
82523
|
minWidth: 24
|
|
82545
82524
|
});
|
|
82546
82525
|
//#endregion
|
|
82547
|
-
//#region src/cli/utils/build-section-divider.ts
|
|
82548
|
-
const DIVIDER_INDENT = " ";
|
|
82549
|
-
const buildSectionDivider = () => highlighter.dim(`${DIVIDER_INDENT}${"─".repeat(resolveMeasureWidth(2))}`);
|
|
82550
|
-
//#endregion
|
|
82551
|
-
//#region src/cli/utils/format-hyperlink.ts
|
|
82552
|
-
const OSC = "\x1B]";
|
|
82553
|
-
const ST = "\x1B\\";
|
|
82554
|
-
/**
|
|
82555
|
-
* Wraps `text` in an OSC 8 hyperlink pointing at `uri`. The visible characters
|
|
82556
|
-
* are exactly `text`; the link is carried in escape sequences a capable
|
|
82557
|
-
* terminal turns into a click target.
|
|
82558
|
-
*/
|
|
82559
|
-
const formatHyperlink = (text, uri) => `${OSC}8;;${uri}${ST}${text}${OSC}8;;${ST}`;
|
|
82560
|
-
//#endregion
|
|
82561
82526
|
//#region src/cli/utils/indent-multiline-text.ts
|
|
82562
82527
|
const indentMultilineText = (text, linePrefix) => text.split("\n").map((lineText) => `${linePrefix}${lineText}`).join("\n");
|
|
82563
82528
|
//#endregion
|
|
@@ -82597,793 +82562,6 @@ const wrapTextToWidth = (text, width, options = {}) => {
|
|
|
82597
82562
|
return text.split("\n").flatMap((lineText) => wrapLine(lineText, width, breakLongWords));
|
|
82598
82563
|
};
|
|
82599
82564
|
//#endregion
|
|
82600
|
-
//#region src/cli/utils/write-stdout.ts
|
|
82601
|
-
const writeStdout = (text) => sync(() => {
|
|
82602
|
-
process.stdout.write(text);
|
|
82603
|
-
});
|
|
82604
|
-
//#endregion
|
|
82605
|
-
//#region src/cli/utils/render-diagnostics.ts
|
|
82606
|
-
const POINTER = isUnicodeSupported() ? "›" : ">";
|
|
82607
|
-
const colorizeBySeverity = (text, severity) => severity === "error" ? highlighter.error(text) : highlighter.warn(text);
|
|
82608
|
-
const collectAffectedFiles = (diagnostics) => new Set(diagnostics.map((diagnostic) => diagnostic.filePath));
|
|
82609
|
-
const formatFileContextTag = (diagnostic) => diagnostic.fileContext ? ` (${diagnostic.fileContext} file)` : "";
|
|
82610
|
-
const buildVerboseFileEntries = (diagnostics) => {
|
|
82611
|
-
const fileEntries = /* @__PURE__ */ new Map();
|
|
82612
|
-
for (const diagnostic of diagnostics) {
|
|
82613
|
-
let entry = fileEntries.get(diagnostic.filePath);
|
|
82614
|
-
if (entry === void 0) {
|
|
82615
|
-
entry = {
|
|
82616
|
-
contextTag: formatFileContextTag(diagnostic),
|
|
82617
|
-
sites: []
|
|
82618
|
-
};
|
|
82619
|
-
fileEntries.set(diagnostic.filePath, entry);
|
|
82620
|
-
}
|
|
82621
|
-
if (diagnostic.line > 0) entry.sites.push({
|
|
82622
|
-
line: diagnostic.line,
|
|
82623
|
-
suppressionHint: diagnostic.suppressionHint
|
|
82624
|
-
});
|
|
82625
|
-
}
|
|
82626
|
-
return fileEntries;
|
|
82627
|
-
};
|
|
82628
|
-
const formatSiteCountBadge = (count) => count > 1 ? `×${count}` : "";
|
|
82629
|
-
const formatTrailingSiteBadge = (count) => {
|
|
82630
|
-
const badge = formatSiteCountBadge(count);
|
|
82631
|
-
return badge.length > 0 ? ` ${highlighter.gray(badge)}` : "";
|
|
82632
|
-
};
|
|
82633
|
-
const CATEGORY_DISPLAY_RANK = new Map(DIAGNOSTIC_CATEGORY_BUCKETS.map((category, index) => [category, index]));
|
|
82634
|
-
const compareCategoriesByDisplayRank = (categoryA, categoryB) => {
|
|
82635
|
-
const rankA = CATEGORY_DISPLAY_RANK.get(categoryA);
|
|
82636
|
-
const rankB = CATEGORY_DISPLAY_RANK.get(categoryB);
|
|
82637
|
-
if (rankA !== void 0 && rankB !== void 0) return rankA - rankB;
|
|
82638
|
-
if (rankA !== void 0) return -1;
|
|
82639
|
-
if (rankB !== void 0) return 1;
|
|
82640
|
-
return categoryA.localeCompare(categoryB);
|
|
82641
|
-
};
|
|
82642
|
-
const buildCategoryDiagnosticGroups = (diagnostics, rulePriority) => {
|
|
82643
|
-
return [...groupBy(diagnostics, (diagnostic) => diagnostic.category).entries()].map(([category, categoryDiagnostics]) => ({
|
|
82644
|
-
category,
|
|
82645
|
-
diagnostics: categoryDiagnostics,
|
|
82646
|
-
ruleGroups: buildSortedRuleGroups(categoryDiagnostics, rulePriority)
|
|
82647
|
-
})).toSorted((categoryGroupA, categoryGroupB) => compareCategoriesByDisplayRank(categoryGroupA.category, categoryGroupB.category));
|
|
82648
|
-
};
|
|
82649
|
-
const formatCategoryTallyLine = (tally, errorShown, warningShown) => {
|
|
82650
|
-
const parts = [];
|
|
82651
|
-
if (tally.errorCount > 0) parts.push(highlighter.error(`${errorShown} ${errorShown === 1 ? "error" : "errors"}`));
|
|
82652
|
-
if (tally.warningCount > 0) parts.push(highlighter.warn(highlighter.dim(`${warningShown} ${warningShown === 1 ? "warning" : "warnings"}`)));
|
|
82653
|
-
return ` ${highlighter.bold(tally.category)} ${highlighter.dim(POINTER)} ${parts.join(highlighter.dim(", "))}`;
|
|
82654
|
-
};
|
|
82655
|
-
const buildCategoryTally = (categoryGroup) => ({
|
|
82656
|
-
category: categoryGroup.category,
|
|
82657
|
-
errorCount: categoryGroup.diagnostics.filter((diagnostic) => diagnostic.severity === "error").length,
|
|
82658
|
-
warningCount: categoryGroup.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").length
|
|
82659
|
-
});
|
|
82660
|
-
const buildCategoryTallyLines = (tallies) => tallies.map((tally) => formatCategoryTallyLine(tally, tally.errorCount, tally.warningCount));
|
|
82661
|
-
const buildPartiallyRevealedTallyLines = (tallies, revealedUnitCount) => {
|
|
82662
|
-
let remainingToReveal = revealedUnitCount;
|
|
82663
|
-
return tallies.map((tally) => {
|
|
82664
|
-
const errorShown = Math.min(tally.errorCount, remainingToReveal);
|
|
82665
|
-
remainingToReveal -= errorShown;
|
|
82666
|
-
const warningShown = Math.min(tally.warningCount, remainingToReveal);
|
|
82667
|
-
remainingToReveal -= warningShown;
|
|
82668
|
-
return formatCategoryTallyLine(tally, errorShown, warningShown);
|
|
82669
|
-
});
|
|
82670
|
-
};
|
|
82671
|
-
const printCategoryCountUp = (tallies) => gen(function* () {
|
|
82672
|
-
const totalUnitCount = tallies.reduce((sum, tally) => sum + tally.errorCount + tally.warningCount, 0);
|
|
82673
|
-
const unitsPerStep = Math.max(1, Math.ceil(totalUnitCount / 24));
|
|
82674
|
-
for (let revealedUnitCount = 0; revealedUnitCount < totalUnitCount; revealedUnitCount += unitsPerStep) {
|
|
82675
|
-
const lines = buildPartiallyRevealedTallyLines(tallies, revealedUnitCount);
|
|
82676
|
-
yield* writeStdout(`${revealedUnitCount === 0 ? "" : `\x1b[${tallies.length}A`}\r${lines.join("\n\r")}\n`);
|
|
82677
|
-
yield* sleep(70);
|
|
82678
|
-
}
|
|
82679
|
-
yield* writeStdout(`${totalUnitCount === 0 ? "" : `\x1b[${tallies.length}A`}\r${buildCategoryTallyLines(tallies).join("\n\r")}\n`);
|
|
82680
|
-
yield* sleep(CATEGORY_COUNTUP_SETTLE_HOLD_MS);
|
|
82681
|
-
});
|
|
82682
|
-
const TOP_ERROR_DETAIL_INDENT = " ";
|
|
82683
|
-
const pickRepresentativeDiagnostic = (ruleDiagnostics) => ruleDiagnostics.find((diagnostic) => diagnostic.line > 0) ?? ruleDiagnostics[0];
|
|
82684
|
-
const hasIndistinctSiteLocations = (ruleDiagnostics) => {
|
|
82685
|
-
const firstDiagnostic = ruleDiagnostics[0];
|
|
82686
|
-
if (firstDiagnostic === void 0) return false;
|
|
82687
|
-
return ruleDiagnostics.every((diagnostic) => diagnostic.line <= 0 && diagnostic.filePath === firstDiagnostic.filePath);
|
|
82688
|
-
};
|
|
82689
|
-
const FRAME_CONTEXT_REACH_LINES = 3;
|
|
82690
|
-
const clusterNearbyDiagnostics = (diagnostics) => {
|
|
82691
|
-
const byFile = groupBy(diagnostics, (diagnostic) => diagnostic.filePath);
|
|
82692
|
-
const clusters = [];
|
|
82693
|
-
for (const fileDiagnostics of byFile.values()) {
|
|
82694
|
-
const sorted = [...fileDiagnostics].sort((left, right) => left.line - right.line);
|
|
82695
|
-
let current = [];
|
|
82696
|
-
const flush = () => {
|
|
82697
|
-
if (current.length === 0) return;
|
|
82698
|
-
clusters.push({
|
|
82699
|
-
diagnostics: current,
|
|
82700
|
-
startLine: current[0].line,
|
|
82701
|
-
endLine: current[current.length - 1].line
|
|
82702
|
-
});
|
|
82703
|
-
current = [];
|
|
82704
|
-
};
|
|
82705
|
-
for (const diagnostic of sorted) {
|
|
82706
|
-
const previous = current[current.length - 1];
|
|
82707
|
-
if (previous != null && (diagnostic.line - previous.line > FRAME_CONTEXT_REACH_LINES || diagnostic.line - current[0].line > 20)) flush();
|
|
82708
|
-
current.push(diagnostic);
|
|
82709
|
-
}
|
|
82710
|
-
flush();
|
|
82711
|
-
}
|
|
82712
|
-
return clusters;
|
|
82713
|
-
};
|
|
82714
|
-
const formatClusterLocationText = (cluster) => {
|
|
82715
|
-
const { filePath } = cluster.diagnostics[0];
|
|
82716
|
-
if (cluster.startLine <= 0) return filePath;
|
|
82717
|
-
if (cluster.endLine > cluster.startLine) return `${filePath}:${cluster.startLine}-${cluster.endLine}`;
|
|
82718
|
-
return `${filePath}:${cluster.startLine}`;
|
|
82719
|
-
};
|
|
82720
|
-
const formatClusterLocation = (cluster, resolveSourceRoot, hyperlinks) => {
|
|
82721
|
-
const lead = cluster.diagnostics[0];
|
|
82722
|
-
const contextTag = formatFileContextTag(lead);
|
|
82723
|
-
const location = formatClusterLocationText(cluster);
|
|
82724
|
-
if (!hyperlinks) return `${location}${contextTag}`;
|
|
82725
|
-
return `${formatHyperlink(location, pathToFileURL(resolveAbsolutePath(lead.filePath, resolveSourceRoot(lead))).href)}${contextTag}`;
|
|
82726
|
-
};
|
|
82727
|
-
const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, resolveFrameSourceRoot, renderCodeFrame, hyperlinks) => {
|
|
82728
|
-
const lead = cluster.diagnostics[0];
|
|
82729
|
-
const isMultiSite = cluster.diagnostics.length > 1;
|
|
82730
|
-
const sourceRoot = resolveSourceRoot(lead);
|
|
82731
|
-
const frameSourceRoot = resolveFrameSourceRoot(lead);
|
|
82732
|
-
const frameFilePath = Path.isAbsolute(lead.filePath) && sourceRoot !== frameSourceRoot ? Path.relative(sourceRoot, lead.filePath) : lead.filePath;
|
|
82733
|
-
const lines = ["", highlighter.gray(`${TOP_ERROR_DETAIL_INDENT}${formatClusterLocation(cluster, resolveSourceRoot, hyperlinks)}`)];
|
|
82734
|
-
const codeFrame = renderCodeFrame ? buildCodeFrame({
|
|
82735
|
-
filePath: frameFilePath,
|
|
82736
|
-
line: cluster.startLine,
|
|
82737
|
-
column: isMultiSite ? 0 : lead.column,
|
|
82738
|
-
endLine: isMultiSite ? cluster.endLine : void 0,
|
|
82739
|
-
rootDirectory: frameSourceRoot
|
|
82740
|
-
}) : null;
|
|
82741
|
-
if (codeFrame) {
|
|
82742
|
-
const boxInnerWidth = resolveMeasureWidth(8);
|
|
82743
|
-
lines.push(indentMultilineText(boxText(codeFrame, boxInnerWidth), TOP_ERROR_DETAIL_INDENT));
|
|
82744
|
-
}
|
|
82745
|
-
const seenHints = /* @__PURE__ */ new Set();
|
|
82746
|
-
for (const diagnostic of cluster.diagnostics) if (diagnostic.suppressionHint && !seenHints.has(diagnostic.suppressionHint)) {
|
|
82747
|
-
seenHints.add(diagnostic.suppressionHint);
|
|
82748
|
-
lines.push(highlighter.gray(`${TOP_ERROR_DETAIL_INDENT}↳ ${diagnostic.suppressionHint}`));
|
|
82749
|
-
}
|
|
82750
|
-
return lines;
|
|
82751
|
-
};
|
|
82752
|
-
const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, renderEverySite, isAgentEnvironment, hyperlinks) => {
|
|
82753
|
-
const representative = pickRepresentativeDiagnostic(ruleDiagnostics);
|
|
82754
|
-
const { severity } = representative;
|
|
82755
|
-
const trailingBadge = formatTrailingSiteBadge(ruleDiagnostics.length);
|
|
82756
|
-
const headline = colorizeBySeverity(`${representative.category}: ${representative.title ?? ruleKey}`, severity);
|
|
82757
|
-
const lines = [` ${colorizeBySeverity(severity === "error" ? "✖" : "⚠", severity)} ${headline}${trailingBadge}`];
|
|
82758
|
-
if (renderEverySite && !isAgentEnvironment) {
|
|
82759
|
-
const learnMoreLine = formatLearnMoreLine(representative);
|
|
82760
|
-
if (learnMoreLine) lines.push(`${TOP_ERROR_DETAIL_INDENT}${highlighter.info(learnMoreLine)}`);
|
|
82761
|
-
}
|
|
82762
|
-
const isCollapsedWarningGroup = severity === "warning" && hasIndistinctSiteLocations(ruleDiagnostics);
|
|
82763
|
-
const impactMessages = isCollapsedWarningGroup ? [...new Set(ruleDiagnostics.map((diagnostic) => diagnostic.message))] : [representative.message];
|
|
82764
|
-
for (const impactMessage of impactMessages) for (const explanationLine of wrapTextToWidth(impactMessage, resolveMeasureWidth(4), { breakLongWords: false })) lines.push(`${TOP_ERROR_DETAIL_INDENT}${explanationLine}`);
|
|
82765
|
-
if (representative.help) for (const fixLine of wrapTextToWidth(`→ ${representative.help}`, resolveMeasureWidth(4), { breakLongWords: false })) lines.push(highlighter.dim(`${TOP_ERROR_DETAIL_INDENT}${fixLine}`));
|
|
82766
|
-
const sharedFixSiteCount = getSharedFixSiteCount(ruleDiagnostics);
|
|
82767
|
-
if (sharedFixSiteCount > 0) lines.push(highlighter.dim(`${TOP_ERROR_DETAIL_INDENT}↳ One fix clears all ${sharedFixSiteCount} findings.`));
|
|
82768
|
-
if (renderEverySite && isAgentEnvironment) {
|
|
82769
|
-
const fixRecipeLine = formatFixRecipeLine(representative);
|
|
82770
|
-
if (fixRecipeLine) lines.push(highlighter.gray(`${TOP_ERROR_DETAIL_INDENT}${fixRecipeLine}`));
|
|
82771
|
-
}
|
|
82772
|
-
const renderCodeFrame = severity === "error";
|
|
82773
|
-
const sites = renderEverySite ? ruleDiagnostics : [representative];
|
|
82774
|
-
if (!(isCollapsedWarningGroup && representative.help.includes(representative.filePath))) for (const cluster of clusterNearbyDiagnostics(sites)) lines.push(...buildDiagnosticClusterLines(cluster, resolveSourceRoot, resolveFrameSourceRoot, renderCodeFrame, hyperlinks));
|
|
82775
|
-
return lines;
|
|
82776
|
-
};
|
|
82777
|
-
const selectErrorRuleGroups = (diagnostics, rulePriority) => buildSortedRuleGroups(diagnostics.filter((diagnostic) => diagnostic.severity === "error"), rulePriority);
|
|
82778
|
-
const selectTopErrorRuleGroups = (diagnostics, limit, rulePriority) => selectErrorRuleGroups(diagnostics, rulePriority).slice(0, limit);
|
|
82779
|
-
const buildOverflowSummaryLine = (diagnostics, rulePriority) => {
|
|
82780
|
-
const errorRuleGroups = selectErrorRuleGroups(diagnostics, rulePriority);
|
|
82781
|
-
const shownErrorRuleCount = Math.min(3, errorRuleGroups.length);
|
|
82782
|
-
if (diagnostics.length <= shownErrorRuleCount) return void 0;
|
|
82783
|
-
const command = highlighter.bold(highlighter.info("npx react-doctor@latest --verbose"));
|
|
82784
|
-
return ` ${highlighter.dim("Run")} ${command} ${highlighter.dim("to list every error and warning")}`;
|
|
82785
|
-
};
|
|
82786
|
-
const formatMigrationBucketLine = (bucket) => `${TOP_ERROR_DETAIL_INDENT}${bucket.title} ${highlighter.gray(`×${bucket.siteCount} across ${bucket.fileCount} files`)}`;
|
|
82787
|
-
const buildMigrationScaleAdvisoryLines = (diagnostics) => {
|
|
82788
|
-
const buckets = findMigrationScaleBuckets(diagnostics);
|
|
82789
|
-
if (buckets.length === 0) return [];
|
|
82790
|
-
const shownBuckets = buckets.slice(0, 3);
|
|
82791
|
-
const lines = [` ${highlighter.warn("⚠")} ${highlighter.bold("Migration-scale change")}${highlighter.dim(": sample before you sweep")}`, ...shownBuckets.map(formatMigrationBucketLine)];
|
|
82792
|
-
const remainingBuckets = buckets.length - shownBuckets.length;
|
|
82793
|
-
if (remainingBuckets > 0) lines.push(highlighter.gray(`${TOP_ERROR_DETAIL_INDENT}+${remainingBuckets} more ${remainingBuckets === 1 ? "rule" : "rules"} at this scale`));
|
|
82794
|
-
for (const guidanceLine of wrapTextToWidth("Fixing all of them at once is hard to review and prone to subtle mistakes across the whole repo. Fix a representative few first and confirm the recipe holds. Then get the code owner's sign-off before changing the rest.", resolveMeasureWidth(4), { breakLongWords: false })) lines.push(highlighter.dim(`${TOP_ERROR_DETAIL_INDENT}${guidanceLine}`));
|
|
82795
|
-
const command = highlighter.info("npx react-doctor@latest <path>");
|
|
82796
|
-
lines.push(`${TOP_ERROR_DETAIL_INDENT}${highlighter.dim("Scope it down one area at a time:")} ${command}`);
|
|
82797
|
-
return lines;
|
|
82798
|
-
};
|
|
82799
|
-
const getTopErrorRuleKeys = (diagnostics, limit, rulePriority) => new Set(selectTopErrorRuleGroups(diagnostics, limit, rulePriority).map(([ruleKey]) => ruleKey));
|
|
82800
|
-
const buildTopErrorsSection = (diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority) => {
|
|
82801
|
-
const topRuleGroups = selectErrorRuleGroups(diagnostics, rulePriority).slice(0, 3);
|
|
82802
|
-
if (topRuleGroups.length === 0) return {
|
|
82803
|
-
lines: [],
|
|
82804
|
-
blockOffsets: []
|
|
82805
|
-
};
|
|
82806
|
-
const lines = [` ${highlighter.bold(`Top ${topRuleGroups.length} ${topRuleGroups.length === 1 ? "error" : "errors"} you should fix`)}`, ""];
|
|
82807
|
-
const blockOffsets = [];
|
|
82808
|
-
for (const [ruleKey, ruleDiagnostics] of topRuleGroups) {
|
|
82809
|
-
blockOffsets.push(lines.length);
|
|
82810
|
-
lines.push(...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, false, false, hyperlinks));
|
|
82811
|
-
lines.push("");
|
|
82812
|
-
}
|
|
82813
|
-
return {
|
|
82814
|
-
lines,
|
|
82815
|
-
blockOffsets
|
|
82816
|
-
};
|
|
82817
|
-
};
|
|
82818
|
-
const joinSections = (...sections) => {
|
|
82819
|
-
const lines = [];
|
|
82820
|
-
const sectionStarts = [];
|
|
82821
|
-
for (const section of sections) {
|
|
82822
|
-
if (section.length === 0) {
|
|
82823
|
-
sectionStarts.push(null);
|
|
82824
|
-
continue;
|
|
82825
|
-
}
|
|
82826
|
-
if (lines.length > 0) lines.push("");
|
|
82827
|
-
sectionStarts.push(lines.length);
|
|
82828
|
-
lines.push(...section);
|
|
82829
|
-
}
|
|
82830
|
-
if (lines.length > 0 && lines[lines.length - 1] !== "") lines.push("");
|
|
82831
|
-
return {
|
|
82832
|
-
lines,
|
|
82833
|
-
sectionStarts
|
|
82834
|
-
};
|
|
82835
|
-
};
|
|
82836
|
-
const buildOverviewHeaderLines = (diagnostics) => {
|
|
82837
|
-
const totalIssueCount = diagnostics.length;
|
|
82838
|
-
if (totalIssueCount === 0) return [];
|
|
82839
|
-
const issueNoun = totalIssueCount === 1 ? "issue" : "issues";
|
|
82840
|
-
return [` ${highlighter.bold(`All ${totalIssueCount} ${issueNoun}`)}`];
|
|
82841
|
-
};
|
|
82842
|
-
/**
|
|
82843
|
-
* Effect-typed diagnostics renderer. Internal helpers build the
|
|
82844
|
-
* line array purely; the IO happens once at the boundary with a
|
|
82845
|
-
* single Effect.forEach over Console.log so failures or fiber
|
|
82846
|
-
* interruption produce predictable partial output.
|
|
82847
|
-
*/
|
|
82848
|
-
const printDiagnostics = (diagnostics, isVerbose, sourceRoot, rulePriority, isAgentEnvironment = false, onboarding = {}, hyperlinks = false, frameSourceRoot = sourceRoot) => gen(function* () {
|
|
82849
|
-
const sectionPause = onboarding.sectionPause ?? void_;
|
|
82850
|
-
const animateCountUp = onboarding.animateCountUp ?? false;
|
|
82851
|
-
const resolveSourceRoot = typeof sourceRoot === "function" ? sourceRoot : () => sourceRoot;
|
|
82852
|
-
const resolveFrameSourceRoot = typeof frameSourceRoot === "function" ? frameSourceRoot : () => frameSourceRoot;
|
|
82853
|
-
let detailLines;
|
|
82854
|
-
let topErrorBlockOffsets = [];
|
|
82855
|
-
if (!isVerbose) {
|
|
82856
|
-
const topErrors = buildTopErrorsSection(diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority);
|
|
82857
|
-
detailLines = topErrors.lines;
|
|
82858
|
-
topErrorBlockOffsets = topErrors.blockOffsets;
|
|
82859
|
-
} else detailLines = buildSortedRuleGroups(diagnostics, rulePriority).flatMap(([ruleKey, ruleDiagnostics]) => {
|
|
82860
|
-
return [...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, true, isAgentEnvironment, hyperlinks), ""];
|
|
82861
|
-
});
|
|
82862
|
-
const overflowLine = isVerbose ? void 0 : buildOverflowSummaryLine(diagnostics, rulePriority);
|
|
82863
|
-
const categoryTallies = buildCategoryDiagnosticGroups(diagnostics, rulePriority).map(buildCategoryTally);
|
|
82864
|
-
const categoryLines = buildCategoryTallyLines(categoryTallies);
|
|
82865
|
-
const overviewDividerLines = detailLines.length > 0 && categoryLines.length > 0 ? [buildSectionDivider()] : [];
|
|
82866
|
-
const { lines, sectionStarts } = joinSections(detailLines, overviewDividerLines, buildOverviewHeaderLines(diagnostics), categoryLines, overflowLine ? [overflowLine] : [], buildMigrationScaleAdvisoryLines(diagnostics));
|
|
82867
|
-
const [detailStart, , , categoryStart] = sectionStarts;
|
|
82868
|
-
const pauseBeforeLineIndices = detailStart == null ? /* @__PURE__ */ new Set() : new Set(topErrorBlockOffsets.map((offset) => detailStart + offset));
|
|
82869
|
-
let lineIndex = 0;
|
|
82870
|
-
while (lineIndex < lines.length) {
|
|
82871
|
-
if (animateCountUp && lineIndex === categoryStart && categoryLines.length > 0) {
|
|
82872
|
-
yield* printCategoryCountUp(categoryTallies);
|
|
82873
|
-
lineIndex += categoryLines.length;
|
|
82874
|
-
continue;
|
|
82875
|
-
}
|
|
82876
|
-
if (pauseBeforeLineIndices.has(lineIndex)) yield* sectionPause;
|
|
82877
|
-
yield* log(lines[lineIndex]);
|
|
82878
|
-
lineIndex += 1;
|
|
82879
|
-
}
|
|
82880
|
-
});
|
|
82881
|
-
const formatElapsedTime = (elapsedMilliseconds) => {
|
|
82882
|
-
if (elapsedMilliseconds < 1e3) return `${Math.round(elapsedMilliseconds)}ms`;
|
|
82883
|
-
return `${(elapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1)}s`;
|
|
82884
|
-
};
|
|
82885
|
-
const formatRuleSummary = (ruleKey, ruleDiagnostics) => {
|
|
82886
|
-
const firstDiagnostic = ruleDiagnostics[0];
|
|
82887
|
-
const distinctMessages = [...new Set(ruleDiagnostics.map((diagnostic) => diagnostic.message))];
|
|
82888
|
-
const sections = [
|
|
82889
|
-
`Rule: ${ruleKey}`,
|
|
82890
|
-
`Severity: ${firstDiagnostic.severity}`,
|
|
82891
|
-
`Category: ${firstDiagnostic.category}`,
|
|
82892
|
-
`Count: ${ruleDiagnostics.length}`,
|
|
82893
|
-
"",
|
|
82894
|
-
distinctMessages.join("\n\n")
|
|
82895
|
-
];
|
|
82896
|
-
if (firstDiagnostic.help) sections.push("", `Suggestion: ${firstDiagnostic.help}`);
|
|
82897
|
-
if (firstDiagnostic.url) sections.push("", `Docs: ${firstDiagnostic.url}`);
|
|
82898
|
-
const fixRecipeLine = formatFixRecipeLine(firstDiagnostic);
|
|
82899
|
-
if (fixRecipeLine) sections.push("", fixRecipeLine);
|
|
82900
|
-
sections.push("", "Files:");
|
|
82901
|
-
const fileEntries = buildVerboseFileEntries(ruleDiagnostics);
|
|
82902
|
-
for (const [filePath, { contextTag, sites }] of fileEntries) if (sites.length > 0) for (const site of sites) {
|
|
82903
|
-
sections.push(` ${filePath}:${site.line}${contextTag}`);
|
|
82904
|
-
if (site.suppressionHint) sections.push(` ${site.suppressionHint}`);
|
|
82905
|
-
}
|
|
82906
|
-
else sections.push(` ${filePath}${contextTag}`);
|
|
82907
|
-
return sections.join("\n") + "\n";
|
|
82908
|
-
};
|
|
82909
|
-
//#endregion
|
|
82910
|
-
//#region src/cli/utils/compute-score-projection.ts
|
|
82911
|
-
const computeProjectedScore = async (topErrorSource, rescoreSource, currentScore) => {
|
|
82912
|
-
const topErrorRuleKeys = getTopErrorRuleKeys(topErrorSource, 3, buildRulePriorityMap([currentScore]));
|
|
82913
|
-
if (topErrorRuleKeys.size === 0) return null;
|
|
82914
|
-
const potentialScore = await calculateScore(rescoreSource.filter((diagnostic) => !topErrorRuleKeys.has(`${diagnostic.plugin}/${diagnostic.rule}`)));
|
|
82915
|
-
if (!potentialScore || potentialScore.score <= currentScore.score) return null;
|
|
82916
|
-
return potentialScore.score;
|
|
82917
|
-
};
|
|
82918
|
-
//#endregion
|
|
82919
|
-
//#region src/cli/utils/filter-diagnostics-by-categories.ts
|
|
82920
|
-
const filterDiagnosticsByCategories = (diagnostics, categories) => categories.size === 0 ? [...diagnostics] : diagnostics.filter((diagnostic) => categories.has(diagnostic.category));
|
|
82921
|
-
//#endregion
|
|
82922
|
-
//#region src/cli/utils/supports-hyperlinks.ts
|
|
82923
|
-
const HYPERLINK_CAPABLE_TERM_PROGRAMS = new Set([
|
|
82924
|
-
"iTerm.app",
|
|
82925
|
-
"WezTerm",
|
|
82926
|
-
"vscode",
|
|
82927
|
-
"Hyper",
|
|
82928
|
-
"ghostty",
|
|
82929
|
-
"Tabby",
|
|
82930
|
-
"rio"
|
|
82931
|
-
]);
|
|
82932
|
-
const parseVteVersion = (raw) => {
|
|
82933
|
-
const parsed = Number.parseInt(raw ?? "", 10);
|
|
82934
|
-
return Number.isNaN(parsed) ? 0 : parsed;
|
|
82935
|
-
};
|
|
82936
|
-
/**
|
|
82937
|
-
* Whether `stream` is a terminal that renders OSC 8 hyperlinks. Auto-detected
|
|
82938
|
-
* from terminal-identity env vars; the de-facto `FORCE_HYPERLINK` env var
|
|
82939
|
-
* overrides detection (`FORCE_HYPERLINK=0`/`false` forces off, any other value
|
|
82940
|
-
* forces on), mirroring how the ecosystem's terminal libraries gate the same
|
|
82941
|
-
* feature. Off for non-TTYs, `TERM=dumb`, and CI (whose log viewers render the
|
|
82942
|
-
* raw escape rather than a link). Unknown terminals default to off.
|
|
82943
|
-
*/
|
|
82944
|
-
const supportsHyperlinks = (stream = process.stdout, env = process.env) => {
|
|
82945
|
-
const forced = env.FORCE_HYPERLINK;
|
|
82946
|
-
if (forced !== void 0 && forced !== "") return forced !== "0" && forced.toLowerCase() !== "false";
|
|
82947
|
-
if (stream.isTTY !== true) return false;
|
|
82948
|
-
if (env.TERM === "dumb") return false;
|
|
82949
|
-
if (isCiEnvironment(env)) return false;
|
|
82950
|
-
if (env.WT_SESSION) return true;
|
|
82951
|
-
if (env.KITTY_WINDOW_ID || env.TERM === "xterm-kitty") return true;
|
|
82952
|
-
if (parseVteVersion(env.VTE_VERSION) >= 5e3) return true;
|
|
82953
|
-
return Boolean(env.TERM_PROGRAM && HYPERLINK_CAPABLE_TERM_PROGRAMS.has(env.TERM_PROGRAM));
|
|
82954
|
-
};
|
|
82955
|
-
//#endregion
|
|
82956
|
-
//#region src/cli/utils/should-render-hyperlinks.ts
|
|
82957
|
-
/**
|
|
82958
|
-
* Whether to emit OSC 8 clickable `file:line` locations for this run: a
|
|
82959
|
-
* hyperlink-capable terminal AND not a coding agent (whose output parsers
|
|
82960
|
-
* would choke on the escape sequences).
|
|
82961
|
-
*/
|
|
82962
|
-
const shouldRenderHyperlinks = (stream = process.stdout) => supportsHyperlinks(stream) && !isCodingAgentEnvironment();
|
|
82963
|
-
//#endregion
|
|
82964
|
-
//#region src/cli/utils/should-show-share-link.ts
|
|
82965
|
-
const shouldShowShareLink = ({ noScore, share, isCi }) => !noScore && share && !isCi;
|
|
82966
|
-
const FORCE_ONBOARDING_ENV_VAR = "REACT_DOCTOR_FORCE_ONBOARDING";
|
|
82967
|
-
const FALSY_FLAG_VALUES = new Set([
|
|
82968
|
-
"",
|
|
82969
|
-
"0",
|
|
82970
|
-
"false"
|
|
82971
|
-
]);
|
|
82972
|
-
const isOnboardingForced = (environment = process.env) => {
|
|
82973
|
-
const value = environment[FORCE_ONBOARDING_ENV_VAR];
|
|
82974
|
-
return value !== void 0 && !FALSY_FLAG_VALUES.has(value.toLowerCase());
|
|
82975
|
-
};
|
|
82976
|
-
const onboardingSectionPause = (shouldPace) => shouldPace ? sleep(850) : void_;
|
|
82977
|
-
const shouldRecordOnboarding = (input) => input.paceOnboardingSections && !input.forceOnboarding && !input.verbose && !input.isNonInteractiveEnvironment;
|
|
82978
|
-
const canAnimateOnboarding = (stream = process.stdout) => {
|
|
82979
|
-
if (!(stream.isTTY === true && (stream.columns ?? 0) > 0 && process.env.TERM !== "dumb")) return false;
|
|
82980
|
-
if (isOnboardingForced()) return true;
|
|
82981
|
-
return !isGitHookEnvironment() && !isCiEnvironment();
|
|
82982
|
-
};
|
|
82983
|
-
//#endregion
|
|
82984
|
-
//#region src/cli/utils/now-iso.ts
|
|
82985
|
-
const nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
82986
|
-
const ONBOARDING_EVENT = "onboarding";
|
|
82987
|
-
const CI_PITCH_EVENT = "ci-pitch";
|
|
82988
|
-
const ACTION_UPGRADE_EVENT = "action-upgrade-v2";
|
|
82989
|
-
const SETUP_HINT_EVENT = "setup-hint";
|
|
82990
|
-
const HANDOFF_TARGET_PREFERENCE_ID = "handoff-target";
|
|
82991
|
-
const INSTALL_AGENTS_PREFERENCE_ID = "install-agents";
|
|
82992
|
-
const foldLegacyDecisions = (projects, legacy, eventId) => {
|
|
82993
|
-
for (const [hash, record] of Object.entries(legacy ?? {})) {
|
|
82994
|
-
const existing = projects[hash] ?? { rootDirectory: record.rootDirectory ?? "" };
|
|
82995
|
-
projects[hash] = {
|
|
82996
|
-
...existing,
|
|
82997
|
-
events: {
|
|
82998
|
-
...existing.events,
|
|
82999
|
-
[eventId]: {
|
|
83000
|
-
firedAt: record.at ?? nowIso(),
|
|
83001
|
-
version: 1,
|
|
83002
|
-
...record.outcome ? { outcome: record.outcome } : {}
|
|
83003
|
-
}
|
|
83004
|
-
}
|
|
83005
|
-
};
|
|
83006
|
-
}
|
|
83007
|
-
};
|
|
83008
|
-
const migrateCliState = (state) => {
|
|
83009
|
-
if (typeof state.schemaVersion === "number" && state.schemaVersion >= 2) return state;
|
|
83010
|
-
const projects = {};
|
|
83011
|
-
for (const [hash, record] of Object.entries(state.projects ?? {})) {
|
|
83012
|
-
const carried = {
|
|
83013
|
-
rootDirectory: record.rootDirectory,
|
|
83014
|
-
...record.events ? { events: record.events } : {},
|
|
83015
|
-
...record.migrations ? { migrations: record.migrations } : {}
|
|
83016
|
-
};
|
|
83017
|
-
projects[hash] = record.setupPrompt === false ? {
|
|
83018
|
-
...carried,
|
|
83019
|
-
events: {
|
|
83020
|
-
...carried.events,
|
|
83021
|
-
[SETUP_HINT_EVENT]: {
|
|
83022
|
-
firedAt: nowIso(),
|
|
83023
|
-
version: 1,
|
|
83024
|
-
outcome: "declined"
|
|
83025
|
-
}
|
|
83026
|
-
}
|
|
83027
|
-
} : carried;
|
|
83028
|
-
}
|
|
83029
|
-
foldLegacyDecisions(projects, state.ciPrompts, CI_PITCH_EVENT);
|
|
83030
|
-
foldLegacyDecisions(projects, state.actionUpgrades, ACTION_UPGRADE_EVENT);
|
|
83031
|
-
return {
|
|
83032
|
-
schemaVersion: 2,
|
|
83033
|
-
global: typeof state.onboardedAt === "string" ? { events: { [ONBOARDING_EVENT]: {
|
|
83034
|
-
firedAt: state.onboardedAt,
|
|
83035
|
-
version: 1
|
|
83036
|
-
} } } : {},
|
|
83037
|
-
projects
|
|
83038
|
-
};
|
|
83039
|
-
};
|
|
83040
|
-
const resolveConfigDir = (options) => options.cwd ?? (process.env["REACT_DOCTOR_CONFIG_DIR"] || void 0);
|
|
83041
|
-
const openStore = (options = {}) => new Conf({
|
|
83042
|
-
projectName: REACT_DOCTOR_CONFIG_PROJECT_NAME,
|
|
83043
|
-
cwd: resolveConfigDir(options)
|
|
83044
|
-
});
|
|
83045
|
-
const openMigratedStore = (options) => {
|
|
83046
|
-
const store = openStore(options);
|
|
83047
|
-
const state = store.store;
|
|
83048
|
-
const migrated = migrateCliState(state);
|
|
83049
|
-
if (migrated !== state) store.store = migrated;
|
|
83050
|
-
return store;
|
|
83051
|
-
};
|
|
83052
|
-
const readCliState = (select, fallback, options = {}) => {
|
|
83053
|
-
try {
|
|
83054
|
-
return select(openMigratedStore(options).store);
|
|
83055
|
-
} catch {
|
|
83056
|
-
return fallback;
|
|
83057
|
-
}
|
|
83058
|
-
};
|
|
83059
|
-
const updateCliState = (update, options = {}) => {
|
|
83060
|
-
try {
|
|
83061
|
-
const store = openMigratedStore(options);
|
|
83062
|
-
store.store = update(store.store);
|
|
83063
|
-
return true;
|
|
83064
|
-
} catch {
|
|
83065
|
-
return false;
|
|
83066
|
-
}
|
|
83067
|
-
};
|
|
83068
|
-
//#endregion
|
|
83069
|
-
//#region src/cli/utils/hash-project-root.ts
|
|
83070
|
-
const hashProjectRoot = (projectRoot) => createHash("sha256").update(Path.resolve(projectRoot)).digest("hex");
|
|
83071
|
-
//#endregion
|
|
83072
|
-
//#region src/cli/utils/cli-lifecycle.ts
|
|
83073
|
-
const versionOf = (item) => item.version ?? 1;
|
|
83074
|
-
const selectScope = (state, scoped, projectRoot) => scoped.scope === "global" ? state.global : projectRoot === void 0 ? void 0 : state.projects?.[hashProjectRoot(projectRoot)];
|
|
83075
|
-
const updateScope = (state, scoped, projectRoot, updateScopeState) => {
|
|
83076
|
-
if (scoped.scope === "global") return {
|
|
83077
|
-
...state,
|
|
83078
|
-
global: updateScopeState(state.global ?? {})
|
|
83079
|
-
};
|
|
83080
|
-
if (projectRoot === void 0) return state;
|
|
83081
|
-
const projectKey = hashProjectRoot(projectRoot);
|
|
83082
|
-
const base = state.projects?.[projectKey] ?? { rootDirectory: Path.resolve(projectRoot) };
|
|
83083
|
-
return {
|
|
83084
|
-
...state,
|
|
83085
|
-
projects: {
|
|
83086
|
-
...state.projects,
|
|
83087
|
-
[projectKey]: {
|
|
83088
|
-
...base,
|
|
83089
|
-
...updateScopeState(base)
|
|
83090
|
-
}
|
|
83091
|
-
}
|
|
83092
|
-
};
|
|
83093
|
-
};
|
|
83094
|
-
const isGatePending = (gate, target = {}, options = {}) => {
|
|
83095
|
-
if (gate.scope === "project" && target.projectRoot === void 0) return false;
|
|
83096
|
-
return readCliState((state) => {
|
|
83097
|
-
const record = selectScope(state, gate, target.projectRoot)?.events?.[gate.id];
|
|
83098
|
-
return !record || record.version < versionOf(gate);
|
|
83099
|
-
}, gate.fireWhenUnknown ?? false, options);
|
|
83100
|
-
};
|
|
83101
|
-
const recordGate = (gate, target = {}, options = {}) => updateCliState((state) => updateScope(state, gate, target.projectRoot, (scope) => ({
|
|
83102
|
-
...scope,
|
|
83103
|
-
events: {
|
|
83104
|
-
...scope.events,
|
|
83105
|
-
[gate.id]: {
|
|
83106
|
-
firedAt: nowIso(),
|
|
83107
|
-
version: versionOf(gate),
|
|
83108
|
-
...target.outcome ? { outcome: target.outcome } : {}
|
|
83109
|
-
}
|
|
83110
|
-
}
|
|
83111
|
-
})), options);
|
|
83112
|
-
const readPreference = (preference, target = {}, options = {}) => readCliState((state) => selectScope(state, preference, target.projectRoot)?.preferences?.[preference.id] ?? null, null, options);
|
|
83113
|
-
const writePreference = (preference, value, target = {}, options = {}) => updateCliState((state) => updateScope(state, preference, target.projectRoot, (scope) => ({
|
|
83114
|
-
...scope,
|
|
83115
|
-
preferences: {
|
|
83116
|
-
...scope.preferences,
|
|
83117
|
-
[preference.id]: value
|
|
83118
|
-
}
|
|
83119
|
-
})), options);
|
|
83120
|
-
const isMigrationPending = (migration, target = {}, options = {}) => {
|
|
83121
|
-
if (migration.scope === "project" && target.projectRoot === void 0) return false;
|
|
83122
|
-
return readCliState((state) => {
|
|
83123
|
-
const record = selectScope(state, migration, target.projectRoot)?.migrations?.[migration.id];
|
|
83124
|
-
return !record || record.version < versionOf(migration);
|
|
83125
|
-
}, false, options);
|
|
83126
|
-
};
|
|
83127
|
-
const recordMigration = (migration, projectRoot, record, options) => updateCliState((state) => updateScope(state, migration, projectRoot, (scope) => ({
|
|
83128
|
-
...scope,
|
|
83129
|
-
migrations: {
|
|
83130
|
-
...scope.migrations,
|
|
83131
|
-
[migration.id]: record
|
|
83132
|
-
}
|
|
83133
|
-
})), options);
|
|
83134
|
-
const runMigrations = async (migrations, target = {}, options = {}) => {
|
|
83135
|
-
const results = [];
|
|
83136
|
-
for (const migration of migrations) {
|
|
83137
|
-
if (!isMigrationPending(migration, target, options)) {
|
|
83138
|
-
results.push({
|
|
83139
|
-
id: migration.id,
|
|
83140
|
-
ran: false,
|
|
83141
|
-
applied: true
|
|
83142
|
-
});
|
|
83143
|
-
continue;
|
|
83144
|
-
}
|
|
83145
|
-
let applied = false;
|
|
83146
|
-
try {
|
|
83147
|
-
applied = await migration.run({ projectRoot: target.projectRoot });
|
|
83148
|
-
} catch {
|
|
83149
|
-
applied = false;
|
|
83150
|
-
}
|
|
83151
|
-
if (applied) recordMigration(migration, target.projectRoot, {
|
|
83152
|
-
ranAt: nowIso(),
|
|
83153
|
-
version: versionOf(migration)
|
|
83154
|
-
}, options);
|
|
83155
|
-
results.push({
|
|
83156
|
-
id: migration.id,
|
|
83157
|
-
ran: true,
|
|
83158
|
-
applied
|
|
83159
|
-
});
|
|
83160
|
-
}
|
|
83161
|
-
return results;
|
|
83162
|
-
};
|
|
83163
|
-
//#endregion
|
|
83164
|
-
//#region src/cli/utils/onboarding-state.ts
|
|
83165
|
-
const ONBOARDING_GATE = {
|
|
83166
|
-
id: ONBOARDING_EVENT,
|
|
83167
|
-
scope: "global"
|
|
83168
|
-
};
|
|
83169
|
-
const hasCompletedOnboarding = (options = {}) => !isGatePending(ONBOARDING_GATE, {}, options);
|
|
83170
|
-
const markOnboardingComplete = (options = {}) => {
|
|
83171
|
-
if (isGatePending(ONBOARDING_GATE, {}, options)) recordGate(ONBOARDING_GATE, {}, options);
|
|
83172
|
-
};
|
|
83173
|
-
//#endregion
|
|
83174
|
-
//#region src/cli/utils/colorize-by-score.ts
|
|
83175
|
-
const colorizeByScore = (text, score) => {
|
|
83176
|
-
if (score >= 75) return highlighter.success(text);
|
|
83177
|
-
if (score >= 50) return highlighter.warn(text);
|
|
83178
|
-
return highlighter.error(text);
|
|
83179
|
-
};
|
|
83180
|
-
//#endregion
|
|
83181
|
-
//#region src/cli/utils/doctor-face.ts
|
|
83182
|
-
const doctorFace = (score) => {
|
|
83183
|
-
if (score >= 75) return ["◠ ◠", " ▽ "];
|
|
83184
|
-
if (score >= 50) return ["• •", " ─ "];
|
|
83185
|
-
return ["x x", " ▽ "];
|
|
83186
|
-
};
|
|
83187
|
-
//#endregion
|
|
83188
|
-
//#region src/cli/utils/ease-out-cubic.ts
|
|
83189
|
-
const easeOutCubic = (progress) => 1 - (1 - progress) ** 3;
|
|
83190
|
-
//#endregion
|
|
83191
|
-
//#region src/cli/utils/render-score-header.ts
|
|
83192
|
-
const RAINBOW_HUE_SHIFT_PER_FRAME = 9;
|
|
83193
|
-
const RAINBOW_GRADIENT_WIDTH = 80;
|
|
83194
|
-
const RAINBOW_OKLCH_LIGHTNESS = .638;
|
|
83195
|
-
const RAINBOW_OKLCH_CHROMA = .129;
|
|
83196
|
-
const FACE_BOX_TOP_BORDER = "┌─────┐";
|
|
83197
|
-
const SCORE_RIGHT_COLUMN_OFFSET = 11;
|
|
83198
|
-
const getScoreBarWidth = () => resolveClampedWidth({
|
|
83199
|
-
reservedColumns: SCORE_RIGHT_COLUMN_OFFSET + 1,
|
|
83200
|
-
fullWidth: 50,
|
|
83201
|
-
minWidth: 10
|
|
83202
|
-
});
|
|
83203
|
-
const buildScoreBarSegments = (filledCount) => {
|
|
83204
|
-
const emptyCount = Math.max(0, getScoreBarWidth() - filledCount);
|
|
83205
|
-
return {
|
|
83206
|
-
filledSegment: "█".repeat(filledCount),
|
|
83207
|
-
emptySegment: "░".repeat(emptyCount)
|
|
83208
|
-
};
|
|
83209
|
-
};
|
|
83210
|
-
const getFilledCount = (score) => Math.round(score / 100 * getScoreBarWidth());
|
|
83211
|
-
const joinScoreHeaderFrame = (lines) => `${lines[0]}\n\r${lines[1]}\n\r${lines[2]}\n\r${lines[3]}\n`;
|
|
83212
|
-
const buildRawScoreBar = (displayScore) => {
|
|
83213
|
-
const { filledSegment, emptySegment } = buildScoreBarSegments(getFilledCount(displayScore));
|
|
83214
|
-
return filledSegment + emptySegment;
|
|
83215
|
-
};
|
|
83216
|
-
const buildScoreHeaderLine = (faceLine, rightColumnContent) => {
|
|
83217
|
-
return ` ${faceLine}${rightColumnContent.length > 0 ? " " : ""}${rightColumnContent}`;
|
|
83218
|
-
};
|
|
83219
|
-
const getRightColumnOffset = (faceLine) => ` ${faceLine} `.length;
|
|
83220
|
-
const clampColorChannel = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
83221
|
-
const encodeSrgb = (value) => value <= .0031308 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - .055;
|
|
83222
|
-
const oklchToRgb = (lightness, chroma, hue) => {
|
|
83223
|
-
const hueRadians = hue * Math.PI / 180;
|
|
83224
|
-
const labA = chroma * Math.cos(hueRadians);
|
|
83225
|
-
const labB = chroma * Math.sin(hueRadians);
|
|
83226
|
-
const longCone = (lightness + .3963377774 * labA + .2158037573 * labB) ** 3;
|
|
83227
|
-
const mediumCone = (lightness - .1055613458 * labA - .0638541728 * labB) ** 3;
|
|
83228
|
-
const shortCone = (lightness - .0894841775 * labA - 1.291485548 * labB) ** 3;
|
|
83229
|
-
return {
|
|
83230
|
-
red: clampColorChannel(encodeSrgb(4.0767416621 * longCone - 3.3077115913 * mediumCone + .2309699292 * shortCone) * 255),
|
|
83231
|
-
green: clampColorChannel(encodeSrgb(-1.2684380046 * longCone + 2.6097574011 * mediumCone - .3413193965 * shortCone) * 255),
|
|
83232
|
-
blue: clampColorChannel(encodeSrgb(-.0041960863 * longCone - .7034186147 * mediumCone + 1.707614701 * shortCone) * 255)
|
|
83233
|
-
};
|
|
83234
|
-
};
|
|
83235
|
-
const colorizeTrueColor = (text, { red, green, blue }) => `\x1b[38;2;${red};${green};${blue}m${text}\x1b[39m`;
|
|
83236
|
-
const colorizeRainbowText = (text, frame, offset = 0) => [...text].map((character, index) => {
|
|
83237
|
-
if (character === " ") return character;
|
|
83238
|
-
return colorizeTrueColor(character, oklchToRgb(RAINBOW_OKLCH_LIGHTNESS, RAINBOW_OKLCH_CHROMA, ((index + offset) / RAINBOW_GRADIENT_WIDTH * 360 + frame * RAINBOW_HUE_SHIFT_PER_FRAME) % 360));
|
|
83239
|
-
}).join("");
|
|
83240
|
-
const buildRainbowHeaderLine = (faceLine, rightColumnContent, frame) => colorizeRainbowText(buildScoreHeaderLine(faceLine, rightColumnContent), frame);
|
|
83241
|
-
const buildScoreBar = (displayScore, colorScore = displayScore) => {
|
|
83242
|
-
const { filledSegment, emptySegment } = buildScoreBarSegments(getFilledCount(displayScore));
|
|
83243
|
-
return colorizeByScore(filledSegment, colorScore) + highlighter.dim(emptySegment);
|
|
83244
|
-
};
|
|
83245
|
-
const buildProjectedScoreBar = (currentScore, potentialScore) => {
|
|
83246
|
-
const barWidth = getScoreBarWidth();
|
|
83247
|
-
const currentFill = getFilledCount(currentScore);
|
|
83248
|
-
const potentialFill = Math.min(getFilledCount(potentialScore), barWidth);
|
|
83249
|
-
const gainCount = Math.max(0, potentialFill - currentFill);
|
|
83250
|
-
const emptyCount = Math.max(0, barWidth - currentFill - gainCount);
|
|
83251
|
-
return colorizeByScore("█".repeat(currentFill), currentScore) + highlighter.dim(colorizeByScore("▓".repeat(gainCount), currentScore)) + highlighter.dim("░".repeat(emptyCount));
|
|
83252
|
-
};
|
|
83253
|
-
const BRANDING_LINE = `React Doctor ${highlighter.dim("(https://react.doctor)")}`;
|
|
83254
|
-
const RAW_BRANDING_LINE = "React Doctor (https://react.doctor)";
|
|
83255
|
-
const buildRawFaceLines = (score) => {
|
|
83256
|
-
const [eyes, mouth] = doctorFace(score);
|
|
83257
|
-
return [
|
|
83258
|
-
FACE_BOX_TOP_BORDER,
|
|
83259
|
-
`│ ${eyes} │`,
|
|
83260
|
-
`│ ${mouth} │`,
|
|
83261
|
-
"└─────┘"
|
|
83262
|
-
];
|
|
83263
|
-
};
|
|
83264
|
-
const buildFaceRenderedLines = (score) => {
|
|
83265
|
-
const colorize = (text) => colorizeByScore(text, score);
|
|
83266
|
-
return buildRawFaceLines(score).map(colorize);
|
|
83267
|
-
};
|
|
83268
|
-
const buildScoreLine = (displayScore, finalScore, label) => {
|
|
83269
|
-
const scoreNumber = colorizeByScore(`${displayScore}`, finalScore);
|
|
83270
|
-
const scoreLabel = colorizeByScore(label, finalScore);
|
|
83271
|
-
return `${scoreNumber} ${highlighter.dim(`/ 100`)} ${scoreLabel}`;
|
|
83272
|
-
};
|
|
83273
|
-
const buildRawScoreLine = (displayScore, label) => `${displayScore} / 100 ${label}`;
|
|
83274
|
-
const buildRainbowScoreHeaderFrame = ({ score, displayScore, label, frame }) => {
|
|
83275
|
-
const rawFaceLines = buildRawFaceLines(score);
|
|
83276
|
-
return joinScoreHeaderFrame([
|
|
83277
|
-
buildRainbowHeaderLine(rawFaceLines[0] ?? "", buildRawScoreLine(displayScore, label), frame),
|
|
83278
|
-
buildRainbowHeaderLine(rawFaceLines[1] ?? "", buildRawScoreBar(displayScore), frame),
|
|
83279
|
-
buildRainbowHeaderLine(rawFaceLines[2] ?? "", RAW_BRANDING_LINE, frame),
|
|
83280
|
-
buildRainbowHeaderLine(rawFaceLines[3] ?? "", "", frame)
|
|
83281
|
-
]);
|
|
83282
|
-
};
|
|
83283
|
-
const buildFinalPerfectScoreHeaderFrame = (score, label, frame) => {
|
|
83284
|
-
const rawFaceLines = buildRawFaceLines(score);
|
|
83285
|
-
const renderedFaceLines = buildFaceRenderedLines(score);
|
|
83286
|
-
const rainbowBarLine = colorizeRainbowText(buildRawScoreBar(score), frame, getRightColumnOffset(rawFaceLines[1] ?? ""));
|
|
83287
|
-
return joinScoreHeaderFrame([
|
|
83288
|
-
buildScoreHeaderLine(renderedFaceLines[0] ?? "", buildScoreLine(score, score, label)),
|
|
83289
|
-
buildScoreHeaderLine(renderedFaceLines[1] ?? "", rainbowBarLine),
|
|
83290
|
-
buildScoreHeaderLine(renderedFaceLines[2] ?? "", BRANDING_LINE),
|
|
83291
|
-
buildScoreHeaderLine(renderedFaceLines[3] ?? "", "")
|
|
83292
|
-
]);
|
|
83293
|
-
};
|
|
83294
|
-
const buildInitialScoreHeaderLine = ({ isPerfectScore, shouldAnimate, lineIndex, renderedFaceLine, rawFaceLine, rightColumnContent, rawRightColumnContent, score }) => {
|
|
83295
|
-
if (!isPerfectScore) return buildScoreHeaderLine(renderedFaceLine, rightColumnContent);
|
|
83296
|
-
if (shouldAnimate) return buildRainbowHeaderLine(rawFaceLine, rawRightColumnContent, 0);
|
|
83297
|
-
if (lineIndex !== 1) return buildScoreHeaderLine(renderedFaceLine, rightColumnContent);
|
|
83298
|
-
return buildScoreHeaderLine(renderedFaceLine, colorizeRainbowText(buildRawScoreBar(score), 0, getRightColumnOffset(rawFaceLine)));
|
|
83299
|
-
};
|
|
83300
|
-
const printAnimatedScore = (scoreFaceLine, barFaceLine, score, label, potentialScore) => gen(function* () {
|
|
83301
|
-
const isPerfectScore = score === 100;
|
|
83302
|
-
for (let frame = 0; frame <= 40; frame += 1) {
|
|
83303
|
-
const progress = easeOutCubic(frame / 40);
|
|
83304
|
-
const animatedScore = Math.round(score * progress);
|
|
83305
|
-
if (isPerfectScore) {
|
|
83306
|
-
yield* writeStdout(`${frame === 0 ? "" : "\x1B[4A"}\r${buildRainbowScoreHeaderFrame({
|
|
83307
|
-
score,
|
|
83308
|
-
displayScore: animatedScore,
|
|
83309
|
-
label,
|
|
83310
|
-
frame
|
|
83311
|
-
})}`);
|
|
83312
|
-
if (frame < 40) yield* sleep(50);
|
|
83313
|
-
continue;
|
|
83314
|
-
}
|
|
83315
|
-
const animatedScoreLine = buildScoreLine(animatedScore, score, label);
|
|
83316
|
-
const animatedBarLine = frame === 40 && potentialScore !== void 0 ? buildProjectedScoreBar(score, potentialScore) : buildScoreBar(animatedScore, score);
|
|
83317
|
-
yield* writeStdout(`${frame === 0 ? "" : "\x1B[2A"}\r${buildScoreHeaderLine(scoreFaceLine, animatedScoreLine)}\n\r${buildScoreHeaderLine(barFaceLine, animatedBarLine)}\n`);
|
|
83318
|
-
if (frame < 40) yield* sleep(50);
|
|
83319
|
-
}
|
|
83320
|
-
if (!isPerfectScore) return;
|
|
83321
|
-
for (let frame = 0; frame < 16; frame += 1) {
|
|
83322
|
-
yield* writeStdout(`\x1b[4A\r${buildRainbowScoreHeaderFrame({
|
|
83323
|
-
score,
|
|
83324
|
-
displayScore: score,
|
|
83325
|
-
label,
|
|
83326
|
-
frame
|
|
83327
|
-
})}`);
|
|
83328
|
-
yield* sleep(50);
|
|
83329
|
-
}
|
|
83330
|
-
yield* writeStdout(`\x1b[4A\r${buildFinalPerfectScoreHeaderFrame(score, label, 16)}\x1b[2A`);
|
|
83331
|
-
});
|
|
83332
|
-
const printScoreHeader = (scoreResult, potentialScore) => gen(function* () {
|
|
83333
|
-
const isPerfectScore = scoreResult.score === 100;
|
|
83334
|
-
const renderedFaceLines = buildFaceRenderedLines(scoreResult.score);
|
|
83335
|
-
const rawFaceLines = buildRawFaceLines(scoreResult.score);
|
|
83336
|
-
const shouldAnimate = !isSpinnerSilent() && canAnimateOnboarding(process.stdout);
|
|
83337
|
-
const displayScore = shouldAnimate ? 0 : scoreResult.score;
|
|
83338
|
-
const rightColumnLines = [
|
|
83339
|
-
buildScoreLine(displayScore, scoreResult.score, scoreResult.label),
|
|
83340
|
-
shouldAnimate ? buildScoreBar(0, scoreResult.score) : potentialScore !== void 0 ? buildProjectedScoreBar(scoreResult.score, potentialScore) : buildScoreBar(scoreResult.score),
|
|
83341
|
-
BRANDING_LINE,
|
|
83342
|
-
""
|
|
83343
|
-
];
|
|
83344
|
-
const rawRightColumnLines = [
|
|
83345
|
-
buildRawScoreLine(displayScore, scoreResult.label),
|
|
83346
|
-
buildRawScoreBar(displayScore),
|
|
83347
|
-
RAW_BRANDING_LINE,
|
|
83348
|
-
""
|
|
83349
|
-
];
|
|
83350
|
-
for (let lineIndex = 0; lineIndex < renderedFaceLines.length; lineIndex += 1) yield* log(buildInitialScoreHeaderLine({
|
|
83351
|
-
isPerfectScore,
|
|
83352
|
-
shouldAnimate,
|
|
83353
|
-
lineIndex,
|
|
83354
|
-
renderedFaceLine: renderedFaceLines[lineIndex] ?? "",
|
|
83355
|
-
rawFaceLine: rawFaceLines[lineIndex] ?? "",
|
|
83356
|
-
rightColumnContent: rightColumnLines[lineIndex] ?? "",
|
|
83357
|
-
rawRightColumnContent: rawRightColumnLines[lineIndex] ?? "",
|
|
83358
|
-
score: scoreResult.score
|
|
83359
|
-
}));
|
|
83360
|
-
yield* log("");
|
|
83361
|
-
if (shouldAnimate) {
|
|
83362
|
-
yield* writeStdout("\x1B[5A");
|
|
83363
|
-
yield* printAnimatedScore(renderedFaceLines[0], renderedFaceLines[1], scoreResult.score, scoreResult.label, potentialScore);
|
|
83364
|
-
yield* writeStdout("\x1B[3B");
|
|
83365
|
-
}
|
|
83366
|
-
});
|
|
83367
|
-
const animateScoreProjection = (scoreResult, potentialScore, linesBelowBar) => gen(function* () {
|
|
83368
|
-
if (scoreResult.score === 100 || potentialScore <= scoreResult.score) return;
|
|
83369
|
-
const barFaceLine = buildFaceRenderedLines(scoreResult.score)[1] ?? "";
|
|
83370
|
-
for (let frame = 1; frame <= 16; frame += 1) {
|
|
83371
|
-
const progress = easeOutCubic(frame / 16);
|
|
83372
|
-
const displayedPotential = scoreResult.score + (potentialScore - scoreResult.score) * progress;
|
|
83373
|
-
yield* writeStdout(`\x1b[${linesBelowBar}A\r${buildScoreHeaderLine(barFaceLine, buildProjectedScoreBar(scoreResult.score, displayedPotential))}\x1b[${linesBelowBar}B\r`);
|
|
83374
|
-
if (frame < 16) yield* sleep(35);
|
|
83375
|
-
}
|
|
83376
|
-
});
|
|
83377
|
-
const printBrandingOnlyHeader = gen(function* () {
|
|
83378
|
-
yield* log(` ${BRANDING_LINE}`);
|
|
83379
|
-
yield* log("");
|
|
83380
|
-
});
|
|
83381
|
-
const printNoScoreHeader = (noScoreMessage) => gen(function* () {
|
|
83382
|
-
yield* log(` ${BRANDING_LINE}`);
|
|
83383
|
-
yield* log(` ${highlighter.gray(noScoreMessage)}`);
|
|
83384
|
-
yield* log("");
|
|
83385
|
-
});
|
|
83386
|
-
//#endregion
|
|
83387
82565
|
//#region src/cli/utils/build-footer-description-lines.ts
|
|
83388
82566
|
const FOOTER_DESCRIPTION_INDENT = " ";
|
|
83389
82567
|
const buildFooterDescriptionLines = (description) => {
|
|
@@ -83404,67 +82582,90 @@ const buildFooterLinkLines = ({ shareUrl }) => [
|
|
|
83404
82582
|
...buildFooterDescriptionLines("Report issues and star the repository!")
|
|
83405
82583
|
];
|
|
83406
82584
|
//#endregion
|
|
83407
|
-
//#region src/cli/utils/
|
|
83408
|
-
const
|
|
83409
|
-
const
|
|
83410
|
-
|
|
83411
|
-
|
|
83412
|
-
|
|
83413
|
-
} catch {
|
|
83414
|
-
return /* @__PURE__ */ new Set();
|
|
83415
|
-
}
|
|
83416
|
-
};
|
|
83417
|
-
const writeDiagnosticsDirectory = (diagnostics, outputDirectory) => {
|
|
83418
|
-
const directory = outputDirectory ? Path.resolve(outputDirectory) : Path.join(tmpdir(), `react-doctor-${randomUUID()}`);
|
|
83419
|
-
if (outputDirectory) for (const fileName of readPreviousRuleDumpFileNames(directory)) NFS.rmSync(Path.join(directory, fileName), { force: true });
|
|
83420
|
-
NFS.mkdirSync(directory, { recursive: true });
|
|
83421
|
-
for (const [ruleKey, ruleDiagnostics] of buildSortedRuleGroups(diagnostics)) NFS.writeFileSync(Path.join(directory, ruleDumpFileName(ruleKey)), formatRuleSummary(ruleKey, ruleDiagnostics));
|
|
83422
|
-
NFS.writeFileSync(Path.join(directory, "diagnostics.json"), JSON.stringify(diagnostics));
|
|
83423
|
-
return directory;
|
|
83424
|
-
};
|
|
82585
|
+
//#region src/cli/utils/build-section-divider.ts
|
|
82586
|
+
const DIVIDER_INDENT = " ";
|
|
82587
|
+
const buildSectionDivider = () => highlighter.dim(`${DIVIDER_INDENT}${"─".repeat(resolveMeasureWidth(2))}`);
|
|
82588
|
+
//#endregion
|
|
82589
|
+
//#region src/cli/utils/collect-affected-files.ts
|
|
82590
|
+
const collectAffectedFiles = (diagnostics) => new Set(diagnostics.map((diagnostic) => diagnostic.filePath));
|
|
83425
82591
|
//#endregion
|
|
83426
|
-
//#region src/cli/utils/
|
|
83427
|
-
const buildShareUrl = (
|
|
83428
|
-
const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
|
|
83429
|
-
const warningCount = diagnostics.
|
|
83430
|
-
const affectedFileCount = collectAffectedFiles(diagnostics).size;
|
|
83431
|
-
const
|
|
83432
|
-
|
|
83433
|
-
if (
|
|
83434
|
-
if (
|
|
83435
|
-
if (
|
|
83436
|
-
|
|
83437
|
-
return `${SHARE_BASE_URL}?${params.toString()}`;
|
|
82592
|
+
//#region src/cli/utils/print-footer.ts
|
|
82593
|
+
const buildShareUrl = (input) => {
|
|
82594
|
+
const errorCount = input.diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
|
|
82595
|
+
const warningCount = input.diagnostics.length - errorCount;
|
|
82596
|
+
const affectedFileCount = collectAffectedFiles(input.diagnostics).size;
|
|
82597
|
+
const parameters = new URLSearchParams({ p: input.projectName });
|
|
82598
|
+
if (input.scoreResult) parameters.set("s", String(input.scoreResult.score));
|
|
82599
|
+
if (errorCount > 0) parameters.set("e", String(errorCount));
|
|
82600
|
+
if (warningCount > 0) parameters.set("w", String(warningCount));
|
|
82601
|
+
if (affectedFileCount > 0) parameters.set("f", String(affectedFileCount));
|
|
82602
|
+
return `${SHARE_BASE_URL}?${parameters.toString()}`;
|
|
83438
82603
|
};
|
|
83439
82604
|
const printFooter = (input) => gen(function* () {
|
|
83440
82605
|
yield* log("");
|
|
83441
82606
|
yield* log(buildSectionDivider());
|
|
83442
82607
|
yield* log("");
|
|
83443
|
-
const shareUrl = input.isOffline ? null : buildShareUrl(input
|
|
82608
|
+
const shareUrl = input.isOffline ? null : buildShareUrl(input);
|
|
83444
82609
|
for (const line of buildFooterLinkLines({ shareUrl })) yield* log(line);
|
|
83445
82610
|
});
|
|
83446
|
-
|
|
83447
|
-
|
|
83448
|
-
|
|
83449
|
-
|
|
83450
|
-
|
|
83451
|
-
|
|
83452
|
-
|
|
83453
|
-
|
|
82611
|
+
//#endregion
|
|
82612
|
+
//#region src/cli/utils/format-elapsed-time.ts
|
|
82613
|
+
const formatElapsedTime = (elapsedMilliseconds) => {
|
|
82614
|
+
if (elapsedMilliseconds < 1e3) return `${Math.round(elapsedMilliseconds)}ms`;
|
|
82615
|
+
return `${(elapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1)}s`;
|
|
82616
|
+
};
|
|
82617
|
+
//#endregion
|
|
82618
|
+
//#region src/cli/utils/pluralize.ts
|
|
82619
|
+
const pluralize = (count, singularNoun) => `${count} ${singularNoun}${count === 1 ? "" : "s"}`;
|
|
82620
|
+
//#endregion
|
|
82621
|
+
//#region src/cli/utils/print-headless-report.ts
|
|
82622
|
+
const formatContextTag = (diagnostic) => diagnostic.fileContext ? ` (${diagnostic.fileContext} file)` : "";
|
|
82623
|
+
const printHeadlessReport = (input) => gen(function* () {
|
|
82624
|
+
yield* log(`${highlighter.success("✔")} Scanned ${pluralize(input.scannedFileCount, "file")} in ${formatElapsedTime(input.elapsedMilliseconds)}`);
|
|
82625
|
+
yield* log("");
|
|
82626
|
+
yield* log(highlighter.bold(`React Doctor — ${input.projectName}`));
|
|
82627
|
+
if (input.scoreResult) yield* log(`Score: ${input.scoreResult.score} / 100 ${input.scoreResult.label}`);
|
|
82628
|
+
else yield* log(highlighter.gray(input.noScoreMessage));
|
|
82629
|
+
if (input.diagnostics.length === 0) {
|
|
82630
|
+
yield* log("");
|
|
82631
|
+
yield* log(highlighter.success(`✔ ${input.emptyStateMessage}`));
|
|
82632
|
+
} else {
|
|
82633
|
+
yield* log("");
|
|
82634
|
+
yield* log(highlighter.bold(pluralize(input.diagnostics.length, "issue")));
|
|
82635
|
+
const categoryCounts = /* @__PURE__ */ new Map();
|
|
82636
|
+
for (const diagnostic of input.diagnostics) {
|
|
82637
|
+
const counts = categoryCounts.get(diagnostic.category) ?? {
|
|
82638
|
+
error: 0,
|
|
82639
|
+
warning: 0
|
|
82640
|
+
};
|
|
82641
|
+
categoryCounts.set(diagnostic.category, {
|
|
82642
|
+
error: counts.error + Number(diagnostic.severity === "error"),
|
|
82643
|
+
warning: counts.warning + Number(diagnostic.severity === "warning")
|
|
82644
|
+
});
|
|
82645
|
+
}
|
|
82646
|
+
for (const [category, counts] of categoryCounts) {
|
|
82647
|
+
const countParts = [];
|
|
82648
|
+
if (counts.error > 0) countParts.push(pluralize(counts.error, "error"));
|
|
82649
|
+
if (counts.warning > 0) countParts.push(pluralize(counts.warning, "warning"));
|
|
82650
|
+
yield* log(`${category}: ${countParts.join(", ")}`);
|
|
82651
|
+
}
|
|
82652
|
+
yield* log("");
|
|
82653
|
+
for (const [ruleKey, ruleDiagnostics] of buildSortedRuleGroups(input.diagnostics)) {
|
|
82654
|
+
const representativeDiagnostic = ruleDiagnostics[0];
|
|
82655
|
+
if (representativeDiagnostic === void 0) continue;
|
|
82656
|
+
const severityIcon = representativeDiagnostic.severity === "error" ? "✖" : "⚠";
|
|
82657
|
+
const colorize = representativeDiagnostic.severity === "error" ? highlighter.error : highlighter.warn;
|
|
82658
|
+
const occurrenceSuffix = ruleDiagnostics.length > 1 ? ` ×${ruleDiagnostics.length}` : "";
|
|
82659
|
+
yield* log(colorize(`${severityIcon} ${representativeDiagnostic.title ?? ruleKey}${occurrenceSuffix}`));
|
|
82660
|
+
yield* log(highlighter.gray(` ${ruleKey}`));
|
|
82661
|
+
for (const diagnostic of ruleDiagnostics) yield* log(` ${formatDiagnosticSite(diagnostic)}${formatContextTag(diagnostic)}`);
|
|
82662
|
+
}
|
|
82663
|
+
}
|
|
82664
|
+
if (input.skippedChecks.length > 0) {
|
|
82665
|
+
yield* log("");
|
|
82666
|
+
yield* warn$1(highlighter.warn(`Results are incomplete: ${input.skippedChecks.join(" and ")} checks failed.`));
|
|
83454
82667
|
}
|
|
83455
82668
|
});
|
|
83456
|
-
const printSummary = (input) => gen(function* () {
|
|
83457
|
-
if (input.scoreResult) {
|
|
83458
|
-
const animateProjection = Boolean(input.animateProjection) && input.potentialScore != null && !input.verbose;
|
|
83459
|
-
yield* printScoreHeader(input.scoreResult, animateProjection ? void 0 : input.potentialScore ?? void 0);
|
|
83460
|
-
if (input.potentialScore != null) {
|
|
83461
|
-
const improvement = input.potentialScore - input.scoreResult.score;
|
|
83462
|
-
yield* log(highlighter.gray(" You could improve ") + colorizeByScore(`+${improvement}%`, input.potentialScore) + highlighter.gray(` by fixing the top 3 issues`));
|
|
83463
|
-
if (animateProjection) yield* animateScoreProjection(input.scoreResult, input.potentialScore, 5);
|
|
83464
|
-
}
|
|
83465
|
-
} else yield* printNoScoreHeader(input.noScoreMessage);
|
|
83466
|
-
yield* printDiagnosticsDump(input.diagnostics, input.outputDirectory, input.verbose);
|
|
83467
|
-
});
|
|
83468
82669
|
//#endregion
|
|
83469
82670
|
//#region src/cli/utils/resolve-oxlint-node.ts
|
|
83470
82671
|
const consoleWarn = (message) => warn$1(highlighter.warn(message));
|
|
@@ -83538,15 +82739,6 @@ const resolveCliCategories = (categoryFlag) => {
|
|
|
83538
82739
|
//#endregion
|
|
83539
82740
|
//#region src/inspect.ts
|
|
83540
82741
|
const silentConsole = makeNoopConsole();
|
|
83541
|
-
const recordOnboardingCompletion = (options) => {
|
|
83542
|
-
const forceOnboarding = isOnboardingForced();
|
|
83543
|
-
if (shouldRecordOnboarding({
|
|
83544
|
-
paceOnboardingSections: !options.silent && !options.scoreOnly && !options.suppressRendering && !options.verbose && canAnimateOnboarding(process.stdout) && (forceOnboarding || !hasCompletedOnboarding()),
|
|
83545
|
-
forceOnboarding,
|
|
83546
|
-
verbose: options.verbose,
|
|
83547
|
-
isNonInteractiveEnvironment: options.isNonInteractiveEnvironment
|
|
83548
|
-
})) markOnboardingComplete();
|
|
83549
|
-
};
|
|
83550
82742
|
const buildChangedLineMatcher = (directory, changedLineRanges) => {
|
|
83551
82743
|
const rangesByFile = /* @__PURE__ */ new Map();
|
|
83552
82744
|
for (const entry of changedLineRanges) rangesByFile.set(toForwardSlashes(entry.file), entry.ranges);
|
|
@@ -83826,7 +83018,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
83826
83018
|
recordSentryProjectContext(cachedPayload.project, rootSentrySpan, { concurrentScan: options.concurrentScan });
|
|
83827
83019
|
recordCount(METRIC.projectDetected, 1);
|
|
83828
83020
|
const baselineDegraded = Boolean(options.baseline) && isDiffMode && cachedPayload.baselineDelta === void 0;
|
|
83829
|
-
|
|
83021
|
+
return await renderAndRecordScan({
|
|
83830
83022
|
payload: cachedPayload,
|
|
83831
83023
|
options,
|
|
83832
83024
|
userConfig,
|
|
@@ -83837,8 +83029,6 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
83837
83029
|
baselineDegraded,
|
|
83838
83030
|
wholeRepoCacheHit: true
|
|
83839
83031
|
});
|
|
83840
|
-
recordOnboardingCompletion(options);
|
|
83841
|
-
return result;
|
|
83842
83032
|
}
|
|
83843
83033
|
const shouldShowProgressSpinners = !options.isCiOrCodingAgentEnvironment && !options.silent && !options.scoreOnly && !options.suppressRendering && options.lint && Boolean(resolvedNodeBinaryPath);
|
|
83844
83034
|
const layers = buildRuntimeLayers({
|
|
@@ -83941,7 +83131,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
83941
83131
|
suppressedRuleCounts: output.suppressedRuleCounts
|
|
83942
83132
|
};
|
|
83943
83133
|
if (cacheKey !== null && scanResultCache !== null && shouldStoreScanPayload(payload) && !baselineDegraded) scanResultCache.store(cacheKey, payload);
|
|
83944
|
-
|
|
83134
|
+
return await renderAndRecordScan({
|
|
83945
83135
|
payload,
|
|
83946
83136
|
options,
|
|
83947
83137
|
userConfig,
|
|
@@ -83959,8 +83149,6 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
83959
83149
|
deadCodeSummaryCacheHits: output.deadCodeSummaryCacheHits,
|
|
83960
83150
|
deadCodeSummaryCacheMisses: output.deadCodeSummaryCacheMisses
|
|
83961
83151
|
});
|
|
83962
|
-
recordOnboardingCompletion(options);
|
|
83963
|
-
return result;
|
|
83964
83152
|
};
|
|
83965
83153
|
const runMaybeSilent = (effect, silent) => silent ? effect.pipe(provideService$2(Console, silentConsole)) : effect;
|
|
83966
83154
|
const renderAndRecordScan = async (input) => {
|
|
@@ -83979,7 +83167,6 @@ const renderAndRecordScan = async (input) => {
|
|
|
83979
83167
|
supplyChainOverlapTimedOut: input.payload.supplyChainOverlapTimedOut,
|
|
83980
83168
|
securityScanFailed: input.payload.securityScanFailed ?? false,
|
|
83981
83169
|
securityScanFailureReason: input.payload.securityScanFailureReason ?? null,
|
|
83982
|
-
directory: input.payload.directory,
|
|
83983
83170
|
scannedFileCount: input.payload.scannedFileCount,
|
|
83984
83171
|
scannedFilePaths: input.payload.scannedFilePaths,
|
|
83985
83172
|
analyzedFiles: input.payload.analyzedFiles ?? [],
|
|
@@ -84030,7 +83217,7 @@ const renderAndRecordScan = async (input) => {
|
|
|
84030
83217
|
return result;
|
|
84031
83218
|
};
|
|
84032
83219
|
const finalizeAndRender = (input) => gen(function* () {
|
|
84033
|
-
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, supplyChainOverlapTimedOut, securityScanFailed, securityScanFailureReason,
|
|
83220
|
+
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, supplyChainOverlapTimedOut, securityScanFailed, securityScanFailureReason, scannedFileCount, scannedFilePaths, analyzedFiles, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, lintSidecarReplayedFileCount, lintSidecarTotalFileCount, deadCodeCacheHit, deadCodeSummaryCacheHits, deadCodeSummaryCacheMisses, baselineDelta } = input;
|
|
84034
83221
|
const { skippedChecks, skippedCheckReasons } = buildSkippedChecks({
|
|
84035
83222
|
didLintFail,
|
|
84036
83223
|
lintFailureReason,
|
|
@@ -84082,69 +83269,32 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
84082
83269
|
else yield* error$1(highlighter.gray(noScoreMessage));
|
|
84083
83270
|
return buildResult();
|
|
84084
83271
|
}
|
|
84085
|
-
const animateRender = !options.silent && !options.verbose && canAnimateOnboarding(process.stdout);
|
|
84086
|
-
const pause = onboardingSectionPause(animateRender);
|
|
84087
|
-
const useHyperlinks = shouldRenderHyperlinks(process.stdout);
|
|
84088
83272
|
const demotedDiagnosticCount = diagnostics.length - surfaceDiagnostics.length;
|
|
84089
|
-
|
|
84090
|
-
|
|
84091
|
-
|
|
84092
|
-
|
|
84093
|
-
|
|
84094
|
-
yield* warn$1(highlighter.warn(`No issues detected, but ${skippedLabel} checks failed — results are incomplete.`));
|
|
84095
|
-
} else yield* log(highlighter.success(buildEmptyReportMessage({
|
|
83273
|
+
if (options.isNonInteractiveEnvironment && options.outputSurface !== "prComment") yield* printAgentGuidance();
|
|
83274
|
+
yield* printHeadlessReport({
|
|
83275
|
+
diagnostics: printedDiagnostics,
|
|
83276
|
+
elapsedMilliseconds,
|
|
83277
|
+
emptyStateMessage: buildEmptyReportMessage({
|
|
84096
83278
|
categoryFilters: options.categoryFilters,
|
|
84097
83279
|
demotedDiagnosticCount,
|
|
84098
83280
|
outputSurface: options.outputSurface
|
|
84099
|
-
})
|
|
84100
|
-
yield* log("");
|
|
84101
|
-
yield* pause;
|
|
84102
|
-
if (hasSkippedChecks) {
|
|
84103
|
-
yield* printBrandingOnlyHeader;
|
|
84104
|
-
yield* log(highlighter.gray(" Score not shown — some checks could not complete."));
|
|
84105
|
-
} else if (score) yield* printScoreHeader(score);
|
|
84106
|
-
else yield* printNoScoreHeader(noScoreMessage);
|
|
84107
|
-
if (options.outputDirectory !== null) yield* printDiagnosticsDump(printedDiagnostics, options.outputDirectory);
|
|
84108
|
-
return buildResult();
|
|
84109
|
-
}
|
|
84110
|
-
yield* pause;
|
|
84111
|
-
yield* log("");
|
|
84112
|
-
yield* printDiagnostics([...printedDiagnostics], options.verbose, directory, buildRulePriorityMap([score]), isCodingAgentEnvironment(), {
|
|
84113
|
-
sectionPause: pause,
|
|
84114
|
-
animateCountUp: animateRender
|
|
84115
|
-
}, useHyperlinks);
|
|
84116
|
-
if (options.isNonInteractiveEnvironment && options.outputSurface !== "prComment") yield* printAgentGuidance();
|
|
84117
|
-
if (options.categoryFilters.size === 0 && demotedDiagnosticCount > 0) {
|
|
84118
|
-
yield* log(highlighter.gray(` ${demotedDiagnosticCount} demoted from the ${options.outputSurface} surface (e.g. design cleanup) — run \`npx react-doctor@latest .\` locally for the full list.`));
|
|
84119
|
-
yield* log("");
|
|
84120
|
-
}
|
|
84121
|
-
const scoreDiagnostics = filterDiagnosticsForSurface([...diagnostics], "score", userConfig);
|
|
84122
|
-
const displayedScoreDiagnostics = filterDiagnosticsForSurface([...printedDiagnostics], "score", userConfig);
|
|
84123
|
-
const potentialScore = score ? yield* promise(() => computeProjectedScore(displayedScoreDiagnostics, scoreDiagnostics, score)) : null;
|
|
84124
|
-
const showShareLink = shouldShowShareLink(options);
|
|
84125
|
-
yield* pause;
|
|
84126
|
-
yield* printSummary({
|
|
84127
|
-
diagnostics: [...printedDiagnostics],
|
|
84128
|
-
elapsedMilliseconds,
|
|
84129
|
-
scoreResult: score,
|
|
84130
|
-
potentialScore,
|
|
84131
|
-
totalSourceFileCount: lintSourceFileCount,
|
|
83281
|
+
}),
|
|
84132
83282
|
noScoreMessage,
|
|
84133
|
-
|
|
84134
|
-
|
|
84135
|
-
|
|
83283
|
+
projectName: project.projectName,
|
|
83284
|
+
scannedFileCount,
|
|
83285
|
+
scoreResult: hasSkippedChecks ? null : score,
|
|
83286
|
+
skippedChecks
|
|
84136
83287
|
});
|
|
84137
|
-
if (
|
|
84138
|
-
|
|
83288
|
+
if (options.outputDirectory !== null || options.verbose) yield* printDiagnosticsDump(printedDiagnostics, options.outputDirectory, options.verbose);
|
|
83289
|
+
if (options.categoryFilters.size === 0 && demotedDiagnosticCount > 0) {
|
|
83290
|
+
yield* log(highlighter.gray(` ${demotedDiagnosticCount} demoted from the ${options.outputSurface} surface (e.g. design cleanup) — run \`npx react-doctor@latest .\` locally for the full list.`));
|
|
84139
83291
|
yield* log("");
|
|
84140
|
-
yield* warn$1(highlighter.warn(` Note: ${skippedLabel} checks failed — score may be incomplete.`));
|
|
84141
83292
|
}
|
|
84142
|
-
yield* pause;
|
|
84143
83293
|
yield* printFooter({
|
|
84144
|
-
diagnostics:
|
|
83294
|
+
diagnostics: printedDiagnostics,
|
|
84145
83295
|
scoreResult: score,
|
|
84146
83296
|
projectName: project.projectName,
|
|
84147
|
-
isOffline: !
|
|
83297
|
+
isOffline: options.isCi || !options.share || score === null
|
|
84148
83298
|
});
|
|
84149
83299
|
return buildResult();
|
|
84150
83300
|
});
|
|
@@ -84175,9 +83325,6 @@ const collectProjectSourceFileCounts = async (rootDirectory, projectDirectories)
|
|
|
84175
83325
|
//#region src/cli/utils/format-skipped-projects-message.ts
|
|
84176
83326
|
const formatSkippedProjectsMessage = (projectCount) => `${projectCount} ${projectCount === 1 ? "project was" : "projects were"} skipped because the max scan duration was reached.`;
|
|
84177
83327
|
//#endregion
|
|
84178
|
-
//#region src/cli/utils/is-share-opted-out.ts
|
|
84179
|
-
const isShareOptedOut = (scans, flagNoScore) => Boolean(flagNoScore) || scans.some((scan) => Boolean(scan.config?.noScore) || scan.config?.share === false);
|
|
84180
|
-
//#endregion
|
|
84181
83328
|
//#region src/cli/utils/build-handoff-payload.ts
|
|
84182
83329
|
const buildHandoffPayload = (input) => {
|
|
84183
83330
|
const topGroups = buildSortedRuleGroups(input.diagnostics).slice(0, 3);
|
|
@@ -84374,6 +83521,186 @@ const detectLaunchableAgents = async () => {
|
|
|
84374
83521
|
return CLI_AGENT_IDS.filter((agentId) => detected.has(agentId) && isCommandAvailable(CLI_AGENT_BINARIES[agentId]));
|
|
84375
83522
|
};
|
|
84376
83523
|
//#endregion
|
|
83524
|
+
//#region src/cli/utils/now-iso.ts
|
|
83525
|
+
const nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
83526
|
+
const ONBOARDING_EVENT = "onboarding";
|
|
83527
|
+
const CI_PITCH_EVENT = "ci-pitch";
|
|
83528
|
+
const ACTION_UPGRADE_EVENT = "action-upgrade-v2";
|
|
83529
|
+
const SETUP_HINT_EVENT = "setup-hint";
|
|
83530
|
+
const HANDOFF_TARGET_PREFERENCE_ID = "handoff-target";
|
|
83531
|
+
const INSTALL_AGENTS_PREFERENCE_ID = "install-agents";
|
|
83532
|
+
const foldLegacyDecisions = (projects, legacy, eventId) => {
|
|
83533
|
+
for (const [hash, record] of Object.entries(legacy ?? {})) {
|
|
83534
|
+
const existing = projects[hash] ?? { rootDirectory: record.rootDirectory ?? "" };
|
|
83535
|
+
projects[hash] = {
|
|
83536
|
+
...existing,
|
|
83537
|
+
events: {
|
|
83538
|
+
...existing.events,
|
|
83539
|
+
[eventId]: {
|
|
83540
|
+
firedAt: record.at ?? nowIso(),
|
|
83541
|
+
version: 1,
|
|
83542
|
+
...record.outcome ? { outcome: record.outcome } : {}
|
|
83543
|
+
}
|
|
83544
|
+
}
|
|
83545
|
+
};
|
|
83546
|
+
}
|
|
83547
|
+
};
|
|
83548
|
+
const migrateCliState = (state) => {
|
|
83549
|
+
if (typeof state.schemaVersion === "number" && state.schemaVersion >= 2) return state;
|
|
83550
|
+
const projects = {};
|
|
83551
|
+
for (const [hash, record] of Object.entries(state.projects ?? {})) {
|
|
83552
|
+
const carried = {
|
|
83553
|
+
rootDirectory: record.rootDirectory,
|
|
83554
|
+
...record.events ? { events: record.events } : {},
|
|
83555
|
+
...record.migrations ? { migrations: record.migrations } : {}
|
|
83556
|
+
};
|
|
83557
|
+
projects[hash] = record.setupPrompt === false ? {
|
|
83558
|
+
...carried,
|
|
83559
|
+
events: {
|
|
83560
|
+
...carried.events,
|
|
83561
|
+
[SETUP_HINT_EVENT]: {
|
|
83562
|
+
firedAt: nowIso(),
|
|
83563
|
+
version: 1,
|
|
83564
|
+
outcome: "declined"
|
|
83565
|
+
}
|
|
83566
|
+
}
|
|
83567
|
+
} : carried;
|
|
83568
|
+
}
|
|
83569
|
+
foldLegacyDecisions(projects, state.ciPrompts, CI_PITCH_EVENT);
|
|
83570
|
+
foldLegacyDecisions(projects, state.actionUpgrades, ACTION_UPGRADE_EVENT);
|
|
83571
|
+
return {
|
|
83572
|
+
schemaVersion: 2,
|
|
83573
|
+
global: typeof state.onboardedAt === "string" ? { events: { [ONBOARDING_EVENT]: {
|
|
83574
|
+
firedAt: state.onboardedAt,
|
|
83575
|
+
version: 1
|
|
83576
|
+
} } } : {},
|
|
83577
|
+
projects
|
|
83578
|
+
};
|
|
83579
|
+
};
|
|
83580
|
+
const resolveConfigDir = (options) => options.cwd ?? (process.env["REACT_DOCTOR_CONFIG_DIR"] || void 0);
|
|
83581
|
+
const openStore = (options = {}) => new Conf({
|
|
83582
|
+
projectName: REACT_DOCTOR_CONFIG_PROJECT_NAME,
|
|
83583
|
+
cwd: resolveConfigDir(options)
|
|
83584
|
+
});
|
|
83585
|
+
const openMigratedStore = (options) => {
|
|
83586
|
+
const store = openStore(options);
|
|
83587
|
+
const state = store.store;
|
|
83588
|
+
const migrated = migrateCliState(state);
|
|
83589
|
+
if (migrated !== state) store.store = migrated;
|
|
83590
|
+
return store;
|
|
83591
|
+
};
|
|
83592
|
+
const readCliState = (select, fallback, options = {}) => {
|
|
83593
|
+
try {
|
|
83594
|
+
return select(openMigratedStore(options).store);
|
|
83595
|
+
} catch {
|
|
83596
|
+
return fallback;
|
|
83597
|
+
}
|
|
83598
|
+
};
|
|
83599
|
+
const updateCliState = (update, options = {}) => {
|
|
83600
|
+
try {
|
|
83601
|
+
const store = openMigratedStore(options);
|
|
83602
|
+
store.store = update(store.store);
|
|
83603
|
+
return true;
|
|
83604
|
+
} catch {
|
|
83605
|
+
return false;
|
|
83606
|
+
}
|
|
83607
|
+
};
|
|
83608
|
+
//#endregion
|
|
83609
|
+
//#region src/cli/utils/hash-project-root.ts
|
|
83610
|
+
const hashProjectRoot = (projectRoot) => createHash("sha256").update(Path.resolve(projectRoot)).digest("hex");
|
|
83611
|
+
//#endregion
|
|
83612
|
+
//#region src/cli/utils/cli-lifecycle.ts
|
|
83613
|
+
const versionOf = (item) => item.version ?? 1;
|
|
83614
|
+
const selectScope = (state, scoped, projectRoot) => scoped.scope === "global" ? state.global : projectRoot === void 0 ? void 0 : state.projects?.[hashProjectRoot(projectRoot)];
|
|
83615
|
+
const updateScope = (state, scoped, projectRoot, updateScopeState) => {
|
|
83616
|
+
if (scoped.scope === "global") return {
|
|
83617
|
+
...state,
|
|
83618
|
+
global: updateScopeState(state.global ?? {})
|
|
83619
|
+
};
|
|
83620
|
+
if (projectRoot === void 0) return state;
|
|
83621
|
+
const projectKey = hashProjectRoot(projectRoot);
|
|
83622
|
+
const base = state.projects?.[projectKey] ?? { rootDirectory: Path.resolve(projectRoot) };
|
|
83623
|
+
return {
|
|
83624
|
+
...state,
|
|
83625
|
+
projects: {
|
|
83626
|
+
...state.projects,
|
|
83627
|
+
[projectKey]: {
|
|
83628
|
+
...base,
|
|
83629
|
+
...updateScopeState(base)
|
|
83630
|
+
}
|
|
83631
|
+
}
|
|
83632
|
+
};
|
|
83633
|
+
};
|
|
83634
|
+
const isGatePending = (gate, target = {}, options = {}) => {
|
|
83635
|
+
if (gate.scope === "project" && target.projectRoot === void 0) return false;
|
|
83636
|
+
return readCliState((state) => {
|
|
83637
|
+
const record = selectScope(state, gate, target.projectRoot)?.events?.[gate.id];
|
|
83638
|
+
return !record || record.version < versionOf(gate);
|
|
83639
|
+
}, gate.fireWhenUnknown ?? false, options);
|
|
83640
|
+
};
|
|
83641
|
+
const recordGate = (gate, target = {}, options = {}) => updateCliState((state) => updateScope(state, gate, target.projectRoot, (scope) => ({
|
|
83642
|
+
...scope,
|
|
83643
|
+
events: {
|
|
83644
|
+
...scope.events,
|
|
83645
|
+
[gate.id]: {
|
|
83646
|
+
firedAt: nowIso(),
|
|
83647
|
+
version: versionOf(gate),
|
|
83648
|
+
...target.outcome ? { outcome: target.outcome } : {}
|
|
83649
|
+
}
|
|
83650
|
+
}
|
|
83651
|
+
})), options);
|
|
83652
|
+
const readPreference = (preference, target = {}, options = {}) => readCliState((state) => selectScope(state, preference, target.projectRoot)?.preferences?.[preference.id] ?? null, null, options);
|
|
83653
|
+
const writePreference = (preference, value, target = {}, options = {}) => updateCliState((state) => updateScope(state, preference, target.projectRoot, (scope) => ({
|
|
83654
|
+
...scope,
|
|
83655
|
+
preferences: {
|
|
83656
|
+
...scope.preferences,
|
|
83657
|
+
[preference.id]: value
|
|
83658
|
+
}
|
|
83659
|
+
})), options);
|
|
83660
|
+
const isMigrationPending = (migration, target = {}, options = {}) => {
|
|
83661
|
+
if (migration.scope === "project" && target.projectRoot === void 0) return false;
|
|
83662
|
+
return readCliState((state) => {
|
|
83663
|
+
const record = selectScope(state, migration, target.projectRoot)?.migrations?.[migration.id];
|
|
83664
|
+
return !record || record.version < versionOf(migration);
|
|
83665
|
+
}, false, options);
|
|
83666
|
+
};
|
|
83667
|
+
const recordMigration = (migration, projectRoot, record, options) => updateCliState((state) => updateScope(state, migration, projectRoot, (scope) => ({
|
|
83668
|
+
...scope,
|
|
83669
|
+
migrations: {
|
|
83670
|
+
...scope.migrations,
|
|
83671
|
+
[migration.id]: record
|
|
83672
|
+
}
|
|
83673
|
+
})), options);
|
|
83674
|
+
const runMigrations = async (migrations, target = {}, options = {}) => {
|
|
83675
|
+
const results = [];
|
|
83676
|
+
for (const migration of migrations) {
|
|
83677
|
+
if (!isMigrationPending(migration, target, options)) {
|
|
83678
|
+
results.push({
|
|
83679
|
+
id: migration.id,
|
|
83680
|
+
ran: false,
|
|
83681
|
+
applied: true
|
|
83682
|
+
});
|
|
83683
|
+
continue;
|
|
83684
|
+
}
|
|
83685
|
+
let applied = false;
|
|
83686
|
+
try {
|
|
83687
|
+
applied = await migration.run({ projectRoot: target.projectRoot });
|
|
83688
|
+
} catch {
|
|
83689
|
+
applied = false;
|
|
83690
|
+
}
|
|
83691
|
+
if (applied) recordMigration(migration, target.projectRoot, {
|
|
83692
|
+
ranAt: nowIso(),
|
|
83693
|
+
version: versionOf(migration)
|
|
83694
|
+
}, options);
|
|
83695
|
+
results.push({
|
|
83696
|
+
id: migration.id,
|
|
83697
|
+
ran: true,
|
|
83698
|
+
applied
|
|
83699
|
+
});
|
|
83700
|
+
}
|
|
83701
|
+
return results;
|
|
83702
|
+
};
|
|
83703
|
+
//#endregion
|
|
84377
83704
|
//#region src/cli/utils/open-url.ts
|
|
84378
83705
|
const resolveOpenCommand = (url) => {
|
|
84379
83706
|
if (process$1.platform === "darwin") return {
|
|
@@ -84619,6 +83946,48 @@ const resolveProjectScan = async (rootScanTarget, projectDirectory) => {
|
|
|
84619
83946
|
};
|
|
84620
83947
|
};
|
|
84621
83948
|
//#endregion
|
|
83949
|
+
//#region src/cli/utils/resolve-absolute-path.ts
|
|
83950
|
+
/**
|
|
83951
|
+
* Resolves a diagnostic's `filePath` (relative to its project root, or
|
|
83952
|
+
* already absolute) to an absolute path. Shared by the code-frame reader and
|
|
83953
|
+
* the terminal hyperlink builder so both turn a relative path into the same
|
|
83954
|
+
* on-disk location.
|
|
83955
|
+
*/
|
|
83956
|
+
const resolveAbsolutePath = (filePath, rootDirectory) => Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory || ".", filePath);
|
|
83957
|
+
//#endregion
|
|
83958
|
+
//#region src/cli/utils/build-code-frame.ts
|
|
83959
|
+
/**
|
|
83960
|
+
* Renders a syntax-highlighted source excerpt around a diagnostic site
|
|
83961
|
+
* with a caret pointing at the offending column. Returns null when the
|
|
83962
|
+
* file can't be read (e.g. multi-project summaries where paths are
|
|
83963
|
+
* resolved against a different cwd), so callers can fall back to the
|
|
83964
|
+
* bare `file:line` reference instead of failing the whole render.
|
|
83965
|
+
*/
|
|
83966
|
+
const buildCodeFrame = (input) => {
|
|
83967
|
+
if (input.line <= 0) return null;
|
|
83968
|
+
const absolutePath = resolveAbsolutePath(input.filePath, input.rootDirectory);
|
|
83969
|
+
let source;
|
|
83970
|
+
try {
|
|
83971
|
+
source = NFS.readFileSync(absolutePath, "utf8");
|
|
83972
|
+
} catch {
|
|
83973
|
+
return null;
|
|
83974
|
+
}
|
|
83975
|
+
if ((source.split("\n", input.line)[input.line - 1] ?? "").length > 200) return null;
|
|
83976
|
+
const location = input.endLine != null && input.endLine > input.line ? {
|
|
83977
|
+
start: { line: input.line },
|
|
83978
|
+
end: { line: input.endLine }
|
|
83979
|
+
} : { start: {
|
|
83980
|
+
line: input.line,
|
|
83981
|
+
column: input.column > 0 ? input.column : void 0
|
|
83982
|
+
} };
|
|
83983
|
+
return codeFrameColumns(source, location, {
|
|
83984
|
+
highlightCode: true,
|
|
83985
|
+
linesAbove: 1,
|
|
83986
|
+
linesBelow: 1,
|
|
83987
|
+
...input.message ? { message: input.message } : {}
|
|
83988
|
+
});
|
|
83989
|
+
};
|
|
83990
|
+
//#endregion
|
|
84622
83991
|
//#region src/cli/utils/select-projects.ts
|
|
84623
83992
|
const discoverWorkspacePackages = (rootDirectory) => {
|
|
84624
83993
|
const hasRootPackageJson = isFile(Path.join(rootDirectory, "package.json"));
|
|
@@ -84738,10 +84107,10 @@ const registerActiveTuiRenderer = (renderer) => {
|
|
|
84738
84107
|
if (activeTuiRenderer === renderer) activeTuiRenderer = null;
|
|
84739
84108
|
};
|
|
84740
84109
|
};
|
|
84741
|
-
const
|
|
84110
|
+
const preserveActiveTuiRendererOutput = () => {
|
|
84742
84111
|
const renderer = activeTuiRenderer;
|
|
84743
84112
|
activeTuiRenderer = null;
|
|
84744
|
-
renderer?.
|
|
84113
|
+
renderer?.preserveOutput();
|
|
84745
84114
|
};
|
|
84746
84115
|
//#endregion
|
|
84747
84116
|
//#region src/cli/utils/exit-gracefully.ts
|
|
@@ -84750,7 +84119,7 @@ const exitGracefully = () => {
|
|
|
84750
84119
|
if (didStartExiting) return process.exit(130);
|
|
84751
84120
|
didStartExiting = true;
|
|
84752
84121
|
activeScanAbortRegistry.abortAll();
|
|
84753
|
-
|
|
84122
|
+
preserveActiveTuiRendererOutput();
|
|
84754
84123
|
try {
|
|
84755
84124
|
if (isJsonModeActive()) writeJsonErrorReport(/* @__PURE__ */ new Error("Scan cancelled by user (SIGINT/SIGTERM)"));
|
|
84756
84125
|
else console.log([
|
|
@@ -84765,7 +84134,7 @@ const exitGracefully = () => {
|
|
|
84765
84134
|
flushSentry().finally(() => process.exit(130));
|
|
84766
84135
|
};
|
|
84767
84136
|
//#endregion
|
|
84768
|
-
export {
|
|
84137
|
+
export { filterDiagnosticsByCategories as $, GITHUB_ACTIONS_SETUP_URL as $n, PRE_COMMIT_CONFIG_FILE as $t, HANDOFF_TARGET_PREFERENCE_ID as A, VERSION as An, loadConfigWithSource as Ar, openWorkflowPullRequest as At, buildHandoffPayload as B, isNonInteractiveEnvironment as Bn, log as Br, spinner as Bt, isGatePending as C, buildSentryScope as Cn, highlighter as Cr, upgradeReactDoctorWorkflowInPlace as Ct, writePreference as D, setJsonReportMode as Dn, isReactDoctorError as Dr, recordDistribution as Dt, runMigrations as E, setJsonReportDirectory as En, isPlainObject as Er, recordCount as Et, CLI_AGENT_BINARIES as F, STAGED_FILES_TEMP_DIR_PREFIX as Fn, setColorEnabled as Fr, hasDoctorDependency as Ft, inspect as G, isCodingAgentEnvironment as Gn, sync as Gr, chalk as Gt, collectProjectSourceFileCounts as H, isDebugFlagEnabled as Hn, provide as Hr, isWide as Ht, copyToClipboard as I, STAGED_SNAPSHOT_ADDITIONAL_CONFIG_FILENAMES as In, toRelativePath as Ir, hasDoctorScript as It, formatElapsedTime as J, CI_URL as Jn, succeed$3 as Jr, HUSKY_HOOKS_PATH as Jt, printHeadlessReport as K, CANONICAL_DISCORD_URL as Kn, void_ as Kr, HOOK_FILE_NAME as Kt, launchCliAgent as L, TUI_REPORT_COMPACT_MAX_ROWS as Ln, validateConfigTypes as Lr, installReactDoctorScriptStep as Lt, ONBOARDING_EVENT as M, METRIC as Mn, messageFromUnknown as Mr, toForwardSlashes as Mt, SETUP_HINT_EVENT as N, MINIMUM_VTE_VERSION_FOR_HYPERLINKS as Nn, remainingDeadlineBudgetMs as Nr, DOCTOR_PACKAGE_NAME as Nt, ACTION_UPGRADE_EVENT as O, writeJsonErrorReport as On, isSameRuleKey as Or, prompts as Ot, detectLaunchableAgents as P, SENTRY_FLUSH_TIMEOUT_MS as Pn, resolveScanTarget as Pr, findNearestPackageDirectory as Pt, formatDiagnosticSite as Q, DIAGNOSTIC_CATEGORY_BUCKETS as Qn, OVERCOMMIT_CONFIG_FILE as Qt, computeDefaultSelectedAgents as R, TUI_REPORT_DETAIL_WIDTH_FRACTION as Rn, yieldToEventLoop as Rr, isSpinnerSilent as Rt, openUrl as S, isEnvironmentError as Sn, hasReactRuntime as Sr, readReactDoctorWorkflow as St, recordGate as T, isJsonModeActive as Tn, isPathInsideDirectory as Tr, workflowUsesV1Action as Tt, deduplicateProjectScans as U, isCiEnvironment as Un, runPromise as Ur, stripAnsi as Ut, formatSkippedProjectsMessage as V, isGitHookEnvironment as Vn, gen as Vr, isFullWidth as Vt, createInvocationInspect as W, isCiOrCodingAgentEnvironment as Wn, runSync as Wr, isUnicodeSupported as Wt, indentMultilineText as X, COMPILER_CLEANUP_RULE_KEYS as Xn, LEGACY_HOOK_RUNNER_RELATIVE_PATH as Xt, printFooter as Y, COMPILER_CLEANUP_BUCKET as Yn, LEFTHOOK_CONFIG_FILES as Yt, printDiagnosticsDump as Z, CONFIG_SCHEMA_URL as Zn, NON_BLOCKING_REACT_DOCTOR_COMMAND as Zt, resolveCliInspectOptions as _, cliLogger as _n, getCategoryImpact as _r, resolveBlockingLevel as _t, shouldFailScanGate as a, getPackageJsonPath as an, STAGED_FILES_PROJECT_CONFIG_FILENAMES as ar, buildRulePriorityMap as at, setUpGitHubActions as b, isExpectedUserError as bn, getEquivalentRuleKeys as br, installReactDoctorWorkflow as bt, selectProjects as c, packageHasNestedRecordKey as cn, buildRuleDocsUrl as cr, formatLearnMoreLine as ct, resolveProjectChangedLineRanges as d, resolveGitPath as dn, detectAiTrainingEnvironment as dr, recordRunTraceId as dt, REACT_DOCTOR_COMMAND as en, Git as er, buildEmptyReportMessage as et, resolveProjectDiffIncludePaths as f, runGit as fn, discoverReactSubprojects as fr, finalizeScope as ft, resolveWorkspaceDeadCodeOwner as g, runCommand as gn, getBaselineDiffPlan as gr, isValidBlockingLevel as gt, retryMissingProjectScores as h, detectDefaultBranch as hn, formatReactDoctorError as hr, warnDeprecatedDiff as ht, validateModeFlags as i, ensureTrailingNewline as in, SKILL_NAME as ir, hasLintHardFailure as it, INSTALL_AGENTS_PREFERENCE_ID as j, CI_TRUST_COMPANIES as jn, mapWithConcurrency as jr, stageWorkflowFile as jt, CI_PITCH_EVENT as k, writeJsonReport as kn, listWorkspacePackages as kr, unrefStdin as kt, buildCodeFrame as l, packageHasRecordKey as ln, calculateScore as lr, getActiveRunTrace as lt, resolveProjectRelativeDirectory as m, writeJsonFile as mn, formatErrorChain as mr, resolveScope as mt, registerActiveTuiRenderer as n, SIMPLE_GIT_HOOKS_PACKAGE_JSON_KEY as nn, Progress as nr, buildNoScoreMessage as nt, projectManifestChanged as o, isRecord as on, StagedFiles as or, buildSortedRuleGroups as ot, resolveProjectSourceFilePaths as p, runGitRaw as pn, findLegacyConfig as pr, isScopeValue as pt, pluralize as q, CANONICAL_GITHUB_URL as qn, provide$2 as qr, HOOK_RELATIVE_PATH as qt, validateIncludeUntrackedScope as r, VITE_PLUS_HOOKS_PATH as rn, Reporter as rr, resolveMergeBaseRef as rt, discoverWorkspacePackages as s, packageHasDependency as sn, buildJsonReport as sr, formatFixRecipeLine as st, exitGracefully as t, SIMPLE_GIT_HOOKS_CONFIG_FILE as tn, LEGACY_CONFIG_FILENAME as tr, hasIncompleteScoreAnalysis as tt, resolveProjectScan as u, readPackageJson as un, clearConfigCache as ur, getLastRunTraceId as ut, filterScansForSurface as v, flushSentry as vn, getChangedLineRanges as vr, buildWorkflowContent as vt, readPreference as w, enableJsonMode as wn, isErrnoException as wr, upgradeWorkflowActionToV2 as wt, reportWorkflowResult as x, formatEnvironmentError as xn, hasPublishedFixRecipe as xr, isReactDoctorWorkflowInstalled as xt, countUniqueScannedFiles as y, initializeSentry as yn, getDiffInfo as yr, getReactDoctorWorkflowPath as yt, detectAvailableAgents as z, CliInputError as zn, error$1 as zr, setSpinnerSilent as zt };
|
|
84769
84138
|
|
|
84770
|
-
//# sourceMappingURL=exit-gracefully-
|
|
84771
|
-
//# debugId=
|
|
84139
|
+
//# sourceMappingURL=exit-gracefully-B18ck0kt.js.map
|
|
84140
|
+
//# debugId=b58d69eb-938f-5abd-9831-40b3dfe65ff2
|