react-doctor 0.1.5 → 0.1.6

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 CHANGED
@@ -39,10 +39,18 @@ const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
39
39
  const OXLINT_NODE_REQUIREMENT = "^20.19.0 || >=22.12.0";
40
40
  const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
41
41
  const IGNORED_DIRECTORIES = new Set([
42
- "node_modules",
43
- "dist",
42
+ ".git",
43
+ ".next",
44
+ ".nuxt",
45
+ ".output",
46
+ ".svelte-kit",
47
+ ".turbo",
44
48
  "build",
45
- "coverage"
49
+ "coverage",
50
+ "dist",
51
+ "node_modules",
52
+ "out",
53
+ "storybook-static"
46
54
  ]);
47
55
  const CANONICAL_GITHUB_URL = "https://github.com/millionco/react-doctor";
48
56
  const SKILL_NAME = "react-doctor";
@@ -1455,36 +1463,58 @@ const hasReactDependency = (packageJson) => {
1455
1463
  const allDependencies = collectAllDependencies(packageJson);
1456
1464
  return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
1457
1465
  };
1458
- const discoverReactSubprojects = (rootDirectory) => {
1459
- if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];
1466
+ const toReactWorkspacePackages = (directories) => {
1460
1467
  const packages = [];
1461
- const rootPackageJsonPath = path.join(rootDirectory, "package.json");
1462
- if (isFile(rootPackageJsonPath)) {
1463
- const rootPackageJson = readPackageJson(rootPackageJsonPath);
1464
- if (hasReactDependency(rootPackageJson)) {
1465
- const name = rootPackageJson.name ?? path.basename(rootDirectory);
1466
- packages.push({
1467
- name,
1468
- directory: rootDirectory
1469
- });
1470
- }
1471
- }
1472
- const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });
1473
- for (const entry of entries) {
1474
- if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") continue;
1475
- const subdirectory = path.join(rootDirectory, entry.name);
1476
- const packageJsonPath = path.join(subdirectory, "package.json");
1468
+ for (const directory of directories) {
1469
+ const packageJsonPath = path.join(directory, "package.json");
1477
1470
  if (!isFile(packageJsonPath)) continue;
1478
1471
  const packageJson = readPackageJson(packageJsonPath);
1479
1472
  if (!hasReactDependency(packageJson)) continue;
1480
- const name = packageJson.name ?? entry.name;
1473
+ const name = packageJson.name ?? path.basename(directory);
1481
1474
  packages.push({
1482
1475
  name,
1483
- directory: subdirectory
1476
+ directory
1484
1477
  });
1485
1478
  }
1486
1479
  return packages;
1487
1480
  };
1481
+ const listManifestWorkspacePackages = (rootDirectory) => {
1482
+ if (isFile(path.join(rootDirectory, "package.json"))) return listWorkspacePackages(rootDirectory);
1483
+ const patterns = parsePnpmWorkspacePatterns(rootDirectory);
1484
+ const nxPatterns = patterns.length > 0 ? [] : getNxWorkspaceDirectories(rootDirectory);
1485
+ return toReactWorkspacePackages((patterns.length > 0 ? patterns : nxPatterns).flatMap((pattern) => resolveWorkspaceDirectories(rootDirectory, pattern)));
1486
+ };
1487
+ const discoverReactSubprojectsByFilesystem = (rootDirectory) => {
1488
+ const packages = [];
1489
+ const pendingDirectories = [rootDirectory];
1490
+ while (pendingDirectories.length > 0) {
1491
+ const currentDirectory = pendingDirectories.shift();
1492
+ if (!currentDirectory) continue;
1493
+ const packageJsonPath = path.join(currentDirectory, "package.json");
1494
+ if (isFile(packageJsonPath)) {
1495
+ const packageJson = readPackageJson(packageJsonPath);
1496
+ if (hasReactDependency(packageJson)) {
1497
+ const name = packageJson.name ?? path.basename(currentDirectory);
1498
+ packages.push({
1499
+ name,
1500
+ directory: currentDirectory
1501
+ });
1502
+ }
1503
+ }
1504
+ const entries = fs.readdirSync(currentDirectory, { withFileTypes: true }).toSorted((firstEntry, secondEntry) => firstEntry.name.localeCompare(secondEntry.name));
1505
+ for (const entry of entries) {
1506
+ if (!entry.isDirectory() || entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
1507
+ pendingDirectories.push(path.join(currentDirectory, entry.name));
1508
+ }
1509
+ }
1510
+ return packages;
1511
+ };
1512
+ const discoverReactSubprojects = (rootDirectory) => {
1513
+ if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];
1514
+ const manifestPackages = listManifestWorkspacePackages(rootDirectory);
1515
+ if (manifestPackages.length > 0) return manifestPackages;
1516
+ return discoverReactSubprojectsByFilesystem(rootDirectory);
1517
+ };
1488
1518
  const listWorkspacePackages = (rootDirectory) => {
1489
1519
  const packageJsonPath = path.join(rootDirectory, "package.json");
1490
1520
  if (!isFile(packageJsonPath)) return [];
@@ -4252,7 +4282,7 @@ const promptProjectSelection = async (workspacePackages, rootDirectory) => {
4252
4282
  };
4253
4283
  //#endregion
4254
4284
  //#region src/cli.ts
4255
- const VERSION = "0.1.5";
4285
+ const VERSION = "0.1.6";
4256
4286
  const VALID_FAIL_ON_LEVELS = new Set([
4257
4287
  "error",
4258
4288
  "warning",
@@ -6946,7 +6946,7 @@ const ALL_RULES_AT_RECOMMENDED_SEVERITY = {
6946
6946
  const eslintPlugin = {
6947
6947
  meta: {
6948
6948
  name: PLUGIN_NAMESPACE,
6949
- version: "0.1.5"
6949
+ version: "0.1.6"
6950
6950
  },
6951
6951
  rules: eslintShapedRules,
6952
6952
  configs: {
package/dist/index.js CHANGED
@@ -28,10 +28,18 @@ const KNIP_CONFIG_LOCATIONS = [
28
28
  ];
29
29
  const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
30
30
  const IGNORED_DIRECTORIES = new Set([
31
- "node_modules",
32
- "dist",
31
+ ".git",
32
+ ".next",
33
+ ".nuxt",
34
+ ".output",
35
+ ".svelte-kit",
36
+ ".turbo",
33
37
  "build",
34
- "coverage"
38
+ "coverage",
39
+ "dist",
40
+ "node_modules",
41
+ "out",
42
+ "storybook-static"
35
43
  ]);
36
44
  const PROXY_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
37
45
  const buildNoReactDependencyError = (directory) => `No React dependency found in ${directory}/package.json. Add "react" to dependencies (or peerDependencies) and re-run.`;
@@ -969,36 +977,86 @@ const hasReactDependency = (packageJson) => {
969
977
  const allDependencies = collectAllDependencies(packageJson);
970
978
  return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
971
979
  };
972
- const discoverReactSubprojects = (rootDirectory) => {
973
- if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];
980
+ const toReactWorkspacePackages = (directories) => {
974
981
  const packages = [];
975
- const rootPackageJsonPath = path.join(rootDirectory, "package.json");
976
- if (isFile(rootPackageJsonPath)) {
977
- const rootPackageJson = readPackageJson(rootPackageJsonPath);
978
- if (hasReactDependency(rootPackageJson)) {
979
- const name = rootPackageJson.name ?? path.basename(rootDirectory);
980
- packages.push({
981
- name,
982
- directory: rootDirectory
983
- });
984
- }
985
- }
986
- const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });
987
- for (const entry of entries) {
988
- if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") continue;
989
- const subdirectory = path.join(rootDirectory, entry.name);
990
- const packageJsonPath = path.join(subdirectory, "package.json");
982
+ for (const directory of directories) {
983
+ const packageJsonPath = path.join(directory, "package.json");
991
984
  if (!isFile(packageJsonPath)) continue;
992
985
  const packageJson = readPackageJson(packageJsonPath);
993
986
  if (!hasReactDependency(packageJson)) continue;
994
- const name = packageJson.name ?? entry.name;
987
+ const name = packageJson.name ?? path.basename(directory);
995
988
  packages.push({
996
989
  name,
997
- directory: subdirectory
990
+ directory
998
991
  });
999
992
  }
1000
993
  return packages;
1001
994
  };
995
+ const listManifestWorkspacePackages = (rootDirectory) => {
996
+ if (isFile(path.join(rootDirectory, "package.json"))) return listWorkspacePackages(rootDirectory);
997
+ const patterns = parsePnpmWorkspacePatterns(rootDirectory);
998
+ const nxPatterns = patterns.length > 0 ? [] : getNxWorkspaceDirectories(rootDirectory);
999
+ return toReactWorkspacePackages((patterns.length > 0 ? patterns : nxPatterns).flatMap((pattern) => resolveWorkspaceDirectories(rootDirectory, pattern)));
1000
+ };
1001
+ const discoverReactSubprojectsByFilesystem = (rootDirectory) => {
1002
+ const packages = [];
1003
+ const pendingDirectories = [rootDirectory];
1004
+ while (pendingDirectories.length > 0) {
1005
+ const currentDirectory = pendingDirectories.shift();
1006
+ if (!currentDirectory) continue;
1007
+ const packageJsonPath = path.join(currentDirectory, "package.json");
1008
+ if (isFile(packageJsonPath)) {
1009
+ const packageJson = readPackageJson(packageJsonPath);
1010
+ if (hasReactDependency(packageJson)) {
1011
+ const name = packageJson.name ?? path.basename(currentDirectory);
1012
+ packages.push({
1013
+ name,
1014
+ directory: currentDirectory
1015
+ });
1016
+ }
1017
+ }
1018
+ const entries = fs.readdirSync(currentDirectory, { withFileTypes: true }).toSorted((firstEntry, secondEntry) => firstEntry.name.localeCompare(secondEntry.name));
1019
+ for (const entry of entries) {
1020
+ if (!entry.isDirectory() || entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
1021
+ pendingDirectories.push(path.join(currentDirectory, entry.name));
1022
+ }
1023
+ }
1024
+ return packages;
1025
+ };
1026
+ const discoverReactSubprojects = (rootDirectory) => {
1027
+ if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];
1028
+ const manifestPackages = listManifestWorkspacePackages(rootDirectory);
1029
+ if (manifestPackages.length > 0) return manifestPackages;
1030
+ return discoverReactSubprojectsByFilesystem(rootDirectory);
1031
+ };
1032
+ const listWorkspacePackages = (rootDirectory) => {
1033
+ const packageJsonPath = path.join(rootDirectory, "package.json");
1034
+ if (!isFile(packageJsonPath)) return [];
1035
+ const packageJson = readPackageJson(packageJsonPath);
1036
+ const patterns = getWorkspacePatterns(rootDirectory, packageJson);
1037
+ if (patterns.length === 0) return [];
1038
+ const packages = [];
1039
+ if (hasReactDependency(packageJson)) {
1040
+ const rootName = packageJson.name ?? path.basename(rootDirectory);
1041
+ packages.push({
1042
+ name: rootName,
1043
+ directory: rootDirectory
1044
+ });
1045
+ }
1046
+ for (const pattern of patterns) {
1047
+ const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
1048
+ for (const workspaceDirectory of directories) {
1049
+ const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, "package.json"));
1050
+ if (!hasReactDependency(workspacePackageJson)) continue;
1051
+ const name = workspacePackageJson.name ?? path.basename(workspaceDirectory);
1052
+ packages.push({
1053
+ name,
1054
+ directory: workspaceDirectory
1055
+ });
1056
+ }
1057
+ }
1058
+ return packages;
1059
+ };
1002
1060
  const hasCompilerPackage = (packageJson) => {
1003
1061
  const allDependencies = collectAllDependencies(packageJson);
1004
1062
  return Object.keys(allDependencies).some((packageName) => REACT_COMPILER_PACKAGES.has(packageName));
@@ -1660,7 +1718,7 @@ const resolveDiagnoseTarget = (directory) => {
1660
1718
  const reactSubprojects = discoverReactSubprojects(directory);
1661
1719
  if (reactSubprojects.length === 0) return null;
1662
1720
  if (reactSubprojects.length === 1) return reactSubprojects[0].directory;
1663
- throw new AmbiguousProjectError(directory, reactSubprojects.map((subproject) => path.relative(directory, subproject.directory)));
1721
+ throw new AmbiguousProjectError(directory, reactSubprojects.map((subproject) => path.relative(directory, subproject.directory)).toSorted());
1664
1722
  };
1665
1723
  //#endregion
1666
1724
  //#region src/utils/resolve-lint-include-paths.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Diagnose and fix React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
5
5
  "keywords": [
6
6
  "accessibility",