react-doctor 0.0.11 → 0.0.13
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 +96 -0
- package/dist/cli.js +55 -19
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<picture>
|
|
2
|
+
<source media="(prefers-color-scheme: dark)" srcset="./assets/react-doctor-readme-logo-dark.svg">
|
|
3
|
+
<source media="(prefers-color-scheme: light)" srcset="./assets/react-doctor-readme-logo-light.svg">
|
|
4
|
+
<img alt="React Doctor" src="./assets/react-doctor-readme-logo-light.svg" width="180" height="40">
|
|
5
|
+
</picture>
|
|
6
|
+
|
|
7
|
+
[](https://npmjs.com/package/react-doctor)
|
|
8
|
+
[](https://npmjs.com/package/react-doctor)
|
|
9
|
+
|
|
10
|
+
Let coding agents diagnose and fix your React code.
|
|
11
|
+
|
|
12
|
+
One command scans your codebase for security, performance, correctness, and architecture issues, then outputs a **0–100 score** with actionable diagnostics.
|
|
13
|
+
|
|
14
|
+
### [See it in action →](https://react.doctor)
|
|
15
|
+
|
|
16
|
+
https://github.com/user-attachments/assets/07cc88d9-9589-44c3-aa73-5d603cb1c570
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
Run this at your project root:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx -y react-doctor@latest .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Use `--verbose` to see affected files and line numbers:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx -y react-doctor@latest . --verbose
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Install as a skill
|
|
33
|
+
|
|
34
|
+
Add React Doctor's rules as a [skill](https://skills.sh) for your coding agent:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx skills add millionco/react-doctor
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This gives agents like Cursor, Claude Code, Copilot, and others access to all 47+ React best practice rules. The CLI will also prompt to install the skill on first run.
|
|
41
|
+
|
|
42
|
+
## Options
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Usage: react-doctor [directory] [options]
|
|
46
|
+
|
|
47
|
+
Options:
|
|
48
|
+
-v, --version display the version number
|
|
49
|
+
--no-lint skip linting
|
|
50
|
+
--no-dead-code skip dead code detection
|
|
51
|
+
--verbose show file details per rule
|
|
52
|
+
--score output only the score
|
|
53
|
+
-y, --yes skip prompts, scan all workspace projects
|
|
54
|
+
--project <name> select workspace project (comma-separated for multiple)
|
|
55
|
+
--fix open Ami to auto-fix all issues
|
|
56
|
+
--prompt copy latest scan output to clipboard
|
|
57
|
+
-h, --help display help for command
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Scores for popular open-source projects
|
|
61
|
+
|
|
62
|
+
| Project | Score | Share |
|
|
63
|
+
| ------------------------------------------------------ | ------ | --------------------------------------------------------------------------------------- |
|
|
64
|
+
| [tldraw](https://github.com/tldraw/tldraw) | **84** | [view](https://www.react.doctor/share?p=tldraw&s=84&e=98&w=139&f=40) |
|
|
65
|
+
| [excalidraw](https://github.com/excalidraw/excalidraw) | **84** | [view](https://www.react.doctor/share?p=%40excalidraw%2Fexcalidraw&s=84&e=2&w=196&f=80) |
|
|
66
|
+
| [twenty](https://github.com/twentyhq/twenty) | **78** | [view](https://www.react.doctor/share?p=twenty-front&s=78&e=99&w=293&f=268) |
|
|
67
|
+
| [plane](https://github.com/makeplane/plane) | **78** | [view](https://www.react.doctor/share?p=web&s=78&e=7&w=525&f=292) |
|
|
68
|
+
| [formbricks](https://github.com/formbricks/formbricks) | **75** | [view](https://www.react.doctor/share?p=%40formbricks%2Fweb&s=75&e=15&w=389&f=242) |
|
|
69
|
+
| [posthog](https://github.com/PostHog/posthog) | **72** | [view](https://www.react.doctor/share?p=%40posthog%2Ffrontend&s=72&e=82&w=1177&f=585) |
|
|
70
|
+
| [supabase](https://github.com/supabase/supabase) | **69** | [view](https://www.react.doctor/share?p=studio&s=69&e=74&w=1087&f=566) |
|
|
71
|
+
| [onlook](https://github.com/onlook-dev/onlook) | **69** | [view](https://www.react.doctor/share?p=%40onlook%2Fweb-client&s=69&e=64&w=418&f=178) |
|
|
72
|
+
| [payload](https://github.com/payloadcms/payload) | **68** | [view](https://www.react.doctor/share?p=%40payloadcms%2Fui&s=68&e=139&w=408&f=298) |
|
|
73
|
+
| [sentry](https://github.com/getsentry/sentry) | **64** | [view](https://www.react.doctor/share?p=sentry&s=64&e=94&w=1345&f=818) |
|
|
74
|
+
| [cal.com](https://github.com/calcom/cal.com) | **63** | [view](https://www.react.doctor/share?p=%40calcom%2Fweb&s=63&e=31&w=558&f=311) |
|
|
75
|
+
| [dub](https://github.com/dubinc/dub) | **62** | [view](https://www.react.doctor/share?p=web&s=62&e=52&w=966&f=457) |
|
|
76
|
+
|
|
77
|
+
## Contributing
|
|
78
|
+
|
|
79
|
+
Want to contribute? Check out the codebase and submit a PR.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/millionco/react-doctor
|
|
83
|
+
cd react-doctor
|
|
84
|
+
pnpm install
|
|
85
|
+
pnpm -r run build
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Run locally:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
node packages/react-doctor/dist/cli.js /path/to/your/react-project
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### License
|
|
95
|
+
|
|
96
|
+
React Doctor is MIT-licensed open-source software.
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { execSync, spawn, spawnSync } from "node:child_process";
|
|
4
|
+
import fs, { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import os, { homedir, tmpdir } from "node:os";
|
|
4
6
|
import path, { join } from "node:path";
|
|
5
7
|
import { Command } from "commander";
|
|
6
8
|
import pc from "picocolors";
|
|
7
9
|
import { randomUUID } from "node:crypto";
|
|
8
|
-
import fs, { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
-
import os, { homedir, tmpdir } from "node:os";
|
|
10
10
|
import { performance } from "node:perf_hooks";
|
|
11
11
|
import { main } from "knip";
|
|
12
12
|
import { createOptions } from "knip/session";
|
|
@@ -28,6 +28,7 @@ const SUMMARY_BOX_HORIZONTAL_PADDING_CHARS = 1;
|
|
|
28
28
|
const SUMMARY_BOX_OUTER_INDENT_CHARS = 2;
|
|
29
29
|
const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
30
30
|
const SHARE_BASE_URL = "https://www.react.doctor/share";
|
|
31
|
+
const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
31
32
|
const OFFLINE_MESSAGE = "You are offline, could not calculate score. Reconnect to calculate.";
|
|
32
33
|
|
|
33
34
|
//#endregion
|
|
@@ -185,7 +186,8 @@ const countSourceFiles = (rootDirectory) => {
|
|
|
185
186
|
"--exclude-standard"
|
|
186
187
|
], {
|
|
187
188
|
cwd: rootDirectory,
|
|
188
|
-
encoding: "utf-8"
|
|
189
|
+
encoding: "utf-8",
|
|
190
|
+
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
189
191
|
});
|
|
190
192
|
if (result.error || result.status !== 0) return 0;
|
|
191
193
|
return result.stdout.split("\n").filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath)).length;
|
|
@@ -1078,7 +1080,7 @@ const buildShareUrl = (diagnostics, scoreResult, projectName) => {
|
|
|
1078
1080
|
if (affectedFileCount > 0) params.set("f", String(affectedFileCount));
|
|
1079
1081
|
return `${SHARE_BASE_URL}?${params.toString()}`;
|
|
1080
1082
|
};
|
|
1081
|
-
const printSummary = (diagnostics, elapsedMilliseconds, scoreResult, projectName) => {
|
|
1083
|
+
const printSummary = (diagnostics, elapsedMilliseconds, scoreResult, projectName, totalSourceFileCount) => {
|
|
1082
1084
|
const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
|
|
1083
1085
|
const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === "warning").length;
|
|
1084
1086
|
const affectedFileCount = collectAffectedFiles(diagnostics).size;
|
|
@@ -1095,7 +1097,7 @@ const printSummary = (diagnostics, elapsedMilliseconds, scoreResult, projectName
|
|
|
1095
1097
|
summaryLinePartsPlain.push(warningText);
|
|
1096
1098
|
summaryLineParts.push(highlighter.warn(warningText));
|
|
1097
1099
|
}
|
|
1098
|
-
const fileCountText = `across ${affectedFileCount} file${affectedFileCount === 1 ? "" : "s"}`;
|
|
1100
|
+
const fileCountText = totalSourceFileCount > 0 ? `across ${affectedFileCount}/${totalSourceFileCount} files` : `across ${affectedFileCount} file${affectedFileCount === 1 ? "" : "s"}`;
|
|
1099
1101
|
const elapsedTimeText = `in ${elapsed}`;
|
|
1100
1102
|
summaryLinePartsPlain.push(fileCountText);
|
|
1101
1103
|
summaryLinePartsPlain.push(elapsedTimeText);
|
|
@@ -1198,7 +1200,7 @@ const scan = async (directory, options) => {
|
|
|
1198
1200
|
return;
|
|
1199
1201
|
}
|
|
1200
1202
|
printDiagnostics(diagnostics, options.verbose);
|
|
1201
|
-
printSummary(diagnostics, elapsedMilliseconds, scoreResult, projectInfo.projectName);
|
|
1203
|
+
printSummary(diagnostics, elapsedMilliseconds, scoreResult, projectInfo.projectName, projectInfo.sourceFileCount);
|
|
1202
1204
|
};
|
|
1203
1205
|
|
|
1204
1206
|
//#endregion
|
|
@@ -1335,11 +1337,11 @@ const maybePromptSkillInstall = async (shouldSkipPrompts) => {
|
|
|
1335
1337
|
if (shouldInstall) {
|
|
1336
1338
|
logger.break();
|
|
1337
1339
|
installSkill();
|
|
1340
|
+
writeConfig({
|
|
1341
|
+
...config,
|
|
1342
|
+
skillPromptDismissed: true
|
|
1343
|
+
});
|
|
1338
1344
|
}
|
|
1339
|
-
writeConfig({
|
|
1340
|
-
...config,
|
|
1341
|
-
skillPromptDismissed: true
|
|
1342
|
-
});
|
|
1343
1345
|
};
|
|
1344
1346
|
|
|
1345
1347
|
//#endregion
|
|
@@ -1412,7 +1414,7 @@ const copyToClipboard = (text) => {
|
|
|
1412
1414
|
|
|
1413
1415
|
//#endregion
|
|
1414
1416
|
//#region src/cli.ts
|
|
1415
|
-
const VERSION = "0.0.
|
|
1417
|
+
const VERSION = "0.0.13";
|
|
1416
1418
|
process.on("SIGINT", () => process.exit(0));
|
|
1417
1419
|
process.on("SIGTERM", () => process.exit(0));
|
|
1418
1420
|
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--no-lint", "skip linting").option("--no-dead-code", "skip dead code detection").option("--verbose", "show file details per rule").option("--score", "output only the score").option("-y, --yes", "skip prompts, scan all workspace projects").option("--project <name>", "select workspace project (comma-separated for multiple)").option("--fix", "open Ami to auto-fix all issues").option("--prompt", "copy latest scan output to clipboard").action(async (directory, flags) => {
|
|
@@ -1465,12 +1467,19 @@ ${highlighter.dim("Learn more:")}
|
|
|
1465
1467
|
${highlighter.info("https://github.com/millionco/react-doctor")}
|
|
1466
1468
|
`);
|
|
1467
1469
|
const AMI_INSTALL_URL = "https://ami.dev/install.sh";
|
|
1468
|
-
const
|
|
1470
|
+
const AMI_RELEASES_URL = "https://github.com/millionco/ami-releases/releases";
|
|
1471
|
+
const DEEPLINK_FIX_PROMPT = "Run `npx -y react-doctor@latest .` to diagnose issues, then fix all reported issues one by one. After applying fixes, run it again to verify the results improved.";
|
|
1472
|
+
const CLIPBOARD_FIX_PROMPT = "Fix all issues reported in the react-doctor diagnostics below, one by one. After applying fixes, run `npx -y react-doctor@latest .` again to verify the results improved.";
|
|
1469
1473
|
const REACT_DOCTOR_OUTPUT_LABEL = "react-doctor output";
|
|
1470
1474
|
const SCAN_SUMMARY_SEPARATOR = "─".repeat(SEPARATOR_LENGTH_CHARS);
|
|
1471
1475
|
const isAmiInstalled = () => {
|
|
1476
|
+
if (process.platform === "darwin") return existsSync("/Applications/Ami.app") || existsSync(path.join(os.homedir(), "Applications", "Ami.app"));
|
|
1477
|
+
if (process.platform === "win32") {
|
|
1478
|
+
const { LOCALAPPDATA, PROGRAMFILES } = process.env;
|
|
1479
|
+
return Boolean(LOCALAPPDATA && existsSync(path.join(LOCALAPPDATA, "Programs", "Ami", "Ami.exe"))) || Boolean(PROGRAMFILES && existsSync(path.join(PROGRAMFILES, "Ami", "Ami.exe")));
|
|
1480
|
+
}
|
|
1472
1481
|
try {
|
|
1473
|
-
execSync("
|
|
1482
|
+
execSync("which ami", { stdio: "ignore" });
|
|
1474
1483
|
return true;
|
|
1475
1484
|
} catch {
|
|
1476
1485
|
return false;
|
|
@@ -1487,13 +1496,35 @@ const installAmi = () => {
|
|
|
1487
1496
|
}
|
|
1488
1497
|
logger.break();
|
|
1489
1498
|
};
|
|
1499
|
+
const openUrl = (url) => {
|
|
1500
|
+
if (process.platform === "win32") {
|
|
1501
|
+
execSync(`start "" "${url.replace(/%/g, "%%")}"`, { stdio: "ignore" });
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
execSync(process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`, { stdio: "ignore" });
|
|
1505
|
+
};
|
|
1506
|
+
const buildDeeplink = (directory) => {
|
|
1507
|
+
return `ami://open-project?cwd=${encodeURIComponent(path.resolve(directory))}&prompt=${encodeURIComponent(DEEPLINK_FIX_PROMPT)}&mode=agent&autoSubmit=true`;
|
|
1508
|
+
};
|
|
1490
1509
|
const openAmiToFix = (directory) => {
|
|
1491
|
-
const
|
|
1492
|
-
|
|
1510
|
+
const isInstalled = isAmiInstalled();
|
|
1511
|
+
const deeplink = buildDeeplink(directory);
|
|
1512
|
+
if (!isInstalled) {
|
|
1513
|
+
if (process.platform === "darwin") {
|
|
1514
|
+
installAmi();
|
|
1515
|
+
logger.success("Ami was installed and opened.");
|
|
1516
|
+
} else {
|
|
1517
|
+
logger.error("Ami is not installed.");
|
|
1518
|
+
logger.dim(`Download it at ${highlighter.info(AMI_RELEASES_URL)}`);
|
|
1519
|
+
}
|
|
1520
|
+
logger.break();
|
|
1521
|
+
logger.dim("Once Ami is running, open this link to start fixing:");
|
|
1522
|
+
logger.info(deeplink);
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1493
1525
|
logger.log("Opening Ami to fix react-doctor issues...");
|
|
1494
|
-
const deeplink = `ami://open-project?cwd=${encodeURIComponent(resolvedDirectory)}&prompt=${encodeURIComponent(FIX_PROMPT)}&mode=agent`;
|
|
1495
1526
|
try {
|
|
1496
|
-
|
|
1527
|
+
openUrl(deeplink);
|
|
1497
1528
|
logger.success("Opened Ami with react-doctor fix prompt.");
|
|
1498
1529
|
} catch {
|
|
1499
1530
|
logger.break();
|
|
@@ -1504,7 +1535,7 @@ const openAmiToFix = (directory) => {
|
|
|
1504
1535
|
const buildPromptWithOutput = (reactDoctorOutput) => {
|
|
1505
1536
|
const summaryStartIndex = reactDoctorOutput.indexOf(SCAN_SUMMARY_SEPARATOR);
|
|
1506
1537
|
const normalizedReactDoctorOutput = (summaryStartIndex === -1 ? reactDoctorOutput : reactDoctorOutput.slice(0, summaryStartIndex).trimEnd()).trim();
|
|
1507
|
-
return `${
|
|
1538
|
+
return `${CLIPBOARD_FIX_PROMPT}\n\n${REACT_DOCTOR_OUTPUT_LABEL}:\n\`\`\`\n${normalizedReactDoctorOutput.length > 0 ? normalizedReactDoctorOutput : "No output captured."}\n\`\`\``;
|
|
1508
1539
|
};
|
|
1509
1540
|
const copyPromptToClipboard = (reactDoctorOutput, shouldLogResult) => {
|
|
1510
1541
|
const promptWithOutput = buildPromptWithOutput(reactDoctorOutput);
|
|
@@ -1518,15 +1549,20 @@ const copyPromptToClipboard = (reactDoctorOutput, shouldLogResult) => {
|
|
|
1518
1549
|
logger.info(promptWithOutput);
|
|
1519
1550
|
};
|
|
1520
1551
|
const maybePromptAmiFix = async (directory) => {
|
|
1552
|
+
const isInstalled = isAmiInstalled();
|
|
1521
1553
|
logger.break();
|
|
1522
1554
|
logger.log(`Fix these issues with ${highlighter.info("Ami")}?`);
|
|
1523
1555
|
logger.dim(" Ami is a coding agent built to understand your codebase and fix issues");
|
|
1524
1556
|
logger.dim(` automatically. Learn more at ${highlighter.info("https://ami.dev")}`);
|
|
1525
1557
|
logger.break();
|
|
1558
|
+
if (!isInstalled && process.platform !== "darwin") {
|
|
1559
|
+
logger.dim(`Download Ami at ${highlighter.info(AMI_RELEASES_URL)}`);
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1526
1562
|
const { shouldFix } = await prompts({
|
|
1527
1563
|
type: "confirm",
|
|
1528
1564
|
name: "shouldFix",
|
|
1529
|
-
message: "Open Ami to fix?",
|
|
1565
|
+
message: isInstalled ? "Open Ami to fix?" : "Install Ami to fix?",
|
|
1530
1566
|
initial: true
|
|
1531
1567
|
});
|
|
1532
1568
|
if (shouldFix) openAmiToFix(directory);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":["esmRequire","main"],"sources":["../src/constants.ts","../src/utils/highlighter.ts","../src/utils/strip-ansi.ts","../src/utils/logger.ts","../src/utils/handle-error.ts","../src/utils/calculate-score.ts","../src/utils/read-package-json.ts","../src/utils/discover-project.ts","../src/utils/group-by.ts","../src/plugin/constants.ts","../src/utils/check-reduced-motion.ts","../src/utils/run-knip.ts","../src/oxlint-config.ts","../src/utils/run-oxlint.ts","../src/utils/spinner.ts","../src/utils/indent-multiline-text.ts","../src/scan.ts","../src/utils/should-select-all-choices.ts","../src/utils/prompts.ts","../src/utils/select-projects.ts","../src/utils/skill-prompt.ts","../src/utils/global-install.ts","../src/utils/copy-to-clipboard.ts","../src/cli.ts"],"sourcesContent":["export const SOURCE_FILE_PATTERN = /\\.(tsx?|jsx?)$/;\n\nexport const JSX_FILE_PATTERN = /\\.(tsx|jsx)$/;\n\nexport const MILLISECONDS_PER_SECOND = 1000;\n\nexport const ERROR_PREVIEW_LENGTH_CHARS = 200;\n\nexport const PERFECT_SCORE = 100;\n\nexport const SCORE_GOOD_THRESHOLD = 75;\n\nexport const SCORE_OK_THRESHOLD = 50;\n\nexport const SCORE_BAR_WIDTH_CHARS = 50;\n\nexport const SEPARATOR_LENGTH_CHARS = 40;\n\nexport const SUMMARY_BOX_HORIZONTAL_PADDING_CHARS = 1;\n\nexport const SUMMARY_BOX_OUTER_INDENT_CHARS = 2;\n\nexport const SCORE_API_URL = \"https://www.react.doctor/api/score\";\n\nexport const SHARE_BASE_URL = \"https://www.react.doctor/share\";\n\nexport const OFFLINE_MESSAGE =\n \"You are offline, could not calculate score. Reconnect to calculate.\";\n","import pc from \"picocolors\";\n\nexport const highlighter = {\n error: pc.red,\n warn: pc.yellow,\n info: pc.cyan,\n success: pc.green,\n dim: pc.dim,\n};\n","const ANSI_ESCAPE_SEQUENCE = String.raw`\\u001B\\[[0-9;]*m`;\nconst ANSI_ESCAPE_PATTERN = new RegExp(ANSI_ESCAPE_SEQUENCE, \"g\");\n\nexport const stripAnsi = (text: string): string => text.replace(ANSI_ESCAPE_PATTERN, \"\");\n","import { highlighter } from \"./highlighter.js\";\nimport { stripAnsi } from \"./strip-ansi.js\";\nimport type { LoggerCaptureState } from \"../types.js\";\n\nconst loggerCaptureState: LoggerCaptureState = {\n isEnabled: false,\n lines: [],\n};\n\nconst captureLogLine = (text: string): void => {\n if (!loggerCaptureState.isEnabled) {\n return;\n }\n\n loggerCaptureState.lines.push(stripAnsi(text));\n};\n\nconst writeLogLine = (text: string): void => {\n console.log(text);\n captureLogLine(text);\n};\n\nexport const startLoggerCapture = (): void => {\n loggerCaptureState.isEnabled = true;\n loggerCaptureState.lines = [];\n};\n\nexport const stopLoggerCapture = (): string => {\n const capturedOutput = loggerCaptureState.lines.join(\"\\n\");\n loggerCaptureState.isEnabled = false;\n loggerCaptureState.lines = [];\n return capturedOutput;\n};\n\nexport const logger = {\n error(...args: unknown[]) {\n writeLogLine(highlighter.error(args.join(\" \")));\n },\n warn(...args: unknown[]) {\n writeLogLine(highlighter.warn(args.join(\" \")));\n },\n info(...args: unknown[]) {\n writeLogLine(highlighter.info(args.join(\" \")));\n },\n success(...args: unknown[]) {\n writeLogLine(highlighter.success(args.join(\" \")));\n },\n dim(...args: unknown[]) {\n writeLogLine(highlighter.dim(args.join(\" \")));\n },\n log(...args: unknown[]) {\n writeLogLine(args.join(\" \"));\n },\n break() {\n writeLogLine(\"\");\n },\n};\n","import { logger } from \"./logger.js\";\nimport type { HandleErrorOptions } from \"../types.js\";\n\nconst DEFAULT_HANDLE_ERROR_OPTIONS: HandleErrorOptions = {\n shouldExit: true,\n};\n\nexport const handleError = (\n error: unknown,\n options: HandleErrorOptions = DEFAULT_HANDLE_ERROR_OPTIONS,\n): void => {\n logger.break();\n logger.error(\"Something went wrong. Please check the error below for more details.\");\n logger.error(\"If the problem persists, please open an issue on GitHub.\");\n logger.error(\"\");\n if (error instanceof Error) {\n logger.error(error.message);\n }\n logger.break();\n if (options.shouldExit) {\n process.exit(1);\n }\n process.exitCode = 1;\n};\n","import { SCORE_API_URL } from \"../constants.js\";\nimport type { Diagnostic, ScoreResult } from \"../types.js\";\n\nexport const calculateScore = async (diagnostics: Diagnostic[]): Promise<ScoreResult | null> => {\n const payload = diagnostics.map((diagnostic) => ({\n plugin: diagnostic.plugin,\n rule: diagnostic.rule,\n severity: diagnostic.severity,\n }));\n\n try {\n const response = await fetch(SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics: payload }),\n });\n\n if (!response.ok) return null;\n\n return (await response.json()) as ScoreResult;\n } catch {\n return null;\n }\n};\n","import fs from \"node:fs\";\nimport type { PackageJson } from \"../types.js\";\n\nexport const readPackageJson = (packageJsonPath: string): PackageJson =>\n JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { SOURCE_FILE_PATTERN } from \"../constants.js\";\nimport type {\n DependencyInfo,\n Framework,\n PackageJson,\n ProjectInfo,\n WorkspacePackage,\n} from \"../types.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REACT_COMPILER_PACKAGES = new Set([\n \"babel-plugin-react-compiler\",\n \"react-compiler-runtime\",\n \"eslint-plugin-react-compiler\",\n]);\n\nconst NEXT_CONFIG_FILENAMES = [\n \"next.config.js\",\n \"next.config.mjs\",\n \"next.config.ts\",\n \"next.config.cjs\",\n];\n\nconst BABEL_CONFIG_FILENAMES = [\n \".babelrc\",\n \".babelrc.json\",\n \"babel.config.js\",\n \"babel.config.json\",\n \"babel.config.cjs\",\n \"babel.config.mjs\",\n];\n\nconst VITE_CONFIG_FILENAMES = [\n \"vite.config.js\",\n \"vite.config.ts\",\n \"vite.config.mjs\",\n \"vite.config.cjs\",\n];\n\nconst REACT_COMPILER_CONFIG_PATTERN = /react-compiler|reactCompiler/;\n\nconst FRAMEWORK_PACKAGES: Record<string, Framework> = {\n next: \"nextjs\",\n vite: \"vite\",\n \"react-scripts\": \"cra\",\n \"@remix-run/react\": \"remix\",\n gatsby: \"gatsby\",\n};\n\nconst FRAMEWORK_DISPLAY_NAMES: Record<Framework, string> = {\n nextjs: \"Next.js\",\n vite: \"Vite\",\n cra: \"Create React App\",\n remix: \"Remix\",\n gatsby: \"Gatsby\",\n unknown: \"React\",\n};\n\nexport const formatFrameworkName = (framework: Framework): string =>\n FRAMEWORK_DISPLAY_NAMES[framework];\n\nconst countSourceFiles = (rootDirectory: string): number => {\n const result = spawnSync(\"git\", [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"], {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n });\n\n if (result.error || result.status !== 0) {\n return 0;\n }\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath)).length;\n};\n\nconst collectAllDependencies = (packageJson: PackageJson): Record<string, string> => ({\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n});\n\nconst detectFramework = (dependencies: Record<string, string>): Framework => {\n for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) {\n if (dependencies[packageName]) {\n return frameworkName;\n }\n }\n return \"unknown\";\n};\n\nconst extractDependencyInfo = (packageJson: PackageJson): DependencyInfo => {\n const allDependencies = collectAllDependencies(packageJson);\n return {\n reactVersion: allDependencies.react ?? null,\n framework: detectFramework(allDependencies),\n };\n};\n\nconst parsePnpmWorkspacePatterns = (rootDirectory: string): string[] => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!fs.existsSync(workspacePath)) return [];\n\n const content = fs.readFileSync(workspacePath, \"utf-8\");\n const patterns: string[] = [];\n let isInsidePackagesBlock = false;\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed === \"packages:\") {\n isInsidePackagesBlock = true;\n continue;\n }\n if (isInsidePackagesBlock && trimmed.startsWith(\"-\")) {\n patterns.push(trimmed.replace(/^-\\s*/, \"\").replace(/[\"']/g, \"\"));\n } else if (isInsidePackagesBlock && trimmed.length > 0 && !trimmed.startsWith(\"#\")) {\n isInsidePackagesBlock = false;\n }\n }\n\n return patterns;\n};\n\nconst getWorkspacePatterns = (rootDirectory: string, packageJson: PackageJson): string[] => {\n const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);\n if (pnpmPatterns.length > 0) return pnpmPatterns;\n\n if (Array.isArray(packageJson.workspaces)) {\n return packageJson.workspaces;\n }\n\n if (packageJson.workspaces?.packages) {\n return packageJson.workspaces.packages;\n }\n\n return [];\n};\n\nconst resolveWorkspaceDirectories = (rootDirectory: string, pattern: string): string[] => {\n const cleanPattern = pattern.replace(/[\"']/g, \"\").replace(/\\/\\*\\*$/, \"/*\");\n\n if (!cleanPattern.includes(\"*\")) {\n const directoryPath = path.join(rootDirectory, cleanPattern);\n if (fs.existsSync(directoryPath) && fs.existsSync(path.join(directoryPath, \"package.json\"))) {\n return [directoryPath];\n }\n return [];\n }\n\n const baseDirectory = path.join(rootDirectory, cleanPattern.slice(0, cleanPattern.indexOf(\"*\")));\n\n if (!fs.existsSync(baseDirectory) || !fs.statSync(baseDirectory).isDirectory()) {\n return [];\n }\n\n return fs\n .readdirSync(baseDirectory)\n .map((entry) => path.join(baseDirectory, entry))\n .filter(\n (entryPath) =>\n fs.statSync(entryPath).isDirectory() && fs.existsSync(path.join(entryPath, \"package.json\")),\n );\n};\n\nconst findDependencyInfoFromAncestors = (startDirectory: string): DependencyInfo => {\n let currentDirectory = path.dirname(startDirectory);\n const result: DependencyInfo = { reactVersion: null, framework: \"unknown\" };\n\n while (currentDirectory !== path.dirname(currentDirectory)) {\n const packageJsonPath = path.join(currentDirectory, \"package.json\");\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = readPackageJson(packageJsonPath);\n const info = extractDependencyInfo(packageJson);\n\n if (!result.reactVersion && info.reactVersion) {\n result.reactVersion = info.reactVersion;\n }\n if (result.framework === \"unknown\" && info.framework !== \"unknown\") {\n result.framework = info.framework;\n }\n\n if (result.reactVersion && result.framework !== \"unknown\") {\n return result;\n }\n }\n\n currentDirectory = path.dirname(currentDirectory);\n }\n\n return result;\n};\n\nconst findReactInWorkspaces = (rootDirectory: string, packageJson: PackageJson): DependencyInfo => {\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n const result: DependencyInfo = { reactVersion: null, framework: \"unknown\" };\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n const info = extractDependencyInfo(workspacePackageJson);\n\n if (info.reactVersion && !result.reactVersion) {\n result.reactVersion = info.reactVersion;\n }\n if (info.framework !== \"unknown\" && result.framework === \"unknown\") {\n result.framework = info.framework;\n }\n\n if (result.reactVersion && result.framework !== \"unknown\") {\n return result;\n }\n }\n }\n\n return result;\n};\n\nconst hasReactDependency = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some(\n (packageName) => packageName === \"next\" || packageName.includes(\"react\"),\n );\n};\n\nexport const discoverReactSubprojects = (rootDirectory: string): WorkspacePackage[] => {\n if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];\n\n const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });\n const packages: WorkspacePackage[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n continue;\n }\n\n const subdirectory = path.join(rootDirectory, entry.name);\n const packageJsonPath = path.join(subdirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) continue;\n\n const packageJson = readPackageJson(packageJsonPath);\n if (!hasReactDependency(packageJson)) continue;\n\n const name = packageJson.name ?? entry.name;\n packages.push({ name, directory: subdirectory });\n }\n\n return packages;\n};\n\nexport const listWorkspacePackages = (rootDirectory: string): WorkspacePackage[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return [];\n\n const packageJson = readPackageJson(packageJsonPath);\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n if (patterns.length === 0) return [];\n\n const packages: WorkspacePackage[] = [];\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n\n if (!hasReactDependency(workspacePackageJson)) continue;\n\n const name = workspacePackageJson.name ?? path.basename(workspaceDirectory);\n packages.push({ name, directory: workspaceDirectory });\n }\n }\n\n return packages;\n};\n\nconst hasCompilerPackage = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some((packageName) =>\n REACT_COMPILER_PACKAGES.has(packageName),\n );\n};\n\nconst fileContainsPattern = (filePath: string, pattern: RegExp): boolean => {\n if (!fs.existsSync(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return pattern.test(content);\n};\n\nconst hasCompilerInConfigFiles = (directory: string, filenames: string[]): boolean =>\n filenames.some((filename) =>\n fileContainsPattern(path.join(directory, filename), REACT_COMPILER_CONFIG_PATTERN),\n );\n\nconst detectReactCompiler = (directory: string, packageJson: PackageJson): boolean => {\n if (hasCompilerPackage(packageJson)) return true;\n\n if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;\n\n let ancestorDirectory = path.dirname(directory);\n while (ancestorDirectory !== path.dirname(ancestorDirectory)) {\n const ancestorPackagePath = path.join(ancestorDirectory, \"package.json\");\n if (fs.existsSync(ancestorPackagePath)) {\n const ancestorPackageJson = readPackageJson(ancestorPackagePath);\n if (hasCompilerPackage(ancestorPackageJson)) return true;\n }\n ancestorDirectory = path.dirname(ancestorDirectory);\n }\n\n return false;\n};\n\nexport const discoverProject = (directory: string): ProjectInfo => {\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`No package.json found in ${directory}`);\n }\n\n const packageJson = readPackageJson(packageJsonPath);\n let { reactVersion, framework } = extractDependencyInfo(packageJson);\n\n if (!reactVersion || framework === \"unknown\") {\n const workspaceInfo = findReactInWorkspaces(directory, packageJson);\n if (!reactVersion && workspaceInfo.reactVersion) {\n reactVersion = workspaceInfo.reactVersion;\n }\n if (framework === \"unknown\" && workspaceInfo.framework !== \"unknown\") {\n framework = workspaceInfo.framework;\n }\n }\n\n if (!reactVersion || framework === \"unknown\") {\n const ancestorInfo = findDependencyInfoFromAncestors(directory);\n if (!reactVersion) {\n reactVersion = ancestorInfo.reactVersion;\n }\n if (framework === \"unknown\") {\n framework = ancestorInfo.framework;\n }\n }\n\n const projectName = packageJson.name ?? path.basename(directory);\n const hasTypeScript = fs.existsSync(path.join(directory, \"tsconfig.json\"));\n const sourceFileCount = countSourceFiles(directory);\n\n const hasReactCompiler = detectReactCompiler(directory, packageJson);\n\n return {\n rootDirectory: directory,\n projectName,\n reactVersion,\n framework,\n hasTypeScript,\n hasReactCompiler,\n sourceFileCount,\n };\n};\n","export const groupBy = <T>(items: T[], keyFn: (item: T) => string): Map<string, T[]> => {\n const groups = new Map<string, T[]>();\n\n for (const item of items) {\n const key = keyFn(item);\n const existing = groups.get(key) ?? [];\n existing.push(item);\n groups.set(key, existing);\n }\n\n return groups;\n};\n","export const GIANT_COMPONENT_LINE_THRESHOLD = 300;\nexport const CASCADING_SET_STATE_THRESHOLD = 3;\nexport const RELATED_USE_STATE_THRESHOLD = 5;\nexport const DEEP_NESTING_THRESHOLD = 3;\nexport const DUPLICATE_STORAGE_READ_THRESHOLD = 2;\nexport const SEQUENTIAL_AWAIT_THRESHOLD = 3;\nexport const SECRET_MIN_LENGTH_CHARS = 8;\nexport const AUTH_CHECK_LOOKAHEAD_STATEMENTS = 3;\n\nexport const LAYOUT_PROPERTIES = new Set([\n \"width\",\n \"height\",\n \"top\",\n \"left\",\n \"right\",\n \"bottom\",\n \"padding\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"margin\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"borderWidth\",\n \"fontSize\",\n \"lineHeight\",\n \"gap\",\n]);\n\nexport const MOTION_ANIMATE_PROPS = new Set([\n \"animate\",\n \"initial\",\n \"exit\",\n \"whileHover\",\n \"whileTap\",\n \"whileFocus\",\n \"whileDrag\",\n \"whileInView\",\n]);\n\nexport const HEAVY_LIBRARIES = new Set([\n \"@monaco-editor/react\",\n \"monaco-editor\",\n \"recharts\",\n \"@react-pdf/renderer\",\n \"react-quill\",\n \"@codemirror/view\",\n \"@codemirror/state\",\n \"chart.js\",\n \"react-chartjs-2\",\n \"@toast-ui/editor\",\n \"draft-js\",\n]);\n\nexport const FETCH_CALLEE_NAMES = new Set([\"fetch\"]);\nexport const FETCH_MEMBER_OBJECTS = new Set([\"axios\", \"ky\", \"got\"]);\nexport const INDEX_PARAMETER_NAMES = new Set([\"index\", \"idx\", \"i\"]);\nexport const BARREL_INDEX_SUFFIXES = [\n \"/index\",\n \"/index.js\",\n \"/index.ts\",\n \"/index.tsx\",\n \"/index.mjs\",\n];\nexport const PASSIVE_EVENT_NAMES = new Set([\n \"scroll\",\n \"wheel\",\n \"touchstart\",\n \"touchmove\",\n \"touchend\",\n]);\n\nexport const LOOP_TYPES = [\n \"ForStatement\",\n \"ForInStatement\",\n \"ForOfStatement\",\n \"WhileStatement\",\n \"DoWhileStatement\",\n];\n\nexport const AUTH_FUNCTION_NAMES = new Set([\n \"auth\",\n \"getSession\",\n \"getServerSession\",\n \"getUser\",\n \"requireAuth\",\n \"checkAuth\",\n \"verifyAuth\",\n \"authenticate\",\n \"currentUser\",\n \"getAuth\",\n \"validateSession\",\n]);\n\nexport const SECRET_PATTERNS = [\n /^sk_live_/,\n /^sk_test_/,\n /^AKIA[0-9A-Z]{16}$/,\n /^ghp_[a-zA-Z0-9]{36}$/,\n /^gho_[a-zA-Z0-9]{36}$/,\n /^github_pat_/,\n /^glpat-/,\n /^xox[bporas]-/,\n /^sk-[a-zA-Z0-9]{32,}$/,\n];\n\nexport const SECRET_VARIABLE_PATTERN = /(?:api_?key|secret|token|password|credential|auth)/i;\n\nexport const SECRET_FALSE_POSITIVE_SUFFIXES = new Set([\n \"modal\",\n \"label\",\n \"text\",\n \"title\",\n \"name\",\n \"id\",\n \"key\",\n \"url\",\n \"path\",\n \"route\",\n \"page\",\n \"param\",\n \"field\",\n \"column\",\n \"header\",\n \"placeholder\",\n \"description\",\n \"type\",\n \"icon\",\n \"class\",\n \"style\",\n \"variant\",\n \"event\",\n \"action\",\n \"status\",\n \"state\",\n \"mode\",\n \"flag\",\n \"option\",\n \"config\",\n \"message\",\n \"error\",\n \"display\",\n \"view\",\n \"component\",\n \"element\",\n \"container\",\n \"wrapper\",\n \"button\",\n \"link\",\n \"input\",\n \"select\",\n \"dialog\",\n \"menu\",\n \"form\",\n \"step\",\n \"index\",\n \"count\",\n \"length\",\n \"role\",\n \"scope\",\n \"context\",\n \"provider\",\n \"ref\",\n \"handler\",\n \"query\",\n \"schema\",\n \"constant\",\n]);\n\nexport const LOADING_STATE_PATTERN = /^(?:isLoading|isPending)$/;\n\nexport const GENERIC_EVENT_SUFFIXES = new Set([\"Click\", \"Change\", \"Input\", \"Blur\", \"Focus\"]);\n\nexport const TRIVIAL_INITIALIZER_NAMES = new Set([\n \"Boolean\",\n \"String\",\n \"Number\",\n \"Array\",\n \"Object\",\n \"parseInt\",\n \"parseFloat\",\n]);\n\nexport const SETTER_PATTERN = /^set[A-Z]/;\nexport const RENDER_FUNCTION_PATTERN = /^render[A-Z]/;\nexport const UPPERCASE_PATTERN = /^[A-Z]/;\nexport const PAGE_FILE_PATTERN = /\\/page\\.(tsx?|jsx?)$/;\nexport const PAGE_OR_LAYOUT_FILE_PATTERN = /\\/(page|layout)\\.(tsx?|jsx?)$/;\n\nexport const INTERNAL_PAGE_PATH_PATTERN =\n /\\/(?:(?:\\((?:dashboard|admin|settings|account|internal|manage|console|portal|auth|onboarding|app|ee|protected)\\))|(?:dashboard|admin|settings|account|internal|manage|console|portal))\\//i;\n\nexport const TEST_FILE_PATTERN = /\\.(?:test|spec|stories)\\.[tj]sx?$/;\nexport const OG_ROUTE_PATTERN = /\\/og\\b/i;\n\nexport const PAGES_DIRECTORY_PATTERN = /\\/pages\\//;\nexport const SERVER_ACTION_FILE_PATTERN = /actions?\\.(tsx?|jsx?)$/;\nexport const SERVER_ACTION_DIRECTORY_PATTERN = /\\/actions\\//;\n\nexport const NEXTJS_NAVIGATION_FUNCTIONS = new Set([\n \"redirect\",\n \"permanentRedirect\",\n \"notFound\",\n \"forbidden\",\n \"unauthorized\",\n]);\n\nexport const GOOGLE_FONTS_PATTERN = /fonts\\.googleapis\\.com/;\n\nexport const POLYFILL_SCRIPT_PATTERN = /polyfill\\.io|polyfill\\.min\\.js|cdn\\.polyfill/;\n\nexport const APP_DIRECTORY_PATTERN = /\\/app\\//;\n\nexport const ROUTE_HANDLER_FILE_PATTERN = /\\/route\\.(tsx?|jsx?)$/;\n\nexport const MUTATION_METHOD_NAMES = new Set([\n \"create\",\n \"insert\",\n \"insertInto\",\n \"update\",\n \"upsert\",\n \"delete\",\n \"remove\",\n \"destroy\",\n \"set\",\n \"append\",\n]);\n\nexport const MUTATING_HTTP_METHODS = new Set([\"POST\", \"PUT\", \"DELETE\", \"PATCH\"]);\n\nexport const MUTATING_ROUTE_SEGMENTS = new Set([\n \"logout\",\n \"log-out\",\n \"signout\",\n \"sign-out\",\n \"unsubscribe\",\n \"delete\",\n \"remove\",\n \"revoke\",\n \"cancel\",\n \"deactivate\",\n]);\n\nexport const EFFECT_HOOK_NAMES = new Set([\"useEffect\", \"useLayoutEffect\"]);\nexport const HOOKS_WITH_DEPS = new Set([\"useEffect\", \"useLayoutEffect\", \"useMemo\", \"useCallback\"]);\nexport const CHAINABLE_ITERATION_METHODS = new Set([\"map\", \"filter\", \"forEach\", \"flatMap\"]);\nexport const STORAGE_OBJECTS = new Set([\"localStorage\", \"sessionStorage\"]);\n\nexport const LARGE_BLUR_THRESHOLD_PX = 10;\nexport const BLUR_VALUE_PATTERN = /blur\\((\\d+(?:\\.\\d+)?)px\\)/;\nexport const ANIMATION_CALLBACK_NAMES = new Set([\"requestAnimationFrame\", \"setInterval\"]);\nexport const MOTION_LIBRARY_PACKAGES = new Set([\"framer-motion\", \"motion\"]);\n","import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { MOTION_LIBRARY_PACKAGES } from \"../plugin/constants.js\";\nimport type { Diagnostic } from \"../types.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REDUCED_MOTION_GREP_PATTERN = \"prefers-reduced-motion|useReducedMotion\";\nconst REDUCED_MOTION_FILE_GLOBS = '\"*.ts\" \"*.tsx\" \"*.js\" \"*.jsx\" \"*.css\" \"*.scss\"';\n\nconst MISSING_REDUCED_MOTION_DIAGNOSTIC: Diagnostic = {\n filePath: \"package.json\",\n plugin: \"react-doctor\",\n rule: \"require-reduced-motion\",\n severity: \"error\",\n message:\n \"Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)\",\n help: \"Add `useReducedMotion()` from your animation library, or a `@media (prefers-reduced-motion: reduce)` CSS query\",\n line: 0,\n column: 0,\n category: \"Accessibility\",\n weight: 2,\n};\n\nexport const checkReducedMotion = (rootDirectory: string): Diagnostic[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return [];\n\n let hasMotionLibrary = false;\n try {\n const packageJson = readPackageJson(packageJsonPath);\n const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };\n hasMotionLibrary = Object.keys(allDependencies).some((packageName) =>\n MOTION_LIBRARY_PACKAGES.has(packageName),\n );\n } catch {\n return [];\n }\n if (!hasMotionLibrary) return [];\n\n try {\n execSync(`git grep -ql -E \"${REDUCED_MOTION_GREP_PATTERN}\" -- ${REDUCED_MOTION_FILE_GLOBS}`, {\n cwd: rootDirectory,\n stdio: \"pipe\",\n });\n return [];\n } catch {\n return [MISSING_REDUCED_MOTION_DIAGNOSTIC];\n }\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { main } from \"knip\";\nimport { createOptions } from \"knip/session\";\nimport type { Diagnostic, KnipIssueRecords, KnipResults } from \"../types.js\";\n\nconst KNIP_CATEGORY_MAP: Record<string, string> = {\n files: \"Dead Code\",\n exports: \"Dead Code\",\n types: \"Dead Code\",\n duplicates: \"Dead Code\",\n};\n\nconst KNIP_MESSAGE_MAP: Record<string, string> = {\n files: \"Unused file\",\n exports: \"Unused export\",\n types: \"Unused type\",\n duplicates: \"Duplicate export\",\n};\n\nconst KNIP_SEVERITY_MAP: Record<string, \"error\" | \"warning\"> = {\n files: \"warning\",\n exports: \"warning\",\n types: \"warning\",\n duplicates: \"warning\",\n};\n\nconst collectIssueRecords = (\n records: KnipIssueRecords,\n issueType: string,\n rootDirectory: string,\n): Diagnostic[] => {\n const diagnostics: Diagnostic[] = [];\n\n for (const issues of Object.values(records)) {\n for (const issue of Object.values(issues)) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, issue.filePath),\n plugin: \"knip\",\n rule: issueType,\n severity: KNIP_SEVERITY_MAP[issueType] ?? \"warning\",\n message: `${KNIP_MESSAGE_MAP[issueType]}: ${issue.symbol}`,\n help: \"\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[issueType] ?? \"Dead Code\",\n weight: 1,\n });\n }\n }\n\n return diagnostics;\n};\n\n// HACK: knip triggers dotenv which logs to stdout/stderr via console methods\nconst silenced = async <T>(fn: () => Promise<T>): Promise<T> => {\n const originalLog = console.log;\n const originalInfo = console.info;\n const originalWarn = console.warn;\n console.log = () => {};\n console.info = () => {};\n console.warn = () => {};\n try {\n return await fn();\n } finally {\n console.log = originalLog;\n console.info = originalInfo;\n console.warn = originalWarn;\n }\n};\n\nconst findMonorepoRoot = (directory: string): string | null => {\n let currentDirectory = path.dirname(directory);\n\n while (currentDirectory !== path.dirname(currentDirectory)) {\n const hasWorkspaceConfig =\n fs.existsSync(path.join(currentDirectory, \"pnpm-workspace.yaml\")) ||\n (() => {\n const packageJsonPath = path.join(currentDirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n return Array.isArray(packageJson.workspaces) || packageJson.workspaces?.packages;\n })();\n\n if (hasWorkspaceConfig) return currentDirectory;\n currentDirectory = path.dirname(currentDirectory);\n }\n\n return null;\n};\n\nconst runKnipWithOptions = async (\n knipCwd: string,\n workspaceName?: string,\n): Promise<KnipResults> => {\n const options = await silenced(() =>\n createOptions({\n cwd: knipCwd,\n isShowProgress: false,\n ...(workspaceName ? { workspace: workspaceName } : {}),\n }),\n );\n return (await silenced(() => main(options))) as KnipResults;\n};\n\nconst hasNodeModules = (directory: string): boolean => {\n const nodeModulesPath = path.join(directory, \"node_modules\");\n return fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory();\n};\n\nexport const runKnip = async (rootDirectory: string): Promise<Diagnostic[]> => {\n const monorepoRoot = findMonorepoRoot(rootDirectory);\n const hasInstalledDependencies =\n hasNodeModules(rootDirectory) || (monorepoRoot !== null && hasNodeModules(monorepoRoot));\n\n if (!hasInstalledDependencies) {\n return [];\n }\n\n let knipResult: KnipResults;\n\n if (monorepoRoot) {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n const packageJson = fs.existsSync(packageJsonPath)\n ? JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"))\n : {};\n const workspaceName = packageJson.name ?? path.basename(rootDirectory);\n\n try {\n knipResult = await runKnipWithOptions(monorepoRoot, workspaceName);\n } catch {\n knipResult = await runKnipWithOptions(rootDirectory);\n }\n } else {\n knipResult = await runKnipWithOptions(rootDirectory);\n }\n\n const { issues } = knipResult;\n const diagnostics: Diagnostic[] = [];\n\n for (const unusedFile of issues.files) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, unusedFile),\n plugin: \"knip\",\n rule: \"files\",\n severity: KNIP_SEVERITY_MAP[\"files\"],\n message: KNIP_MESSAGE_MAP[\"files\"],\n help: \"This file is not imported by any other file in the project.\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[\"files\"],\n weight: 1,\n });\n }\n\n const recordTypes = [\"exports\", \"types\", \"duplicates\"] as const;\n\n for (const issueType of recordTypes) {\n diagnostics.push(...collectIssueRecords(issues[issueType], issueType, rootDirectory));\n }\n\n return diagnostics;\n};\n","import { createRequire } from \"node:module\";\nimport type { Framework } from \"./types.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst NEXTJS_RULES: Record<string, string> = {\n \"react-doctor/nextjs-no-img-element\": \"warn\",\n \"react-doctor/nextjs-async-client-component\": \"error\",\n \"react-doctor/nextjs-no-a-element\": \"warn\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"warn\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"warn\",\n \"react-doctor/nextjs-missing-metadata\": \"warn\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"warn\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"warn\",\n \"react-doctor/nextjs-image-missing-sizes\": \"warn\",\n \"react-doctor/nextjs-no-native-script\": \"warn\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"warn\",\n \"react-doctor/nextjs-no-font-link\": \"warn\",\n \"react-doctor/nextjs-no-css-link\": \"warn\",\n \"react-doctor/nextjs-no-polyfill-script\": \"warn\",\n \"react-doctor/nextjs-no-head-import\": \"error\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"error\",\n};\n\nconst REACT_COMPILER_RULES: Record<string, string> = {\n \"react-hooks-js/set-state-in-render\": \"error\",\n \"react-hooks-js/immutability\": \"error\",\n \"react-hooks-js/refs\": \"error\",\n \"react-hooks-js/purity\": \"error\",\n \"react-hooks-js/hooks\": \"error\",\n \"react-hooks-js/set-state-in-effect\": \"error\",\n \"react-hooks-js/globals\": \"error\",\n \"react-hooks-js/error-boundaries\": \"error\",\n \"react-hooks-js/preserve-manual-memoization\": \"error\",\n \"react-hooks-js/unsupported-syntax\": \"error\",\n \"react-hooks-js/component-hook-factories\": \"error\",\n \"react-hooks-js/static-components\": \"error\",\n \"react-hooks-js/use-memo\": \"error\",\n \"react-hooks-js/void-use-memo\": \"error\",\n \"react-hooks-js/incompatible-library\": \"error\",\n \"react-hooks-js/todo\": \"error\",\n};\n\ninterface OxlintConfigOptions {\n pluginPath: string;\n framework: Framework;\n hasReactCompiler: boolean;\n}\n\nexport const createOxlintConfig = ({\n pluginPath,\n framework,\n hasReactCompiler,\n}: OxlintConfigOptions) => ({\n categories: {\n correctness: \"off\",\n suspicious: \"off\",\n pedantic: \"off\",\n perf: \"off\",\n restriction: \"off\",\n style: \"off\",\n nursery: \"off\",\n },\n plugins: [\"react\", \"jsx-a11y\", ...(hasReactCompiler ? [] : [\"react-perf\"])],\n jsPlugins: [\n ...(hasReactCompiler\n ? [{ name: \"react-hooks-js\", specifier: esmRequire.resolve(\"eslint-plugin-react-hooks\") }]\n : []),\n pluginPath,\n ],\n rules: {\n \"react/rules-of-hooks\": \"error\",\n \"react/no-direct-mutation-state\": \"error\",\n \"react/jsx-no-duplicate-props\": \"error\",\n \"react/jsx-key\": \"error\",\n \"react/no-children-prop\": \"warn\",\n \"react/no-danger\": \"warn\",\n \"react/jsx-no-script-url\": \"error\",\n \"react/no-render-return-value\": \"warn\",\n \"react/no-string-refs\": \"warn\",\n \"react/no-is-mounted\": \"warn\",\n \"react/require-render-return\": \"error\",\n \"react/no-unknown-property\": \"warn\",\n\n \"jsx-a11y/alt-text\": \"error\",\n \"jsx-a11y/anchor-is-valid\": \"warn\",\n \"jsx-a11y/click-events-have-key-events\": \"warn\",\n \"jsx-a11y/no-static-element-interactions\": \"warn\",\n \"jsx-a11y/no-noninteractive-element-interactions\": \"warn\",\n \"jsx-a11y/role-has-required-aria-props\": \"error\",\n \"jsx-a11y/no-autofocus\": \"warn\",\n \"jsx-a11y/heading-has-content\": \"warn\",\n \"jsx-a11y/html-has-lang\": \"warn\",\n \"jsx-a11y/no-redundant-roles\": \"warn\",\n \"jsx-a11y/scope\": \"warn\",\n \"jsx-a11y/tabindex-no-positive\": \"warn\",\n \"jsx-a11y/label-has-associated-control\": \"warn\",\n \"jsx-a11y/no-distracting-elements\": \"error\",\n \"jsx-a11y/iframe-has-title\": \"warn\",\n\n ...(hasReactCompiler ? REACT_COMPILER_RULES : {}),\n\n \"react-doctor/no-derived-state-effect\": \"error\",\n \"react-doctor/no-fetch-in-effect\": \"error\",\n \"react-doctor/no-cascading-set-state\": \"warn\",\n \"react-doctor/no-effect-event-handler\": \"warn\",\n \"react-doctor/no-derived-useState\": \"warn\",\n \"react-doctor/prefer-useReducer\": \"warn\",\n \"react-doctor/rerender-lazy-state-init\": \"warn\",\n \"react-doctor/rerender-functional-setstate\": \"warn\",\n \"react-doctor/rerender-dependencies\": \"error\",\n\n \"react-doctor/no-giant-component\": \"warn\",\n \"react-doctor/no-render-in-render\": \"warn\",\n \"react-doctor/no-nested-component-definition\": \"error\",\n\n \"react-doctor/no-usememo-simple-expression\": \"warn\",\n \"react-doctor/no-layout-property-animation\": \"error\",\n \"react-doctor/rerender-memo-with-default-value\": \"warn\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"warn\",\n \"react-doctor/no-inline-prop-on-memo-component\": \"warn\",\n \"react-doctor/rendering-hydration-no-flicker\": \"warn\",\n\n \"react-doctor/no-transition-all\": \"warn\",\n \"react-doctor/no-global-css-variable-animation\": \"error\",\n \"react-doctor/no-large-animated-blur\": \"warn\",\n \"react-doctor/no-scale-from-zero\": \"warn\",\n \"react-doctor/no-permanent-will-change\": \"warn\",\n\n \"react-doctor/no-secrets-in-client-code\": \"error\",\n\n \"react-doctor/no-barrel-import\": \"warn\",\n \"react-doctor/no-full-lodash-import\": \"warn\",\n \"react-doctor/no-moment\": \"warn\",\n \"react-doctor/prefer-dynamic-import\": \"warn\",\n \"react-doctor/use-lazy-motion\": \"warn\",\n \"react-doctor/no-undeferred-third-party\": \"warn\",\n\n \"react-doctor/no-array-index-as-key\": \"warn\",\n \"react-doctor/rendering-conditional-render\": \"warn\",\n \"react-doctor/no-prevent-default\": \"warn\",\n\n \"react-doctor/server-auth-actions\": \"error\",\n \"react-doctor/server-after-nonblocking\": \"warn\",\n\n \"react-doctor/client-passive-event-listeners\": \"warn\",\n\n \"react-doctor/async-parallel\": \"warn\",\n ...(framework === \"nextjs\" ? NEXTJS_RULES : {}),\n },\n});\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ERROR_PREVIEW_LENGTH_CHARS, JSX_FILE_PATTERN } from \"../constants.js\";\nimport { createOxlintConfig } from \"../oxlint-config.js\";\nimport type { CleanedDiagnostic, Diagnostic, Framework, OxlintOutput } from \"../types.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst PLUGIN_CATEGORY_MAP: Record<string, string> = {\n react: \"Correctness\",\n \"react-hooks\": \"Correctness\",\n \"react-hooks-js\": \"React Compiler\",\n \"react-perf\": \"Performance\",\n \"jsx-a11y\": \"Accessibility\",\n};\n\nconst RULE_CATEGORY_MAP: Record<string, string> = {\n \"react-doctor/no-derived-state-effect\": \"State & Effects\",\n \"react-doctor/no-fetch-in-effect\": \"State & Effects\",\n \"react-doctor/no-cascading-set-state\": \"State & Effects\",\n \"react-doctor/no-effect-event-handler\": \"State & Effects\",\n \"react-doctor/no-derived-useState\": \"State & Effects\",\n \"react-doctor/prefer-useReducer\": \"State & Effects\",\n \"react-doctor/rerender-lazy-state-init\": \"Performance\",\n \"react-doctor/rerender-functional-setstate\": \"Performance\",\n \"react-doctor/rerender-dependencies\": \"State & Effects\",\n\n \"react-doctor/no-generic-handler-names\": \"Architecture\",\n \"react-doctor/no-giant-component\": \"Architecture\",\n \"react-doctor/no-render-in-render\": \"Architecture\",\n \"react-doctor/no-nested-component-definition\": \"Correctness\",\n\n \"react-doctor/no-usememo-simple-expression\": \"Performance\",\n \"react-doctor/no-layout-property-animation\": \"Performance\",\n \"react-doctor/rerender-memo-with-default-value\": \"Performance\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"Performance\",\n \"react-doctor/rendering-usetransition-loading\": \"Performance\",\n \"react-doctor/rendering-hydration-no-flicker\": \"Performance\",\n\n \"react-doctor/no-transition-all\": \"Performance\",\n \"react-doctor/no-global-css-variable-animation\": \"Performance\",\n \"react-doctor/no-large-animated-blur\": \"Performance\",\n \"react-doctor/no-scale-from-zero\": \"Performance\",\n \"react-doctor/no-permanent-will-change\": \"Performance\",\n\n \"react-doctor/no-secrets-in-client-code\": \"Security\",\n\n \"react-doctor/no-barrel-import\": \"Bundle Size\",\n \"react-doctor/no-full-lodash-import\": \"Bundle Size\",\n \"react-doctor/no-moment\": \"Bundle Size\",\n \"react-doctor/prefer-dynamic-import\": \"Bundle Size\",\n \"react-doctor/use-lazy-motion\": \"Bundle Size\",\n \"react-doctor/no-undeferred-third-party\": \"Bundle Size\",\n\n \"react-doctor/no-array-index-as-key\": \"Correctness\",\n \"react-doctor/rendering-conditional-render\": \"Correctness\",\n \"react-doctor/no-prevent-default\": \"Correctness\",\n \"react-doctor/nextjs-no-img-element\": \"Next.js\",\n \"react-doctor/nextjs-async-client-component\": \"Next.js\",\n \"react-doctor/nextjs-no-a-element\": \"Next.js\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"Next.js\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"Next.js\",\n \"react-doctor/nextjs-missing-metadata\": \"Next.js\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"Next.js\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"Next.js\",\n \"react-doctor/nextjs-image-missing-sizes\": \"Next.js\",\n \"react-doctor/nextjs-no-native-script\": \"Next.js\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"Next.js\",\n \"react-doctor/nextjs-no-font-link\": \"Next.js\",\n \"react-doctor/nextjs-no-css-link\": \"Next.js\",\n \"react-doctor/nextjs-no-polyfill-script\": \"Next.js\",\n \"react-doctor/nextjs-no-head-import\": \"Next.js\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"Security\",\n\n \"react-doctor/server-auth-actions\": \"Server\",\n \"react-doctor/server-after-nonblocking\": \"Server\",\n\n \"react-doctor/client-passive-event-listeners\": \"Performance\",\n\n \"react-doctor/async-parallel\": \"Performance\",\n};\n\nconst RULE_HELP_MAP: Record<string, string> = {\n \"no-derived-state-effect\":\n \"Compute during render: `const derived = computeFrom(dep1, dep2)` — no useEffect needed\",\n \"no-fetch-in-effect\":\n \"Use `useQuery()` from @tanstack/react-query, `useSWR()`, or fetch in a Server Component instead\",\n \"no-cascading-set-state\":\n \"Combine into useReducer: `const [state, dispatch] = useReducer(reducer, initialState)`\",\n \"no-effect-event-handler\":\n \"Move the conditional logic into onClick, onChange, or onSubmit handlers directly\",\n \"no-derived-useState\":\n \"Remove useState and compute the value inline: `const value = transform(propName)`\",\n \"prefer-useReducer\":\n \"Group related state: `const [state, dispatch] = useReducer(reducer, { field1, field2, ... })`\",\n \"rerender-lazy-state-init\":\n \"Wrap in an arrow function so it only runs once: `useState(() => expensiveComputation())`\",\n \"rerender-functional-setstate\":\n \"Use the callback form: `setState(prev => prev + 1)` to always read the latest value\",\n \"rerender-dependencies\":\n \"Extract to a useMemo, useRef, or module-level constant so the reference is stable\",\n\n \"no-generic-handler-names\":\n \"Rename to describe the action: e.g. `handleSubmit` → `saveUserProfile`, `handleClick` → `toggleSidebar`\",\n \"no-giant-component\":\n \"Extract logical sections into focused components: `<UserHeader />`, `<UserActions />`, etc.\",\n \"no-render-in-render\":\n \"Extract to a named component: `const ListItem = ({ item }) => <div>{item.name}</div>`\",\n \"no-nested-component-definition\":\n \"Move to a separate file or to module scope above the parent component\",\n\n \"no-usememo-simple-expression\":\n \"Remove useMemo — property access, math, and ternaries are already cheap without memoization\",\n \"no-layout-property-animation\":\n \"Use `transform: translateX()` or `scale()` instead — they run on the compositor and skip layout/paint\",\n \"rerender-memo-with-default-value\":\n \"Move to module scope: `const EMPTY_ITEMS: Item[] = []` then use as the default value\",\n \"rendering-animate-svg-wrapper\":\n \"Wrap the SVG: `<motion.div animate={...}><svg>...</svg></motion.div>`\",\n \"rendering-usetransition-loading\":\n \"Replace with `const [isPending, startTransition] = useTransition()` — avoids a re-render for the loading state\",\n \"rendering-hydration-no-flicker\":\n \"Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` or add `suppressHydrationWarning` to the element\",\n\n \"no-transition-all\":\n 'List specific properties: `transition: \"opacity 200ms, transform 200ms\"` — or in Tailwind use `transition-colors`, `transition-opacity`, or `transition-transform`',\n \"no-global-css-variable-animation\":\n \"Set the variable on the nearest element instead of a parent, or use `@property` with `inherits: false` to prevent cascade. Better yet, use targeted `element.style.transform` updates\",\n \"no-large-animated-blur\":\n \"Keep blur radius under 10px, or apply blur to a smaller element. Large blurs multiply GPU memory usage with layer size\",\n \"no-scale-from-zero\":\n \"Use `initial={{ scale: 0.95, opacity: 0 }}` — elements should deflate like a balloon, not vanish into a point\",\n \"no-permanent-will-change\":\n \"Add will-change on animation start (`onMouseEnter`) and remove on end (`onAnimationEnd`). Permanent promotion wastes GPU memory and can degrade performance\",\n\n \"no-secrets-in-client-code\":\n \"Move to server-side `process.env.SECRET_NAME`. Only `NEXT_PUBLIC_*` vars are safe for the client (and should not contain secrets)\",\n\n \"no-barrel-import\":\n \"Import from the direct path: `import { Button } from './components/Button'` instead of `./components`\",\n \"no-full-lodash-import\":\n \"Import the specific function: `import debounce from 'lodash/debounce'` — saves ~70kb\",\n \"no-moment\":\n \"Replace with `import { format } from 'date-fns'` (tree-shakeable) or `import dayjs from 'dayjs'` (2kb)\",\n \"prefer-dynamic-import\":\n \"Use `const Component = dynamic(() => import('library'), { ssr: false })` from next/dynamic or React.lazy()\",\n \"use-lazy-motion\":\n 'Use `import { LazyMotion, m } from \"framer-motion\"` with `domAnimation` features — saves ~30kb',\n \"no-undeferred-third-party\":\n 'Use `next/script` with `strategy=\"lazyOnload\"` or add the `defer` attribute',\n\n \"no-array-index-as-key\":\n \"Use a stable unique identifier: `key={item.id}` or `key={item.slug}` — index keys break on reorder/filter\",\n \"rendering-conditional-render\":\n \"Change to `{items.length > 0 && <List />}` or use a ternary: `{items.length ? <List /> : null}`\",\n \"no-prevent-default\":\n \"Use `<form action={serverAction}>` (works without JS) or `<button>` instead of `<a>` with preventDefault\",\n\n \"nextjs-no-img-element\":\n \"`import Image from 'next/image'` — provides automatic WebP/AVIF, lazy loading, and responsive srcset\",\n \"nextjs-async-client-component\":\n \"Fetch data in a parent Server Component and pass it as props, or use useQuery/useSWR in the client component\",\n \"nextjs-no-a-element\":\n \"`import Link from 'next/link'` — enables client-side navigation, prefetching, and preserves scroll position\",\n \"nextjs-no-use-search-params-without-suspense\":\n \"Wrap the component using useSearchParams: `<Suspense fallback={<Skeleton />}><SearchComponent /></Suspense>`\",\n \"nextjs-no-client-fetch-for-server-data\":\n \"Remove 'use client' and fetch directly in the Server Component — no API round-trip, secrets stay on server\",\n \"nextjs-missing-metadata\":\n \"Add `export const metadata = { title: '...', description: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-client-side-redirect\":\n \"Use `redirect('/path')` from 'next/navigation' in a Server Component, or handle in middleware\",\n \"nextjs-no-redirect-in-try-catch\":\n \"Move the redirect/notFound call outside the try block, or add `unstable_rethrow(error)` in the catch\",\n \"nextjs-image-missing-sizes\":\n 'Add sizes for responsive behavior: `sizes=\"(max-width: 768px) 100vw, 50vw\"` matching your layout breakpoints',\n \"nextjs-no-native-script\":\n '`import Script from \"next/script\"` — use `strategy=\"afterInteractive\"` for analytics or `\"lazyOnload\"` for widgets',\n \"nextjs-inline-script-missing-id\":\n 'Add `id=\"descriptive-name\"` so Next.js can track, deduplicate, and re-execute the script correctly',\n \"nextjs-no-font-link\":\n '`import { Inter } from \"next/font/google\"` — self-hosted, zero layout shift, no render-blocking requests',\n \"nextjs-no-css-link\":\n \"Import CSS directly: `import './styles.css'` or use CSS Modules: `import styles from './Button.module.css'`\",\n \"nextjs-no-polyfill-script\":\n \"Next.js includes polyfills for fetch, Promise, Object.assign, Array.from, and 50+ others automatically\",\n \"nextjs-no-head-import\":\n \"Use the Metadata API instead: `export const metadata = { title: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-side-effect-in-get-handler\":\n \"Move the side effect to a POST handler and use a <form> or fetch with method POST — GET requests can be triggered by prefetching and are vulnerable to CSRF\",\n\n \"server-auth-actions\":\n \"Add `const session = await auth()` at the top and throw/redirect if unauthorized before any data access\",\n \"server-after-nonblocking\":\n \"`import { after } from 'next/server'` then wrap: `after(() => analytics.track(...))` — response isn't blocked\",\n\n \"client-passive-event-listeners\":\n \"Add `{ passive: true }` as the third argument: `addEventListener('scroll', handler, { passive: true })`\",\n\n \"async-parallel\":\n \"Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to run independent operations concurrently\",\n};\n\nconst FILEPATH_WITH_LOCATION_PATTERN = /\\S+\\.\\w+:\\d+:\\d+[\\s\\S]*$/;\n\nconst REACT_COMPILER_MESSAGE = \"React Compiler can't optimize this code\";\n\nconst cleanDiagnosticMessage = (\n message: string,\n help: string,\n plugin: string,\n rule: string,\n): CleanedDiagnostic => {\n if (plugin === \"react-hooks-js\") {\n const rawMessage = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: REACT_COMPILER_MESSAGE, help: rawMessage || help };\n }\n const cleaned = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: cleaned || message, help: help || RULE_HELP_MAP[rule] || \"\" };\n};\n\nconst parseRuleCode = (code: string): { plugin: string; rule: string } => {\n const match = code.match(/^(.+)\\((.+)\\)$/);\n if (!match) return { plugin: \"unknown\", rule: code };\n return { plugin: match[1].replace(/^eslint-plugin-/, \"\"), rule: match[2] };\n};\n\nconst resolveOxlintBinary = (): string => {\n const oxlintMainPath = esmRequire.resolve(\"oxlint\");\n const oxlintPackageDirectory = path.resolve(path.dirname(oxlintMainPath), \"..\");\n return path.join(oxlintPackageDirectory, \"bin\", \"oxlint\");\n};\n\nconst resolvePluginPath = (): string => {\n const currentDirectory = path.dirname(fileURLToPath(import.meta.url));\n const pluginPath = path.join(currentDirectory, \"react-doctor-plugin.js\");\n if (fs.existsSync(pluginPath)) return pluginPath;\n\n const distPluginPath = path.resolve(currentDirectory, \"../../dist/react-doctor-plugin.js\");\n if (fs.existsSync(distPluginPath)) return distPluginPath;\n\n return pluginPath;\n};\n\nconst resolveDiagnosticCategory = (plugin: string, rule: string): string => {\n const ruleKey = `${plugin}/${rule}`;\n return RULE_CATEGORY_MAP[ruleKey] ?? PLUGIN_CATEGORY_MAP[plugin] ?? \"Other\";\n};\n\nexport const runOxlint = async (\n rootDirectory: string,\n hasTypeScript: boolean,\n framework: Framework,\n hasReactCompiler: boolean,\n): Promise<Diagnostic[]> => {\n const configPath = path.join(os.tmpdir(), `react-doctor-oxlintrc-${process.pid}.json`);\n const pluginPath = resolvePluginPath();\n const config = createOxlintConfig({ pluginPath, framework, hasReactCompiler });\n\n try {\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2));\n\n const oxlintBinary = resolveOxlintBinary();\n const args = [oxlintBinary, \"-c\", configPath, \"--format\", \"json\"];\n\n if (hasTypeScript) {\n args.push(\"--tsconfig\", \"./tsconfig.json\");\n }\n\n args.push(\".\");\n\n const stdout = await new Promise<string>((resolve, reject) => {\n const child = spawn(process.execPath, args, {\n cwd: rootDirectory,\n });\n\n const stdoutBuffers: Buffer[] = [];\n const stderrBuffers: Buffer[] = [];\n\n child.stdout.on(\"data\", (buffer: Buffer) => stdoutBuffers.push(buffer));\n child.stderr.on(\"data\", (buffer: Buffer) => stderrBuffers.push(buffer));\n\n child.on(\"error\", (error) => reject(new Error(`Failed to run oxlint: ${error.message}`)));\n child.on(\"close\", () => {\n const output = Buffer.concat(stdoutBuffers).toString(\"utf-8\").trim();\n if (!output) {\n const stderrOutput = Buffer.concat(stderrBuffers).toString(\"utf-8\").trim();\n if (stderrOutput) {\n reject(new Error(`Failed to run oxlint: ${stderrOutput}`));\n return;\n }\n }\n resolve(output);\n });\n });\n\n if (!stdout) {\n return [];\n }\n\n let output: OxlintOutput;\n try {\n output = JSON.parse(stdout) as OxlintOutput;\n } catch {\n throw new Error(\n `Failed to parse oxlint output: ${stdout.slice(0, ERROR_PREVIEW_LENGTH_CHARS)}`,\n );\n }\n\n return output.diagnostics\n .filter((diagnostic) => JSX_FILE_PATTERN.test(diagnostic.filename))\n .map((diagnostic) => {\n const { plugin, rule } = parseRuleCode(diagnostic.code);\n const primaryLabel = diagnostic.labels[0];\n\n const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule);\n\n return {\n filePath: diagnostic.filename,\n plugin,\n rule,\n severity: diagnostic.severity,\n message: cleaned.message,\n help: cleaned.help,\n line: primaryLabel?.span.line ?? 0,\n column: primaryLabel?.span.column ?? 0,\n category: resolveDiagnosticCategory(plugin, rule),\n };\n });\n } finally {\n if (fs.existsSync(configPath)) {\n fs.unlinkSync(configPath);\n }\n }\n};\n","import ora from \"ora\";\n\nlet sharedInstance: ReturnType<typeof ora> | null = null;\nlet activeCount = 0;\nconst pendingTexts = new Set<string>();\n\nconst finalize = (method: \"succeed\" | \"fail\", originalText: string, displayText: string) => {\n pendingTexts.delete(originalText);\n activeCount--;\n\n if (activeCount <= 0 || !sharedInstance) {\n sharedInstance?.[method](displayText);\n sharedInstance = null;\n activeCount = 0;\n return;\n }\n\n sharedInstance.stop();\n ora(displayText).start()[method](displayText);\n\n const [remainingText] = pendingTexts;\n if (remainingText) {\n sharedInstance.text = remainingText;\n }\n sharedInstance.start();\n};\n\nexport const spinner = (text: string) => ({\n start() {\n activeCount++;\n pendingTexts.add(text);\n\n if (!sharedInstance) {\n sharedInstance = ora({ text }).start();\n } else {\n sharedInstance.text = text;\n }\n\n return {\n succeed: (displayText: string) => finalize(\"succeed\", text, displayText),\n fail: (displayText: string) => finalize(\"fail\", text, displayText),\n };\n },\n});\n","export const indentMultilineText = (text: string, linePrefix: string): string =>\n text\n .split(\"\\n\")\n .map((lineText) => `${linePrefix}${lineText}`)\n .join(\"\\n\");\n","import { randomUUID } from \"node:crypto\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport {\n MILLISECONDS_PER_SECOND,\n OFFLINE_MESSAGE,\n PERFECT_SCORE,\n SCORE_BAR_WIDTH_CHARS,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n SUMMARY_BOX_HORIZONTAL_PADDING_CHARS,\n SUMMARY_BOX_OUTER_INDENT_CHARS,\n SHARE_BASE_URL,\n} from \"./constants.js\";\nimport type { Diagnostic, ScanOptions, ScoreResult } from \"./types.js\";\nimport { calculateScore } from \"./utils/calculate-score.js\";\nimport { discoverProject, formatFrameworkName } from \"./utils/discover-project.js\";\nimport { groupBy } from \"./utils/group-by.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { checkReducedMotion } from \"./utils/check-reduced-motion.js\";\nimport { runKnip } from \"./utils/run-knip.js\";\nimport { runOxlint } from \"./utils/run-oxlint.js\";\nimport { spinner } from \"./utils/spinner.js\";\nimport { indentMultilineText } from \"./utils/indent-multiline-text.js\";\n\ninterface FramedLine {\n plainText: string;\n renderedText: string;\n}\n\ninterface ScoreBarSegments {\n filledSegment: string;\n emptySegment: string;\n}\n\nconst SEVERITY_ORDER: Record<Diagnostic[\"severity\"], number> = {\n error: 0,\n warning: 1,\n};\n\nconst colorizeBySeverity = (text: string, severity: Diagnostic[\"severity\"]): string =>\n severity === \"error\" ? highlighter.error(text) : highlighter.warn(text);\n\nconst sortBySeverity = (diagnosticGroups: [string, Diagnostic[]][]): [string, Diagnostic[]][] =>\n diagnosticGroups.toSorted(([, diagnosticsA], [, diagnosticsB]) => {\n const severityA = SEVERITY_ORDER[diagnosticsA[0].severity];\n const severityB = SEVERITY_ORDER[diagnosticsB[0].severity];\n return severityA - severityB;\n });\n\nconst collectAffectedFiles = (diagnostics: Diagnostic[]): Set<string> =>\n new Set(diagnostics.map((diagnostic) => diagnostic.filePath));\n\nconst buildFileLineMap = (diagnostics: Diagnostic[]): Map<string, number[]> => {\n const fileLines = new Map<string, number[]>();\n for (const diagnostic of diagnostics) {\n const lines = fileLines.get(diagnostic.filePath) ?? [];\n if (diagnostic.line > 0) {\n lines.push(diagnostic.line);\n }\n fileLines.set(diagnostic.filePath, lines);\n }\n return fileLines;\n};\n\nconst printDiagnostics = (diagnostics: Diagnostic[], isVerbose: boolean): void => {\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [, ruleDiagnostics] of sortedRuleGroups) {\n const firstDiagnostic = ruleDiagnostics[0];\n const severitySymbol = firstDiagnostic.severity === \"error\" ? \"✗\" : \"⚠\";\n const icon = colorizeBySeverity(severitySymbol, firstDiagnostic.severity);\n const count = ruleDiagnostics.length;\n const countLabel = count > 1 ? colorizeBySeverity(` (${count})`, firstDiagnostic.severity) : \"\";\n\n logger.log(` ${icon} ${firstDiagnostic.message}${countLabel}`);\n if (firstDiagnostic.help) {\n logger.dim(indentMultilineText(firstDiagnostic.help, \" \"));\n }\n\n if (isVerbose) {\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n logger.dim(` ${filePath}${lineLabel}`);\n }\n }\n\n logger.break();\n }\n};\n\nconst formatElapsedTime = (elapsedMilliseconds: number): string => {\n if (elapsedMilliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(elapsedMilliseconds)}ms`;\n }\n return `${(elapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1)}s`;\n};\n\nconst formatRuleSummary = (ruleKey: string, ruleDiagnostics: Diagnostic[]): string => {\n const firstDiagnostic = ruleDiagnostics[0];\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n const sections = [\n `Rule: ${ruleKey}`,\n `Severity: ${firstDiagnostic.severity}`,\n `Category: ${firstDiagnostic.category}`,\n `Count: ${ruleDiagnostics.length}`,\n \"\",\n firstDiagnostic.message,\n ];\n\n if (firstDiagnostic.help) {\n sections.push(\"\", `Suggestion: ${firstDiagnostic.help}`);\n }\n\n sections.push(\"\", \"Files:\");\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n sections.push(` ${filePath}${lineLabel}`);\n }\n\n return sections.join(\"\\n\") + \"\\n\";\n};\n\nconst writeDiagnosticsDirectory = (diagnostics: Diagnostic[]): string => {\n const outputDirectory = join(tmpdir(), `react-doctor-${randomUUID()}`);\n mkdirSync(outputDirectory);\n\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [ruleKey, ruleDiagnostics] of sortedRuleGroups) {\n const fileName = ruleKey.replace(/\\//g, \"--\") + \".txt\";\n writeFileSync(join(outputDirectory, fileName), formatRuleSummary(ruleKey, ruleDiagnostics));\n }\n\n writeFileSync(join(outputDirectory, \"diagnostics.json\"), JSON.stringify(diagnostics, null, 2));\n\n return outputDirectory;\n};\n\nconst colorizeByScore = (text: string, score: number): string => {\n if (score >= SCORE_GOOD_THRESHOLD) return highlighter.success(text);\n if (score >= SCORE_OK_THRESHOLD) return highlighter.warn(text);\n return highlighter.error(text);\n};\n\nconst createFramedLine = (plainText: string, renderedText: string = plainText): FramedLine => ({\n plainText,\n renderedText,\n});\n\nconst buildScoreBarSegments = (score: number): ScoreBarSegments => {\n const filledCount = Math.round((score / PERFECT_SCORE) * SCORE_BAR_WIDTH_CHARS);\n const emptyCount = SCORE_BAR_WIDTH_CHARS - filledCount;\n\n return {\n filledSegment: \"█\".repeat(filledCount),\n emptySegment: \"░\".repeat(emptyCount),\n };\n};\n\nconst buildPlainScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return `${filledSegment}${emptySegment}`;\n};\n\nconst buildScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return colorizeByScore(filledSegment, score) + highlighter.dim(emptySegment);\n};\n\nconst printFramedBox = (framedLines: FramedLine[]): void => {\n if (framedLines.length === 0) {\n return;\n }\n\n const borderColorizer = highlighter.dim;\n const outerIndent = \" \".repeat(SUMMARY_BOX_OUTER_INDENT_CHARS);\n const horizontalPadding = \" \".repeat(SUMMARY_BOX_HORIZONTAL_PADDING_CHARS);\n const maximumLineLength = Math.max(\n ...framedLines.map((framedLine) => framedLine.plainText.length),\n );\n const borderLine = \"─\".repeat(maximumLineLength + SUMMARY_BOX_HORIZONTAL_PADDING_CHARS * 2);\n\n logger.log(`${outerIndent}${borderColorizer(`┌${borderLine}┐`)}`);\n\n for (const framedLine of framedLines) {\n const trailingSpaces = \" \".repeat(maximumLineLength - framedLine.plainText.length);\n logger.log(\n `${outerIndent}${borderColorizer(\"│\")}${horizontalPadding}${framedLine.renderedText}${trailingSpaces}${horizontalPadding}${borderColorizer(\"│\")}`,\n );\n }\n\n logger.log(`${outerIndent}${borderColorizer(`└${borderLine}┘`)}`);\n};\n\nconst printScoreGauge = (score: number, label: string): void => {\n const scoreDisplay = colorizeByScore(`${score}`, score);\n const labelDisplay = colorizeByScore(label, score);\n logger.log(` ${scoreDisplay} / ${PERFECT_SCORE} ${labelDisplay}`);\n logger.break();\n logger.log(` ${buildScoreBar(score)}`);\n logger.break();\n};\n\nconst getDoctorFace = (score: number): string[] => {\n if (score >= SCORE_GOOD_THRESHOLD) return [\"◠ ◠\", \" ▽ \"];\n if (score >= SCORE_OK_THRESHOLD) return [\"• •\", \" ─ \"];\n return [\"x x\", \" ▽ \"];\n};\n\nconst printBranding = (score?: number): void => {\n if (score !== undefined) {\n const [eyes, mouth] = getDoctorFace(score);\n const colorize = (text: string) => colorizeByScore(text, score);\n logger.log(colorize(\" ┌─────┐\"));\n logger.log(colorize(` │ ${eyes} │`));\n logger.log(colorize(` │ ${mouth} │`));\n logger.log(colorize(\" └─────┘\"));\n }\n logger.log(` React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`);\n logger.break();\n};\n\nconst buildShareUrl = (\n diagnostics: Diagnostic[],\n scoreResult: ScoreResult | null,\n projectName: string,\n): string => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n\n const params = new URLSearchParams();\n params.set(\"p\", projectName);\n if (scoreResult) params.set(\"s\", String(scoreResult.score));\n if (errorCount > 0) params.set(\"e\", String(errorCount));\n if (warningCount > 0) params.set(\"w\", String(warningCount));\n if (affectedFileCount > 0) params.set(\"f\", String(affectedFileCount));\n\n return `${SHARE_BASE_URL}?${params.toString()}`;\n};\n\nconst printSummary = (\n diagnostics: Diagnostic[],\n elapsedMilliseconds: number,\n scoreResult: ScoreResult | null,\n projectName: string,\n): void => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n const elapsed = formatElapsedTime(elapsedMilliseconds);\n\n const summaryLineParts: string[] = [];\n const summaryLinePartsPlain: string[] = [];\n if (errorCount > 0) {\n const errorText = `✗ ${errorCount} error${errorCount === 1 ? \"\" : \"s\"}`;\n summaryLinePartsPlain.push(errorText);\n summaryLineParts.push(highlighter.error(errorText));\n }\n if (warningCount > 0) {\n const warningText = `⚠ ${warningCount} warning${warningCount === 1 ? \"\" : \"s\"}`;\n summaryLinePartsPlain.push(warningText);\n summaryLineParts.push(highlighter.warn(warningText));\n }\n const fileCountText = `across ${affectedFileCount} file${affectedFileCount === 1 ? \"\" : \"s\"}`;\n const elapsedTimeText = `in ${elapsed}`;\n\n summaryLinePartsPlain.push(fileCountText);\n summaryLinePartsPlain.push(elapsedTimeText);\n summaryLineParts.push(highlighter.dim(fileCountText));\n summaryLineParts.push(highlighter.dim(elapsedTimeText));\n\n const summaryFramedLines: FramedLine[] = [];\n if (scoreResult) {\n const [eyes, mouth] = getDoctorFace(scoreResult.score);\n const scoreColorizer = (text: string): string => colorizeByScore(text, scoreResult.score);\n\n summaryFramedLines.push(createFramedLine(\"┌─────┐\", scoreColorizer(\"┌─────┐\")));\n summaryFramedLines.push(createFramedLine(`│ ${eyes} │`, scoreColorizer(`│ ${eyes} │`)));\n summaryFramedLines.push(createFramedLine(`│ ${mouth} │`, scoreColorizer(`│ ${mouth} │`)));\n summaryFramedLines.push(createFramedLine(\"└─────┘\", scoreColorizer(\"└─────┘\")));\n summaryFramedLines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n summaryFramedLines.push(createFramedLine(\"\"));\n\n const scoreLinePlainText = `${scoreResult.score} / ${PERFECT_SCORE} ${scoreResult.label}`;\n const scoreLineRenderedText = `${colorizeByScore(String(scoreResult.score), scoreResult.score)} / ${PERFECT_SCORE} ${colorizeByScore(scoreResult.label, scoreResult.score)}`;\n summaryFramedLines.push(createFramedLine(scoreLinePlainText, scoreLineRenderedText));\n summaryFramedLines.push(createFramedLine(\"\"));\n summaryFramedLines.push(\n createFramedLine(buildPlainScoreBar(scoreResult.score), buildScoreBar(scoreResult.score)),\n );\n summaryFramedLines.push(createFramedLine(\"\"));\n } else {\n summaryFramedLines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n summaryFramedLines.push(createFramedLine(\"\"));\n summaryFramedLines.push(createFramedLine(OFFLINE_MESSAGE, highlighter.dim(OFFLINE_MESSAGE)));\n summaryFramedLines.push(createFramedLine(\"\"));\n }\n\n summaryFramedLines.push(\n createFramedLine(summaryLinePartsPlain.join(\" \"), summaryLineParts.join(\" \")),\n );\n printFramedBox(summaryFramedLines);\n\n try {\n const diagnosticsDirectory = writeDiagnosticsDirectory(diagnostics);\n logger.break();\n logger.dim(` Full diagnostics written to ${diagnosticsDirectory}`);\n } catch {\n logger.break();\n }\n\n const shareUrl = buildShareUrl(diagnostics, scoreResult, projectName);\n logger.break();\n logger.dim(` Share your results: ${highlighter.info(shareUrl)}`);\n};\n\nexport const scan = async (directory: string, options: ScanOptions): Promise<void> => {\n const startTime = performance.now();\n const projectInfo = discoverProject(directory);\n\n if (!projectInfo.reactVersion) {\n throw new Error(\"No React dependency found in package.json\");\n }\n\n if (!options.scoreOnly) {\n const frameworkLabel = formatFrameworkName(projectInfo.framework);\n const languageLabel = projectInfo.hasTypeScript ? \"TypeScript\" : \"JavaScript\";\n\n const completeStep = (message: string) => {\n spinner(message).start().succeed(message);\n };\n\n completeStep(`Detecting framework. Found ${highlighter.info(frameworkLabel)}.`);\n completeStep(\n `Detecting React version. Found ${highlighter.info(`React ${projectInfo.reactVersion}`)}.`,\n );\n completeStep(`Detecting language. Found ${highlighter.info(languageLabel)}.`);\n completeStep(\n `Detecting React Compiler. ${projectInfo.hasReactCompiler ? highlighter.info(\"Found React Compiler.\") : \"Not found.\"}`,\n );\n completeStep(`Found ${highlighter.info(`${projectInfo.sourceFileCount}`)} source files.`);\n\n logger.break();\n }\n\n const lintPromise = options.lint\n ? (async () => {\n const lintSpinner = options.scoreOnly ? null : spinner(\"Running lint checks...\").start();\n try {\n const lintDiagnostics = await runOxlint(\n directory,\n projectInfo.hasTypeScript,\n projectInfo.framework,\n projectInfo.hasReactCompiler,\n );\n lintSpinner?.succeed(\"Running lint checks.\");\n return lintDiagnostics;\n } catch {\n lintSpinner?.fail(\"Lint checks failed (non-fatal, skipping).\");\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const deadCodePromise = options.deadCode\n ? (async () => {\n const deadCodeSpinner = options.scoreOnly\n ? null\n : spinner(\"Detecting dead code...\").start();\n try {\n const knipDiagnostics = await runKnip(directory);\n deadCodeSpinner?.succeed(\"Detecting dead code.\");\n return knipDiagnostics;\n } catch {\n deadCodeSpinner?.fail(\"Dead code detection failed (non-fatal, skipping).\");\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const [lintDiagnostics, deadCodeDiagnostics] = await Promise.all([lintPromise, deadCodePromise]);\n const diagnostics = [\n ...lintDiagnostics,\n ...deadCodeDiagnostics,\n ...checkReducedMotion(directory),\n ];\n\n const elapsedMilliseconds = performance.now() - startTime;\n\n const scoreResult = await calculateScore(diagnostics);\n\n if (options.scoreOnly) {\n if (scoreResult) {\n logger.log(`${scoreResult.score}`);\n } else {\n logger.dim(OFFLINE_MESSAGE);\n }\n return;\n }\n\n if (diagnostics.length === 0) {\n logger.success(\"No issues found!\");\n logger.break();\n if (scoreResult) {\n printBranding(scoreResult.score);\n printScoreGauge(scoreResult.score, scoreResult.label);\n } else {\n logger.dim(` ${OFFLINE_MESSAGE}`);\n }\n return;\n }\n\n printDiagnostics(diagnostics, options.verbose);\n\n printSummary(diagnostics, elapsedMilliseconds, scoreResult, projectInfo.projectName);\n};\n","import type { PromptMultiselectChoiceState } from \"../types.js\";\n\nexport const shouldSelectAllChoices = (choiceStates: PromptMultiselectChoiceState[]): boolean => {\n const enabledChoiceStates = choiceStates.filter((choiceState) => !choiceState.disabled);\n return enabledChoiceStates.some((choiceState) => choiceState.selected !== true);\n};\n","import { createRequire } from \"node:module\";\nimport basePrompts, { type PromptObject, type Answers } from \"prompts\";\nimport type { PromptMultiselectContext } from \"../types.js\";\nimport { logger } from \"./logger.js\";\nimport { shouldSelectAllChoices } from \"./should-select-all-choices.js\";\n\nconst require = createRequire(import.meta.url);\nconst PROMPTS_MULTISELECT_MODULE_PATH = \"prompts/lib/elements/multiselect\";\nlet didPatchMultiselectToggleAll = false;\n\nconst onCancel = () => {\n logger.break();\n logger.log(\"Cancelled.\");\n logger.break();\n process.exit(0);\n};\n\nconst patchMultiselectToggleAll = (): void => {\n if (didPatchMultiselectToggleAll) return;\n didPatchMultiselectToggleAll = true;\n\n const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);\n\n multiselectPromptConstructor.prototype.toggleAll = function (\n this: PromptMultiselectContext,\n ): void {\n const isCurrentChoiceDisabled = Boolean(this.value[this.cursor]?.disabled);\n if (this.maxChoices !== undefined || isCurrentChoiceDisabled) {\n this.bell();\n return;\n }\n\n const shouldSelectAllEnabledChoices = shouldSelectAllChoices(this.value);\n\n for (const choiceState of this.value) {\n if (choiceState.disabled) continue;\n choiceState.selected = shouldSelectAllEnabledChoices;\n }\n\n this.render();\n };\n};\n\nexport const prompts = <T extends string = string>(\n questions: PromptObject<T> | PromptObject<T>[],\n): Promise<Answers<T>> => {\n patchMultiselectToggleAll();\n return basePrompts(questions, { onCancel });\n};\n","import path from \"node:path\";\nimport type { WorkspacePackage } from \"../types.js\";\nimport { discoverReactSubprojects, listWorkspacePackages } from \"./discover-project.js\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nexport const selectProjects = async (\n rootDirectory: string,\n projectFlag: string | undefined,\n skipPrompts: boolean,\n): Promise<string[]> => {\n let packages = listWorkspacePackages(rootDirectory);\n if (packages.length === 0) {\n packages = discoverReactSubprojects(rootDirectory);\n }\n\n if (packages.length === 0) return [rootDirectory];\n if (packages.length === 1) {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages[0].name}`,\n );\n return [packages[0].directory];\n }\n\n if (projectFlag) return resolveProjectFlag(projectFlag, packages);\n\n if (skipPrompts) {\n printDiscoveredProjects(packages);\n return packages.map((workspacePackage) => workspacePackage.directory);\n }\n\n return promptProjectSelection(packages, rootDirectory);\n};\n\nconst resolveProjectFlag = (\n projectFlag: string,\n workspacePackages: WorkspacePackage[],\n): string[] => {\n const requestedNames = projectFlag.split(\",\").map((name) => name.trim());\n const resolvedDirectories: string[] = [];\n\n for (const requestedName of requestedNames) {\n const matched = workspacePackages.find(\n (workspacePackage) =>\n workspacePackage.name === requestedName ||\n path.basename(workspacePackage.directory) === requestedName,\n );\n\n if (!matched) {\n const availableNames = workspacePackages\n .map((workspacePackage) => workspacePackage.name)\n .join(\", \");\n throw new Error(`Project \"${requestedName}\" not found. Available: ${availableNames}`);\n }\n\n resolvedDirectories.push(matched.directory);\n }\n\n return resolvedDirectories;\n};\n\nconst printDiscoveredProjects = (packages: WorkspacePackage[]): void => {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages.map((workspacePackage) => workspacePackage.name).join(\", \")}`,\n );\n};\n\nconst promptProjectSelection = async (\n workspacePackages: WorkspacePackage[],\n rootDirectory: string,\n): Promise<string[]> => {\n const { selectedDirectories } = await prompts({\n type: \"multiselect\",\n name: \"selectedDirectories\",\n message: \"Select projects to scan\",\n choices: workspacePackages.map((workspacePackage) => ({\n title: workspacePackage.name,\n description: path.relative(rootDirectory, workspacePackage.directory),\n value: workspacePackage.directory,\n })),\n min: 1,\n });\n\n return selectedDirectories;\n};\n","import { execSync } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nconst CONFIG_DIRECTORY = join(homedir(), \".react-doctor\");\nconst CONFIG_FILE = join(CONFIG_DIRECTORY, \"config.json\");\nconst SKILL_REPO = \"millionco/react-doctor\";\n\ninterface UserConfig {\n skillPromptDismissed?: boolean;\n}\n\nconst readConfig = (): UserConfig => {\n try {\n if (!existsSync(CONFIG_FILE)) return {};\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf-8\"));\n } catch {\n return {};\n }\n};\n\nconst writeConfig = (config: UserConfig): void => {\n try {\n if (!existsSync(CONFIG_DIRECTORY)) {\n mkdirSync(CONFIG_DIRECTORY, { recursive: true });\n }\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n } catch {}\n};\n\nconst installSkill = (): void => {\n try {\n execSync(`npx -y skills add ${SKILL_REPO}`, { stdio: \"inherit\" });\n } catch {\n logger.break();\n logger.dim(\"Skill install failed. You can install manually:\");\n logger.dim(` npx skills add ${SKILL_REPO}`);\n }\n};\n\nexport const maybePromptSkillInstall = async (shouldSkipPrompts: boolean): Promise<void> => {\n const config = readConfig();\n if (config.skillPromptDismissed) return;\n if (shouldSkipPrompts) return;\n\n logger.break();\n logger.log(`${highlighter.info(\"💡\")} Have your coding agent fix these issues automatically?`);\n logger.dim(\n ` Install the ${highlighter.info(\"react-doctor\")} skill to teach Cursor, Claude Code, Copilot,`,\n );\n logger.dim(\" Ami, and other AI agents how to diagnose and fix these React issues.\");\n logger.break();\n\n const { shouldInstall } = await prompts({\n type: \"confirm\",\n name: \"shouldInstall\",\n message: \"Install skill?\",\n initial: true,\n });\n\n if (shouldInstall) {\n logger.break();\n installSkill();\n }\n\n writeConfig({ ...config, skillPromptDismissed: true });\n};\n","import { spawn, execSync } from \"node:child_process\";\n\nconst isGloballyInstalled = (): boolean => {\n try {\n const globalBinPath = execSync(\"which react-doctor\", {\n stdio: \"pipe\",\n encoding: \"utf-8\",\n }).trim();\n return !globalBinPath.includes(\"/_npx/\");\n } catch {\n return false;\n }\n};\n\nexport const maybeInstallGlobally = (): void => {\n try {\n if (isGloballyInstalled()) return;\n\n const child = spawn(\"npm\", [\"install\", \"-g\", \"react-doctor@latest\"], {\n detached: true,\n stdio: \"ignore\",\n });\n child.on(\"error\", () => {});\n child.unref();\n } catch {\n // noop\n }\n};\n","import { spawnSync } from \"node:child_process\";\nimport type { ClipboardCommand } from \"../types.js\";\n\nconst getClipboardCommands = (): ClipboardCommand[] => {\n if (process.platform === \"darwin\") {\n return [{ command: \"pbcopy\", args: [] }];\n }\n\n if (process.platform === \"win32\") {\n return [{ command: \"clip\", args: [] }];\n }\n\n return [\n { command: \"wl-copy\", args: [] },\n { command: \"xclip\", args: [\"-selection\", \"clipboard\"] },\n { command: \"xsel\", args: [\"--clipboard\", \"--input\"] },\n ];\n};\n\nexport const copyToClipboard = (text: string): boolean => {\n const clipboardCommands = getClipboardCommands();\n\n for (const clipboardCommand of clipboardCommands) {\n const clipboardProcess = spawnSync(clipboardCommand.command, clipboardCommand.args, {\n input: text,\n stdio: [\"pipe\", \"ignore\", \"ignore\"],\n encoding: \"utf8\",\n });\n\n if (clipboardProcess.status === 0) {\n return true;\n }\n }\n\n return false;\n};\n","import { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport { SEPARATOR_LENGTH_CHARS } from \"./constants.js\";\nimport type { ScanOptions } from \"./types.js\";\nimport { handleError } from \"./utils/handle-error.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { logger, startLoggerCapture, stopLoggerCapture } from \"./utils/logger.js\";\nimport { scan } from \"./scan.js\";\nimport { selectProjects } from \"./utils/select-projects.js\";\nimport { prompts } from \"./utils/prompts.js\";\nimport { maybePromptSkillInstall } from \"./utils/skill-prompt.js\";\nimport { maybeInstallGlobally } from \"./utils/global-install.js\";\nimport { copyToClipboard } from \"./utils/copy-to-clipboard.js\";\n\nconst VERSION = process.env.VERSION ?? \"0.0.0\";\n\ninterface CliFlags {\n lint: boolean;\n deadCode: boolean;\n verbose: boolean;\n score: boolean;\n fix: boolean;\n prompt: boolean;\n yes: boolean;\n project?: string;\n}\n\nprocess.on(\"SIGINT\", () => process.exit(0));\nprocess.on(\"SIGTERM\", () => process.exit(0));\n\nconst program = new Command()\n .name(\"react-doctor\")\n .description(\"Diagnose React codebase health\")\n .version(VERSION, \"-v, --version\", \"display the version number\")\n .argument(\"[directory]\", \"project directory to scan\", \".\")\n .option(\"--no-lint\", \"skip linting\")\n .option(\"--no-dead-code\", \"skip dead code detection\")\n .option(\"--verbose\", \"show file details per rule\")\n .option(\"--score\", \"output only the score\")\n .option(\"-y, --yes\", \"skip prompts, scan all workspace projects\")\n .option(\"--project <name>\", \"select workspace project (comma-separated for multiple)\")\n .option(\"--fix\", \"open Ami to auto-fix all issues\")\n .option(\"--prompt\", \"copy latest scan output to clipboard\")\n .action(async (directory: string, flags: CliFlags) => {\n const isScoreOnly = flags.score && !flags.prompt;\n const shouldCopyPromptOutput = flags.prompt;\n\n if (shouldCopyPromptOutput) {\n startLoggerCapture();\n }\n\n try {\n const resolvedDirectory = path.resolve(directory);\n\n if (!isScoreOnly) {\n logger.log(`react-doctor v${VERSION}`);\n logger.break();\n }\n\n const scanOptions: ScanOptions = {\n lint: flags.lint,\n deadCode: flags.deadCode,\n verbose: flags.prompt || Boolean(flags.verbose),\n scoreOnly: isScoreOnly,\n };\n\n const isAutomatedEnvironment = [\n process.env.CI,\n process.env.CLAUDECODE,\n process.env.CURSOR_AGENT,\n process.env.CODEX_CI,\n process.env.OPENCODE,\n process.env.AMP_HOME,\n process.env.AMI,\n ].some(Boolean);\n const shouldSkipPrompts = flags.yes || isAutomatedEnvironment || !process.stdin.isTTY;\n const projectDirectories = await selectProjects(\n resolvedDirectory,\n flags.project,\n shouldSkipPrompts,\n );\n\n for (const projectDirectory of projectDirectories) {\n if (!isScoreOnly) {\n logger.dim(`Scanning ${projectDirectory}...`);\n logger.break();\n }\n await scan(projectDirectory, scanOptions);\n if (!isScoreOnly) {\n logger.break();\n }\n }\n\n if (flags.fix) {\n openAmiToFix(resolvedDirectory);\n }\n\n if (!isScoreOnly && !flags.prompt) {\n await maybePromptSkillInstall(shouldSkipPrompts);\n if (!shouldSkipPrompts && !flags.fix) {\n await maybePromptAmiFix(resolvedDirectory);\n }\n }\n } catch (error) {\n handleError(error, { shouldExit: !shouldCopyPromptOutput });\n } finally {\n if (shouldCopyPromptOutput) {\n const capturedOutput = stopLoggerCapture();\n copyPromptToClipboard(capturedOutput, !isScoreOnly);\n }\n }\n })\n .addHelpText(\n \"after\",\n `\n${highlighter.dim(\"Learn more:\")}\n ${highlighter.info(\"https://github.com/millionco/react-doctor\")}\n`,\n );\n\nconst AMI_INSTALL_URL = \"https://ami.dev/install.sh\";\nconst FIX_PROMPT =\n \"Fix all issues reported in the react-doctor diagnostics below, one by one. After applying fixes, run `react-dcotor` again to verify the results improved.\";\nconst REACT_DOCTOR_OUTPUT_LABEL = \"react-doctor output\";\nconst SCAN_SUMMARY_SEPARATOR = \"─\".repeat(SEPARATOR_LENGTH_CHARS);\n\nconst isAmiInstalled = (): boolean => {\n try {\n execSync(\"ls /Applications/Ami.app\", { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n};\n\nconst installAmi = (): void => {\n logger.log(\"Ami not found. Installing...\");\n logger.break();\n try {\n execSync(`curl -fsSL ${AMI_INSTALL_URL} | bash`, { stdio: \"inherit\" });\n } catch {\n logger.error(\"Failed to install Ami. Visit https://ami.dev to install manually.\");\n process.exit(1);\n }\n logger.break();\n};\n\nconst openAmiToFix = (directory: string): void => {\n const resolvedDirectory = path.resolve(directory);\n\n if (!isAmiInstalled()) {\n installAmi();\n }\n\n logger.log(\"Opening Ami to fix react-doctor issues...\");\n\n const encodedDirectory = encodeURIComponent(resolvedDirectory);\n const encodedPrompt = encodeURIComponent(FIX_PROMPT);\n const deeplink = `ami://open-project?cwd=${encodedDirectory}&prompt=${encodedPrompt}&mode=agent`;\n\n try {\n execSync(`open \"${deeplink}\"`, { stdio: \"ignore\" });\n logger.success(\"Opened Ami with react-doctor fix prompt.\");\n } catch {\n logger.break();\n logger.dim(\"Could not open Ami automatically. Open this URL manually:\");\n logger.info(deeplink);\n }\n};\n\nconst buildPromptWithOutput = (reactDoctorOutput: string): string => {\n const summaryStartIndex = reactDoctorOutput.indexOf(SCAN_SUMMARY_SEPARATOR);\n const diagnosticsOutput =\n summaryStartIndex === -1\n ? reactDoctorOutput\n : reactDoctorOutput.slice(0, summaryStartIndex).trimEnd();\n const normalizedReactDoctorOutput = diagnosticsOutput.trim();\n const outputContent =\n normalizedReactDoctorOutput.length > 0 ? normalizedReactDoctorOutput : \"No output captured.\";\n return `${FIX_PROMPT}\\n\\n${REACT_DOCTOR_OUTPUT_LABEL}:\\n\\`\\`\\`\\n${outputContent}\\n\\`\\`\\``;\n};\n\nconst copyPromptToClipboard = (reactDoctorOutput: string, shouldLogResult: boolean): void => {\n const promptWithOutput = buildPromptWithOutput(reactDoctorOutput);\n const didCopyPromptToClipboard = copyToClipboard(promptWithOutput);\n\n if (!shouldLogResult) {\n return;\n }\n\n if (didCopyPromptToClipboard) {\n logger.success(\"Copied latest scan output to clipboard\");\n return;\n }\n\n logger.warn(\"Could not copy prompt to clipboard automatically. Use this prompt:\");\n logger.info(promptWithOutput);\n};\n\nconst maybePromptAmiFix = async (directory: string): Promise<void> => {\n logger.break();\n logger.log(`Fix these issues with ${highlighter.info(\"Ami\")}?`);\n logger.dim(\" Ami is a coding agent built to understand your codebase and fix issues\");\n logger.dim(` automatically. Learn more at ${highlighter.info(\"https://ami.dev\")}`);\n logger.break();\n\n const { shouldFix } = await prompts({\n type: \"confirm\",\n name: \"shouldFix\",\n message: \"Open Ami to fix?\",\n initial: true,\n });\n\n if (shouldFix) {\n openAmiToFix(directory);\n }\n};\n\nconst fixAction = (directory: string) => {\n try {\n openAmiToFix(directory);\n } catch (error) {\n handleError(error);\n }\n};\n\nconst fixCommand = new Command(\"fix\")\n .description(\"Open Ami to auto-fix react-doctor issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nconst installAmiCommand = new Command(\"install-ami\")\n .description(\"Install Ami and open it to auto-fix issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nprogram.addCommand(fixCommand);\nprogram.addCommand(installAmiCommand);\n\nconst main = async () => {\n maybeInstallGlobally();\n await program.parseAsync();\n};\n\nmain();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":["esmRequire","main"],"sources":["../src/constants.ts","../src/utils/highlighter.ts","../src/utils/strip-ansi.ts","../src/utils/logger.ts","../src/utils/handle-error.ts","../src/utils/calculate-score.ts","../src/utils/read-package-json.ts","../src/utils/discover-project.ts","../src/utils/group-by.ts","../src/plugin/constants.ts","../src/utils/check-reduced-motion.ts","../src/utils/run-knip.ts","../src/oxlint-config.ts","../src/utils/run-oxlint.ts","../src/utils/spinner.ts","../src/utils/indent-multiline-text.ts","../src/scan.ts","../src/utils/should-select-all-choices.ts","../src/utils/prompts.ts","../src/utils/select-projects.ts","../src/utils/skill-prompt.ts","../src/utils/global-install.ts","../src/utils/copy-to-clipboard.ts","../src/cli.ts"],"sourcesContent":["export const SOURCE_FILE_PATTERN = /\\.(tsx?|jsx?)$/;\n\nexport const JSX_FILE_PATTERN = /\\.(tsx|jsx)$/;\n\nexport const MILLISECONDS_PER_SECOND = 1000;\n\nexport const ERROR_PREVIEW_LENGTH_CHARS = 200;\n\nexport const PERFECT_SCORE = 100;\n\nexport const SCORE_GOOD_THRESHOLD = 75;\n\nexport const SCORE_OK_THRESHOLD = 50;\n\nexport const SCORE_BAR_WIDTH_CHARS = 50;\n\nexport const SEPARATOR_LENGTH_CHARS = 40;\n\nexport const SUMMARY_BOX_HORIZONTAL_PADDING_CHARS = 1;\n\nexport const SUMMARY_BOX_OUTER_INDENT_CHARS = 2;\n\nexport const SCORE_API_URL = \"https://www.react.doctor/api/score\";\n\nexport const SHARE_BASE_URL = \"https://www.react.doctor/share\";\n\nexport const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport const OFFLINE_MESSAGE =\n \"You are offline, could not calculate score. Reconnect to calculate.\";\n","import pc from \"picocolors\";\n\nexport const highlighter = {\n error: pc.red,\n warn: pc.yellow,\n info: pc.cyan,\n success: pc.green,\n dim: pc.dim,\n};\n","const ANSI_ESCAPE_SEQUENCE = String.raw`\\u001B\\[[0-9;]*m`;\nconst ANSI_ESCAPE_PATTERN = new RegExp(ANSI_ESCAPE_SEQUENCE, \"g\");\n\nexport const stripAnsi = (text: string): string => text.replace(ANSI_ESCAPE_PATTERN, \"\");\n","import { highlighter } from \"./highlighter.js\";\nimport { stripAnsi } from \"./strip-ansi.js\";\nimport type { LoggerCaptureState } from \"../types.js\";\n\nconst loggerCaptureState: LoggerCaptureState = {\n isEnabled: false,\n lines: [],\n};\n\nconst captureLogLine = (text: string): void => {\n if (!loggerCaptureState.isEnabled) {\n return;\n }\n\n loggerCaptureState.lines.push(stripAnsi(text));\n};\n\nconst writeLogLine = (text: string): void => {\n console.log(text);\n captureLogLine(text);\n};\n\nexport const startLoggerCapture = (): void => {\n loggerCaptureState.isEnabled = true;\n loggerCaptureState.lines = [];\n};\n\nexport const stopLoggerCapture = (): string => {\n const capturedOutput = loggerCaptureState.lines.join(\"\\n\");\n loggerCaptureState.isEnabled = false;\n loggerCaptureState.lines = [];\n return capturedOutput;\n};\n\nexport const logger = {\n error(...args: unknown[]) {\n writeLogLine(highlighter.error(args.join(\" \")));\n },\n warn(...args: unknown[]) {\n writeLogLine(highlighter.warn(args.join(\" \")));\n },\n info(...args: unknown[]) {\n writeLogLine(highlighter.info(args.join(\" \")));\n },\n success(...args: unknown[]) {\n writeLogLine(highlighter.success(args.join(\" \")));\n },\n dim(...args: unknown[]) {\n writeLogLine(highlighter.dim(args.join(\" \")));\n },\n log(...args: unknown[]) {\n writeLogLine(args.join(\" \"));\n },\n break() {\n writeLogLine(\"\");\n },\n};\n","import { logger } from \"./logger.js\";\nimport type { HandleErrorOptions } from \"../types.js\";\n\nconst DEFAULT_HANDLE_ERROR_OPTIONS: HandleErrorOptions = {\n shouldExit: true,\n};\n\nexport const handleError = (\n error: unknown,\n options: HandleErrorOptions = DEFAULT_HANDLE_ERROR_OPTIONS,\n): void => {\n logger.break();\n logger.error(\"Something went wrong. Please check the error below for more details.\");\n logger.error(\"If the problem persists, please open an issue on GitHub.\");\n logger.error(\"\");\n if (error instanceof Error) {\n logger.error(error.message);\n }\n logger.break();\n if (options.shouldExit) {\n process.exit(1);\n }\n process.exitCode = 1;\n};\n","import { SCORE_API_URL } from \"../constants.js\";\nimport type { Diagnostic, ScoreResult } from \"../types.js\";\n\nexport const calculateScore = async (diagnostics: Diagnostic[]): Promise<ScoreResult | null> => {\n const payload = diagnostics.map((diagnostic) => ({\n plugin: diagnostic.plugin,\n rule: diagnostic.rule,\n severity: diagnostic.severity,\n }));\n\n try {\n const response = await fetch(SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics: payload }),\n });\n\n if (!response.ok) return null;\n\n return (await response.json()) as ScoreResult;\n } catch {\n return null;\n }\n};\n","import fs from \"node:fs\";\nimport type { PackageJson } from \"../types.js\";\n\nexport const readPackageJson = (packageJsonPath: string): PackageJson =>\n JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { GIT_LS_FILES_MAX_BUFFER_BYTES, SOURCE_FILE_PATTERN } from \"../constants.js\";\nimport type {\n DependencyInfo,\n Framework,\n PackageJson,\n ProjectInfo,\n WorkspacePackage,\n} from \"../types.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REACT_COMPILER_PACKAGES = new Set([\n \"babel-plugin-react-compiler\",\n \"react-compiler-runtime\",\n \"eslint-plugin-react-compiler\",\n]);\n\nconst NEXT_CONFIG_FILENAMES = [\n \"next.config.js\",\n \"next.config.mjs\",\n \"next.config.ts\",\n \"next.config.cjs\",\n];\n\nconst BABEL_CONFIG_FILENAMES = [\n \".babelrc\",\n \".babelrc.json\",\n \"babel.config.js\",\n \"babel.config.json\",\n \"babel.config.cjs\",\n \"babel.config.mjs\",\n];\n\nconst VITE_CONFIG_FILENAMES = [\n \"vite.config.js\",\n \"vite.config.ts\",\n \"vite.config.mjs\",\n \"vite.config.cjs\",\n];\n\nconst REACT_COMPILER_CONFIG_PATTERN = /react-compiler|reactCompiler/;\n\nconst FRAMEWORK_PACKAGES: Record<string, Framework> = {\n next: \"nextjs\",\n vite: \"vite\",\n \"react-scripts\": \"cra\",\n \"@remix-run/react\": \"remix\",\n gatsby: \"gatsby\",\n};\n\nconst FRAMEWORK_DISPLAY_NAMES: Record<Framework, string> = {\n nextjs: \"Next.js\",\n vite: \"Vite\",\n cra: \"Create React App\",\n remix: \"Remix\",\n gatsby: \"Gatsby\",\n unknown: \"React\",\n};\n\nexport const formatFrameworkName = (framework: Framework): string =>\n FRAMEWORK_DISPLAY_NAMES[framework];\n\nconst countSourceFiles = (rootDirectory: string): number => {\n const result = spawnSync(\"git\", [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"], {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,\n });\n\n if (result.error || result.status !== 0) {\n return 0;\n }\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath)).length;\n};\n\nconst collectAllDependencies = (packageJson: PackageJson): Record<string, string> => ({\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n});\n\nconst detectFramework = (dependencies: Record<string, string>): Framework => {\n for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) {\n if (dependencies[packageName]) {\n return frameworkName;\n }\n }\n return \"unknown\";\n};\n\nconst extractDependencyInfo = (packageJson: PackageJson): DependencyInfo => {\n const allDependencies = collectAllDependencies(packageJson);\n return {\n reactVersion: allDependencies.react ?? null,\n framework: detectFramework(allDependencies),\n };\n};\n\nconst parsePnpmWorkspacePatterns = (rootDirectory: string): string[] => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!fs.existsSync(workspacePath)) return [];\n\n const content = fs.readFileSync(workspacePath, \"utf-8\");\n const patterns: string[] = [];\n let isInsidePackagesBlock = false;\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed === \"packages:\") {\n isInsidePackagesBlock = true;\n continue;\n }\n if (isInsidePackagesBlock && trimmed.startsWith(\"-\")) {\n patterns.push(trimmed.replace(/^-\\s*/, \"\").replace(/[\"']/g, \"\"));\n } else if (isInsidePackagesBlock && trimmed.length > 0 && !trimmed.startsWith(\"#\")) {\n isInsidePackagesBlock = false;\n }\n }\n\n return patterns;\n};\n\nconst getWorkspacePatterns = (rootDirectory: string, packageJson: PackageJson): string[] => {\n const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);\n if (pnpmPatterns.length > 0) return pnpmPatterns;\n\n if (Array.isArray(packageJson.workspaces)) {\n return packageJson.workspaces;\n }\n\n if (packageJson.workspaces?.packages) {\n return packageJson.workspaces.packages;\n }\n\n return [];\n};\n\nconst resolveWorkspaceDirectories = (rootDirectory: string, pattern: string): string[] => {\n const cleanPattern = pattern.replace(/[\"']/g, \"\").replace(/\\/\\*\\*$/, \"/*\");\n\n if (!cleanPattern.includes(\"*\")) {\n const directoryPath = path.join(rootDirectory, cleanPattern);\n if (fs.existsSync(directoryPath) && fs.existsSync(path.join(directoryPath, \"package.json\"))) {\n return [directoryPath];\n }\n return [];\n }\n\n const baseDirectory = path.join(rootDirectory, cleanPattern.slice(0, cleanPattern.indexOf(\"*\")));\n\n if (!fs.existsSync(baseDirectory) || !fs.statSync(baseDirectory).isDirectory()) {\n return [];\n }\n\n return fs\n .readdirSync(baseDirectory)\n .map((entry) => path.join(baseDirectory, entry))\n .filter(\n (entryPath) =>\n fs.statSync(entryPath).isDirectory() && fs.existsSync(path.join(entryPath, \"package.json\")),\n );\n};\n\nconst findDependencyInfoFromAncestors = (startDirectory: string): DependencyInfo => {\n let currentDirectory = path.dirname(startDirectory);\n const result: DependencyInfo = { reactVersion: null, framework: \"unknown\" };\n\n while (currentDirectory !== path.dirname(currentDirectory)) {\n const packageJsonPath = path.join(currentDirectory, \"package.json\");\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = readPackageJson(packageJsonPath);\n const info = extractDependencyInfo(packageJson);\n\n if (!result.reactVersion && info.reactVersion) {\n result.reactVersion = info.reactVersion;\n }\n if (result.framework === \"unknown\" && info.framework !== \"unknown\") {\n result.framework = info.framework;\n }\n\n if (result.reactVersion && result.framework !== \"unknown\") {\n return result;\n }\n }\n\n currentDirectory = path.dirname(currentDirectory);\n }\n\n return result;\n};\n\nconst findReactInWorkspaces = (rootDirectory: string, packageJson: PackageJson): DependencyInfo => {\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n const result: DependencyInfo = { reactVersion: null, framework: \"unknown\" };\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n const info = extractDependencyInfo(workspacePackageJson);\n\n if (info.reactVersion && !result.reactVersion) {\n result.reactVersion = info.reactVersion;\n }\n if (info.framework !== \"unknown\" && result.framework === \"unknown\") {\n result.framework = info.framework;\n }\n\n if (result.reactVersion && result.framework !== \"unknown\") {\n return result;\n }\n }\n }\n\n return result;\n};\n\nconst hasReactDependency = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some(\n (packageName) => packageName === \"next\" || packageName.includes(\"react\"),\n );\n};\n\nexport const discoverReactSubprojects = (rootDirectory: string): WorkspacePackage[] => {\n if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];\n\n const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });\n const packages: WorkspacePackage[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n continue;\n }\n\n const subdirectory = path.join(rootDirectory, entry.name);\n const packageJsonPath = path.join(subdirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) continue;\n\n const packageJson = readPackageJson(packageJsonPath);\n if (!hasReactDependency(packageJson)) continue;\n\n const name = packageJson.name ?? entry.name;\n packages.push({ name, directory: subdirectory });\n }\n\n return packages;\n};\n\nexport const listWorkspacePackages = (rootDirectory: string): WorkspacePackage[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return [];\n\n const packageJson = readPackageJson(packageJsonPath);\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n if (patterns.length === 0) return [];\n\n const packages: WorkspacePackage[] = [];\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n\n if (!hasReactDependency(workspacePackageJson)) continue;\n\n const name = workspacePackageJson.name ?? path.basename(workspaceDirectory);\n packages.push({ name, directory: workspaceDirectory });\n }\n }\n\n return packages;\n};\n\nconst hasCompilerPackage = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some((packageName) =>\n REACT_COMPILER_PACKAGES.has(packageName),\n );\n};\n\nconst fileContainsPattern = (filePath: string, pattern: RegExp): boolean => {\n if (!fs.existsSync(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return pattern.test(content);\n};\n\nconst hasCompilerInConfigFiles = (directory: string, filenames: string[]): boolean =>\n filenames.some((filename) =>\n fileContainsPattern(path.join(directory, filename), REACT_COMPILER_CONFIG_PATTERN),\n );\n\nconst detectReactCompiler = (directory: string, packageJson: PackageJson): boolean => {\n if (hasCompilerPackage(packageJson)) return true;\n\n if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;\n\n let ancestorDirectory = path.dirname(directory);\n while (ancestorDirectory !== path.dirname(ancestorDirectory)) {\n const ancestorPackagePath = path.join(ancestorDirectory, \"package.json\");\n if (fs.existsSync(ancestorPackagePath)) {\n const ancestorPackageJson = readPackageJson(ancestorPackagePath);\n if (hasCompilerPackage(ancestorPackageJson)) return true;\n }\n ancestorDirectory = path.dirname(ancestorDirectory);\n }\n\n return false;\n};\n\nexport const discoverProject = (directory: string): ProjectInfo => {\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`No package.json found in ${directory}`);\n }\n\n const packageJson = readPackageJson(packageJsonPath);\n let { reactVersion, framework } = extractDependencyInfo(packageJson);\n\n if (!reactVersion || framework === \"unknown\") {\n const workspaceInfo = findReactInWorkspaces(directory, packageJson);\n if (!reactVersion && workspaceInfo.reactVersion) {\n reactVersion = workspaceInfo.reactVersion;\n }\n if (framework === \"unknown\" && workspaceInfo.framework !== \"unknown\") {\n framework = workspaceInfo.framework;\n }\n }\n\n if (!reactVersion || framework === \"unknown\") {\n const ancestorInfo = findDependencyInfoFromAncestors(directory);\n if (!reactVersion) {\n reactVersion = ancestorInfo.reactVersion;\n }\n if (framework === \"unknown\") {\n framework = ancestorInfo.framework;\n }\n }\n\n const projectName = packageJson.name ?? path.basename(directory);\n const hasTypeScript = fs.existsSync(path.join(directory, \"tsconfig.json\"));\n const sourceFileCount = countSourceFiles(directory);\n\n const hasReactCompiler = detectReactCompiler(directory, packageJson);\n\n return {\n rootDirectory: directory,\n projectName,\n reactVersion,\n framework,\n hasTypeScript,\n hasReactCompiler,\n sourceFileCount,\n };\n};\n","export const groupBy = <T>(items: T[], keyFn: (item: T) => string): Map<string, T[]> => {\n const groups = new Map<string, T[]>();\n\n for (const item of items) {\n const key = keyFn(item);\n const existing = groups.get(key) ?? [];\n existing.push(item);\n groups.set(key, existing);\n }\n\n return groups;\n};\n","export const GIANT_COMPONENT_LINE_THRESHOLD = 300;\nexport const CASCADING_SET_STATE_THRESHOLD = 3;\nexport const RELATED_USE_STATE_THRESHOLD = 5;\nexport const DEEP_NESTING_THRESHOLD = 3;\nexport const DUPLICATE_STORAGE_READ_THRESHOLD = 2;\nexport const SEQUENTIAL_AWAIT_THRESHOLD = 3;\nexport const SECRET_MIN_LENGTH_CHARS = 8;\nexport const AUTH_CHECK_LOOKAHEAD_STATEMENTS = 3;\n\nexport const LAYOUT_PROPERTIES = new Set([\n \"width\",\n \"height\",\n \"top\",\n \"left\",\n \"right\",\n \"bottom\",\n \"padding\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"margin\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"borderWidth\",\n \"fontSize\",\n \"lineHeight\",\n \"gap\",\n]);\n\nexport const MOTION_ANIMATE_PROPS = new Set([\n \"animate\",\n \"initial\",\n \"exit\",\n \"whileHover\",\n \"whileTap\",\n \"whileFocus\",\n \"whileDrag\",\n \"whileInView\",\n]);\n\nexport const HEAVY_LIBRARIES = new Set([\n \"@monaco-editor/react\",\n \"monaco-editor\",\n \"recharts\",\n \"@react-pdf/renderer\",\n \"react-quill\",\n \"@codemirror/view\",\n \"@codemirror/state\",\n \"chart.js\",\n \"react-chartjs-2\",\n \"@toast-ui/editor\",\n \"draft-js\",\n]);\n\nexport const FETCH_CALLEE_NAMES = new Set([\"fetch\"]);\nexport const FETCH_MEMBER_OBJECTS = new Set([\"axios\", \"ky\", \"got\"]);\nexport const INDEX_PARAMETER_NAMES = new Set([\"index\", \"idx\", \"i\"]);\nexport const BARREL_INDEX_SUFFIXES = [\n \"/index\",\n \"/index.js\",\n \"/index.ts\",\n \"/index.tsx\",\n \"/index.mjs\",\n];\nexport const PASSIVE_EVENT_NAMES = new Set([\n \"scroll\",\n \"wheel\",\n \"touchstart\",\n \"touchmove\",\n \"touchend\",\n]);\n\nexport const LOOP_TYPES = [\n \"ForStatement\",\n \"ForInStatement\",\n \"ForOfStatement\",\n \"WhileStatement\",\n \"DoWhileStatement\",\n];\n\nexport const AUTH_FUNCTION_NAMES = new Set([\n \"auth\",\n \"getSession\",\n \"getServerSession\",\n \"getUser\",\n \"requireAuth\",\n \"checkAuth\",\n \"verifyAuth\",\n \"authenticate\",\n \"currentUser\",\n \"getAuth\",\n \"validateSession\",\n]);\n\nexport const SECRET_PATTERNS = [\n /^sk_live_/,\n /^sk_test_/,\n /^AKIA[0-9A-Z]{16}$/,\n /^ghp_[a-zA-Z0-9]{36}$/,\n /^gho_[a-zA-Z0-9]{36}$/,\n /^github_pat_/,\n /^glpat-/,\n /^xox[bporas]-/,\n /^sk-[a-zA-Z0-9]{32,}$/,\n];\n\nexport const SECRET_VARIABLE_PATTERN = /(?:api_?key|secret|token|password|credential|auth)/i;\n\nexport const SECRET_FALSE_POSITIVE_SUFFIXES = new Set([\n \"modal\",\n \"label\",\n \"text\",\n \"title\",\n \"name\",\n \"id\",\n \"key\",\n \"url\",\n \"path\",\n \"route\",\n \"page\",\n \"param\",\n \"field\",\n \"column\",\n \"header\",\n \"placeholder\",\n \"description\",\n \"type\",\n \"icon\",\n \"class\",\n \"style\",\n \"variant\",\n \"event\",\n \"action\",\n \"status\",\n \"state\",\n \"mode\",\n \"flag\",\n \"option\",\n \"config\",\n \"message\",\n \"error\",\n \"display\",\n \"view\",\n \"component\",\n \"element\",\n \"container\",\n \"wrapper\",\n \"button\",\n \"link\",\n \"input\",\n \"select\",\n \"dialog\",\n \"menu\",\n \"form\",\n \"step\",\n \"index\",\n \"count\",\n \"length\",\n \"role\",\n \"scope\",\n \"context\",\n \"provider\",\n \"ref\",\n \"handler\",\n \"query\",\n \"schema\",\n \"constant\",\n]);\n\nexport const LOADING_STATE_PATTERN = /^(?:isLoading|isPending)$/;\n\nexport const GENERIC_EVENT_SUFFIXES = new Set([\"Click\", \"Change\", \"Input\", \"Blur\", \"Focus\"]);\n\nexport const TRIVIAL_INITIALIZER_NAMES = new Set([\n \"Boolean\",\n \"String\",\n \"Number\",\n \"Array\",\n \"Object\",\n \"parseInt\",\n \"parseFloat\",\n]);\n\nexport const SETTER_PATTERN = /^set[A-Z]/;\nexport const RENDER_FUNCTION_PATTERN = /^render[A-Z]/;\nexport const UPPERCASE_PATTERN = /^[A-Z]/;\nexport const PAGE_FILE_PATTERN = /\\/page\\.(tsx?|jsx?)$/;\nexport const PAGE_OR_LAYOUT_FILE_PATTERN = /\\/(page|layout)\\.(tsx?|jsx?)$/;\n\nexport const INTERNAL_PAGE_PATH_PATTERN =\n /\\/(?:(?:\\((?:dashboard|admin|settings|account|internal|manage|console|portal|auth|onboarding|app|ee|protected)\\))|(?:dashboard|admin|settings|account|internal|manage|console|portal))\\//i;\n\nexport const TEST_FILE_PATTERN = /\\.(?:test|spec|stories)\\.[tj]sx?$/;\nexport const OG_ROUTE_PATTERN = /\\/og\\b/i;\n\nexport const PAGES_DIRECTORY_PATTERN = /\\/pages\\//;\nexport const SERVER_ACTION_FILE_PATTERN = /actions?\\.(tsx?|jsx?)$/;\nexport const SERVER_ACTION_DIRECTORY_PATTERN = /\\/actions\\//;\n\nexport const NEXTJS_NAVIGATION_FUNCTIONS = new Set([\n \"redirect\",\n \"permanentRedirect\",\n \"notFound\",\n \"forbidden\",\n \"unauthorized\",\n]);\n\nexport const GOOGLE_FONTS_PATTERN = /fonts\\.googleapis\\.com/;\n\nexport const POLYFILL_SCRIPT_PATTERN = /polyfill\\.io|polyfill\\.min\\.js|cdn\\.polyfill/;\n\nexport const APP_DIRECTORY_PATTERN = /\\/app\\//;\n\nexport const ROUTE_HANDLER_FILE_PATTERN = /\\/route\\.(tsx?|jsx?)$/;\n\nexport const MUTATION_METHOD_NAMES = new Set([\n \"create\",\n \"insert\",\n \"insertInto\",\n \"update\",\n \"upsert\",\n \"delete\",\n \"remove\",\n \"destroy\",\n \"set\",\n \"append\",\n]);\n\nexport const MUTATING_HTTP_METHODS = new Set([\"POST\", \"PUT\", \"DELETE\", \"PATCH\"]);\n\nexport const MUTATING_ROUTE_SEGMENTS = new Set([\n \"logout\",\n \"log-out\",\n \"signout\",\n \"sign-out\",\n \"unsubscribe\",\n \"delete\",\n \"remove\",\n \"revoke\",\n \"cancel\",\n \"deactivate\",\n]);\n\nexport const EFFECT_HOOK_NAMES = new Set([\"useEffect\", \"useLayoutEffect\"]);\nexport const HOOKS_WITH_DEPS = new Set([\"useEffect\", \"useLayoutEffect\", \"useMemo\", \"useCallback\"]);\nexport const CHAINABLE_ITERATION_METHODS = new Set([\"map\", \"filter\", \"forEach\", \"flatMap\"]);\nexport const STORAGE_OBJECTS = new Set([\"localStorage\", \"sessionStorage\"]);\n\nexport const LARGE_BLUR_THRESHOLD_PX = 10;\nexport const BLUR_VALUE_PATTERN = /blur\\((\\d+(?:\\.\\d+)?)px\\)/;\nexport const ANIMATION_CALLBACK_NAMES = new Set([\"requestAnimationFrame\", \"setInterval\"]);\nexport const MOTION_LIBRARY_PACKAGES = new Set([\"framer-motion\", \"motion\"]);\n","import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { MOTION_LIBRARY_PACKAGES } from \"../plugin/constants.js\";\nimport type { Diagnostic } from \"../types.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REDUCED_MOTION_GREP_PATTERN = \"prefers-reduced-motion|useReducedMotion\";\nconst REDUCED_MOTION_FILE_GLOBS = '\"*.ts\" \"*.tsx\" \"*.js\" \"*.jsx\" \"*.css\" \"*.scss\"';\n\nconst MISSING_REDUCED_MOTION_DIAGNOSTIC: Diagnostic = {\n filePath: \"package.json\",\n plugin: \"react-doctor\",\n rule: \"require-reduced-motion\",\n severity: \"error\",\n message:\n \"Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)\",\n help: \"Add `useReducedMotion()` from your animation library, or a `@media (prefers-reduced-motion: reduce)` CSS query\",\n line: 0,\n column: 0,\n category: \"Accessibility\",\n weight: 2,\n};\n\nexport const checkReducedMotion = (rootDirectory: string): Diagnostic[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return [];\n\n let hasMotionLibrary = false;\n try {\n const packageJson = readPackageJson(packageJsonPath);\n const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };\n hasMotionLibrary = Object.keys(allDependencies).some((packageName) =>\n MOTION_LIBRARY_PACKAGES.has(packageName),\n );\n } catch {\n return [];\n }\n if (!hasMotionLibrary) return [];\n\n try {\n execSync(`git grep -ql -E \"${REDUCED_MOTION_GREP_PATTERN}\" -- ${REDUCED_MOTION_FILE_GLOBS}`, {\n cwd: rootDirectory,\n stdio: \"pipe\",\n });\n return [];\n } catch {\n return [MISSING_REDUCED_MOTION_DIAGNOSTIC];\n }\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { main } from \"knip\";\nimport { createOptions } from \"knip/session\";\nimport type { Diagnostic, KnipIssueRecords, KnipResults } from \"../types.js\";\n\nconst KNIP_CATEGORY_MAP: Record<string, string> = {\n files: \"Dead Code\",\n exports: \"Dead Code\",\n types: \"Dead Code\",\n duplicates: \"Dead Code\",\n};\n\nconst KNIP_MESSAGE_MAP: Record<string, string> = {\n files: \"Unused file\",\n exports: \"Unused export\",\n types: \"Unused type\",\n duplicates: \"Duplicate export\",\n};\n\nconst KNIP_SEVERITY_MAP: Record<string, \"error\" | \"warning\"> = {\n files: \"warning\",\n exports: \"warning\",\n types: \"warning\",\n duplicates: \"warning\",\n};\n\nconst collectIssueRecords = (\n records: KnipIssueRecords,\n issueType: string,\n rootDirectory: string,\n): Diagnostic[] => {\n const diagnostics: Diagnostic[] = [];\n\n for (const issues of Object.values(records)) {\n for (const issue of Object.values(issues)) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, issue.filePath),\n plugin: \"knip\",\n rule: issueType,\n severity: KNIP_SEVERITY_MAP[issueType] ?? \"warning\",\n message: `${KNIP_MESSAGE_MAP[issueType]}: ${issue.symbol}`,\n help: \"\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[issueType] ?? \"Dead Code\",\n weight: 1,\n });\n }\n }\n\n return diagnostics;\n};\n\n// HACK: knip triggers dotenv which logs to stdout/stderr via console methods\nconst silenced = async <T>(fn: () => Promise<T>): Promise<T> => {\n const originalLog = console.log;\n const originalInfo = console.info;\n const originalWarn = console.warn;\n console.log = () => {};\n console.info = () => {};\n console.warn = () => {};\n try {\n return await fn();\n } finally {\n console.log = originalLog;\n console.info = originalInfo;\n console.warn = originalWarn;\n }\n};\n\nconst findMonorepoRoot = (directory: string): string | null => {\n let currentDirectory = path.dirname(directory);\n\n while (currentDirectory !== path.dirname(currentDirectory)) {\n const hasWorkspaceConfig =\n fs.existsSync(path.join(currentDirectory, \"pnpm-workspace.yaml\")) ||\n (() => {\n const packageJsonPath = path.join(currentDirectory, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n return Array.isArray(packageJson.workspaces) || packageJson.workspaces?.packages;\n })();\n\n if (hasWorkspaceConfig) return currentDirectory;\n currentDirectory = path.dirname(currentDirectory);\n }\n\n return null;\n};\n\nconst runKnipWithOptions = async (\n knipCwd: string,\n workspaceName?: string,\n): Promise<KnipResults> => {\n const options = await silenced(() =>\n createOptions({\n cwd: knipCwd,\n isShowProgress: false,\n ...(workspaceName ? { workspace: workspaceName } : {}),\n }),\n );\n return (await silenced(() => main(options))) as KnipResults;\n};\n\nconst hasNodeModules = (directory: string): boolean => {\n const nodeModulesPath = path.join(directory, \"node_modules\");\n return fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory();\n};\n\nexport const runKnip = async (rootDirectory: string): Promise<Diagnostic[]> => {\n const monorepoRoot = findMonorepoRoot(rootDirectory);\n const hasInstalledDependencies =\n hasNodeModules(rootDirectory) || (monorepoRoot !== null && hasNodeModules(monorepoRoot));\n\n if (!hasInstalledDependencies) {\n return [];\n }\n\n let knipResult: KnipResults;\n\n if (monorepoRoot) {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n const packageJson = fs.existsSync(packageJsonPath)\n ? JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"))\n : {};\n const workspaceName = packageJson.name ?? path.basename(rootDirectory);\n\n try {\n knipResult = await runKnipWithOptions(monorepoRoot, workspaceName);\n } catch {\n knipResult = await runKnipWithOptions(rootDirectory);\n }\n } else {\n knipResult = await runKnipWithOptions(rootDirectory);\n }\n\n const { issues } = knipResult;\n const diagnostics: Diagnostic[] = [];\n\n for (const unusedFile of issues.files) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, unusedFile),\n plugin: \"knip\",\n rule: \"files\",\n severity: KNIP_SEVERITY_MAP[\"files\"],\n message: KNIP_MESSAGE_MAP[\"files\"],\n help: \"This file is not imported by any other file in the project.\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[\"files\"],\n weight: 1,\n });\n }\n\n const recordTypes = [\"exports\", \"types\", \"duplicates\"] as const;\n\n for (const issueType of recordTypes) {\n diagnostics.push(...collectIssueRecords(issues[issueType], issueType, rootDirectory));\n }\n\n return diagnostics;\n};\n","import { createRequire } from \"node:module\";\nimport type { Framework } from \"./types.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst NEXTJS_RULES: Record<string, string> = {\n \"react-doctor/nextjs-no-img-element\": \"warn\",\n \"react-doctor/nextjs-async-client-component\": \"error\",\n \"react-doctor/nextjs-no-a-element\": \"warn\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"warn\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"warn\",\n \"react-doctor/nextjs-missing-metadata\": \"warn\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"warn\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"warn\",\n \"react-doctor/nextjs-image-missing-sizes\": \"warn\",\n \"react-doctor/nextjs-no-native-script\": \"warn\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"warn\",\n \"react-doctor/nextjs-no-font-link\": \"warn\",\n \"react-doctor/nextjs-no-css-link\": \"warn\",\n \"react-doctor/nextjs-no-polyfill-script\": \"warn\",\n \"react-doctor/nextjs-no-head-import\": \"error\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"error\",\n};\n\nconst REACT_COMPILER_RULES: Record<string, string> = {\n \"react-hooks-js/set-state-in-render\": \"error\",\n \"react-hooks-js/immutability\": \"error\",\n \"react-hooks-js/refs\": \"error\",\n \"react-hooks-js/purity\": \"error\",\n \"react-hooks-js/hooks\": \"error\",\n \"react-hooks-js/set-state-in-effect\": \"error\",\n \"react-hooks-js/globals\": \"error\",\n \"react-hooks-js/error-boundaries\": \"error\",\n \"react-hooks-js/preserve-manual-memoization\": \"error\",\n \"react-hooks-js/unsupported-syntax\": \"error\",\n \"react-hooks-js/component-hook-factories\": \"error\",\n \"react-hooks-js/static-components\": \"error\",\n \"react-hooks-js/use-memo\": \"error\",\n \"react-hooks-js/void-use-memo\": \"error\",\n \"react-hooks-js/incompatible-library\": \"error\",\n \"react-hooks-js/todo\": \"error\",\n};\n\ninterface OxlintConfigOptions {\n pluginPath: string;\n framework: Framework;\n hasReactCompiler: boolean;\n}\n\nexport const createOxlintConfig = ({\n pluginPath,\n framework,\n hasReactCompiler,\n}: OxlintConfigOptions) => ({\n categories: {\n correctness: \"off\",\n suspicious: \"off\",\n pedantic: \"off\",\n perf: \"off\",\n restriction: \"off\",\n style: \"off\",\n nursery: \"off\",\n },\n plugins: [\"react\", \"jsx-a11y\", ...(hasReactCompiler ? [] : [\"react-perf\"])],\n jsPlugins: [\n ...(hasReactCompiler\n ? [{ name: \"react-hooks-js\", specifier: esmRequire.resolve(\"eslint-plugin-react-hooks\") }]\n : []),\n pluginPath,\n ],\n rules: {\n \"react/rules-of-hooks\": \"error\",\n \"react/no-direct-mutation-state\": \"error\",\n \"react/jsx-no-duplicate-props\": \"error\",\n \"react/jsx-key\": \"error\",\n \"react/no-children-prop\": \"warn\",\n \"react/no-danger\": \"warn\",\n \"react/jsx-no-script-url\": \"error\",\n \"react/no-render-return-value\": \"warn\",\n \"react/no-string-refs\": \"warn\",\n \"react/no-is-mounted\": \"warn\",\n \"react/require-render-return\": \"error\",\n \"react/no-unknown-property\": \"warn\",\n\n \"jsx-a11y/alt-text\": \"error\",\n \"jsx-a11y/anchor-is-valid\": \"warn\",\n \"jsx-a11y/click-events-have-key-events\": \"warn\",\n \"jsx-a11y/no-static-element-interactions\": \"warn\",\n \"jsx-a11y/no-noninteractive-element-interactions\": \"warn\",\n \"jsx-a11y/role-has-required-aria-props\": \"error\",\n \"jsx-a11y/no-autofocus\": \"warn\",\n \"jsx-a11y/heading-has-content\": \"warn\",\n \"jsx-a11y/html-has-lang\": \"warn\",\n \"jsx-a11y/no-redundant-roles\": \"warn\",\n \"jsx-a11y/scope\": \"warn\",\n \"jsx-a11y/tabindex-no-positive\": \"warn\",\n \"jsx-a11y/label-has-associated-control\": \"warn\",\n \"jsx-a11y/no-distracting-elements\": \"error\",\n \"jsx-a11y/iframe-has-title\": \"warn\",\n\n ...(hasReactCompiler ? REACT_COMPILER_RULES : {}),\n\n \"react-doctor/no-derived-state-effect\": \"error\",\n \"react-doctor/no-fetch-in-effect\": \"error\",\n \"react-doctor/no-cascading-set-state\": \"warn\",\n \"react-doctor/no-effect-event-handler\": \"warn\",\n \"react-doctor/no-derived-useState\": \"warn\",\n \"react-doctor/prefer-useReducer\": \"warn\",\n \"react-doctor/rerender-lazy-state-init\": \"warn\",\n \"react-doctor/rerender-functional-setstate\": \"warn\",\n \"react-doctor/rerender-dependencies\": \"error\",\n\n \"react-doctor/no-giant-component\": \"warn\",\n \"react-doctor/no-render-in-render\": \"warn\",\n \"react-doctor/no-nested-component-definition\": \"error\",\n\n \"react-doctor/no-usememo-simple-expression\": \"warn\",\n \"react-doctor/no-layout-property-animation\": \"error\",\n \"react-doctor/rerender-memo-with-default-value\": \"warn\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"warn\",\n \"react-doctor/no-inline-prop-on-memo-component\": \"warn\",\n \"react-doctor/rendering-hydration-no-flicker\": \"warn\",\n\n \"react-doctor/no-transition-all\": \"warn\",\n \"react-doctor/no-global-css-variable-animation\": \"error\",\n \"react-doctor/no-large-animated-blur\": \"warn\",\n \"react-doctor/no-scale-from-zero\": \"warn\",\n \"react-doctor/no-permanent-will-change\": \"warn\",\n\n \"react-doctor/no-secrets-in-client-code\": \"error\",\n\n \"react-doctor/no-barrel-import\": \"warn\",\n \"react-doctor/no-full-lodash-import\": \"warn\",\n \"react-doctor/no-moment\": \"warn\",\n \"react-doctor/prefer-dynamic-import\": \"warn\",\n \"react-doctor/use-lazy-motion\": \"warn\",\n \"react-doctor/no-undeferred-third-party\": \"warn\",\n\n \"react-doctor/no-array-index-as-key\": \"warn\",\n \"react-doctor/rendering-conditional-render\": \"warn\",\n \"react-doctor/no-prevent-default\": \"warn\",\n\n \"react-doctor/server-auth-actions\": \"error\",\n \"react-doctor/server-after-nonblocking\": \"warn\",\n\n \"react-doctor/client-passive-event-listeners\": \"warn\",\n\n \"react-doctor/async-parallel\": \"warn\",\n ...(framework === \"nextjs\" ? NEXTJS_RULES : {}),\n },\n});\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ERROR_PREVIEW_LENGTH_CHARS, JSX_FILE_PATTERN } from \"../constants.js\";\nimport { createOxlintConfig } from \"../oxlint-config.js\";\nimport type { CleanedDiagnostic, Diagnostic, Framework, OxlintOutput } from \"../types.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst PLUGIN_CATEGORY_MAP: Record<string, string> = {\n react: \"Correctness\",\n \"react-hooks\": \"Correctness\",\n \"react-hooks-js\": \"React Compiler\",\n \"react-perf\": \"Performance\",\n \"jsx-a11y\": \"Accessibility\",\n};\n\nconst RULE_CATEGORY_MAP: Record<string, string> = {\n \"react-doctor/no-derived-state-effect\": \"State & Effects\",\n \"react-doctor/no-fetch-in-effect\": \"State & Effects\",\n \"react-doctor/no-cascading-set-state\": \"State & Effects\",\n \"react-doctor/no-effect-event-handler\": \"State & Effects\",\n \"react-doctor/no-derived-useState\": \"State & Effects\",\n \"react-doctor/prefer-useReducer\": \"State & Effects\",\n \"react-doctor/rerender-lazy-state-init\": \"Performance\",\n \"react-doctor/rerender-functional-setstate\": \"Performance\",\n \"react-doctor/rerender-dependencies\": \"State & Effects\",\n\n \"react-doctor/no-generic-handler-names\": \"Architecture\",\n \"react-doctor/no-giant-component\": \"Architecture\",\n \"react-doctor/no-render-in-render\": \"Architecture\",\n \"react-doctor/no-nested-component-definition\": \"Correctness\",\n\n \"react-doctor/no-usememo-simple-expression\": \"Performance\",\n \"react-doctor/no-layout-property-animation\": \"Performance\",\n \"react-doctor/rerender-memo-with-default-value\": \"Performance\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"Performance\",\n \"react-doctor/rendering-usetransition-loading\": \"Performance\",\n \"react-doctor/rendering-hydration-no-flicker\": \"Performance\",\n\n \"react-doctor/no-transition-all\": \"Performance\",\n \"react-doctor/no-global-css-variable-animation\": \"Performance\",\n \"react-doctor/no-large-animated-blur\": \"Performance\",\n \"react-doctor/no-scale-from-zero\": \"Performance\",\n \"react-doctor/no-permanent-will-change\": \"Performance\",\n\n \"react-doctor/no-secrets-in-client-code\": \"Security\",\n\n \"react-doctor/no-barrel-import\": \"Bundle Size\",\n \"react-doctor/no-full-lodash-import\": \"Bundle Size\",\n \"react-doctor/no-moment\": \"Bundle Size\",\n \"react-doctor/prefer-dynamic-import\": \"Bundle Size\",\n \"react-doctor/use-lazy-motion\": \"Bundle Size\",\n \"react-doctor/no-undeferred-third-party\": \"Bundle Size\",\n\n \"react-doctor/no-array-index-as-key\": \"Correctness\",\n \"react-doctor/rendering-conditional-render\": \"Correctness\",\n \"react-doctor/no-prevent-default\": \"Correctness\",\n \"react-doctor/nextjs-no-img-element\": \"Next.js\",\n \"react-doctor/nextjs-async-client-component\": \"Next.js\",\n \"react-doctor/nextjs-no-a-element\": \"Next.js\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"Next.js\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"Next.js\",\n \"react-doctor/nextjs-missing-metadata\": \"Next.js\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"Next.js\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"Next.js\",\n \"react-doctor/nextjs-image-missing-sizes\": \"Next.js\",\n \"react-doctor/nextjs-no-native-script\": \"Next.js\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"Next.js\",\n \"react-doctor/nextjs-no-font-link\": \"Next.js\",\n \"react-doctor/nextjs-no-css-link\": \"Next.js\",\n \"react-doctor/nextjs-no-polyfill-script\": \"Next.js\",\n \"react-doctor/nextjs-no-head-import\": \"Next.js\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"Security\",\n\n \"react-doctor/server-auth-actions\": \"Server\",\n \"react-doctor/server-after-nonblocking\": \"Server\",\n\n \"react-doctor/client-passive-event-listeners\": \"Performance\",\n\n \"react-doctor/async-parallel\": \"Performance\",\n};\n\nconst RULE_HELP_MAP: Record<string, string> = {\n \"no-derived-state-effect\":\n \"Compute during render: `const derived = computeFrom(dep1, dep2)` — no useEffect needed\",\n \"no-fetch-in-effect\":\n \"Use `useQuery()` from @tanstack/react-query, `useSWR()`, or fetch in a Server Component instead\",\n \"no-cascading-set-state\":\n \"Combine into useReducer: `const [state, dispatch] = useReducer(reducer, initialState)`\",\n \"no-effect-event-handler\":\n \"Move the conditional logic into onClick, onChange, or onSubmit handlers directly\",\n \"no-derived-useState\":\n \"Remove useState and compute the value inline: `const value = transform(propName)`\",\n \"prefer-useReducer\":\n \"Group related state: `const [state, dispatch] = useReducer(reducer, { field1, field2, ... })`\",\n \"rerender-lazy-state-init\":\n \"Wrap in an arrow function so it only runs once: `useState(() => expensiveComputation())`\",\n \"rerender-functional-setstate\":\n \"Use the callback form: `setState(prev => prev + 1)` to always read the latest value\",\n \"rerender-dependencies\":\n \"Extract to a useMemo, useRef, or module-level constant so the reference is stable\",\n\n \"no-generic-handler-names\":\n \"Rename to describe the action: e.g. `handleSubmit` → `saveUserProfile`, `handleClick` → `toggleSidebar`\",\n \"no-giant-component\":\n \"Extract logical sections into focused components: `<UserHeader />`, `<UserActions />`, etc.\",\n \"no-render-in-render\":\n \"Extract to a named component: `const ListItem = ({ item }) => <div>{item.name}</div>`\",\n \"no-nested-component-definition\":\n \"Move to a separate file or to module scope above the parent component\",\n\n \"no-usememo-simple-expression\":\n \"Remove useMemo — property access, math, and ternaries are already cheap without memoization\",\n \"no-layout-property-animation\":\n \"Use `transform: translateX()` or `scale()` instead — they run on the compositor and skip layout/paint\",\n \"rerender-memo-with-default-value\":\n \"Move to module scope: `const EMPTY_ITEMS: Item[] = []` then use as the default value\",\n \"rendering-animate-svg-wrapper\":\n \"Wrap the SVG: `<motion.div animate={...}><svg>...</svg></motion.div>`\",\n \"rendering-usetransition-loading\":\n \"Replace with `const [isPending, startTransition] = useTransition()` — avoids a re-render for the loading state\",\n \"rendering-hydration-no-flicker\":\n \"Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` or add `suppressHydrationWarning` to the element\",\n\n \"no-transition-all\":\n 'List specific properties: `transition: \"opacity 200ms, transform 200ms\"` — or in Tailwind use `transition-colors`, `transition-opacity`, or `transition-transform`',\n \"no-global-css-variable-animation\":\n \"Set the variable on the nearest element instead of a parent, or use `@property` with `inherits: false` to prevent cascade. Better yet, use targeted `element.style.transform` updates\",\n \"no-large-animated-blur\":\n \"Keep blur radius under 10px, or apply blur to a smaller element. Large blurs multiply GPU memory usage with layer size\",\n \"no-scale-from-zero\":\n \"Use `initial={{ scale: 0.95, opacity: 0 }}` — elements should deflate like a balloon, not vanish into a point\",\n \"no-permanent-will-change\":\n \"Add will-change on animation start (`onMouseEnter`) and remove on end (`onAnimationEnd`). Permanent promotion wastes GPU memory and can degrade performance\",\n\n \"no-secrets-in-client-code\":\n \"Move to server-side `process.env.SECRET_NAME`. Only `NEXT_PUBLIC_*` vars are safe for the client (and should not contain secrets)\",\n\n \"no-barrel-import\":\n \"Import from the direct path: `import { Button } from './components/Button'` instead of `./components`\",\n \"no-full-lodash-import\":\n \"Import the specific function: `import debounce from 'lodash/debounce'` — saves ~70kb\",\n \"no-moment\":\n \"Replace with `import { format } from 'date-fns'` (tree-shakeable) or `import dayjs from 'dayjs'` (2kb)\",\n \"prefer-dynamic-import\":\n \"Use `const Component = dynamic(() => import('library'), { ssr: false })` from next/dynamic or React.lazy()\",\n \"use-lazy-motion\":\n 'Use `import { LazyMotion, m } from \"framer-motion\"` with `domAnimation` features — saves ~30kb',\n \"no-undeferred-third-party\":\n 'Use `next/script` with `strategy=\"lazyOnload\"` or add the `defer` attribute',\n\n \"no-array-index-as-key\":\n \"Use a stable unique identifier: `key={item.id}` or `key={item.slug}` — index keys break on reorder/filter\",\n \"rendering-conditional-render\":\n \"Change to `{items.length > 0 && <List />}` or use a ternary: `{items.length ? <List /> : null}`\",\n \"no-prevent-default\":\n \"Use `<form action={serverAction}>` (works without JS) or `<button>` instead of `<a>` with preventDefault\",\n\n \"nextjs-no-img-element\":\n \"`import Image from 'next/image'` — provides automatic WebP/AVIF, lazy loading, and responsive srcset\",\n \"nextjs-async-client-component\":\n \"Fetch data in a parent Server Component and pass it as props, or use useQuery/useSWR in the client component\",\n \"nextjs-no-a-element\":\n \"`import Link from 'next/link'` — enables client-side navigation, prefetching, and preserves scroll position\",\n \"nextjs-no-use-search-params-without-suspense\":\n \"Wrap the component using useSearchParams: `<Suspense fallback={<Skeleton />}><SearchComponent /></Suspense>`\",\n \"nextjs-no-client-fetch-for-server-data\":\n \"Remove 'use client' and fetch directly in the Server Component — no API round-trip, secrets stay on server\",\n \"nextjs-missing-metadata\":\n \"Add `export const metadata = { title: '...', description: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-client-side-redirect\":\n \"Use `redirect('/path')` from 'next/navigation' in a Server Component, or handle in middleware\",\n \"nextjs-no-redirect-in-try-catch\":\n \"Move the redirect/notFound call outside the try block, or add `unstable_rethrow(error)` in the catch\",\n \"nextjs-image-missing-sizes\":\n 'Add sizes for responsive behavior: `sizes=\"(max-width: 768px) 100vw, 50vw\"` matching your layout breakpoints',\n \"nextjs-no-native-script\":\n '`import Script from \"next/script\"` — use `strategy=\"afterInteractive\"` for analytics or `\"lazyOnload\"` for widgets',\n \"nextjs-inline-script-missing-id\":\n 'Add `id=\"descriptive-name\"` so Next.js can track, deduplicate, and re-execute the script correctly',\n \"nextjs-no-font-link\":\n '`import { Inter } from \"next/font/google\"` — self-hosted, zero layout shift, no render-blocking requests',\n \"nextjs-no-css-link\":\n \"Import CSS directly: `import './styles.css'` or use CSS Modules: `import styles from './Button.module.css'`\",\n \"nextjs-no-polyfill-script\":\n \"Next.js includes polyfills for fetch, Promise, Object.assign, Array.from, and 50+ others automatically\",\n \"nextjs-no-head-import\":\n \"Use the Metadata API instead: `export const metadata = { title: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-side-effect-in-get-handler\":\n \"Move the side effect to a POST handler and use a <form> or fetch with method POST — GET requests can be triggered by prefetching and are vulnerable to CSRF\",\n\n \"server-auth-actions\":\n \"Add `const session = await auth()` at the top and throw/redirect if unauthorized before any data access\",\n \"server-after-nonblocking\":\n \"`import { after } from 'next/server'` then wrap: `after(() => analytics.track(...))` — response isn't blocked\",\n\n \"client-passive-event-listeners\":\n \"Add `{ passive: true }` as the third argument: `addEventListener('scroll', handler, { passive: true })`\",\n\n \"async-parallel\":\n \"Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to run independent operations concurrently\",\n};\n\nconst FILEPATH_WITH_LOCATION_PATTERN = /\\S+\\.\\w+:\\d+:\\d+[\\s\\S]*$/;\n\nconst REACT_COMPILER_MESSAGE = \"React Compiler can't optimize this code\";\n\nconst cleanDiagnosticMessage = (\n message: string,\n help: string,\n plugin: string,\n rule: string,\n): CleanedDiagnostic => {\n if (plugin === \"react-hooks-js\") {\n const rawMessage = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: REACT_COMPILER_MESSAGE, help: rawMessage || help };\n }\n const cleaned = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: cleaned || message, help: help || RULE_HELP_MAP[rule] || \"\" };\n};\n\nconst parseRuleCode = (code: string): { plugin: string; rule: string } => {\n const match = code.match(/^(.+)\\((.+)\\)$/);\n if (!match) return { plugin: \"unknown\", rule: code };\n return { plugin: match[1].replace(/^eslint-plugin-/, \"\"), rule: match[2] };\n};\n\nconst resolveOxlintBinary = (): string => {\n const oxlintMainPath = esmRequire.resolve(\"oxlint\");\n const oxlintPackageDirectory = path.resolve(path.dirname(oxlintMainPath), \"..\");\n return path.join(oxlintPackageDirectory, \"bin\", \"oxlint\");\n};\n\nconst resolvePluginPath = (): string => {\n const currentDirectory = path.dirname(fileURLToPath(import.meta.url));\n const pluginPath = path.join(currentDirectory, \"react-doctor-plugin.js\");\n if (fs.existsSync(pluginPath)) return pluginPath;\n\n const distPluginPath = path.resolve(currentDirectory, \"../../dist/react-doctor-plugin.js\");\n if (fs.existsSync(distPluginPath)) return distPluginPath;\n\n return pluginPath;\n};\n\nconst resolveDiagnosticCategory = (plugin: string, rule: string): string => {\n const ruleKey = `${plugin}/${rule}`;\n return RULE_CATEGORY_MAP[ruleKey] ?? PLUGIN_CATEGORY_MAP[plugin] ?? \"Other\";\n};\n\nexport const runOxlint = async (\n rootDirectory: string,\n hasTypeScript: boolean,\n framework: Framework,\n hasReactCompiler: boolean,\n): Promise<Diagnostic[]> => {\n const configPath = path.join(os.tmpdir(), `react-doctor-oxlintrc-${process.pid}.json`);\n const pluginPath = resolvePluginPath();\n const config = createOxlintConfig({ pluginPath, framework, hasReactCompiler });\n\n try {\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2));\n\n const oxlintBinary = resolveOxlintBinary();\n const args = [oxlintBinary, \"-c\", configPath, \"--format\", \"json\"];\n\n if (hasTypeScript) {\n args.push(\"--tsconfig\", \"./tsconfig.json\");\n }\n\n args.push(\".\");\n\n const stdout = await new Promise<string>((resolve, reject) => {\n const child = spawn(process.execPath, args, {\n cwd: rootDirectory,\n });\n\n const stdoutBuffers: Buffer[] = [];\n const stderrBuffers: Buffer[] = [];\n\n child.stdout.on(\"data\", (buffer: Buffer) => stdoutBuffers.push(buffer));\n child.stderr.on(\"data\", (buffer: Buffer) => stderrBuffers.push(buffer));\n\n child.on(\"error\", (error) => reject(new Error(`Failed to run oxlint: ${error.message}`)));\n child.on(\"close\", () => {\n const output = Buffer.concat(stdoutBuffers).toString(\"utf-8\").trim();\n if (!output) {\n const stderrOutput = Buffer.concat(stderrBuffers).toString(\"utf-8\").trim();\n if (stderrOutput) {\n reject(new Error(`Failed to run oxlint: ${stderrOutput}`));\n return;\n }\n }\n resolve(output);\n });\n });\n\n if (!stdout) {\n return [];\n }\n\n let output: OxlintOutput;\n try {\n output = JSON.parse(stdout) as OxlintOutput;\n } catch {\n throw new Error(\n `Failed to parse oxlint output: ${stdout.slice(0, ERROR_PREVIEW_LENGTH_CHARS)}`,\n );\n }\n\n return output.diagnostics\n .filter((diagnostic) => JSX_FILE_PATTERN.test(diagnostic.filename))\n .map((diagnostic) => {\n const { plugin, rule } = parseRuleCode(diagnostic.code);\n const primaryLabel = diagnostic.labels[0];\n\n const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule);\n\n return {\n filePath: diagnostic.filename,\n plugin,\n rule,\n severity: diagnostic.severity,\n message: cleaned.message,\n help: cleaned.help,\n line: primaryLabel?.span.line ?? 0,\n column: primaryLabel?.span.column ?? 0,\n category: resolveDiagnosticCategory(plugin, rule),\n };\n });\n } finally {\n if (fs.existsSync(configPath)) {\n fs.unlinkSync(configPath);\n }\n }\n};\n","import ora from \"ora\";\n\nlet sharedInstance: ReturnType<typeof ora> | null = null;\nlet activeCount = 0;\nconst pendingTexts = new Set<string>();\n\nconst finalize = (method: \"succeed\" | \"fail\", originalText: string, displayText: string) => {\n pendingTexts.delete(originalText);\n activeCount--;\n\n if (activeCount <= 0 || !sharedInstance) {\n sharedInstance?.[method](displayText);\n sharedInstance = null;\n activeCount = 0;\n return;\n }\n\n sharedInstance.stop();\n ora(displayText).start()[method](displayText);\n\n const [remainingText] = pendingTexts;\n if (remainingText) {\n sharedInstance.text = remainingText;\n }\n sharedInstance.start();\n};\n\nexport const spinner = (text: string) => ({\n start() {\n activeCount++;\n pendingTexts.add(text);\n\n if (!sharedInstance) {\n sharedInstance = ora({ text }).start();\n } else {\n sharedInstance.text = text;\n }\n\n return {\n succeed: (displayText: string) => finalize(\"succeed\", text, displayText),\n fail: (displayText: string) => finalize(\"fail\", text, displayText),\n };\n },\n});\n","export const indentMultilineText = (text: string, linePrefix: string): string =>\n text\n .split(\"\\n\")\n .map((lineText) => `${linePrefix}${lineText}`)\n .join(\"\\n\");\n","import { randomUUID } from \"node:crypto\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport {\n MILLISECONDS_PER_SECOND,\n OFFLINE_MESSAGE,\n PERFECT_SCORE,\n SCORE_BAR_WIDTH_CHARS,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n SUMMARY_BOX_HORIZONTAL_PADDING_CHARS,\n SUMMARY_BOX_OUTER_INDENT_CHARS,\n SHARE_BASE_URL,\n} from \"./constants.js\";\nimport type { Diagnostic, ScanOptions, ScoreResult } from \"./types.js\";\nimport { calculateScore } from \"./utils/calculate-score.js\";\nimport { discoverProject, formatFrameworkName } from \"./utils/discover-project.js\";\nimport { groupBy } from \"./utils/group-by.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { checkReducedMotion } from \"./utils/check-reduced-motion.js\";\nimport { runKnip } from \"./utils/run-knip.js\";\nimport { runOxlint } from \"./utils/run-oxlint.js\";\nimport { spinner } from \"./utils/spinner.js\";\nimport { indentMultilineText } from \"./utils/indent-multiline-text.js\";\n\ninterface FramedLine {\n plainText: string;\n renderedText: string;\n}\n\ninterface ScoreBarSegments {\n filledSegment: string;\n emptySegment: string;\n}\n\nconst SEVERITY_ORDER: Record<Diagnostic[\"severity\"], number> = {\n error: 0,\n warning: 1,\n};\n\nconst colorizeBySeverity = (text: string, severity: Diagnostic[\"severity\"]): string =>\n severity === \"error\" ? highlighter.error(text) : highlighter.warn(text);\n\nconst sortBySeverity = (diagnosticGroups: [string, Diagnostic[]][]): [string, Diagnostic[]][] =>\n diagnosticGroups.toSorted(([, diagnosticsA], [, diagnosticsB]) => {\n const severityA = SEVERITY_ORDER[diagnosticsA[0].severity];\n const severityB = SEVERITY_ORDER[diagnosticsB[0].severity];\n return severityA - severityB;\n });\n\nconst collectAffectedFiles = (diagnostics: Diagnostic[]): Set<string> =>\n new Set(diagnostics.map((diagnostic) => diagnostic.filePath));\n\nconst buildFileLineMap = (diagnostics: Diagnostic[]): Map<string, number[]> => {\n const fileLines = new Map<string, number[]>();\n for (const diagnostic of diagnostics) {\n const lines = fileLines.get(diagnostic.filePath) ?? [];\n if (diagnostic.line > 0) {\n lines.push(diagnostic.line);\n }\n fileLines.set(diagnostic.filePath, lines);\n }\n return fileLines;\n};\n\nconst printDiagnostics = (diagnostics: Diagnostic[], isVerbose: boolean): void => {\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [, ruleDiagnostics] of sortedRuleGroups) {\n const firstDiagnostic = ruleDiagnostics[0];\n const severitySymbol = firstDiagnostic.severity === \"error\" ? \"✗\" : \"⚠\";\n const icon = colorizeBySeverity(severitySymbol, firstDiagnostic.severity);\n const count = ruleDiagnostics.length;\n const countLabel = count > 1 ? colorizeBySeverity(` (${count})`, firstDiagnostic.severity) : \"\";\n\n logger.log(` ${icon} ${firstDiagnostic.message}${countLabel}`);\n if (firstDiagnostic.help) {\n logger.dim(indentMultilineText(firstDiagnostic.help, \" \"));\n }\n\n if (isVerbose) {\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n logger.dim(` ${filePath}${lineLabel}`);\n }\n }\n\n logger.break();\n }\n};\n\nconst formatElapsedTime = (elapsedMilliseconds: number): string => {\n if (elapsedMilliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(elapsedMilliseconds)}ms`;\n }\n return `${(elapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1)}s`;\n};\n\nconst formatRuleSummary = (ruleKey: string, ruleDiagnostics: Diagnostic[]): string => {\n const firstDiagnostic = ruleDiagnostics[0];\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n const sections = [\n `Rule: ${ruleKey}`,\n `Severity: ${firstDiagnostic.severity}`,\n `Category: ${firstDiagnostic.category}`,\n `Count: ${ruleDiagnostics.length}`,\n \"\",\n firstDiagnostic.message,\n ];\n\n if (firstDiagnostic.help) {\n sections.push(\"\", `Suggestion: ${firstDiagnostic.help}`);\n }\n\n sections.push(\"\", \"Files:\");\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n sections.push(` ${filePath}${lineLabel}`);\n }\n\n return sections.join(\"\\n\") + \"\\n\";\n};\n\nconst writeDiagnosticsDirectory = (diagnostics: Diagnostic[]): string => {\n const outputDirectory = join(tmpdir(), `react-doctor-${randomUUID()}`);\n mkdirSync(outputDirectory);\n\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [ruleKey, ruleDiagnostics] of sortedRuleGroups) {\n const fileName = ruleKey.replace(/\\//g, \"--\") + \".txt\";\n writeFileSync(join(outputDirectory, fileName), formatRuleSummary(ruleKey, ruleDiagnostics));\n }\n\n writeFileSync(join(outputDirectory, \"diagnostics.json\"), JSON.stringify(diagnostics, null, 2));\n\n return outputDirectory;\n};\n\nconst colorizeByScore = (text: string, score: number): string => {\n if (score >= SCORE_GOOD_THRESHOLD) return highlighter.success(text);\n if (score >= SCORE_OK_THRESHOLD) return highlighter.warn(text);\n return highlighter.error(text);\n};\n\nconst createFramedLine = (plainText: string, renderedText: string = plainText): FramedLine => ({\n plainText,\n renderedText,\n});\n\nconst buildScoreBarSegments = (score: number): ScoreBarSegments => {\n const filledCount = Math.round((score / PERFECT_SCORE) * SCORE_BAR_WIDTH_CHARS);\n const emptyCount = SCORE_BAR_WIDTH_CHARS - filledCount;\n\n return {\n filledSegment: \"█\".repeat(filledCount),\n emptySegment: \"░\".repeat(emptyCount),\n };\n};\n\nconst buildPlainScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return `${filledSegment}${emptySegment}`;\n};\n\nconst buildScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return colorizeByScore(filledSegment, score) + highlighter.dim(emptySegment);\n};\n\nconst printFramedBox = (framedLines: FramedLine[]): void => {\n if (framedLines.length === 0) {\n return;\n }\n\n const borderColorizer = highlighter.dim;\n const outerIndent = \" \".repeat(SUMMARY_BOX_OUTER_INDENT_CHARS);\n const horizontalPadding = \" \".repeat(SUMMARY_BOX_HORIZONTAL_PADDING_CHARS);\n const maximumLineLength = Math.max(\n ...framedLines.map((framedLine) => framedLine.plainText.length),\n );\n const borderLine = \"─\".repeat(maximumLineLength + SUMMARY_BOX_HORIZONTAL_PADDING_CHARS * 2);\n\n logger.log(`${outerIndent}${borderColorizer(`┌${borderLine}┐`)}`);\n\n for (const framedLine of framedLines) {\n const trailingSpaces = \" \".repeat(maximumLineLength - framedLine.plainText.length);\n logger.log(\n `${outerIndent}${borderColorizer(\"│\")}${horizontalPadding}${framedLine.renderedText}${trailingSpaces}${horizontalPadding}${borderColorizer(\"│\")}`,\n );\n }\n\n logger.log(`${outerIndent}${borderColorizer(`└${borderLine}┘`)}`);\n};\n\nconst printScoreGauge = (score: number, label: string): void => {\n const scoreDisplay = colorizeByScore(`${score}`, score);\n const labelDisplay = colorizeByScore(label, score);\n logger.log(` ${scoreDisplay} / ${PERFECT_SCORE} ${labelDisplay}`);\n logger.break();\n logger.log(` ${buildScoreBar(score)}`);\n logger.break();\n};\n\nconst getDoctorFace = (score: number): string[] => {\n if (score >= SCORE_GOOD_THRESHOLD) return [\"◠ ◠\", \" ▽ \"];\n if (score >= SCORE_OK_THRESHOLD) return [\"• •\", \" ─ \"];\n return [\"x x\", \" ▽ \"];\n};\n\nconst printBranding = (score?: number): void => {\n if (score !== undefined) {\n const [eyes, mouth] = getDoctorFace(score);\n const colorize = (text: string) => colorizeByScore(text, score);\n logger.log(colorize(\" ┌─────┐\"));\n logger.log(colorize(` │ ${eyes} │`));\n logger.log(colorize(` │ ${mouth} │`));\n logger.log(colorize(\" └─────┘\"));\n }\n logger.log(` React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`);\n logger.break();\n};\n\nconst buildShareUrl = (\n diagnostics: Diagnostic[],\n scoreResult: ScoreResult | null,\n projectName: string,\n): string => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n\n const params = new URLSearchParams();\n params.set(\"p\", projectName);\n if (scoreResult) params.set(\"s\", String(scoreResult.score));\n if (errorCount > 0) params.set(\"e\", String(errorCount));\n if (warningCount > 0) params.set(\"w\", String(warningCount));\n if (affectedFileCount > 0) params.set(\"f\", String(affectedFileCount));\n\n return `${SHARE_BASE_URL}?${params.toString()}`;\n};\n\nconst printSummary = (\n diagnostics: Diagnostic[],\n elapsedMilliseconds: number,\n scoreResult: ScoreResult | null,\n projectName: string,\n totalSourceFileCount: number,\n): void => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n const elapsed = formatElapsedTime(elapsedMilliseconds);\n\n const summaryLineParts: string[] = [];\n const summaryLinePartsPlain: string[] = [];\n if (errorCount > 0) {\n const errorText = `✗ ${errorCount} error${errorCount === 1 ? \"\" : \"s\"}`;\n summaryLinePartsPlain.push(errorText);\n summaryLineParts.push(highlighter.error(errorText));\n }\n if (warningCount > 0) {\n const warningText = `⚠ ${warningCount} warning${warningCount === 1 ? \"\" : \"s\"}`;\n summaryLinePartsPlain.push(warningText);\n summaryLineParts.push(highlighter.warn(warningText));\n }\n const fileCountText =\n totalSourceFileCount > 0\n ? `across ${affectedFileCount}/${totalSourceFileCount} files`\n : `across ${affectedFileCount} file${affectedFileCount === 1 ? \"\" : \"s\"}`;\n const elapsedTimeText = `in ${elapsed}`;\n\n summaryLinePartsPlain.push(fileCountText);\n summaryLinePartsPlain.push(elapsedTimeText);\n summaryLineParts.push(highlighter.dim(fileCountText));\n summaryLineParts.push(highlighter.dim(elapsedTimeText));\n\n const summaryFramedLines: FramedLine[] = [];\n if (scoreResult) {\n const [eyes, mouth] = getDoctorFace(scoreResult.score);\n const scoreColorizer = (text: string): string => colorizeByScore(text, scoreResult.score);\n\n summaryFramedLines.push(createFramedLine(\"┌─────┐\", scoreColorizer(\"┌─────┐\")));\n summaryFramedLines.push(createFramedLine(`│ ${eyes} │`, scoreColorizer(`│ ${eyes} │`)));\n summaryFramedLines.push(createFramedLine(`│ ${mouth} │`, scoreColorizer(`│ ${mouth} │`)));\n summaryFramedLines.push(createFramedLine(\"└─────┘\", scoreColorizer(\"└─────┘\")));\n summaryFramedLines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n summaryFramedLines.push(createFramedLine(\"\"));\n\n const scoreLinePlainText = `${scoreResult.score} / ${PERFECT_SCORE} ${scoreResult.label}`;\n const scoreLineRenderedText = `${colorizeByScore(String(scoreResult.score), scoreResult.score)} / ${PERFECT_SCORE} ${colorizeByScore(scoreResult.label, scoreResult.score)}`;\n summaryFramedLines.push(createFramedLine(scoreLinePlainText, scoreLineRenderedText));\n summaryFramedLines.push(createFramedLine(\"\"));\n summaryFramedLines.push(\n createFramedLine(buildPlainScoreBar(scoreResult.score), buildScoreBar(scoreResult.score)),\n );\n summaryFramedLines.push(createFramedLine(\"\"));\n } else {\n summaryFramedLines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n summaryFramedLines.push(createFramedLine(\"\"));\n summaryFramedLines.push(createFramedLine(OFFLINE_MESSAGE, highlighter.dim(OFFLINE_MESSAGE)));\n summaryFramedLines.push(createFramedLine(\"\"));\n }\n\n summaryFramedLines.push(\n createFramedLine(summaryLinePartsPlain.join(\" \"), summaryLineParts.join(\" \")),\n );\n printFramedBox(summaryFramedLines);\n\n try {\n const diagnosticsDirectory = writeDiagnosticsDirectory(diagnostics);\n logger.break();\n logger.dim(` Full diagnostics written to ${diagnosticsDirectory}`);\n } catch {\n logger.break();\n }\n\n const shareUrl = buildShareUrl(diagnostics, scoreResult, projectName);\n logger.break();\n logger.dim(` Share your results: ${highlighter.info(shareUrl)}`);\n};\n\nexport const scan = async (directory: string, options: ScanOptions): Promise<void> => {\n const startTime = performance.now();\n const projectInfo = discoverProject(directory);\n\n if (!projectInfo.reactVersion) {\n throw new Error(\"No React dependency found in package.json\");\n }\n\n if (!options.scoreOnly) {\n const frameworkLabel = formatFrameworkName(projectInfo.framework);\n const languageLabel = projectInfo.hasTypeScript ? \"TypeScript\" : \"JavaScript\";\n\n const completeStep = (message: string) => {\n spinner(message).start().succeed(message);\n };\n\n completeStep(`Detecting framework. Found ${highlighter.info(frameworkLabel)}.`);\n completeStep(\n `Detecting React version. Found ${highlighter.info(`React ${projectInfo.reactVersion}`)}.`,\n );\n completeStep(`Detecting language. Found ${highlighter.info(languageLabel)}.`);\n completeStep(\n `Detecting React Compiler. ${projectInfo.hasReactCompiler ? highlighter.info(\"Found React Compiler.\") : \"Not found.\"}`,\n );\n completeStep(`Found ${highlighter.info(`${projectInfo.sourceFileCount}`)} source files.`);\n\n logger.break();\n }\n\n const lintPromise = options.lint\n ? (async () => {\n const lintSpinner = options.scoreOnly ? null : spinner(\"Running lint checks...\").start();\n try {\n const lintDiagnostics = await runOxlint(\n directory,\n projectInfo.hasTypeScript,\n projectInfo.framework,\n projectInfo.hasReactCompiler,\n );\n lintSpinner?.succeed(\"Running lint checks.\");\n return lintDiagnostics;\n } catch {\n lintSpinner?.fail(\"Lint checks failed (non-fatal, skipping).\");\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const deadCodePromise = options.deadCode\n ? (async () => {\n const deadCodeSpinner = options.scoreOnly\n ? null\n : spinner(\"Detecting dead code...\").start();\n try {\n const knipDiagnostics = await runKnip(directory);\n deadCodeSpinner?.succeed(\"Detecting dead code.\");\n return knipDiagnostics;\n } catch {\n deadCodeSpinner?.fail(\"Dead code detection failed (non-fatal, skipping).\");\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const [lintDiagnostics, deadCodeDiagnostics] = await Promise.all([lintPromise, deadCodePromise]);\n const diagnostics = [\n ...lintDiagnostics,\n ...deadCodeDiagnostics,\n ...checkReducedMotion(directory),\n ];\n\n const elapsedMilliseconds = performance.now() - startTime;\n\n const scoreResult = await calculateScore(diagnostics);\n\n if (options.scoreOnly) {\n if (scoreResult) {\n logger.log(`${scoreResult.score}`);\n } else {\n logger.dim(OFFLINE_MESSAGE);\n }\n return;\n }\n\n if (diagnostics.length === 0) {\n logger.success(\"No issues found!\");\n logger.break();\n if (scoreResult) {\n printBranding(scoreResult.score);\n printScoreGauge(scoreResult.score, scoreResult.label);\n } else {\n logger.dim(` ${OFFLINE_MESSAGE}`);\n }\n return;\n }\n\n printDiagnostics(diagnostics, options.verbose);\n\n printSummary(\n diagnostics,\n elapsedMilliseconds,\n scoreResult,\n projectInfo.projectName,\n projectInfo.sourceFileCount,\n );\n};\n","import type { PromptMultiselectChoiceState } from \"../types.js\";\n\nexport const shouldSelectAllChoices = (choiceStates: PromptMultiselectChoiceState[]): boolean => {\n const enabledChoiceStates = choiceStates.filter((choiceState) => !choiceState.disabled);\n return enabledChoiceStates.some((choiceState) => choiceState.selected !== true);\n};\n","import { createRequire } from \"node:module\";\nimport basePrompts, { type PromptObject, type Answers } from \"prompts\";\nimport type { PromptMultiselectContext } from \"../types.js\";\nimport { logger } from \"./logger.js\";\nimport { shouldSelectAllChoices } from \"./should-select-all-choices.js\";\n\nconst require = createRequire(import.meta.url);\nconst PROMPTS_MULTISELECT_MODULE_PATH = \"prompts/lib/elements/multiselect\";\nlet didPatchMultiselectToggleAll = false;\n\nconst onCancel = () => {\n logger.break();\n logger.log(\"Cancelled.\");\n logger.break();\n process.exit(0);\n};\n\nconst patchMultiselectToggleAll = (): void => {\n if (didPatchMultiselectToggleAll) return;\n didPatchMultiselectToggleAll = true;\n\n const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);\n\n multiselectPromptConstructor.prototype.toggleAll = function (\n this: PromptMultiselectContext,\n ): void {\n const isCurrentChoiceDisabled = Boolean(this.value[this.cursor]?.disabled);\n if (this.maxChoices !== undefined || isCurrentChoiceDisabled) {\n this.bell();\n return;\n }\n\n const shouldSelectAllEnabledChoices = shouldSelectAllChoices(this.value);\n\n for (const choiceState of this.value) {\n if (choiceState.disabled) continue;\n choiceState.selected = shouldSelectAllEnabledChoices;\n }\n\n this.render();\n };\n};\n\nexport const prompts = <T extends string = string>(\n questions: PromptObject<T> | PromptObject<T>[],\n): Promise<Answers<T>> => {\n patchMultiselectToggleAll();\n return basePrompts(questions, { onCancel });\n};\n","import path from \"node:path\";\nimport type { WorkspacePackage } from \"../types.js\";\nimport { discoverReactSubprojects, listWorkspacePackages } from \"./discover-project.js\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nexport const selectProjects = async (\n rootDirectory: string,\n projectFlag: string | undefined,\n skipPrompts: boolean,\n): Promise<string[]> => {\n let packages = listWorkspacePackages(rootDirectory);\n if (packages.length === 0) {\n packages = discoverReactSubprojects(rootDirectory);\n }\n\n if (packages.length === 0) return [rootDirectory];\n if (packages.length === 1) {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages[0].name}`,\n );\n return [packages[0].directory];\n }\n\n if (projectFlag) return resolveProjectFlag(projectFlag, packages);\n\n if (skipPrompts) {\n printDiscoveredProjects(packages);\n return packages.map((workspacePackage) => workspacePackage.directory);\n }\n\n return promptProjectSelection(packages, rootDirectory);\n};\n\nconst resolveProjectFlag = (\n projectFlag: string,\n workspacePackages: WorkspacePackage[],\n): string[] => {\n const requestedNames = projectFlag.split(\",\").map((name) => name.trim());\n const resolvedDirectories: string[] = [];\n\n for (const requestedName of requestedNames) {\n const matched = workspacePackages.find(\n (workspacePackage) =>\n workspacePackage.name === requestedName ||\n path.basename(workspacePackage.directory) === requestedName,\n );\n\n if (!matched) {\n const availableNames = workspacePackages\n .map((workspacePackage) => workspacePackage.name)\n .join(\", \");\n throw new Error(`Project \"${requestedName}\" not found. Available: ${availableNames}`);\n }\n\n resolvedDirectories.push(matched.directory);\n }\n\n return resolvedDirectories;\n};\n\nconst printDiscoveredProjects = (packages: WorkspacePackage[]): void => {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages.map((workspacePackage) => workspacePackage.name).join(\", \")}`,\n );\n};\n\nconst promptProjectSelection = async (\n workspacePackages: WorkspacePackage[],\n rootDirectory: string,\n): Promise<string[]> => {\n const { selectedDirectories } = await prompts({\n type: \"multiselect\",\n name: \"selectedDirectories\",\n message: \"Select projects to scan\",\n choices: workspacePackages.map((workspacePackage) => ({\n title: workspacePackage.name,\n description: path.relative(rootDirectory, workspacePackage.directory),\n value: workspacePackage.directory,\n })),\n min: 1,\n });\n\n return selectedDirectories;\n};\n","import { execSync } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nconst CONFIG_DIRECTORY = join(homedir(), \".react-doctor\");\nconst CONFIG_FILE = join(CONFIG_DIRECTORY, \"config.json\");\nconst SKILL_REPO = \"millionco/react-doctor\";\n\ninterface UserConfig {\n skillPromptDismissed?: boolean;\n}\n\nconst readConfig = (): UserConfig => {\n try {\n if (!existsSync(CONFIG_FILE)) return {};\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf-8\"));\n } catch {\n return {};\n }\n};\n\nconst writeConfig = (config: UserConfig): void => {\n try {\n if (!existsSync(CONFIG_DIRECTORY)) {\n mkdirSync(CONFIG_DIRECTORY, { recursive: true });\n }\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n } catch {}\n};\n\nconst installSkill = (): void => {\n try {\n execSync(`npx -y skills add ${SKILL_REPO}`, { stdio: \"inherit\" });\n } catch {\n logger.break();\n logger.dim(\"Skill install failed. You can install manually:\");\n logger.dim(` npx skills add ${SKILL_REPO}`);\n }\n};\n\nexport const maybePromptSkillInstall = async (shouldSkipPrompts: boolean): Promise<void> => {\n const config = readConfig();\n if (config.skillPromptDismissed) return;\n if (shouldSkipPrompts) return;\n\n logger.break();\n logger.log(`${highlighter.info(\"💡\")} Have your coding agent fix these issues automatically?`);\n logger.dim(\n ` Install the ${highlighter.info(\"react-doctor\")} skill to teach Cursor, Claude Code, Copilot,`,\n );\n logger.dim(\" Ami, and other AI agents how to diagnose and fix these React issues.\");\n logger.break();\n\n const { shouldInstall } = await prompts({\n type: \"confirm\",\n name: \"shouldInstall\",\n message: \"Install skill?\",\n initial: true,\n });\n\n if (shouldInstall) {\n logger.break();\n installSkill();\n writeConfig({ ...config, skillPromptDismissed: true });\n }\n};\n","import { spawn, execSync } from \"node:child_process\";\n\nconst isGloballyInstalled = (): boolean => {\n try {\n const globalBinPath = execSync(\"which react-doctor\", {\n stdio: \"pipe\",\n encoding: \"utf-8\",\n }).trim();\n return !globalBinPath.includes(\"/_npx/\");\n } catch {\n return false;\n }\n};\n\nexport const maybeInstallGlobally = (): void => {\n try {\n if (isGloballyInstalled()) return;\n\n const child = spawn(\"npm\", [\"install\", \"-g\", \"react-doctor@latest\"], {\n detached: true,\n stdio: \"ignore\",\n });\n child.on(\"error\", () => {});\n child.unref();\n } catch {\n // noop\n }\n};\n","import { spawnSync } from \"node:child_process\";\nimport type { ClipboardCommand } from \"../types.js\";\n\nconst getClipboardCommands = (): ClipboardCommand[] => {\n if (process.platform === \"darwin\") {\n return [{ command: \"pbcopy\", args: [] }];\n }\n\n if (process.platform === \"win32\") {\n return [{ command: \"clip\", args: [] }];\n }\n\n return [\n { command: \"wl-copy\", args: [] },\n { command: \"xclip\", args: [\"-selection\", \"clipboard\"] },\n { command: \"xsel\", args: [\"--clipboard\", \"--input\"] },\n ];\n};\n\nexport const copyToClipboard = (text: string): boolean => {\n const clipboardCommands = getClipboardCommands();\n\n for (const clipboardCommand of clipboardCommands) {\n const clipboardProcess = spawnSync(clipboardCommand.command, clipboardCommand.args, {\n input: text,\n stdio: [\"pipe\", \"ignore\", \"ignore\"],\n encoding: \"utf8\",\n });\n\n if (clipboardProcess.status === 0) {\n return true;\n }\n }\n\n return false;\n};\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport { SEPARATOR_LENGTH_CHARS } from \"./constants.js\";\nimport type { ScanOptions } from \"./types.js\";\nimport { handleError } from \"./utils/handle-error.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { logger, startLoggerCapture, stopLoggerCapture } from \"./utils/logger.js\";\nimport { scan } from \"./scan.js\";\nimport { selectProjects } from \"./utils/select-projects.js\";\nimport { prompts } from \"./utils/prompts.js\";\nimport { maybePromptSkillInstall } from \"./utils/skill-prompt.js\";\nimport { maybeInstallGlobally } from \"./utils/global-install.js\";\nimport { copyToClipboard } from \"./utils/copy-to-clipboard.js\";\n\nconst VERSION = process.env.VERSION ?? \"0.0.0\";\n\ninterface CliFlags {\n lint: boolean;\n deadCode: boolean;\n verbose: boolean;\n score: boolean;\n fix: boolean;\n prompt: boolean;\n yes: boolean;\n project?: string;\n}\n\nprocess.on(\"SIGINT\", () => process.exit(0));\nprocess.on(\"SIGTERM\", () => process.exit(0));\n\nconst program = new Command()\n .name(\"react-doctor\")\n .description(\"Diagnose React codebase health\")\n .version(VERSION, \"-v, --version\", \"display the version number\")\n .argument(\"[directory]\", \"project directory to scan\", \".\")\n .option(\"--no-lint\", \"skip linting\")\n .option(\"--no-dead-code\", \"skip dead code detection\")\n .option(\"--verbose\", \"show file details per rule\")\n .option(\"--score\", \"output only the score\")\n .option(\"-y, --yes\", \"skip prompts, scan all workspace projects\")\n .option(\"--project <name>\", \"select workspace project (comma-separated for multiple)\")\n .option(\"--fix\", \"open Ami to auto-fix all issues\")\n .option(\"--prompt\", \"copy latest scan output to clipboard\")\n .action(async (directory: string, flags: CliFlags) => {\n const isScoreOnly = flags.score && !flags.prompt;\n const shouldCopyPromptOutput = flags.prompt;\n\n if (shouldCopyPromptOutput) {\n startLoggerCapture();\n }\n\n try {\n const resolvedDirectory = path.resolve(directory);\n\n if (!isScoreOnly) {\n logger.log(`react-doctor v${VERSION}`);\n logger.break();\n }\n\n const scanOptions: ScanOptions = {\n lint: flags.lint,\n deadCode: flags.deadCode,\n verbose: flags.prompt || Boolean(flags.verbose),\n scoreOnly: isScoreOnly,\n };\n\n const isAutomatedEnvironment = [\n process.env.CI,\n process.env.CLAUDECODE,\n process.env.CURSOR_AGENT,\n process.env.CODEX_CI,\n process.env.OPENCODE,\n process.env.AMP_HOME,\n process.env.AMI,\n ].some(Boolean);\n const shouldSkipPrompts = flags.yes || isAutomatedEnvironment || !process.stdin.isTTY;\n const projectDirectories = await selectProjects(\n resolvedDirectory,\n flags.project,\n shouldSkipPrompts,\n );\n\n for (const projectDirectory of projectDirectories) {\n if (!isScoreOnly) {\n logger.dim(`Scanning ${projectDirectory}...`);\n logger.break();\n }\n await scan(projectDirectory, scanOptions);\n if (!isScoreOnly) {\n logger.break();\n }\n }\n\n if (flags.fix) {\n openAmiToFix(resolvedDirectory);\n }\n\n if (!isScoreOnly && !flags.prompt) {\n await maybePromptSkillInstall(shouldSkipPrompts);\n if (!shouldSkipPrompts && !flags.fix) {\n await maybePromptAmiFix(resolvedDirectory);\n }\n }\n } catch (error) {\n handleError(error, { shouldExit: !shouldCopyPromptOutput });\n } finally {\n if (shouldCopyPromptOutput) {\n const capturedOutput = stopLoggerCapture();\n copyPromptToClipboard(capturedOutput, !isScoreOnly);\n }\n }\n })\n .addHelpText(\n \"after\",\n `\n${highlighter.dim(\"Learn more:\")}\n ${highlighter.info(\"https://github.com/millionco/react-doctor\")}\n`,\n );\n\nconst AMI_INSTALL_URL = \"https://ami.dev/install.sh\";\nconst AMI_RELEASES_URL = \"https://github.com/millionco/ami-releases/releases\";\nconst DEEPLINK_FIX_PROMPT =\n \"Run `npx -y react-doctor@latest .` to diagnose issues, then fix all reported issues one by one. After applying fixes, run it again to verify the results improved.\";\nconst CLIPBOARD_FIX_PROMPT =\n \"Fix all issues reported in the react-doctor diagnostics below, one by one. After applying fixes, run `npx -y react-doctor@latest .` again to verify the results improved.\";\nconst REACT_DOCTOR_OUTPUT_LABEL = \"react-doctor output\";\nconst SCAN_SUMMARY_SEPARATOR = \"─\".repeat(SEPARATOR_LENGTH_CHARS);\n\nconst isAmiInstalled = (): boolean => {\n if (process.platform === \"darwin\") {\n return (\n existsSync(\"/Applications/Ami.app\") ||\n existsSync(path.join(os.homedir(), \"Applications\", \"Ami.app\"))\n );\n }\n\n if (process.platform === \"win32\") {\n const { LOCALAPPDATA, PROGRAMFILES } = process.env;\n return (\n Boolean(LOCALAPPDATA && existsSync(path.join(LOCALAPPDATA, \"Programs\", \"Ami\", \"Ami.exe\"))) ||\n Boolean(PROGRAMFILES && existsSync(path.join(PROGRAMFILES, \"Ami\", \"Ami.exe\")))\n );\n }\n\n try {\n execSync(\"which ami\", { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n};\n\nconst installAmi = (): void => {\n logger.log(\"Ami not found. Installing...\");\n logger.break();\n try {\n execSync(`curl -fsSL ${AMI_INSTALL_URL} | bash`, { stdio: \"inherit\" });\n } catch {\n logger.error(\"Failed to install Ami. Visit https://ami.dev to install manually.\");\n process.exit(1);\n }\n logger.break();\n};\n\nconst openUrl = (url: string): void => {\n if (process.platform === \"win32\") {\n // HACK: cmd.exe interprets %XX% as env var expansion, which mangles encoded URLs.\n // Escaping % as %% produces literal % in cmd output.\n const cmdEscapedUrl = url.replace(/%/g, \"%%\");\n execSync(`start \"\" \"${cmdEscapedUrl}\"`, { stdio: \"ignore\" });\n return;\n }\n const openCommand = process.platform === \"darwin\" ? `open \"${url}\"` : `xdg-open \"${url}\"`;\n execSync(openCommand, { stdio: \"ignore\" });\n};\n\nconst buildDeeplink = (directory: string): string => {\n const encodedDirectory = encodeURIComponent(path.resolve(directory));\n const encodedPrompt = encodeURIComponent(DEEPLINK_FIX_PROMPT);\n return `ami://open-project?cwd=${encodedDirectory}&prompt=${encodedPrompt}&mode=agent&autoSubmit=true`;\n};\n\nconst openAmiToFix = (directory: string): void => {\n const isInstalled = isAmiInstalled();\n const deeplink = buildDeeplink(directory);\n\n if (!isInstalled) {\n if (process.platform === \"darwin\") {\n installAmi();\n logger.success(\"Ami was installed and opened.\");\n } else {\n logger.error(\"Ami is not installed.\");\n logger.dim(`Download it at ${highlighter.info(AMI_RELEASES_URL)}`);\n }\n logger.break();\n logger.dim(\"Once Ami is running, open this link to start fixing:\");\n logger.info(deeplink);\n return;\n }\n\n logger.log(\"Opening Ami to fix react-doctor issues...\");\n\n try {\n openUrl(deeplink);\n logger.success(\"Opened Ami with react-doctor fix prompt.\");\n } catch {\n logger.break();\n logger.dim(\"Could not open Ami automatically. Open this URL manually:\");\n logger.info(deeplink);\n }\n};\n\nconst buildPromptWithOutput = (reactDoctorOutput: string): string => {\n const summaryStartIndex = reactDoctorOutput.indexOf(SCAN_SUMMARY_SEPARATOR);\n const diagnosticsOutput =\n summaryStartIndex === -1\n ? reactDoctorOutput\n : reactDoctorOutput.slice(0, summaryStartIndex).trimEnd();\n const normalizedReactDoctorOutput = diagnosticsOutput.trim();\n const outputContent =\n normalizedReactDoctorOutput.length > 0 ? normalizedReactDoctorOutput : \"No output captured.\";\n return `${CLIPBOARD_FIX_PROMPT}\\n\\n${REACT_DOCTOR_OUTPUT_LABEL}:\\n\\`\\`\\`\\n${outputContent}\\n\\`\\`\\``;\n};\n\nconst copyPromptToClipboard = (reactDoctorOutput: string, shouldLogResult: boolean): void => {\n const promptWithOutput = buildPromptWithOutput(reactDoctorOutput);\n const didCopyPromptToClipboard = copyToClipboard(promptWithOutput);\n\n if (!shouldLogResult) {\n return;\n }\n\n if (didCopyPromptToClipboard) {\n logger.success(\"Copied latest scan output to clipboard\");\n return;\n }\n\n logger.warn(\"Could not copy prompt to clipboard automatically. Use this prompt:\");\n logger.info(promptWithOutput);\n};\n\nconst maybePromptAmiFix = async (directory: string): Promise<void> => {\n const isInstalled = isAmiInstalled();\n\n logger.break();\n logger.log(`Fix these issues with ${highlighter.info(\"Ami\")}?`);\n logger.dim(\" Ami is a coding agent built to understand your codebase and fix issues\");\n logger.dim(` automatically. Learn more at ${highlighter.info(\"https://ami.dev\")}`);\n logger.break();\n\n if (!isInstalled && process.platform !== \"darwin\") {\n logger.dim(`Download Ami at ${highlighter.info(AMI_RELEASES_URL)}`);\n return;\n }\n\n const promptMessage = isInstalled ? \"Open Ami to fix?\" : \"Install Ami to fix?\";\n const { shouldFix } = await prompts({\n type: \"confirm\",\n name: \"shouldFix\",\n message: promptMessage,\n initial: true,\n });\n\n if (shouldFix) {\n openAmiToFix(directory);\n }\n};\n\nconst fixAction = (directory: string) => {\n try {\n openAmiToFix(directory);\n } catch (error) {\n handleError(error);\n }\n};\n\nconst fixCommand = new Command(\"fix\")\n .description(\"Open Ami to auto-fix react-doctor issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nconst installAmiCommand = new Command(\"install-ami\")\n .description(\"Install Ami and open it to auto-fix issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nprogram.addCommand(fixCommand);\nprogram.addCommand(installAmiCommand);\n\nconst main = async () => {\n maybeInstallGlobally();\n await program.parseAsync();\n};\n\nmain();\n"],"mappings":"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"}
|