react-doctor 0.0.30 → 0.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +198 -30
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +181 -22
- package/dist/index.js.map +1 -1
- package/dist/react-doctor-plugin.js +23 -8
- package/dist/react-doctor-plugin.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -32,7 +32,7 @@ const OPEN_BASE_URL = "https://www.react.doctor/open";
|
|
|
32
32
|
const FETCH_TIMEOUT_MS = 1e4;
|
|
33
33
|
const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
34
34
|
const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
|
|
35
|
-
const OFFLINE_MESSAGE = "
|
|
35
|
+
const OFFLINE_MESSAGE = "Score calculated locally (offline mode).";
|
|
36
36
|
const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
|
|
37
37
|
const ERROR_RULE_PENALTY = 1.5;
|
|
38
38
|
const WARNING_RULE_PENALTY = .75;
|
|
@@ -41,6 +41,12 @@ const WARNING_ESTIMATED_FIX_RATE = .8;
|
|
|
41
41
|
const MAX_KNIP_RETRIES = 5;
|
|
42
42
|
const OXLINT_NODE_REQUIREMENT = "^20.19.0 || >=22.12.0";
|
|
43
43
|
const OXLINT_RECOMMENDED_NODE_MAJOR = 24;
|
|
44
|
+
const IGNORED_DIRECTORIES = new Set([
|
|
45
|
+
"node_modules",
|
|
46
|
+
"dist",
|
|
47
|
+
"build",
|
|
48
|
+
"coverage"
|
|
49
|
+
]);
|
|
44
50
|
const AMI_WEBSITE_URL = "https://ami.dev";
|
|
45
51
|
const AMI_INSTALL_URL = `${AMI_WEBSITE_URL}/install.sh`;
|
|
46
52
|
const AMI_RELEASES_URL = "https://github.com/millionco/ami-releases/releases";
|
|
@@ -278,17 +284,31 @@ const compileGlobPattern = (pattern) => {
|
|
|
278
284
|
return new RegExp(regexSource);
|
|
279
285
|
};
|
|
280
286
|
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/utils/is-ignored-file.ts
|
|
289
|
+
const toRelativePath = (filePath, rootDirectory) => {
|
|
290
|
+
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
291
|
+
const normalizedRoot = rootDirectory.replace(/\\/g, "/").replace(/\/$/, "") + "/";
|
|
292
|
+
if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
|
|
293
|
+
return normalizedFilePath.replace(/^\.\//, "");
|
|
294
|
+
};
|
|
295
|
+
const compileIgnoredFilePatterns = (userConfig) => Array.isArray(userConfig?.ignore?.files) ? userConfig.ignore.files.map(compileGlobPattern) : [];
|
|
296
|
+
const isFileIgnoredByPatterns = (filePath, rootDirectory, patterns) => {
|
|
297
|
+
if (patterns.length === 0) return false;
|
|
298
|
+
const relativePath = toRelativePath(filePath, rootDirectory);
|
|
299
|
+
return patterns.some((pattern) => pattern.test(relativePath));
|
|
300
|
+
};
|
|
301
|
+
|
|
281
302
|
//#endregion
|
|
282
303
|
//#region src/utils/filter-diagnostics.ts
|
|
283
|
-
const filterIgnoredDiagnostics = (diagnostics, config) => {
|
|
304
|
+
const filterIgnoredDiagnostics = (diagnostics, config, rootDirectory) => {
|
|
284
305
|
const ignoredRules = new Set(Array.isArray(config.ignore?.rules) ? config.ignore.rules : []);
|
|
285
|
-
const ignoredFilePatterns =
|
|
306
|
+
const ignoredFilePatterns = compileIgnoredFilePatterns(config);
|
|
286
307
|
if (ignoredRules.size === 0 && ignoredFilePatterns.length === 0) return diagnostics;
|
|
287
308
|
return diagnostics.filter((diagnostic) => {
|
|
288
309
|
const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
289
310
|
if (ignoredRules.has(ruleIdentifier)) return false;
|
|
290
|
-
|
|
291
|
-
if (ignoredFilePatterns.some((pattern) => pattern.test(normalizedPath))) return false;
|
|
311
|
+
if (isFileIgnoredByPatterns(diagnostic.filePath, rootDirectory, ignoredFilePatterns)) return false;
|
|
292
312
|
return true;
|
|
293
313
|
});
|
|
294
314
|
};
|
|
@@ -343,7 +363,7 @@ const combineDiagnostics = (lintDiagnostics, deadCodeDiagnostics, directory, isD
|
|
|
343
363
|
...deadCodeDiagnostics,
|
|
344
364
|
...isDiffMode ? [] : checkReducedMotion(directory)
|
|
345
365
|
];
|
|
346
|
-
return filterInlineSuppressions(userConfig ? filterIgnoredDiagnostics(merged, userConfig) : merged, directory);
|
|
366
|
+
return filterInlineSuppressions(userConfig ? filterIgnoredDiagnostics(merged, userConfig, directory) : merged, directory);
|
|
347
367
|
};
|
|
348
368
|
|
|
349
369
|
//#endregion
|
|
@@ -422,12 +442,6 @@ const FRAMEWORK_DISPLAY_NAMES = {
|
|
|
422
442
|
unknown: "React"
|
|
423
443
|
};
|
|
424
444
|
const formatFrameworkName = (framework) => FRAMEWORK_DISPLAY_NAMES[framework];
|
|
425
|
-
const IGNORED_DIRECTORIES = new Set([
|
|
426
|
-
"node_modules",
|
|
427
|
-
"dist",
|
|
428
|
-
"build",
|
|
429
|
-
"coverage"
|
|
430
|
-
]);
|
|
431
445
|
const countSourceFilesViaFilesystem = (rootDirectory) => {
|
|
432
446
|
let count = 0;
|
|
433
447
|
const stack = [rootDirectory];
|
|
@@ -469,23 +483,115 @@ const detectFramework = (dependencies) => {
|
|
|
469
483
|
return "unknown";
|
|
470
484
|
};
|
|
471
485
|
const isCatalogReference = (version) => version.startsWith("catalog:");
|
|
486
|
+
const extractCatalogName = (version) => {
|
|
487
|
+
if (!isCatalogReference(version)) return null;
|
|
488
|
+
const name = version.slice(8).trim();
|
|
489
|
+
return name.length > 0 ? name : null;
|
|
490
|
+
};
|
|
472
491
|
const resolveVersionFromCatalog = (catalog, packageName) => {
|
|
473
492
|
const version = catalog[packageName];
|
|
474
493
|
if (typeof version === "string" && !isCatalogReference(version)) return version;
|
|
475
494
|
return null;
|
|
476
495
|
};
|
|
477
|
-
const
|
|
496
|
+
const parsePnpmWorkspaceCatalogs = (rootDirectory) => {
|
|
497
|
+
const workspacePath = path.join(rootDirectory, "pnpm-workspace.yaml");
|
|
498
|
+
if (!isFile(workspacePath)) return {
|
|
499
|
+
defaultCatalog: {},
|
|
500
|
+
namedCatalogs: {}
|
|
501
|
+
};
|
|
502
|
+
const content = fs.readFileSync(workspacePath, "utf-8");
|
|
503
|
+
const defaultCatalog = {};
|
|
504
|
+
const namedCatalogs = {};
|
|
505
|
+
let currentSection = "none";
|
|
506
|
+
let currentCatalogName = "";
|
|
507
|
+
for (const line of content.split("\n")) {
|
|
508
|
+
const trimmed = line.trim();
|
|
509
|
+
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
|
|
510
|
+
const indentLevel = line.search(/\S/);
|
|
511
|
+
if (indentLevel === 0 && trimmed === "catalog:") {
|
|
512
|
+
currentSection = "catalog";
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (indentLevel === 0 && trimmed === "catalogs:") {
|
|
516
|
+
currentSection = "catalogs";
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
if (indentLevel === 0) {
|
|
520
|
+
currentSection = "none";
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
if (currentSection === "catalog" && indentLevel > 0) {
|
|
524
|
+
const colonIndex = trimmed.indexOf(":");
|
|
525
|
+
if (colonIndex > 0) {
|
|
526
|
+
const key = trimmed.slice(0, colonIndex).trim().replace(/["']/g, "");
|
|
527
|
+
const value = trimmed.slice(colonIndex + 1).trim().replace(/["']/g, "");
|
|
528
|
+
if (key && value) defaultCatalog[key] = value;
|
|
529
|
+
}
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
if (currentSection === "catalogs" && indentLevel > 0) {
|
|
533
|
+
if (trimmed.endsWith(":") && !trimmed.includes(" ")) {
|
|
534
|
+
currentCatalogName = trimmed.slice(0, -1).replace(/["']/g, "");
|
|
535
|
+
currentSection = "named-catalog";
|
|
536
|
+
namedCatalogs[currentCatalogName] = {};
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (currentSection === "named-catalog" && indentLevel > 0) {
|
|
541
|
+
if (indentLevel <= 2 && trimmed.endsWith(":") && !trimmed.includes(" ")) {
|
|
542
|
+
currentCatalogName = trimmed.slice(0, -1).replace(/["']/g, "");
|
|
543
|
+
namedCatalogs[currentCatalogName] = {};
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
const colonIndex = trimmed.indexOf(":");
|
|
547
|
+
if (colonIndex > 0 && currentCatalogName) {
|
|
548
|
+
const key = trimmed.slice(0, colonIndex).trim().replace(/["']/g, "");
|
|
549
|
+
const value = trimmed.slice(colonIndex + 1).trim().replace(/["']/g, "");
|
|
550
|
+
if (key && value) namedCatalogs[currentCatalogName][key] = value;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return {
|
|
555
|
+
defaultCatalog,
|
|
556
|
+
namedCatalogs
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
const resolveCatalogVersionFromCollection = (catalogs, packageName, catalogReference) => {
|
|
560
|
+
if (catalogReference) {
|
|
561
|
+
const namedCatalog = catalogs.namedCatalogs[catalogReference];
|
|
562
|
+
if (namedCatalog?.[packageName]) return namedCatalog[packageName];
|
|
563
|
+
}
|
|
564
|
+
if (catalogs.defaultCatalog[packageName]) return catalogs.defaultCatalog[packageName];
|
|
565
|
+
for (const namedCatalog of Object.values(catalogs.namedCatalogs)) if (namedCatalog[packageName]) return namedCatalog[packageName];
|
|
566
|
+
return null;
|
|
567
|
+
};
|
|
568
|
+
const resolveCatalogVersion = (packageJson, packageName, rootDirectory) => {
|
|
569
|
+
const rawVersion = collectAllDependencies(packageJson)[packageName];
|
|
570
|
+
const catalogName = rawVersion ? extractCatalogName(rawVersion) : null;
|
|
478
571
|
const raw = packageJson;
|
|
479
572
|
if (isPlainObject(raw.catalog)) {
|
|
480
573
|
const version = resolveVersionFromCatalog(raw.catalog, packageName);
|
|
481
574
|
if (version) return version;
|
|
482
575
|
}
|
|
483
576
|
if (isPlainObject(raw.catalogs)) {
|
|
577
|
+
if (catalogName && isPlainObject(raw.catalogs[catalogName])) {
|
|
578
|
+
const version = resolveVersionFromCatalog(raw.catalogs[catalogName], packageName);
|
|
579
|
+
if (version) return version;
|
|
580
|
+
}
|
|
484
581
|
for (const catalogEntries of Object.values(raw.catalogs)) if (isPlainObject(catalogEntries)) {
|
|
485
582
|
const version = resolveVersionFromCatalog(catalogEntries, packageName);
|
|
486
583
|
if (version) return version;
|
|
487
584
|
}
|
|
488
585
|
}
|
|
586
|
+
const workspaces = packageJson.workspaces;
|
|
587
|
+
if (workspaces && !Array.isArray(workspaces) && isPlainObject(workspaces.catalog)) {
|
|
588
|
+
const version = resolveVersionFromCatalog(workspaces.catalog, packageName);
|
|
589
|
+
if (version) return version;
|
|
590
|
+
}
|
|
591
|
+
if (rootDirectory) {
|
|
592
|
+
const pnpmVersion = resolveCatalogVersionFromCollection(parsePnpmWorkspaceCatalogs(rootDirectory), packageName, catalogName);
|
|
593
|
+
if (pnpmVersion) return pnpmVersion;
|
|
594
|
+
}
|
|
489
595
|
return null;
|
|
490
596
|
};
|
|
491
597
|
const extractDependencyInfo = (packageJson) => {
|
|
@@ -546,7 +652,7 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
|
546
652
|
};
|
|
547
653
|
const rootPackageJson = readPackageJson(monorepoPackageJsonPath);
|
|
548
654
|
const rootInfo = extractDependencyInfo(rootPackageJson);
|
|
549
|
-
const catalogVersion = resolveCatalogVersion(rootPackageJson, "react");
|
|
655
|
+
const catalogVersion = resolveCatalogVersion(rootPackageJson, "react", monorepoRoot);
|
|
550
656
|
const workspaceInfo = findReactInWorkspaces(monorepoRoot, rootPackageJson);
|
|
551
657
|
return {
|
|
552
658
|
reactVersion: rootInfo.reactVersion ?? catalogVersion ?? workspaceInfo.reactVersion,
|
|
@@ -612,9 +718,17 @@ const discoverReactSubprojects = (rootDirectory) => {
|
|
|
612
718
|
const listWorkspacePackages = (rootDirectory) => {
|
|
613
719
|
const packageJsonPath = path.join(rootDirectory, "package.json");
|
|
614
720
|
if (!isFile(packageJsonPath)) return [];
|
|
615
|
-
const
|
|
721
|
+
const packageJson = readPackageJson(packageJsonPath);
|
|
722
|
+
const patterns = getWorkspacePatterns(rootDirectory, packageJson);
|
|
616
723
|
if (patterns.length === 0) return [];
|
|
617
724
|
const packages = [];
|
|
725
|
+
if (hasReactDependency(packageJson)) {
|
|
726
|
+
const rootName = packageJson.name ?? path.basename(rootDirectory);
|
|
727
|
+
packages.push({
|
|
728
|
+
name: rootName,
|
|
729
|
+
directory: rootDirectory
|
|
730
|
+
});
|
|
731
|
+
}
|
|
618
732
|
for (const pattern of patterns) {
|
|
619
733
|
const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
|
|
620
734
|
for (const workspaceDirectory of directories) {
|
|
@@ -660,7 +774,14 @@ const discoverProject = (directory) => {
|
|
|
660
774
|
if (!isFile(packageJsonPath)) throw new Error(`No package.json found in ${directory}`);
|
|
661
775
|
const packageJson = readPackageJson(packageJsonPath);
|
|
662
776
|
let { reactVersion, framework } = extractDependencyInfo(packageJson);
|
|
663
|
-
if (!reactVersion) reactVersion = resolveCatalogVersion(packageJson, "react");
|
|
777
|
+
if (!reactVersion) reactVersion = resolveCatalogVersion(packageJson, "react", directory);
|
|
778
|
+
if (!reactVersion) {
|
|
779
|
+
const monorepoRoot = findMonorepoRoot(directory);
|
|
780
|
+
if (monorepoRoot) {
|
|
781
|
+
const monorepoPackageJsonPath = path.join(monorepoRoot, "package.json");
|
|
782
|
+
if (isFile(monorepoPackageJsonPath)) reactVersion = resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), "react", monorepoRoot);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
664
785
|
if (!reactVersion || framework === "unknown") {
|
|
665
786
|
const workspaceInfo = findReactInWorkspaces(directory, packageJson);
|
|
666
787
|
if (!reactVersion && workspaceInfo.reactVersion) reactVersion = workspaceInfo.reactVersion;
|
|
@@ -942,6 +1063,49 @@ const resolveNodeForOxlint = () => {
|
|
|
942
1063
|
};
|
|
943
1064
|
};
|
|
944
1065
|
|
|
1066
|
+
//#endregion
|
|
1067
|
+
//#region src/utils/resolve-lint-include-paths.ts
|
|
1068
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
1069
|
+
const result = spawnSync("git", [
|
|
1070
|
+
"ls-files",
|
|
1071
|
+
"--cached",
|
|
1072
|
+
"--others",
|
|
1073
|
+
"--exclude-standard"
|
|
1074
|
+
], {
|
|
1075
|
+
cwd: rootDirectory,
|
|
1076
|
+
encoding: "utf-8",
|
|
1077
|
+
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
1078
|
+
});
|
|
1079
|
+
if (result.error || result.status !== 0) return null;
|
|
1080
|
+
return result.stdout.split("\n").filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath));
|
|
1081
|
+
};
|
|
1082
|
+
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
1083
|
+
const filePaths = [];
|
|
1084
|
+
const stack = [rootDirectory];
|
|
1085
|
+
while (stack.length > 0) {
|
|
1086
|
+
const currentDirectory = stack.pop();
|
|
1087
|
+
const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
|
|
1088
|
+
for (const entry of entries) {
|
|
1089
|
+
const absolutePath = path.join(currentDirectory, entry.name);
|
|
1090
|
+
if (entry.isDirectory()) {
|
|
1091
|
+
if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
if (entry.isFile() && SOURCE_FILE_PATTERN.test(entry.name)) filePaths.push(path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return filePaths;
|
|
1098
|
+
};
|
|
1099
|
+
const listSourceFiles = (rootDirectory) => listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory);
|
|
1100
|
+
const resolveLintIncludePaths = (rootDirectory, userConfig) => {
|
|
1101
|
+
if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
|
|
1102
|
+
const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
|
|
1103
|
+
return listSourceFiles(rootDirectory).filter((filePath) => {
|
|
1104
|
+
if (!JSX_FILE_PATTERN.test(filePath)) return false;
|
|
1105
|
+
return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
|
|
1106
|
+
});
|
|
1107
|
+
};
|
|
1108
|
+
|
|
945
1109
|
//#endregion
|
|
946
1110
|
//#region src/utils/run-knip.ts
|
|
947
1111
|
const KNIP_CATEGORY_MAP = {
|
|
@@ -1200,24 +1364,27 @@ const createOxlintConfig = ({ pluginPath, framework, hasReactCompiler }) => ({
|
|
|
1200
1364
|
|
|
1201
1365
|
//#endregion
|
|
1202
1366
|
//#region src/utils/neutralize-disable-directives.ts
|
|
1203
|
-
const findFilesWithDisableDirectives = (rootDirectory) => {
|
|
1204
|
-
const
|
|
1367
|
+
const findFilesWithDisableDirectives = (rootDirectory, includePaths) => {
|
|
1368
|
+
const grepArgs = [
|
|
1205
1369
|
"grep",
|
|
1206
1370
|
"-l",
|
|
1207
1371
|
"--untracked",
|
|
1208
1372
|
"-E",
|
|
1209
1373
|
"(eslint|oxlint)-disable"
|
|
1210
|
-
]
|
|
1374
|
+
];
|
|
1375
|
+
if (includePaths && includePaths.length > 0) grepArgs.push("--", ...includePaths);
|
|
1376
|
+
const result = spawnSync("git", grepArgs, {
|
|
1211
1377
|
cwd: rootDirectory,
|
|
1212
1378
|
encoding: "utf-8",
|
|
1213
1379
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
1214
1380
|
});
|
|
1215
1381
|
if (result.error || result.status === null) return [];
|
|
1382
|
+
if (result.status !== 0 && result.stdout.trim().length === 0) return [];
|
|
1216
1383
|
return result.stdout.split("\n").filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath));
|
|
1217
1384
|
};
|
|
1218
1385
|
const neutralizeContent = (content) => content.replaceAll("eslint-disable", "eslint_disable").replaceAll("oxlint-disable", "oxlint_disable");
|
|
1219
|
-
const neutralizeDisableDirectives = (rootDirectory) => {
|
|
1220
|
-
const filePaths = findFilesWithDisableDirectives(rootDirectory);
|
|
1386
|
+
const neutralizeDisableDirectives = (rootDirectory, includePaths) => {
|
|
1387
|
+
const filePaths = findFilesWithDisableDirectives(rootDirectory, includePaths);
|
|
1221
1388
|
const originalContents = /* @__PURE__ */ new Map();
|
|
1222
1389
|
for (const relativePath of filePaths) {
|
|
1223
1390
|
const absolutePath = path.join(rootDirectory, relativePath);
|
|
@@ -1493,7 +1660,7 @@ const runOxlint = async (rootDirectory, hasTypeScript, framework, hasReactCompil
|
|
|
1493
1660
|
framework,
|
|
1494
1661
|
hasReactCompiler
|
|
1495
1662
|
});
|
|
1496
|
-
const restoreDisableDirectives = neutralizeDisableDirectives(rootDirectory);
|
|
1663
|
+
const restoreDisableDirectives = neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
1497
1664
|
try {
|
|
1498
1665
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1499
1666
|
const baseArgs = [
|
|
@@ -1780,7 +1947,7 @@ const mergeScanOptions = (inputOptions, userConfig) => ({
|
|
|
1780
1947
|
offline: inputOptions.offline ?? false,
|
|
1781
1948
|
includePaths: inputOptions.includePaths ?? []
|
|
1782
1949
|
});
|
|
1783
|
-
const printProjectDetection = (projectInfo, userConfig, isDiffMode, includePaths) => {
|
|
1950
|
+
const printProjectDetection = (projectInfo, userConfig, isDiffMode, includePaths, lintSourceFileCount) => {
|
|
1784
1951
|
const frameworkLabel = formatFrameworkName(projectInfo.framework);
|
|
1785
1952
|
const languageLabel = projectInfo.hasTypeScript ? "TypeScript" : "JavaScript";
|
|
1786
1953
|
const completeStep = (message) => {
|
|
@@ -1791,7 +1958,7 @@ const printProjectDetection = (projectInfo, userConfig, isDiffMode, includePaths
|
|
|
1791
1958
|
completeStep(`Detecting language. Found ${highlighter.info(languageLabel)}.`);
|
|
1792
1959
|
completeStep(`Detecting React Compiler. ${projectInfo.hasReactCompiler ? highlighter.info("Found React Compiler.") : "Not found."}`);
|
|
1793
1960
|
if (isDiffMode) completeStep(`Scanning ${highlighter.info(`${includePaths.length}`)} changed source files.`);
|
|
1794
|
-
else completeStep(`Found ${highlighter.info(`${projectInfo.sourceFileCount}`)} source files.`);
|
|
1961
|
+
else completeStep(`Found ${highlighter.info(`${lintSourceFileCount ?? projectInfo.sourceFileCount}`)} source files.`);
|
|
1795
1962
|
if (userConfig) completeStep(`Loaded ${highlighter.info("react-doctor config")}.`);
|
|
1796
1963
|
logger.break();
|
|
1797
1964
|
};
|
|
@@ -1803,8 +1970,9 @@ const scan = async (directory, inputOptions = {}) => {
|
|
|
1803
1970
|
const { includePaths } = options;
|
|
1804
1971
|
const isDiffMode = includePaths.length > 0;
|
|
1805
1972
|
if (!projectInfo.reactVersion) throw new Error("No React dependency found in package.json");
|
|
1806
|
-
|
|
1807
|
-
const
|
|
1973
|
+
const lintIncludePaths = computeJsxIncludePaths(includePaths) ?? resolveLintIncludePaths(directory, userConfig);
|
|
1974
|
+
const lintSourceFileCount = lintIncludePaths?.length ?? projectInfo.sourceFileCount;
|
|
1975
|
+
if (!options.scoreOnly) printProjectDetection(projectInfo, userConfig, isDiffMode, includePaths, lintSourceFileCount);
|
|
1808
1976
|
let didLintFail = false;
|
|
1809
1977
|
let didDeadCodeFail = false;
|
|
1810
1978
|
const resolvedNodeBinaryPath = await resolveOxlintNode(options.lint, options.scoreOnly);
|
|
@@ -1812,7 +1980,7 @@ const scan = async (directory, inputOptions = {}) => {
|
|
|
1812
1980
|
const lintPromise = resolvedNodeBinaryPath ? (async () => {
|
|
1813
1981
|
const lintSpinner = options.scoreOnly ? null : spinner("Running lint checks...").start();
|
|
1814
1982
|
try {
|
|
1815
|
-
const lintDiagnostics = await runOxlint(directory, projectInfo.hasTypeScript, projectInfo.framework, projectInfo.hasReactCompiler,
|
|
1983
|
+
const lintDiagnostics = await runOxlint(directory, projectInfo.hasTypeScript, projectInfo.framework, projectInfo.hasReactCompiler, lintIncludePaths, resolvedNodeBinaryPath);
|
|
1816
1984
|
lintSpinner?.succeed("Running lint checks.");
|
|
1817
1985
|
return lintDiagnostics;
|
|
1818
1986
|
} catch (error) {
|
|
@@ -1883,7 +2051,7 @@ const scan = async (directory, inputOptions = {}) => {
|
|
|
1883
2051
|
};
|
|
1884
2052
|
}
|
|
1885
2053
|
printDiagnostics(diagnostics, options.verbose);
|
|
1886
|
-
const displayedSourceFileCount = isDiffMode ? includePaths.length :
|
|
2054
|
+
const displayedSourceFileCount = isDiffMode ? includePaths.length : lintSourceFileCount;
|
|
1887
2055
|
printSummary(diagnostics, elapsedMilliseconds, scoreResult, projectInfo.projectName, displayedSourceFileCount, noScoreMessage, options.offline);
|
|
1888
2056
|
if (hasSkippedChecks) {
|
|
1889
2057
|
const skippedLabel = skippedChecks.join(" and ");
|
|
@@ -2211,7 +2379,7 @@ const maybePromptSkillInstall = async (shouldSkipPrompts) => {
|
|
|
2211
2379
|
|
|
2212
2380
|
//#endregion
|
|
2213
2381
|
//#region src/cli.ts
|
|
2214
|
-
const VERSION = "0.0.
|
|
2382
|
+
const VERSION = "0.0.32";
|
|
2215
2383
|
const VALID_FAIL_ON_LEVELS = new Set([
|
|
2216
2384
|
"error",
|
|
2217
2385
|
"warning",
|
|
@@ -2264,7 +2432,7 @@ const resolveDiffMode = async (diffInfo, effectiveDiff, shouldSkipPrompts, isSco
|
|
|
2264
2432
|
if (effectiveDiff === false || !diffInfo) return false;
|
|
2265
2433
|
const changedSourceFiles = filterSourceFiles(diffInfo.changedFiles);
|
|
2266
2434
|
if (changedSourceFiles.length === 0) return false;
|
|
2267
|
-
if (shouldSkipPrompts) return
|
|
2435
|
+
if (shouldSkipPrompts) return false;
|
|
2268
2436
|
if (isScoreOnly) return false;
|
|
2269
2437
|
const { shouldScanChangedOnly } = await prompts({
|
|
2270
2438
|
type: "confirm",
|