react-doctor 0.2.0-beta.6 → 0.2.1

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 CHANGED
@@ -447,16 +447,16 @@ Top React codebases scanned by React Doctor, ranked by score. Updated automatica
447
447
  <!-- prettier-ignore -->
448
448
  | # | Repo | Score |
449
449
  | -- | ---- | ----: |
450
- | 1 | [executor](https://github.com/RhysSullivan/executor) | 94 |
450
+ | 1 | [executor](https://github.com/RhysSullivan/executor) | 96 |
451
451
  | 2 | [nodejs.org](https://github.com/nodejs/nodejs.org) | 86 |
452
- | 3 | [tldraw](https://github.com/tldraw/tldraw) | 70 |
453
- | 4 | [t3code](https://github.com/pingdotgg/t3code) | 68 |
452
+ | 3 | [tldraw](https://github.com/tldraw/tldraw) | 71 |
453
+ | 4 | [t3code](https://github.com/pingdotgg/t3code) | 69 |
454
454
  | 5 | [better-auth](https://github.com/better-auth/better-auth) | 64 |
455
- | 6 | [excalidraw](https://github.com/excalidraw/excalidraw) | 63 |
456
- | 7 | [mastra](https://github.com/mastra-ai/mastra) | 63 |
455
+ | 6 | [mastra](https://github.com/mastra-ai/mastra) | 63 |
456
+ | 7 | [excalidraw](https://github.com/excalidraw/excalidraw) | 62 |
457
457
  | 8 | [payload](https://github.com/payloadcms/payload) | 60 |
458
458
  | 9 | [typebot](https://github.com/baptisteArno/typebot.io) | 57 |
459
- | 10 | [plane](https://github.com/makeplane/plane) | 56 |
459
+ | 10 | [medusajs/admin](https://github.com/medusajs/medusa) | 56 |
460
460
 
461
461
  <!-- LEADERBOARD:END -->
462
462
 
package/dist/cli.js CHANGED
@@ -34,7 +34,6 @@ var __toESM$1 = (mod, isNodeMode, target) => (target = mod != null ? __create$1(
34
34
  value: mod,
35
35
  enumerable: true
36
36
  }) : target, mod));
37
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
38
37
  //#endregion
39
38
  //#region ../types/dist/index.js
40
39
  const REACT_NATIVE_DEPENDENCY_NAMES = new Set([
@@ -102,12 +101,31 @@ const IGNORED_DIRECTORIES = new Set([
102
101
  "out",
103
102
  "storybook-static"
104
103
  ]);
104
+ const IGNORABLE_READDIR_ERROR_CODES = new Set([
105
+ "EACCES",
106
+ "EPERM",
107
+ "ENOENT",
108
+ "ENOTDIR"
109
+ ]);
110
+ const isIgnorableReaddirError = (error) => {
111
+ if (typeof error !== "object" || error === null) return false;
112
+ const errorCode = error.code;
113
+ return typeof errorCode === "string" && IGNORABLE_READDIR_ERROR_CODES.has(errorCode);
114
+ };
115
+ const readDirectoryEntries = (directoryPath) => {
116
+ try {
117
+ return fs.readdirSync(directoryPath, { withFileTypes: true });
118
+ } catch (error) {
119
+ if (isIgnorableReaddirError(error)) return [];
120
+ throw error;
121
+ }
122
+ };
105
123
  const countSourceFilesViaFilesystem = (rootDirectory) => {
106
124
  let count = 0;
107
125
  const stack = [rootDirectory];
108
126
  while (stack.length > 0) {
109
127
  const currentDirectory = stack.pop();
110
- const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
128
+ const entries = readDirectoryEntries(currentDirectory);
111
129
  for (const entry of entries) {
112
130
  if (entry.isDirectory()) {
113
131
  if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(path.join(currentDirectory, entry.name));
@@ -142,7 +160,7 @@ const readPackageJsonUncached = (packageJsonPath) => {
142
160
  if (error instanceof SyntaxError) return {};
143
161
  if (error instanceof Error && "code" in error) {
144
162
  const { code } = error;
145
- if (code === "EISDIR" || code === "EACCES") return {};
163
+ if (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "ENOENT") return {};
146
164
  }
147
165
  throw error;
148
166
  }
@@ -513,6 +531,13 @@ const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
513
531
  version: null
514
532
  };
515
533
  };
534
+ const isDirectory = (directoryPath) => {
535
+ try {
536
+ return fs.statSync(directoryPath).isDirectory();
537
+ } catch {
538
+ return false;
539
+ }
540
+ };
516
541
  const NX_PROJECT_DISCOVERY_DIRS = [
517
542
  "apps",
518
543
  "libs",
@@ -523,8 +548,8 @@ const getNxWorkspaceDirectories = (rootDirectory) => {
523
548
  const collected = [];
524
549
  for (const candidate of NX_PROJECT_DISCOVERY_DIRS) {
525
550
  const candidatePath = path.join(rootDirectory, candidate);
526
- if (!fs.existsSync(candidatePath) || !fs.statSync(candidatePath).isDirectory()) continue;
527
- for (const entry of fs.readdirSync(candidatePath, { withFileTypes: true })) {
551
+ if (!isDirectory(candidatePath)) continue;
552
+ for (const entry of readDirectoryEntries(candidatePath)) {
528
553
  if (!entry.isDirectory()) continue;
529
554
  const projectDirectory = path.join(candidatePath, entry.name);
530
555
  if (isFile(path.join(projectDirectory, "project.json")) || isFile(path.join(projectDirectory, "package.json"))) collected.push(`${candidate}/${entry.name}`);
@@ -566,17 +591,17 @@ const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
566
591
  const cleanPattern = pattern.replace(/["']/g, "").replace(/\/\*\*$/, "/*");
567
592
  if (!cleanPattern.includes("*")) {
568
593
  const directoryPath = path.join(rootDirectory, cleanPattern);
569
- if (fs.existsSync(directoryPath) && isFile(path.join(directoryPath, "package.json"))) return [directoryPath];
594
+ if (isDirectory(directoryPath) && isFile(path.join(directoryPath, "package.json"))) return [directoryPath];
570
595
  return [];
571
596
  }
572
597
  const wildcardIndex = cleanPattern.indexOf("*");
573
598
  const baseDirectory = path.join(rootDirectory, cleanPattern.slice(0, wildcardIndex));
574
599
  const suffixAfterWildcard = cleanPattern.slice(wildcardIndex + 1);
575
- if (!fs.existsSync(baseDirectory) || !fs.statSync(baseDirectory).isDirectory()) return [];
600
+ if (!isDirectory(baseDirectory)) return [];
576
601
  const resolved = [];
577
- for (const entry of fs.readdirSync(baseDirectory)) {
578
- const entryPath = path.join(baseDirectory, entry, suffixAfterWildcard);
579
- if (fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory() && isFile(path.join(entryPath, "package.json"))) resolved.push(entryPath);
602
+ for (const entry of readDirectoryEntries(baseDirectory)) {
603
+ const entryPath = path.join(baseDirectory, entry.name, suffixAfterWildcard);
604
+ if (isDirectory(entryPath) && isFile(path.join(entryPath, "package.json"))) resolved.push(entryPath);
580
605
  }
581
606
  return resolved;
582
607
  };
@@ -821,7 +846,7 @@ const discoverReactSubprojectsByFilesystem = (rootDirectory) => {
821
846
  });
822
847
  }
823
848
  }
824
- const entries = fs.readdirSync(currentDirectory, { withFileTypes: true }).toSorted((firstEntry, secondEntry) => firstEntry.name.localeCompare(secondEntry.name));
849
+ const entries = readDirectoryEntries(currentDirectory).toSorted((firstEntry, secondEntry) => firstEntry.name.localeCompare(secondEntry.name));
825
850
  for (const entry of entries) {
826
851
  if (!entry.isDirectory() || entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
827
852
  pendingDirectories.push(path.join(currentDirectory, entry.name));
@@ -830,7 +855,7 @@ const discoverReactSubprojectsByFilesystem = (rootDirectory) => {
830
855
  return packages;
831
856
  };
832
857
  const discoverReactSubprojects = (rootDirectory) => {
833
- if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];
858
+ if (!isDirectory(rootDirectory)) return [];
834
859
  const manifestPackages = listManifestWorkspacePackages(rootDirectory);
835
860
  if (manifestPackages.length > 0) return manifestPackages;
836
861
  return discoverReactSubprojectsByFilesystem(rootDirectory);
@@ -938,11 +963,11 @@ const isTailwindAtLeast = (detected, required) => {
938
963
  return detected.minor >= required.minor;
939
964
  };
940
965
  //#endregion
941
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/constants.js
966
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js
942
967
  var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
943
- const path$3 = __require("path");
944
968
  const WIN_SLASH = "\\\\/";
945
969
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
970
+ const DEFAULT_MAX_EXTGLOB_RECURSION = 0;
946
971
  /**
947
972
  * Posix glob regex
948
973
  */
@@ -970,7 +995,8 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
970
995
  NO_DOTS_SLASH: `(?!${DOTS_SLASH})`,
971
996
  QMARK_NO_DOT: `[^.${SLASH_LITERAL}]`,
972
997
  STAR: `${QMARK}*?`,
973
- START_ANCHOR
998
+ START_ANCHOR,
999
+ SEP: "/"
974
1000
  };
975
1001
  /**
976
1002
  * Windows glob regex
@@ -987,11 +1013,14 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
987
1013
  NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
988
1014
  QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
989
1015
  START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
990
- END_ANCHOR: `(?:[${WIN_SLASH}]|$)`
1016
+ END_ANCHOR: `(?:[${WIN_SLASH}]|$)`,
1017
+ SEP: "\\"
991
1018
  };
992
1019
  module.exports = {
1020
+ DEFAULT_MAX_EXTGLOB_RECURSION,
993
1021
  MAX_LENGTH: 1024 * 64,
994
1022
  POSIX_REGEX_SOURCE: {
1023
+ __proto__: null,
995
1024
  alnum: "a-zA-Z0-9",
996
1025
  alpha: "a-zA-Z",
997
1026
  ascii: "\\x00-\\x7F",
@@ -1014,6 +1043,7 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1014
1043
  REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g,
1015
1044
  REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g,
1016
1045
  REPLACEMENTS: {
1046
+ __proto__: null,
1017
1047
  "***": "*",
1018
1048
  "**/**": "**",
1019
1049
  "**/**/**": "**"
@@ -1061,7 +1091,6 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1061
1091
  CHAR_UNDERSCORE: 95,
1062
1092
  CHAR_VERTICAL_LINE: 124,
1063
1093
  CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279,
1064
- SEP: path$3.sep,
1065
1094
  /**
1066
1095
  * Create EXTGLOB_CHARS
1067
1096
  */
@@ -1103,30 +1132,27 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1103
1132
  };
1104
1133
  }));
1105
1134
  //#endregion
1106
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/utils.js
1135
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js
1107
1136
  var require_utils = /* @__PURE__ */ __commonJSMin$1(((exports) => {
1108
- const path$2 = __require("path");
1109
- const win32 = process.platform === "win32";
1110
1137
  const { REGEX_BACKSLASH, REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL } = require_constants();
1111
1138
  exports.isObject = (val) => val !== null && typeof val === "object" && !Array.isArray(val);
1112
1139
  exports.hasRegexChars = (str) => REGEX_SPECIAL_CHARS.test(str);
1113
1140
  exports.isRegexChar = (str) => str.length === 1 && exports.hasRegexChars(str);
1114
1141
  exports.escapeRegex = (str) => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, "\\$1");
1115
1142
  exports.toPosixSlashes = (str) => str.replace(REGEX_BACKSLASH, "/");
1143
+ exports.isWindows = () => {
1144
+ if (typeof navigator !== "undefined" && navigator.platform) {
1145
+ const platform = navigator.platform.toLowerCase();
1146
+ return platform === "win32" || platform === "windows";
1147
+ }
1148
+ if (typeof process !== "undefined" && process.platform) return process.platform === "win32";
1149
+ return false;
1150
+ };
1116
1151
  exports.removeBackslashes = (str) => {
1117
1152
  return str.replace(REGEX_REMOVE_BACKSLASH, (match) => {
1118
1153
  return match === "\\" ? "" : match;
1119
1154
  });
1120
1155
  };
1121
- exports.supportsLookbehinds = () => {
1122
- const segs = process.version.slice(1).split(".").map(Number);
1123
- if (segs.length === 3 && segs[0] >= 9 || segs[0] === 8 && segs[1] >= 10) return true;
1124
- return false;
1125
- };
1126
- exports.isWindows = (options) => {
1127
- if (options && typeof options.windows === "boolean") return options.windows;
1128
- return win32 === true || path$2.sep === "\\";
1129
- };
1130
1156
  exports.escapeLast = (input, char, lastIdx) => {
1131
1157
  const idx = input.lastIndexOf(char, lastIdx);
1132
1158
  if (idx === -1) return input;
@@ -1146,9 +1172,15 @@ var require_utils = /* @__PURE__ */ __commonJSMin$1(((exports) => {
1146
1172
  if (state.negated === true) output = `(?:^(?!${output}).*$)`;
1147
1173
  return output;
1148
1174
  };
1175
+ exports.basename = (path, { windows } = {}) => {
1176
+ const segs = path.split(windows ? /[\\/]/ : "/");
1177
+ const last = segs[segs.length - 1];
1178
+ if (last === "") return segs[segs.length - 2];
1179
+ return last;
1180
+ };
1149
1181
  }));
1150
1182
  //#endregion
1151
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/scan.js
1183
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/scan.js
1152
1184
  var require_scan = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1153
1185
  const utils = require_utils();
1154
1186
  const { CHAR_ASTERISK, CHAR_AT, CHAR_BACKWARD_SLASH, CHAR_COMMA, CHAR_DOT, CHAR_EXCLAMATION_MARK, CHAR_FORWARD_SLASH, CHAR_LEFT_CURLY_BRACE, CHAR_LEFT_PARENTHESES, CHAR_LEFT_SQUARE_BRACKET, CHAR_PLUS, CHAR_QUESTION_MARK, CHAR_RIGHT_CURLY_BRACE, CHAR_RIGHT_PARENTHESES, CHAR_RIGHT_SQUARE_BRACKET } = require_constants();
@@ -1435,7 +1467,7 @@ var require_scan = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1435
1467
  module.exports = scan;
1436
1468
  }));
1437
1469
  //#endregion
1438
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/parse.js
1470
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/parse.js
1439
1471
  var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1440
1472
  const constants = require_constants();
1441
1473
  const utils = require_utils();
@@ -1463,6 +1495,177 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1463
1495
  const syntaxError = (type, char) => {
1464
1496
  return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
1465
1497
  };
1498
+ const splitTopLevel = (input) => {
1499
+ const parts = [];
1500
+ let bracket = 0;
1501
+ let paren = 0;
1502
+ let quote = 0;
1503
+ let value = "";
1504
+ let escaped = false;
1505
+ for (const ch of input) {
1506
+ if (escaped === true) {
1507
+ value += ch;
1508
+ escaped = false;
1509
+ continue;
1510
+ }
1511
+ if (ch === "\\") {
1512
+ value += ch;
1513
+ escaped = true;
1514
+ continue;
1515
+ }
1516
+ if (ch === "\"") {
1517
+ quote = quote === 1 ? 0 : 1;
1518
+ value += ch;
1519
+ continue;
1520
+ }
1521
+ if (quote === 0) {
1522
+ if (ch === "[") bracket++;
1523
+ else if (ch === "]" && bracket > 0) bracket--;
1524
+ else if (bracket === 0) {
1525
+ if (ch === "(") paren++;
1526
+ else if (ch === ")" && paren > 0) paren--;
1527
+ else if (ch === "|" && paren === 0) {
1528
+ parts.push(value);
1529
+ value = "";
1530
+ continue;
1531
+ }
1532
+ }
1533
+ }
1534
+ value += ch;
1535
+ }
1536
+ parts.push(value);
1537
+ return parts;
1538
+ };
1539
+ const isPlainBranch = (branch) => {
1540
+ let escaped = false;
1541
+ for (const ch of branch) {
1542
+ if (escaped === true) {
1543
+ escaped = false;
1544
+ continue;
1545
+ }
1546
+ if (ch === "\\") {
1547
+ escaped = true;
1548
+ continue;
1549
+ }
1550
+ if (/[?*+@!()[\]{}]/.test(ch)) return false;
1551
+ }
1552
+ return true;
1553
+ };
1554
+ const normalizeSimpleBranch = (branch) => {
1555
+ let value = branch.trim();
1556
+ let changed = true;
1557
+ while (changed === true) {
1558
+ changed = false;
1559
+ if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
1560
+ value = value.slice(2, -1);
1561
+ changed = true;
1562
+ }
1563
+ }
1564
+ if (!isPlainBranch(value)) return;
1565
+ return value.replace(/\\(.)/g, "$1");
1566
+ };
1567
+ const hasRepeatedCharPrefixOverlap = (branches) => {
1568
+ const values = branches.map(normalizeSimpleBranch).filter(Boolean);
1569
+ for (let i = 0; i < values.length; i++) for (let j = i + 1; j < values.length; j++) {
1570
+ const a = values[i];
1571
+ const b = values[j];
1572
+ const char = a[0];
1573
+ if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) continue;
1574
+ if (a === b || a.startsWith(b) || b.startsWith(a)) return true;
1575
+ }
1576
+ return false;
1577
+ };
1578
+ const parseRepeatedExtglob = (pattern, requireEnd = true) => {
1579
+ if (pattern[0] !== "+" && pattern[0] !== "*" || pattern[1] !== "(") return;
1580
+ let bracket = 0;
1581
+ let paren = 0;
1582
+ let quote = 0;
1583
+ let escaped = false;
1584
+ for (let i = 1; i < pattern.length; i++) {
1585
+ const ch = pattern[i];
1586
+ if (escaped === true) {
1587
+ escaped = false;
1588
+ continue;
1589
+ }
1590
+ if (ch === "\\") {
1591
+ escaped = true;
1592
+ continue;
1593
+ }
1594
+ if (ch === "\"") {
1595
+ quote = quote === 1 ? 0 : 1;
1596
+ continue;
1597
+ }
1598
+ if (quote === 1) continue;
1599
+ if (ch === "[") {
1600
+ bracket++;
1601
+ continue;
1602
+ }
1603
+ if (ch === "]" && bracket > 0) {
1604
+ bracket--;
1605
+ continue;
1606
+ }
1607
+ if (bracket > 0) continue;
1608
+ if (ch === "(") {
1609
+ paren++;
1610
+ continue;
1611
+ }
1612
+ if (ch === ")") {
1613
+ paren--;
1614
+ if (paren === 0) {
1615
+ if (requireEnd === true && i !== pattern.length - 1) return;
1616
+ return {
1617
+ type: pattern[0],
1618
+ body: pattern.slice(2, i),
1619
+ end: i
1620
+ };
1621
+ }
1622
+ }
1623
+ }
1624
+ };
1625
+ const getStarExtglobSequenceOutput = (pattern) => {
1626
+ let index = 0;
1627
+ const chars = [];
1628
+ while (index < pattern.length) {
1629
+ const match = parseRepeatedExtglob(pattern.slice(index), false);
1630
+ if (!match || match.type !== "*") return;
1631
+ const branches = splitTopLevel(match.body).map((branch) => branch.trim());
1632
+ if (branches.length !== 1) return;
1633
+ const branch = normalizeSimpleBranch(branches[0]);
1634
+ if (!branch || branch.length !== 1) return;
1635
+ chars.push(branch);
1636
+ index += match.end + 1;
1637
+ }
1638
+ if (chars.length < 1) return;
1639
+ return `${chars.length === 1 ? utils.escapeRegex(chars[0]) : `[${chars.map((ch) => utils.escapeRegex(ch)).join("")}]`}*`;
1640
+ };
1641
+ const repeatedExtglobRecursion = (pattern) => {
1642
+ let depth = 0;
1643
+ let value = pattern.trim();
1644
+ let match = parseRepeatedExtglob(value);
1645
+ while (match) {
1646
+ depth++;
1647
+ value = match.body.trim();
1648
+ match = parseRepeatedExtglob(value);
1649
+ }
1650
+ return depth;
1651
+ };
1652
+ const analyzeRepeatedExtglob = (body, options) => {
1653
+ if (options.maxExtglobRecursion === false) return { risky: false };
1654
+ const max = typeof options.maxExtglobRecursion === "number" ? options.maxExtglobRecursion : constants.DEFAULT_MAX_EXTGLOB_RECURSION;
1655
+ const branches = splitTopLevel(body).map((branch) => branch.trim());
1656
+ if (branches.length > 1) {
1657
+ if (branches.some((branch) => branch === "") || branches.some((branch) => /^[*?]+$/.test(branch)) || hasRepeatedCharPrefixOverlap(branches)) return { risky: true };
1658
+ }
1659
+ for (const branch of branches) {
1660
+ const safeOutput = getStarExtglobSequenceOutput(branch);
1661
+ if (safeOutput) return {
1662
+ risky: true,
1663
+ safeOutput
1664
+ };
1665
+ if (repeatedExtglobRecursion(branch) > max) return { risky: true };
1666
+ }
1667
+ return { risky: false };
1668
+ };
1466
1669
  /**
1467
1670
  * Parse the given input string.
1468
1671
  * @param {String} input
@@ -1483,8 +1686,7 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1483
1686
  };
1484
1687
  const tokens = [bos];
1485
1688
  const capture = opts.capture ? "" : "?:";
1486
- const win32 = utils.isWindows(options);
1487
- const PLATFORM_CHARS = constants.globChars(win32);
1689
+ const PLATFORM_CHARS = constants.globChars(opts.windows);
1488
1690
  const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);
1489
1691
  const { DOT_LITERAL, PLUS_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOT_SLASH, NO_DOTS_SLASH, QMARK, QMARK_NO_DOT, STAR, START_ANCHOR } = PLATFORM_CHARS;
1490
1692
  const globstar = (opts) => {
@@ -1576,8 +1778,8 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1576
1778
  if (extglobs.length && tok.type !== "paren") extglobs[extglobs.length - 1].inner += tok.value;
1577
1779
  if (tok.value || tok.output) append(tok);
1578
1780
  if (prev && prev.type === "text" && tok.type === "text") {
1781
+ prev.output = (prev.output || prev.value) + tok.value;
1579
1782
  prev.value += tok.value;
1580
- prev.output = (prev.output || "") + tok.value;
1581
1783
  return;
1582
1784
  }
1583
1785
  tok.prev = prev;
@@ -1593,6 +1795,8 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1593
1795
  token.prev = prev;
1594
1796
  token.parens = state.parens;
1595
1797
  token.output = state.output;
1798
+ token.startIndex = state.index;
1799
+ token.tokensIndex = tokens.length;
1596
1800
  const output = (opts.capture ? "(" : "") + token.open;
1597
1801
  increment("parens");
1598
1802
  push({
@@ -1609,6 +1813,30 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1609
1813
  extglobs.push(token);
1610
1814
  };
1611
1815
  const extglobClose = (token) => {
1816
+ const literal = input.slice(token.startIndex, state.index + 1);
1817
+ const analysis = analyzeRepeatedExtglob(input.slice(token.startIndex + 2, state.index), opts);
1818
+ if ((token.type === "plus" || token.type === "star") && analysis.risky) {
1819
+ const safeOutput = analysis.safeOutput ? (token.output ? "" : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : void 0;
1820
+ const open = tokens[token.tokensIndex];
1821
+ open.type = "text";
1822
+ open.value = literal;
1823
+ open.output = safeOutput || utils.escapeRegex(literal);
1824
+ for (let i = token.tokensIndex + 1; i < tokens.length; i++) {
1825
+ tokens[i].value = "";
1826
+ tokens[i].output = "";
1827
+ delete tokens[i].suffix;
1828
+ }
1829
+ state.output = token.output + open.output;
1830
+ state.backtrack = true;
1831
+ push({
1832
+ type: "paren",
1833
+ extglob: true,
1834
+ value,
1835
+ output: ""
1836
+ });
1837
+ decrement("parens");
1838
+ return;
1839
+ }
1612
1840
  let output = token.close + (opts.capture ? ")" : "");
1613
1841
  let rest;
1614
1842
  if (token.type === "negate") {
@@ -1967,7 +2195,6 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1967
2195
  if (prev && prev.type === "paren") {
1968
2196
  const next = peek();
1969
2197
  let output = value;
1970
- if (next === "<" && !utils.supportsLookbehinds()) throw new Error("Node.js v10 or higher is required for regex lookbehinds");
1971
2198
  if (prev.value === "(" && !/[!=<:]/.test(next) || next === "<" && !/<([!=]|\w+>)/.test(remaining())) output = `\\${value}`;
1972
2199
  push({
1973
2200
  type: "text",
@@ -2255,8 +2482,7 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2255
2482
  const len = input.length;
2256
2483
  if (len > max) throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
2257
2484
  input = REPLACEMENTS[input] || input;
2258
- const win32 = utils.isWindows(options);
2259
- const { DOT_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOTS, NO_DOTS_SLASH, STAR, START_ANCHOR } = constants.globChars(win32);
2485
+ const { DOT_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOTS, NO_DOTS_SLASH, STAR, START_ANCHOR } = constants.globChars(opts.windows);
2260
2486
  const nodot = opts.dot ? NO_DOTS : NO_DOT;
2261
2487
  const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
2262
2488
  const capture = opts.capture ? "" : "?:";
@@ -2296,9 +2522,8 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2296
2522
  module.exports = parse;
2297
2523
  }));
2298
2524
  //#endregion
2299
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/picomatch.js
2525
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/picomatch.js
2300
2526
  var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2301
- const path$1 = __require("path");
2302
2527
  const scan = require_scan();
2303
2528
  const parse = require_parse();
2304
2529
  const utils = require_utils();
@@ -2340,7 +2565,7 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2340
2565
  const isState = isObject(glob) && glob.tokens && glob.input;
2341
2566
  if (glob === "" || typeof glob !== "string" && !isState) throw new TypeError("Expected pattern to be a non-empty string");
2342
2567
  const opts = options || {};
2343
- const posix = utils.isWindows(options);
2568
+ const posix = opts.windows;
2344
2569
  const regex = isState ? picomatch.compileRe(glob, options) : picomatch.makeRe(glob, options, false, true);
2345
2570
  const state = regex.state;
2346
2571
  delete regex.state;
@@ -2436,8 +2661,8 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2436
2661
  * @return {Boolean}
2437
2662
  * @api public
2438
2663
  */
2439
- picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
2440
- return (glob instanceof RegExp ? glob : picomatch.makeRe(glob, options)).test(path$1.basename(input));
2664
+ picomatch.matchBase = (input, glob, options) => {
2665
+ return (glob instanceof RegExp ? glob : picomatch.makeRe(glob, options)).test(utils.basename(input));
2441
2666
  };
2442
2667
  /**
2443
2668
  * Returns true if **any** of the given glob `patterns` match the specified `string`.
@@ -2507,6 +2732,14 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2507
2732
  * Compile a regular expression from the `state` object returned by the
2508
2733
  * [parse()](#parse) method.
2509
2734
  *
2735
+ * ```js
2736
+ * const picomatch = require('picomatch');
2737
+ * const state = picomatch.parse('*.js');
2738
+ * // picomatch.compileRe(state[, options]);
2739
+ *
2740
+ * console.log(picomatch.compileRe(state));
2741
+ * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
2742
+ * ```
2510
2743
  * @param {Object} `state`
2511
2744
  * @param {Object} `options`
2512
2745
  * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
@@ -2530,10 +2763,10 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2530
2763
  *
2531
2764
  * ```js
2532
2765
  * const picomatch = require('picomatch');
2533
- * const state = picomatch.parse('*.js');
2534
- * // picomatch.compileRe(state[, options]);
2766
+ * // picomatch.makeRe(state[, options]);
2535
2767
  *
2536
- * console.log(picomatch.compileRe(state));
2768
+ * const result = picomatch.makeRe('*.js');
2769
+ * console.log(result);
2537
2770
  * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
2538
2771
  * ```
2539
2772
  * @param {String} `state` The object returned from the `.parse` method.
@@ -2591,7 +2824,17 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2591
2824
  //#endregion
2592
2825
  //#region ../core/dist/index.js
2593
2826
  var import_picomatch = /* @__PURE__ */ __toESM$1((/* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2594
- module.exports = require_picomatch$1();
2827
+ const pico = require_picomatch$1();
2828
+ const utils = require_utils();
2829
+ function picomatch(glob, options, returnState = false) {
2830
+ if (options && (options.windows === null || options.windows === void 0)) options = {
2831
+ ...options,
2832
+ windows: utils.isWindows()
2833
+ };
2834
+ return pico(glob, options, returnState);
2835
+ }
2836
+ Object.assign(picomatch, pico);
2837
+ module.exports = picomatch;
2595
2838
  })))(), 1);
2596
2839
  var __create = Object.create;
2597
2840
  var __defProp = Object.defineProperty;
@@ -2618,6 +2861,7 @@ const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
2618
2861
  const MILLISECONDS_PER_SECOND = 1e3;
2619
2862
  const SCORE_API_URL = "https://www.react.doctor/api/score";
2620
2863
  const SHARE_BASE_URL = "https://www.react.doctor/share";
2864
+ const REACT_REVIEW_URL = "https://react.review";
2621
2865
  const FETCH_TIMEOUT_MS = 1e4;
2622
2866
  const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
2623
2867
  const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
@@ -4071,12 +4315,7 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
4071
4315
  while (stack.length > 0) {
4072
4316
  const current = stack.pop();
4073
4317
  if (current === void 0) continue;
4074
- let entries;
4075
- try {
4076
- entries = fs.readdirSync(current, { withFileTypes: true });
4077
- } catch {
4078
- continue;
4079
- }
4318
+ const entries = readDirectoryEntries(current);
4080
4319
  for (const entry of entries) {
4081
4320
  if (entry.isDirectory()) {
4082
4321
  if (entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
@@ -4208,7 +4447,7 @@ const resolveConfigRootDir = (config, configSourceDirectory) => {
4208
4447
  if (trimmedRootDir.length === 0) return null;
4209
4448
  const resolvedRootDir = path.isAbsolute(trimmedRootDir) ? trimmedRootDir : path.resolve(configSourceDirectory, trimmedRootDir);
4210
4449
  if (resolvedRootDir === configSourceDirectory) return null;
4211
- if (!fs.existsSync(resolvedRootDir) || !fs.statSync(resolvedRootDir).isDirectory()) {
4450
+ if (!isDirectory(resolvedRootDir)) {
4212
4451
  logger.warn(`react-doctor config "rootDir" points to "${rawRootDir}" (resolved to ${resolvedRootDir}), which is not a directory. Ignoring.`);
4213
4452
  return null;
4214
4453
  }
@@ -4234,7 +4473,7 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
4234
4473
  const stack = [rootDirectory];
4235
4474
  while (stack.length > 0) {
4236
4475
  const currentDirectory = stack.pop();
4237
- const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
4476
+ const entries = readDirectoryEntries(currentDirectory);
4238
4477
  for (const entry of entries) {
4239
4478
  const absolutePath = path.join(currentDirectory, entry.name);
4240
4479
  if (entry.isDirectory()) {
@@ -5356,6 +5595,12 @@ const printNoScoreHeader = (noScoreMessage) => {
5356
5595
  logger.log(` ${highlighter.gray(noScoreMessage)}`);
5357
5596
  logger.break();
5358
5597
  };
5598
+ const printReactReviewCta = () => {
5599
+ logger.log(` ${highlighter.bold("→ Catch these issues on every PR:")} ${highlighter.info(REACT_REVIEW_URL)}`);
5600
+ logger.log(` ${highlighter.dim("React Review is a GitHub App built on React Doctor, and it runs on each pull request,")}`);
5601
+ logger.log(` ${highlighter.dim("posts new issues as inline review comments, and tracks your team's score over time.")}`);
5602
+ logger.break();
5603
+ };
5359
5604
  //#endregion
5360
5605
  //#region src/cli/utils/write-diagnostics-directory.ts
5361
5606
  const writeDiagnosticsDirectory = (diagnostics) => {
@@ -5404,6 +5649,8 @@ const printSummary = (diagnostics, elapsedMilliseconds, scoreResult, projectName
5404
5649
  logger.break();
5405
5650
  const shareUrl = buildShareUrl(diagnostics, scoreResult, projectName);
5406
5651
  logger.log(` ${highlighter.bold("→ Share your results:")} ${highlighter.info(shareUrl)}`);
5652
+ logger.break();
5653
+ printReactReviewCta();
5407
5654
  }
5408
5655
  };
5409
5656
  //#endregion
@@ -5751,7 +5998,7 @@ const CI_ENVIRONMENT_VARIABLES = [
5751
5998
  const isCiEnvironment = () => CI_ENVIRONMENT_VARIABLES.some((envVariable) => Boolean(process.env[envVariable])) || process.env.CI === "true";
5752
5999
  //#endregion
5753
6000
  //#region src/cli/utils/version.ts
5754
- const VERSION = "0.2.0-beta.6";
6001
+ const VERSION = "0.2.1";
5755
6002
  //#endregion
5756
6003
  //#region src/cli/utils/json-mode.ts
5757
6004
  let context = null;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import fs from "node:fs";
1
2
  //#region ../types/dist/index.d.ts
2
3
  //#region src/config.d.ts
3
4
  type FailOnLevel = "error" | "warning" | "none";
@@ -401,7 +402,7 @@ declare class AmbiguousProjectError extends ReactDoctorError {
401
402
  constructor(directory: string, candidates: readonly string[], options?: ErrorOptions);
402
403
  }
403
404
  declare const isReactDoctorError: (value: unknown) => value is ReactDoctorError; //#endregion
404
- //#region src/utils/is-file.d.ts
405
+ //#region src/utils/is-directory.d.ts
405
406
  //#endregion
406
407
  //#region ../core/dist/index.d.ts
407
408
  //#endregion
package/dist/index.js CHANGED
@@ -27,7 +27,6 @@ var __toESM$1 = (mod, isNodeMode, target) => (target = mod != null ? __create$1(
27
27
  value: mod,
28
28
  enumerable: true
29
29
  }) : target, mod));
30
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
31
30
  //#endregion
32
31
  //#region ../types/dist/index.js
33
32
  const REACT_NATIVE_DEPENDENCY_NAMES = new Set([
@@ -114,12 +113,31 @@ const IGNORED_DIRECTORIES = new Set([
114
113
  "out",
115
114
  "storybook-static"
116
115
  ]);
116
+ const IGNORABLE_READDIR_ERROR_CODES = new Set([
117
+ "EACCES",
118
+ "EPERM",
119
+ "ENOENT",
120
+ "ENOTDIR"
121
+ ]);
122
+ const isIgnorableReaddirError = (error) => {
123
+ if (typeof error !== "object" || error === null) return false;
124
+ const errorCode = error.code;
125
+ return typeof errorCode === "string" && IGNORABLE_READDIR_ERROR_CODES.has(errorCode);
126
+ };
127
+ const readDirectoryEntries = (directoryPath) => {
128
+ try {
129
+ return fs.readdirSync(directoryPath, { withFileTypes: true });
130
+ } catch (error) {
131
+ if (isIgnorableReaddirError(error)) return [];
132
+ throw error;
133
+ }
134
+ };
117
135
  const countSourceFilesViaFilesystem = (rootDirectory) => {
118
136
  let count = 0;
119
137
  const stack = [rootDirectory];
120
138
  while (stack.length > 0) {
121
139
  const currentDirectory = stack.pop();
122
- const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
140
+ const entries = readDirectoryEntries(currentDirectory);
123
141
  for (const entry of entries) {
124
142
  if (entry.isDirectory()) {
125
143
  if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(path.join(currentDirectory, entry.name));
@@ -157,7 +175,7 @@ const readPackageJsonUncached = (packageJsonPath) => {
157
175
  if (error instanceof SyntaxError) return {};
158
176
  if (error instanceof Error && "code" in error) {
159
177
  const { code } = error;
160
- if (code === "EISDIR" || code === "EACCES") return {};
178
+ if (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "ENOENT") return {};
161
179
  }
162
180
  throw error;
163
181
  }
@@ -528,6 +546,13 @@ const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
528
546
  version: null
529
547
  };
530
548
  };
549
+ const isDirectory = (directoryPath) => {
550
+ try {
551
+ return fs.statSync(directoryPath).isDirectory();
552
+ } catch {
553
+ return false;
554
+ }
555
+ };
531
556
  const NX_PROJECT_DISCOVERY_DIRS = [
532
557
  "apps",
533
558
  "libs",
@@ -538,8 +563,8 @@ const getNxWorkspaceDirectories = (rootDirectory) => {
538
563
  const collected = [];
539
564
  for (const candidate of NX_PROJECT_DISCOVERY_DIRS) {
540
565
  const candidatePath = path.join(rootDirectory, candidate);
541
- if (!fs.existsSync(candidatePath) || !fs.statSync(candidatePath).isDirectory()) continue;
542
- for (const entry of fs.readdirSync(candidatePath, { withFileTypes: true })) {
566
+ if (!isDirectory(candidatePath)) continue;
567
+ for (const entry of readDirectoryEntries(candidatePath)) {
543
568
  if (!entry.isDirectory()) continue;
544
569
  const projectDirectory = path.join(candidatePath, entry.name);
545
570
  if (isFile(path.join(projectDirectory, "project.json")) || isFile(path.join(projectDirectory, "package.json"))) collected.push(`${candidate}/${entry.name}`);
@@ -581,17 +606,17 @@ const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
581
606
  const cleanPattern = pattern.replace(/["']/g, "").replace(/\/\*\*$/, "/*");
582
607
  if (!cleanPattern.includes("*")) {
583
608
  const directoryPath = path.join(rootDirectory, cleanPattern);
584
- if (fs.existsSync(directoryPath) && isFile(path.join(directoryPath, "package.json"))) return [directoryPath];
609
+ if (isDirectory(directoryPath) && isFile(path.join(directoryPath, "package.json"))) return [directoryPath];
585
610
  return [];
586
611
  }
587
612
  const wildcardIndex = cleanPattern.indexOf("*");
588
613
  const baseDirectory = path.join(rootDirectory, cleanPattern.slice(0, wildcardIndex));
589
614
  const suffixAfterWildcard = cleanPattern.slice(wildcardIndex + 1);
590
- if (!fs.existsSync(baseDirectory) || !fs.statSync(baseDirectory).isDirectory()) return [];
615
+ if (!isDirectory(baseDirectory)) return [];
591
616
  const resolved = [];
592
- for (const entry of fs.readdirSync(baseDirectory)) {
593
- const entryPath = path.join(baseDirectory, entry, suffixAfterWildcard);
594
- if (fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory() && isFile(path.join(entryPath, "package.json"))) resolved.push(entryPath);
617
+ for (const entry of readDirectoryEntries(baseDirectory)) {
618
+ const entryPath = path.join(baseDirectory, entry.name, suffixAfterWildcard);
619
+ if (isDirectory(entryPath) && isFile(path.join(entryPath, "package.json"))) resolved.push(entryPath);
595
620
  }
596
621
  return resolved;
597
622
  };
@@ -836,7 +861,7 @@ const discoverReactSubprojectsByFilesystem = (rootDirectory) => {
836
861
  });
837
862
  }
838
863
  }
839
- const entries = fs.readdirSync(currentDirectory, { withFileTypes: true }).toSorted((firstEntry, secondEntry) => firstEntry.name.localeCompare(secondEntry.name));
864
+ const entries = readDirectoryEntries(currentDirectory).toSorted((firstEntry, secondEntry) => firstEntry.name.localeCompare(secondEntry.name));
840
865
  for (const entry of entries) {
841
866
  if (!entry.isDirectory() || entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
842
867
  pendingDirectories.push(path.join(currentDirectory, entry.name));
@@ -845,7 +870,7 @@ const discoverReactSubprojectsByFilesystem = (rootDirectory) => {
845
870
  return packages;
846
871
  };
847
872
  const discoverReactSubprojects = (rootDirectory) => {
848
- if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];
873
+ if (!isDirectory(rootDirectory)) return [];
849
874
  const manifestPackages = listManifestWorkspacePackages(rootDirectory);
850
875
  if (manifestPackages.length > 0) return manifestPackages;
851
876
  return discoverReactSubprojectsByFilesystem(rootDirectory);
@@ -956,11 +981,11 @@ const isTailwindAtLeast = (detected, required) => {
956
981
  return detected.minor >= required.minor;
957
982
  };
958
983
  //#endregion
959
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/constants.js
984
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js
960
985
  var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
961
- const path$3 = __require("path");
962
986
  const WIN_SLASH = "\\\\/";
963
987
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
988
+ const DEFAULT_MAX_EXTGLOB_RECURSION = 0;
964
989
  /**
965
990
  * Posix glob regex
966
991
  */
@@ -988,7 +1013,8 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
988
1013
  NO_DOTS_SLASH: `(?!${DOTS_SLASH})`,
989
1014
  QMARK_NO_DOT: `[^.${SLASH_LITERAL}]`,
990
1015
  STAR: `${QMARK}*?`,
991
- START_ANCHOR
1016
+ START_ANCHOR,
1017
+ SEP: "/"
992
1018
  };
993
1019
  /**
994
1020
  * Windows glob regex
@@ -1005,11 +1031,14 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1005
1031
  NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
1006
1032
  QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
1007
1033
  START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
1008
- END_ANCHOR: `(?:[${WIN_SLASH}]|$)`
1034
+ END_ANCHOR: `(?:[${WIN_SLASH}]|$)`,
1035
+ SEP: "\\"
1009
1036
  };
1010
1037
  module.exports = {
1038
+ DEFAULT_MAX_EXTGLOB_RECURSION,
1011
1039
  MAX_LENGTH: 1024 * 64,
1012
1040
  POSIX_REGEX_SOURCE: {
1041
+ __proto__: null,
1013
1042
  alnum: "a-zA-Z0-9",
1014
1043
  alpha: "a-zA-Z",
1015
1044
  ascii: "\\x00-\\x7F",
@@ -1032,6 +1061,7 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1032
1061
  REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g,
1033
1062
  REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g,
1034
1063
  REPLACEMENTS: {
1064
+ __proto__: null,
1035
1065
  "***": "*",
1036
1066
  "**/**": "**",
1037
1067
  "**/**/**": "**"
@@ -1079,7 +1109,6 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1079
1109
  CHAR_UNDERSCORE: 95,
1080
1110
  CHAR_VERTICAL_LINE: 124,
1081
1111
  CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279,
1082
- SEP: path$3.sep,
1083
1112
  /**
1084
1113
  * Create EXTGLOB_CHARS
1085
1114
  */
@@ -1121,30 +1150,27 @@ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1121
1150
  };
1122
1151
  }));
1123
1152
  //#endregion
1124
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/utils.js
1153
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js
1125
1154
  var require_utils = /* @__PURE__ */ __commonJSMin$1(((exports) => {
1126
- const path$2 = __require("path");
1127
- const win32 = process.platform === "win32";
1128
1155
  const { REGEX_BACKSLASH, REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL } = require_constants();
1129
1156
  exports.isObject = (val) => val !== null && typeof val === "object" && !Array.isArray(val);
1130
1157
  exports.hasRegexChars = (str) => REGEX_SPECIAL_CHARS.test(str);
1131
1158
  exports.isRegexChar = (str) => str.length === 1 && exports.hasRegexChars(str);
1132
1159
  exports.escapeRegex = (str) => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, "\\$1");
1133
1160
  exports.toPosixSlashes = (str) => str.replace(REGEX_BACKSLASH, "/");
1161
+ exports.isWindows = () => {
1162
+ if (typeof navigator !== "undefined" && navigator.platform) {
1163
+ const platform = navigator.platform.toLowerCase();
1164
+ return platform === "win32" || platform === "windows";
1165
+ }
1166
+ if (typeof process !== "undefined" && process.platform) return process.platform === "win32";
1167
+ return false;
1168
+ };
1134
1169
  exports.removeBackslashes = (str) => {
1135
1170
  return str.replace(REGEX_REMOVE_BACKSLASH, (match) => {
1136
1171
  return match === "\\" ? "" : match;
1137
1172
  });
1138
1173
  };
1139
- exports.supportsLookbehinds = () => {
1140
- const segs = process.version.slice(1).split(".").map(Number);
1141
- if (segs.length === 3 && segs[0] >= 9 || segs[0] === 8 && segs[1] >= 10) return true;
1142
- return false;
1143
- };
1144
- exports.isWindows = (options) => {
1145
- if (options && typeof options.windows === "boolean") return options.windows;
1146
- return win32 === true || path$2.sep === "\\";
1147
- };
1148
1174
  exports.escapeLast = (input, char, lastIdx) => {
1149
1175
  const idx = input.lastIndexOf(char, lastIdx);
1150
1176
  if (idx === -1) return input;
@@ -1164,9 +1190,15 @@ var require_utils = /* @__PURE__ */ __commonJSMin$1(((exports) => {
1164
1190
  if (state.negated === true) output = `(?:^(?!${output}).*$)`;
1165
1191
  return output;
1166
1192
  };
1193
+ exports.basename = (path, { windows } = {}) => {
1194
+ const segs = path.split(windows ? /[\\/]/ : "/");
1195
+ const last = segs[segs.length - 1];
1196
+ if (last === "") return segs[segs.length - 2];
1197
+ return last;
1198
+ };
1167
1199
  }));
1168
1200
  //#endregion
1169
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/scan.js
1201
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/scan.js
1170
1202
  var require_scan = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1171
1203
  const utils = require_utils();
1172
1204
  const { CHAR_ASTERISK, CHAR_AT, CHAR_BACKWARD_SLASH, CHAR_COMMA, CHAR_DOT, CHAR_EXCLAMATION_MARK, CHAR_FORWARD_SLASH, CHAR_LEFT_CURLY_BRACE, CHAR_LEFT_PARENTHESES, CHAR_LEFT_SQUARE_BRACKET, CHAR_PLUS, CHAR_QUESTION_MARK, CHAR_RIGHT_CURLY_BRACE, CHAR_RIGHT_PARENTHESES, CHAR_RIGHT_SQUARE_BRACKET } = require_constants();
@@ -1453,7 +1485,7 @@ var require_scan = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1453
1485
  module.exports = scan;
1454
1486
  }));
1455
1487
  //#endregion
1456
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/parse.js
1488
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/parse.js
1457
1489
  var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1458
1490
  const constants = require_constants();
1459
1491
  const utils = require_utils();
@@ -1481,6 +1513,177 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1481
1513
  const syntaxError = (type, char) => {
1482
1514
  return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
1483
1515
  };
1516
+ const splitTopLevel = (input) => {
1517
+ const parts = [];
1518
+ let bracket = 0;
1519
+ let paren = 0;
1520
+ let quote = 0;
1521
+ let value = "";
1522
+ let escaped = false;
1523
+ for (const ch of input) {
1524
+ if (escaped === true) {
1525
+ value += ch;
1526
+ escaped = false;
1527
+ continue;
1528
+ }
1529
+ if (ch === "\\") {
1530
+ value += ch;
1531
+ escaped = true;
1532
+ continue;
1533
+ }
1534
+ if (ch === "\"") {
1535
+ quote = quote === 1 ? 0 : 1;
1536
+ value += ch;
1537
+ continue;
1538
+ }
1539
+ if (quote === 0) {
1540
+ if (ch === "[") bracket++;
1541
+ else if (ch === "]" && bracket > 0) bracket--;
1542
+ else if (bracket === 0) {
1543
+ if (ch === "(") paren++;
1544
+ else if (ch === ")" && paren > 0) paren--;
1545
+ else if (ch === "|" && paren === 0) {
1546
+ parts.push(value);
1547
+ value = "";
1548
+ continue;
1549
+ }
1550
+ }
1551
+ }
1552
+ value += ch;
1553
+ }
1554
+ parts.push(value);
1555
+ return parts;
1556
+ };
1557
+ const isPlainBranch = (branch) => {
1558
+ let escaped = false;
1559
+ for (const ch of branch) {
1560
+ if (escaped === true) {
1561
+ escaped = false;
1562
+ continue;
1563
+ }
1564
+ if (ch === "\\") {
1565
+ escaped = true;
1566
+ continue;
1567
+ }
1568
+ if (/[?*+@!()[\]{}]/.test(ch)) return false;
1569
+ }
1570
+ return true;
1571
+ };
1572
+ const normalizeSimpleBranch = (branch) => {
1573
+ let value = branch.trim();
1574
+ let changed = true;
1575
+ while (changed === true) {
1576
+ changed = false;
1577
+ if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
1578
+ value = value.slice(2, -1);
1579
+ changed = true;
1580
+ }
1581
+ }
1582
+ if (!isPlainBranch(value)) return;
1583
+ return value.replace(/\\(.)/g, "$1");
1584
+ };
1585
+ const hasRepeatedCharPrefixOverlap = (branches) => {
1586
+ const values = branches.map(normalizeSimpleBranch).filter(Boolean);
1587
+ for (let i = 0; i < values.length; i++) for (let j = i + 1; j < values.length; j++) {
1588
+ const a = values[i];
1589
+ const b = values[j];
1590
+ const char = a[0];
1591
+ if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) continue;
1592
+ if (a === b || a.startsWith(b) || b.startsWith(a)) return true;
1593
+ }
1594
+ return false;
1595
+ };
1596
+ const parseRepeatedExtglob = (pattern, requireEnd = true) => {
1597
+ if (pattern[0] !== "+" && pattern[0] !== "*" || pattern[1] !== "(") return;
1598
+ let bracket = 0;
1599
+ let paren = 0;
1600
+ let quote = 0;
1601
+ let escaped = false;
1602
+ for (let i = 1; i < pattern.length; i++) {
1603
+ const ch = pattern[i];
1604
+ if (escaped === true) {
1605
+ escaped = false;
1606
+ continue;
1607
+ }
1608
+ if (ch === "\\") {
1609
+ escaped = true;
1610
+ continue;
1611
+ }
1612
+ if (ch === "\"") {
1613
+ quote = quote === 1 ? 0 : 1;
1614
+ continue;
1615
+ }
1616
+ if (quote === 1) continue;
1617
+ if (ch === "[") {
1618
+ bracket++;
1619
+ continue;
1620
+ }
1621
+ if (ch === "]" && bracket > 0) {
1622
+ bracket--;
1623
+ continue;
1624
+ }
1625
+ if (bracket > 0) continue;
1626
+ if (ch === "(") {
1627
+ paren++;
1628
+ continue;
1629
+ }
1630
+ if (ch === ")") {
1631
+ paren--;
1632
+ if (paren === 0) {
1633
+ if (requireEnd === true && i !== pattern.length - 1) return;
1634
+ return {
1635
+ type: pattern[0],
1636
+ body: pattern.slice(2, i),
1637
+ end: i
1638
+ };
1639
+ }
1640
+ }
1641
+ }
1642
+ };
1643
+ const getStarExtglobSequenceOutput = (pattern) => {
1644
+ let index = 0;
1645
+ const chars = [];
1646
+ while (index < pattern.length) {
1647
+ const match = parseRepeatedExtglob(pattern.slice(index), false);
1648
+ if (!match || match.type !== "*") return;
1649
+ const branches = splitTopLevel(match.body).map((branch) => branch.trim());
1650
+ if (branches.length !== 1) return;
1651
+ const branch = normalizeSimpleBranch(branches[0]);
1652
+ if (!branch || branch.length !== 1) return;
1653
+ chars.push(branch);
1654
+ index += match.end + 1;
1655
+ }
1656
+ if (chars.length < 1) return;
1657
+ return `${chars.length === 1 ? utils.escapeRegex(chars[0]) : `[${chars.map((ch) => utils.escapeRegex(ch)).join("")}]`}*`;
1658
+ };
1659
+ const repeatedExtglobRecursion = (pattern) => {
1660
+ let depth = 0;
1661
+ let value = pattern.trim();
1662
+ let match = parseRepeatedExtglob(value);
1663
+ while (match) {
1664
+ depth++;
1665
+ value = match.body.trim();
1666
+ match = parseRepeatedExtglob(value);
1667
+ }
1668
+ return depth;
1669
+ };
1670
+ const analyzeRepeatedExtglob = (body, options) => {
1671
+ if (options.maxExtglobRecursion === false) return { risky: false };
1672
+ const max = typeof options.maxExtglobRecursion === "number" ? options.maxExtglobRecursion : constants.DEFAULT_MAX_EXTGLOB_RECURSION;
1673
+ const branches = splitTopLevel(body).map((branch) => branch.trim());
1674
+ if (branches.length > 1) {
1675
+ if (branches.some((branch) => branch === "") || branches.some((branch) => /^[*?]+$/.test(branch)) || hasRepeatedCharPrefixOverlap(branches)) return { risky: true };
1676
+ }
1677
+ for (const branch of branches) {
1678
+ const safeOutput = getStarExtglobSequenceOutput(branch);
1679
+ if (safeOutput) return {
1680
+ risky: true,
1681
+ safeOutput
1682
+ };
1683
+ if (repeatedExtglobRecursion(branch) > max) return { risky: true };
1684
+ }
1685
+ return { risky: false };
1686
+ };
1484
1687
  /**
1485
1688
  * Parse the given input string.
1486
1689
  * @param {String} input
@@ -1501,8 +1704,7 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1501
1704
  };
1502
1705
  const tokens = [bos];
1503
1706
  const capture = opts.capture ? "" : "?:";
1504
- const win32 = utils.isWindows(options);
1505
- const PLATFORM_CHARS = constants.globChars(win32);
1707
+ const PLATFORM_CHARS = constants.globChars(opts.windows);
1506
1708
  const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);
1507
1709
  const { DOT_LITERAL, PLUS_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOT_SLASH, NO_DOTS_SLASH, QMARK, QMARK_NO_DOT, STAR, START_ANCHOR } = PLATFORM_CHARS;
1508
1710
  const globstar = (opts) => {
@@ -1594,8 +1796,8 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1594
1796
  if (extglobs.length && tok.type !== "paren") extglobs[extglobs.length - 1].inner += tok.value;
1595
1797
  if (tok.value || tok.output) append(tok);
1596
1798
  if (prev && prev.type === "text" && tok.type === "text") {
1799
+ prev.output = (prev.output || prev.value) + tok.value;
1597
1800
  prev.value += tok.value;
1598
- prev.output = (prev.output || "") + tok.value;
1599
1801
  return;
1600
1802
  }
1601
1803
  tok.prev = prev;
@@ -1611,6 +1813,8 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1611
1813
  token.prev = prev;
1612
1814
  token.parens = state.parens;
1613
1815
  token.output = state.output;
1816
+ token.startIndex = state.index;
1817
+ token.tokensIndex = tokens.length;
1614
1818
  const output = (opts.capture ? "(" : "") + token.open;
1615
1819
  increment("parens");
1616
1820
  push({
@@ -1627,6 +1831,30 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1627
1831
  extglobs.push(token);
1628
1832
  };
1629
1833
  const extglobClose = (token) => {
1834
+ const literal = input.slice(token.startIndex, state.index + 1);
1835
+ const analysis = analyzeRepeatedExtglob(input.slice(token.startIndex + 2, state.index), opts);
1836
+ if ((token.type === "plus" || token.type === "star") && analysis.risky) {
1837
+ const safeOutput = analysis.safeOutput ? (token.output ? "" : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : void 0;
1838
+ const open = tokens[token.tokensIndex];
1839
+ open.type = "text";
1840
+ open.value = literal;
1841
+ open.output = safeOutput || utils.escapeRegex(literal);
1842
+ for (let i = token.tokensIndex + 1; i < tokens.length; i++) {
1843
+ tokens[i].value = "";
1844
+ tokens[i].output = "";
1845
+ delete tokens[i].suffix;
1846
+ }
1847
+ state.output = token.output + open.output;
1848
+ state.backtrack = true;
1849
+ push({
1850
+ type: "paren",
1851
+ extglob: true,
1852
+ value,
1853
+ output: ""
1854
+ });
1855
+ decrement("parens");
1856
+ return;
1857
+ }
1630
1858
  let output = token.close + (opts.capture ? ")" : "");
1631
1859
  let rest;
1632
1860
  if (token.type === "negate") {
@@ -1985,7 +2213,6 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1985
2213
  if (prev && prev.type === "paren") {
1986
2214
  const next = peek();
1987
2215
  let output = value;
1988
- if (next === "<" && !utils.supportsLookbehinds()) throw new Error("Node.js v10 or higher is required for regex lookbehinds");
1989
2216
  if (prev.value === "(" && !/[!=<:]/.test(next) || next === "<" && !/<([!=]|\w+>)/.test(remaining())) output = `\\${value}`;
1990
2217
  push({
1991
2218
  type: "text",
@@ -2273,8 +2500,7 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2273
2500
  const len = input.length;
2274
2501
  if (len > max) throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
2275
2502
  input = REPLACEMENTS[input] || input;
2276
- const win32 = utils.isWindows(options);
2277
- const { DOT_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOTS, NO_DOTS_SLASH, STAR, START_ANCHOR } = constants.globChars(win32);
2503
+ const { DOT_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOTS, NO_DOTS_SLASH, STAR, START_ANCHOR } = constants.globChars(opts.windows);
2278
2504
  const nodot = opts.dot ? NO_DOTS : NO_DOT;
2279
2505
  const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
2280
2506
  const capture = opts.capture ? "" : "?:";
@@ -2314,9 +2540,8 @@ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2314
2540
  module.exports = parse;
2315
2541
  }));
2316
2542
  //#endregion
2317
- //#region ../../node_modules/.pnpm/picomatch@2.3.1/node_modules/picomatch/lib/picomatch.js
2543
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/picomatch.js
2318
2544
  var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2319
- const path$1 = __require("path");
2320
2545
  const scan = require_scan();
2321
2546
  const parse = require_parse();
2322
2547
  const utils = require_utils();
@@ -2358,7 +2583,7 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2358
2583
  const isState = isObject(glob) && glob.tokens && glob.input;
2359
2584
  if (glob === "" || typeof glob !== "string" && !isState) throw new TypeError("Expected pattern to be a non-empty string");
2360
2585
  const opts = options || {};
2361
- const posix = utils.isWindows(options);
2586
+ const posix = opts.windows;
2362
2587
  const regex = isState ? picomatch.compileRe(glob, options) : picomatch.makeRe(glob, options, false, true);
2363
2588
  const state = regex.state;
2364
2589
  delete regex.state;
@@ -2454,8 +2679,8 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2454
2679
  * @return {Boolean}
2455
2680
  * @api public
2456
2681
  */
2457
- picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
2458
- return (glob instanceof RegExp ? glob : picomatch.makeRe(glob, options)).test(path$1.basename(input));
2682
+ picomatch.matchBase = (input, glob, options) => {
2683
+ return (glob instanceof RegExp ? glob : picomatch.makeRe(glob, options)).test(utils.basename(input));
2459
2684
  };
2460
2685
  /**
2461
2686
  * Returns true if **any** of the given glob `patterns` match the specified `string`.
@@ -2525,6 +2750,14 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2525
2750
  * Compile a regular expression from the `state` object returned by the
2526
2751
  * [parse()](#parse) method.
2527
2752
  *
2753
+ * ```js
2754
+ * const picomatch = require('picomatch');
2755
+ * const state = picomatch.parse('*.js');
2756
+ * // picomatch.compileRe(state[, options]);
2757
+ *
2758
+ * console.log(picomatch.compileRe(state));
2759
+ * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
2760
+ * ```
2528
2761
  * @param {Object} `state`
2529
2762
  * @param {Object} `options`
2530
2763
  * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
@@ -2548,10 +2781,10 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2548
2781
  *
2549
2782
  * ```js
2550
2783
  * const picomatch = require('picomatch');
2551
- * const state = picomatch.parse('*.js');
2552
- * // picomatch.compileRe(state[, options]);
2784
+ * // picomatch.makeRe(state[, options]);
2553
2785
  *
2554
- * console.log(picomatch.compileRe(state));
2786
+ * const result = picomatch.makeRe('*.js');
2787
+ * console.log(result);
2555
2788
  * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
2556
2789
  * ```
2557
2790
  * @param {String} `state` The object returned from the `.parse` method.
@@ -2609,7 +2842,17 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
2609
2842
  //#endregion
2610
2843
  //#region ../core/dist/index.js
2611
2844
  var import_picomatch = /* @__PURE__ */ __toESM$1((/* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2612
- module.exports = require_picomatch$1();
2845
+ const pico = require_picomatch$1();
2846
+ const utils = require_utils();
2847
+ function picomatch(glob, options, returnState = false) {
2848
+ if (options && (options.windows === null || options.windows === void 0)) options = {
2849
+ ...options,
2850
+ windows: utils.isWindows()
2851
+ };
2852
+ return pico(glob, options, returnState);
2853
+ }
2854
+ Object.assign(picomatch, pico);
2855
+ module.exports = picomatch;
2613
2856
  })))(), 1);
2614
2857
  var __create = Object.create;
2615
2858
  var __defProp = Object.defineProperty;
@@ -4032,12 +4275,7 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
4032
4275
  while (stack.length > 0) {
4033
4276
  const current = stack.pop();
4034
4277
  if (current === void 0) continue;
4035
- let entries;
4036
- try {
4037
- entries = fs.readdirSync(current, { withFileTypes: true });
4038
- } catch {
4039
- continue;
4040
- }
4278
+ const entries = readDirectoryEntries(current);
4041
4279
  for (const entry of entries) {
4042
4280
  if (entry.isDirectory()) {
4043
4281
  if (entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
@@ -4095,7 +4333,7 @@ const resolveConfigRootDir = (config, configSourceDirectory) => {
4095
4333
  if (trimmedRootDir.length === 0) return null;
4096
4334
  const resolvedRootDir = path.isAbsolute(trimmedRootDir) ? trimmedRootDir : path.resolve(configSourceDirectory, trimmedRootDir);
4097
4335
  if (resolvedRootDir === configSourceDirectory) return null;
4098
- if (!fs.existsSync(resolvedRootDir) || !fs.statSync(resolvedRootDir).isDirectory()) {
4336
+ if (!isDirectory(resolvedRootDir)) {
4099
4337
  logger.warn(`react-doctor config "rootDir" points to "${rawRootDir}" (resolved to ${resolvedRootDir}), which is not a directory. Ignoring.`);
4100
4338
  return null;
4101
4339
  }
@@ -4128,7 +4366,7 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
4128
4366
  const stack = [rootDirectory];
4129
4367
  while (stack.length > 0) {
4130
4368
  const currentDirectory = stack.pop();
4131
- const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
4369
+ const entries = readDirectoryEntries(currentDirectory);
4132
4370
  for (const entry of entries) {
4133
4371
  const absolutePath = path.join(currentDirectory, entry.name);
4134
4372
  if (entry.isDirectory()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.2.0-beta.6",
3
+ "version": "0.2.1",
4
4
  "description": "Diagnose and fix React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -56,15 +56,15 @@
56
56
  "picocolors": "^1.1.1",
57
57
  "prompts": "^2.4.2",
58
58
  "typescript": ">=5.0.4 <7",
59
- "oxlint-plugin-react-doctor": "0.2.0-beta.6"
59
+ "oxlint-plugin-react-doctor": "0.2.1"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/prompts": "^2.4.9",
63
63
  "eslint-plugin-react-hooks": "^7.1.1",
64
64
  "eslint-plugin-react-you-might-not-need-an-effect": "^0.10.1",
65
- "@react-doctor/project-info": "0.2.0-beta.6",
66
- "@react-doctor/types": "0.2.0-beta.6",
67
- "@react-doctor/core": "0.2.0-beta.6"
65
+ "@react-doctor/core": "0.2.1",
66
+ "@react-doctor/types": "0.2.1",
67
+ "@react-doctor/project-info": "0.2.1"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "eslint-plugin-react-hooks": "^6 || ^7",