react-doctor 0.2.0-beta.5 → 0.2.0

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
@@ -3,7 +3,7 @@ import { Command } from "commander";
3
3
  import fs, { accessSync, constants, existsSync, mkdirSync, mkdtempSync, readdirSync, statSync, writeFileSync } from "node:fs";
4
4
  import path, { join } from "node:path";
5
5
  import { spawn, spawnSync } from "node:child_process";
6
- import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES } from "oxlint-plugin-react-doctor";
6
+ import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, BUILTIN_A11Y_RULES, BUILTIN_REACT_RULES, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, YOU_MIGHT_NOT_NEED_EFFECT_RULES } from "oxlint-plugin-react-doctor";
7
7
  import os, { tmpdir } from "node:os";
8
8
  import * as ts from "typescript";
9
9
  import { performance } from "node:perf_hooks";
@@ -12,6 +12,29 @@ import { randomUUID } from "node:crypto";
12
12
  import basePrompts from "prompts";
13
13
  import { fileURLToPath } from "node:url";
14
14
  import { SKILL_MANIFEST_FILE, detectInstalledSkillAgents, getSkillAgentConfig, getSkillAgentTypes, installSkillsFromSource } from "agent-install";
15
+ //#region \0rolldown/runtime.js
16
+ var __create$1 = Object.create;
17
+ var __defProp$1 = Object.defineProperty;
18
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
19
+ var __getOwnPropNames$1 = Object.getOwnPropertyNames;
20
+ var __getProtoOf$1 = Object.getPrototypeOf;
21
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
22
+ var __commonJSMin$1 = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
23
+ var __copyProps$1 = (to, from, except, desc) => {
24
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
25
+ key = keys[i];
26
+ if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$1(to, key, {
27
+ get: ((k) => from[k]).bind(null, key),
28
+ enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
29
+ });
30
+ }
31
+ return to;
32
+ };
33
+ var __toESM$1 = (mod, isNodeMode, target) => (target = mod != null ? __create$1(__getProtoOf$1(mod)) : {}, __copyProps$1(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
34
+ value: mod,
35
+ enumerable: true
36
+ }) : target, mod));
37
+ //#endregion
15
38
  //#region ../types/dist/index.js
16
39
  const REACT_NATIVE_DEPENDENCY_NAMES = new Set([
17
40
  "react-native",
@@ -914,7 +937,1879 @@ const isTailwindAtLeast = (detected, required) => {
914
937
  return detected.minor >= required.minor;
915
938
  };
916
939
  //#endregion
940
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js
941
+ var require_constants = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
942
+ const WIN_SLASH = "\\\\/";
943
+ const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
944
+ const DEFAULT_MAX_EXTGLOB_RECURSION = 0;
945
+ /**
946
+ * Posix glob regex
947
+ */
948
+ const DOT_LITERAL = "\\.";
949
+ const PLUS_LITERAL = "\\+";
950
+ const QMARK_LITERAL = "\\?";
951
+ const SLASH_LITERAL = "\\/";
952
+ const ONE_CHAR = "(?=.)";
953
+ const QMARK = "[^/]";
954
+ const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`;
955
+ const START_ANCHOR = `(?:^|${SLASH_LITERAL})`;
956
+ const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`;
957
+ const POSIX_CHARS = {
958
+ DOT_LITERAL,
959
+ PLUS_LITERAL,
960
+ QMARK_LITERAL,
961
+ SLASH_LITERAL,
962
+ ONE_CHAR,
963
+ QMARK,
964
+ END_ANCHOR,
965
+ DOTS_SLASH,
966
+ NO_DOT: `(?!${DOT_LITERAL})`,
967
+ NO_DOTS: `(?!${START_ANCHOR}${DOTS_SLASH})`,
968
+ NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`,
969
+ NO_DOTS_SLASH: `(?!${DOTS_SLASH})`,
970
+ QMARK_NO_DOT: `[^.${SLASH_LITERAL}]`,
971
+ STAR: `${QMARK}*?`,
972
+ START_ANCHOR,
973
+ SEP: "/"
974
+ };
975
+ /**
976
+ * Windows glob regex
977
+ */
978
+ const WINDOWS_CHARS = {
979
+ ...POSIX_CHARS,
980
+ SLASH_LITERAL: `[${WIN_SLASH}]`,
981
+ QMARK: WIN_NO_SLASH,
982
+ STAR: `${WIN_NO_SLASH}*?`,
983
+ DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`,
984
+ NO_DOT: `(?!${DOT_LITERAL})`,
985
+ NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
986
+ NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`,
987
+ NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
988
+ QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
989
+ START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
990
+ END_ANCHOR: `(?:[${WIN_SLASH}]|$)`,
991
+ SEP: "\\"
992
+ };
993
+ module.exports = {
994
+ DEFAULT_MAX_EXTGLOB_RECURSION,
995
+ MAX_LENGTH: 1024 * 64,
996
+ POSIX_REGEX_SOURCE: {
997
+ __proto__: null,
998
+ alnum: "a-zA-Z0-9",
999
+ alpha: "a-zA-Z",
1000
+ ascii: "\\x00-\\x7F",
1001
+ blank: " \\t",
1002
+ cntrl: "\\x00-\\x1F\\x7F",
1003
+ digit: "0-9",
1004
+ graph: "\\x21-\\x7E",
1005
+ lower: "a-z",
1006
+ print: "\\x20-\\x7E ",
1007
+ punct: "\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",
1008
+ space: " \\t\\r\\n\\v\\f",
1009
+ upper: "A-Z",
1010
+ word: "A-Za-z0-9_",
1011
+ xdigit: "A-Fa-f0-9"
1012
+ },
1013
+ REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g,
1014
+ REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/,
1015
+ REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/,
1016
+ REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g,
1017
+ REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g,
1018
+ REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g,
1019
+ REPLACEMENTS: {
1020
+ __proto__: null,
1021
+ "***": "*",
1022
+ "**/**": "**",
1023
+ "**/**/**": "**"
1024
+ },
1025
+ CHAR_0: 48,
1026
+ CHAR_9: 57,
1027
+ CHAR_UPPERCASE_A: 65,
1028
+ CHAR_LOWERCASE_A: 97,
1029
+ CHAR_UPPERCASE_Z: 90,
1030
+ CHAR_LOWERCASE_Z: 122,
1031
+ CHAR_LEFT_PARENTHESES: 40,
1032
+ CHAR_RIGHT_PARENTHESES: 41,
1033
+ CHAR_ASTERISK: 42,
1034
+ CHAR_AMPERSAND: 38,
1035
+ CHAR_AT: 64,
1036
+ CHAR_BACKWARD_SLASH: 92,
1037
+ CHAR_CARRIAGE_RETURN: 13,
1038
+ CHAR_CIRCUMFLEX_ACCENT: 94,
1039
+ CHAR_COLON: 58,
1040
+ CHAR_COMMA: 44,
1041
+ CHAR_DOT: 46,
1042
+ CHAR_DOUBLE_QUOTE: 34,
1043
+ CHAR_EQUAL: 61,
1044
+ CHAR_EXCLAMATION_MARK: 33,
1045
+ CHAR_FORM_FEED: 12,
1046
+ CHAR_FORWARD_SLASH: 47,
1047
+ CHAR_GRAVE_ACCENT: 96,
1048
+ CHAR_HASH: 35,
1049
+ CHAR_HYPHEN_MINUS: 45,
1050
+ CHAR_LEFT_ANGLE_BRACKET: 60,
1051
+ CHAR_LEFT_CURLY_BRACE: 123,
1052
+ CHAR_LEFT_SQUARE_BRACKET: 91,
1053
+ CHAR_LINE_FEED: 10,
1054
+ CHAR_NO_BREAK_SPACE: 160,
1055
+ CHAR_PERCENT: 37,
1056
+ CHAR_PLUS: 43,
1057
+ CHAR_QUESTION_MARK: 63,
1058
+ CHAR_RIGHT_ANGLE_BRACKET: 62,
1059
+ CHAR_RIGHT_CURLY_BRACE: 125,
1060
+ CHAR_RIGHT_SQUARE_BRACKET: 93,
1061
+ CHAR_SEMICOLON: 59,
1062
+ CHAR_SINGLE_QUOTE: 39,
1063
+ CHAR_SPACE: 32,
1064
+ CHAR_TAB: 9,
1065
+ CHAR_UNDERSCORE: 95,
1066
+ CHAR_VERTICAL_LINE: 124,
1067
+ CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279,
1068
+ /**
1069
+ * Create EXTGLOB_CHARS
1070
+ */
1071
+ extglobChars(chars) {
1072
+ return {
1073
+ "!": {
1074
+ type: "negate",
1075
+ open: "(?:(?!(?:",
1076
+ close: `))${chars.STAR})`
1077
+ },
1078
+ "?": {
1079
+ type: "qmark",
1080
+ open: "(?:",
1081
+ close: ")?"
1082
+ },
1083
+ "+": {
1084
+ type: "plus",
1085
+ open: "(?:",
1086
+ close: ")+"
1087
+ },
1088
+ "*": {
1089
+ type: "star",
1090
+ open: "(?:",
1091
+ close: ")*"
1092
+ },
1093
+ "@": {
1094
+ type: "at",
1095
+ open: "(?:",
1096
+ close: ")"
1097
+ }
1098
+ };
1099
+ },
1100
+ /**
1101
+ * Create GLOB_CHARS
1102
+ */
1103
+ globChars(win32) {
1104
+ return win32 === true ? WINDOWS_CHARS : POSIX_CHARS;
1105
+ }
1106
+ };
1107
+ }));
1108
+ //#endregion
1109
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js
1110
+ var require_utils = /* @__PURE__ */ __commonJSMin$1(((exports) => {
1111
+ const { REGEX_BACKSLASH, REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL } = require_constants();
1112
+ exports.isObject = (val) => val !== null && typeof val === "object" && !Array.isArray(val);
1113
+ exports.hasRegexChars = (str) => REGEX_SPECIAL_CHARS.test(str);
1114
+ exports.isRegexChar = (str) => str.length === 1 && exports.hasRegexChars(str);
1115
+ exports.escapeRegex = (str) => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, "\\$1");
1116
+ exports.toPosixSlashes = (str) => str.replace(REGEX_BACKSLASH, "/");
1117
+ exports.isWindows = () => {
1118
+ if (typeof navigator !== "undefined" && navigator.platform) {
1119
+ const platform = navigator.platform.toLowerCase();
1120
+ return platform === "win32" || platform === "windows";
1121
+ }
1122
+ if (typeof process !== "undefined" && process.platform) return process.platform === "win32";
1123
+ return false;
1124
+ };
1125
+ exports.removeBackslashes = (str) => {
1126
+ return str.replace(REGEX_REMOVE_BACKSLASH, (match) => {
1127
+ return match === "\\" ? "" : match;
1128
+ });
1129
+ };
1130
+ exports.escapeLast = (input, char, lastIdx) => {
1131
+ const idx = input.lastIndexOf(char, lastIdx);
1132
+ if (idx === -1) return input;
1133
+ if (input[idx - 1] === "\\") return exports.escapeLast(input, char, idx - 1);
1134
+ return `${input.slice(0, idx)}\\${input.slice(idx)}`;
1135
+ };
1136
+ exports.removePrefix = (input, state = {}) => {
1137
+ let output = input;
1138
+ if (output.startsWith("./")) {
1139
+ output = output.slice(2);
1140
+ state.prefix = "./";
1141
+ }
1142
+ return output;
1143
+ };
1144
+ exports.wrapOutput = (input, state = {}, options = {}) => {
1145
+ let output = `${options.contains ? "" : "^"}(?:${input})${options.contains ? "" : "$"}`;
1146
+ if (state.negated === true) output = `(?:^(?!${output}).*$)`;
1147
+ return output;
1148
+ };
1149
+ exports.basename = (path, { windows } = {}) => {
1150
+ const segs = path.split(windows ? /[\\/]/ : "/");
1151
+ const last = segs[segs.length - 1];
1152
+ if (last === "") return segs[segs.length - 2];
1153
+ return last;
1154
+ };
1155
+ }));
1156
+ //#endregion
1157
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/scan.js
1158
+ var require_scan = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1159
+ const utils = require_utils();
1160
+ 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();
1161
+ const isPathSeparator = (code) => {
1162
+ return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
1163
+ };
1164
+ const depth = (token) => {
1165
+ if (token.isPrefix !== true) token.depth = token.isGlobstar ? Infinity : 1;
1166
+ };
1167
+ /**
1168
+ * Quickly scans a glob pattern and returns an object with a handful of
1169
+ * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists),
1170
+ * `glob` (the actual pattern), `negated` (true if the path starts with `!` but not
1171
+ * with `!(`) and `negatedExtglob` (true if the path starts with `!(`).
1172
+ *
1173
+ * ```js
1174
+ * const pm = require('picomatch');
1175
+ * console.log(pm.scan('foo/bar/*.js'));
1176
+ * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' }
1177
+ * ```
1178
+ * @param {String} `str`
1179
+ * @param {Object} `options`
1180
+ * @return {Object} Returns an object with tokens and regex source string.
1181
+ * @api public
1182
+ */
1183
+ const scan = (input, options) => {
1184
+ const opts = options || {};
1185
+ const length = input.length - 1;
1186
+ const scanToEnd = opts.parts === true || opts.scanToEnd === true;
1187
+ const slashes = [];
1188
+ const tokens = [];
1189
+ const parts = [];
1190
+ let str = input;
1191
+ let index = -1;
1192
+ let start = 0;
1193
+ let lastIndex = 0;
1194
+ let isBrace = false;
1195
+ let isBracket = false;
1196
+ let isGlob = false;
1197
+ let isExtglob = false;
1198
+ let isGlobstar = false;
1199
+ let braceEscaped = false;
1200
+ let backslashes = false;
1201
+ let negated = false;
1202
+ let negatedExtglob = false;
1203
+ let finished = false;
1204
+ let braces = 0;
1205
+ let prev;
1206
+ let code;
1207
+ let token = {
1208
+ value: "",
1209
+ depth: 0,
1210
+ isGlob: false
1211
+ };
1212
+ const eos = () => index >= length;
1213
+ const peek = () => str.charCodeAt(index + 1);
1214
+ const advance = () => {
1215
+ prev = code;
1216
+ return str.charCodeAt(++index);
1217
+ };
1218
+ while (index < length) {
1219
+ code = advance();
1220
+ let next;
1221
+ if (code === CHAR_BACKWARD_SLASH) {
1222
+ backslashes = token.backslashes = true;
1223
+ code = advance();
1224
+ if (code === CHAR_LEFT_CURLY_BRACE) braceEscaped = true;
1225
+ continue;
1226
+ }
1227
+ if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) {
1228
+ braces++;
1229
+ while (eos() !== true && (code = advance())) {
1230
+ if (code === CHAR_BACKWARD_SLASH) {
1231
+ backslashes = token.backslashes = true;
1232
+ advance();
1233
+ continue;
1234
+ }
1235
+ if (code === CHAR_LEFT_CURLY_BRACE) {
1236
+ braces++;
1237
+ continue;
1238
+ }
1239
+ if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) {
1240
+ isBrace = token.isBrace = true;
1241
+ isGlob = token.isGlob = true;
1242
+ finished = true;
1243
+ if (scanToEnd === true) continue;
1244
+ break;
1245
+ }
1246
+ if (braceEscaped !== true && code === CHAR_COMMA) {
1247
+ isBrace = token.isBrace = true;
1248
+ isGlob = token.isGlob = true;
1249
+ finished = true;
1250
+ if (scanToEnd === true) continue;
1251
+ break;
1252
+ }
1253
+ if (code === CHAR_RIGHT_CURLY_BRACE) {
1254
+ braces--;
1255
+ if (braces === 0) {
1256
+ braceEscaped = false;
1257
+ isBrace = token.isBrace = true;
1258
+ finished = true;
1259
+ break;
1260
+ }
1261
+ }
1262
+ }
1263
+ if (scanToEnd === true) continue;
1264
+ break;
1265
+ }
1266
+ if (code === CHAR_FORWARD_SLASH) {
1267
+ slashes.push(index);
1268
+ tokens.push(token);
1269
+ token = {
1270
+ value: "",
1271
+ depth: 0,
1272
+ isGlob: false
1273
+ };
1274
+ if (finished === true) continue;
1275
+ if (prev === CHAR_DOT && index === start + 1) {
1276
+ start += 2;
1277
+ continue;
1278
+ }
1279
+ lastIndex = index + 1;
1280
+ continue;
1281
+ }
1282
+ if (opts.noext !== true) {
1283
+ if ((code === CHAR_PLUS || code === CHAR_AT || code === CHAR_ASTERISK || code === CHAR_QUESTION_MARK || code === CHAR_EXCLAMATION_MARK) === true && peek() === CHAR_LEFT_PARENTHESES) {
1284
+ isGlob = token.isGlob = true;
1285
+ isExtglob = token.isExtglob = true;
1286
+ finished = true;
1287
+ if (code === CHAR_EXCLAMATION_MARK && index === start) negatedExtglob = true;
1288
+ if (scanToEnd === true) {
1289
+ while (eos() !== true && (code = advance())) {
1290
+ if (code === CHAR_BACKWARD_SLASH) {
1291
+ backslashes = token.backslashes = true;
1292
+ code = advance();
1293
+ continue;
1294
+ }
1295
+ if (code === CHAR_RIGHT_PARENTHESES) {
1296
+ isGlob = token.isGlob = true;
1297
+ finished = true;
1298
+ break;
1299
+ }
1300
+ }
1301
+ continue;
1302
+ }
1303
+ break;
1304
+ }
1305
+ }
1306
+ if (code === CHAR_ASTERISK) {
1307
+ if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true;
1308
+ isGlob = token.isGlob = true;
1309
+ finished = true;
1310
+ if (scanToEnd === true) continue;
1311
+ break;
1312
+ }
1313
+ if (code === CHAR_QUESTION_MARK) {
1314
+ isGlob = token.isGlob = true;
1315
+ finished = true;
1316
+ if (scanToEnd === true) continue;
1317
+ break;
1318
+ }
1319
+ if (code === CHAR_LEFT_SQUARE_BRACKET) {
1320
+ while (eos() !== true && (next = advance())) {
1321
+ if (next === CHAR_BACKWARD_SLASH) {
1322
+ backslashes = token.backslashes = true;
1323
+ advance();
1324
+ continue;
1325
+ }
1326
+ if (next === CHAR_RIGHT_SQUARE_BRACKET) {
1327
+ isBracket = token.isBracket = true;
1328
+ isGlob = token.isGlob = true;
1329
+ finished = true;
1330
+ break;
1331
+ }
1332
+ }
1333
+ if (scanToEnd === true) continue;
1334
+ break;
1335
+ }
1336
+ if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) {
1337
+ negated = token.negated = true;
1338
+ start++;
1339
+ continue;
1340
+ }
1341
+ if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) {
1342
+ isGlob = token.isGlob = true;
1343
+ if (scanToEnd === true) {
1344
+ while (eos() !== true && (code = advance())) {
1345
+ if (code === CHAR_LEFT_PARENTHESES) {
1346
+ backslashes = token.backslashes = true;
1347
+ code = advance();
1348
+ continue;
1349
+ }
1350
+ if (code === CHAR_RIGHT_PARENTHESES) {
1351
+ finished = true;
1352
+ break;
1353
+ }
1354
+ }
1355
+ continue;
1356
+ }
1357
+ break;
1358
+ }
1359
+ if (isGlob === true) {
1360
+ finished = true;
1361
+ if (scanToEnd === true) continue;
1362
+ break;
1363
+ }
1364
+ }
1365
+ if (opts.noext === true) {
1366
+ isExtglob = false;
1367
+ isGlob = false;
1368
+ }
1369
+ let base = str;
1370
+ let prefix = "";
1371
+ let glob = "";
1372
+ if (start > 0) {
1373
+ prefix = str.slice(0, start);
1374
+ str = str.slice(start);
1375
+ lastIndex -= start;
1376
+ }
1377
+ if (base && isGlob === true && lastIndex > 0) {
1378
+ base = str.slice(0, lastIndex);
1379
+ glob = str.slice(lastIndex);
1380
+ } else if (isGlob === true) {
1381
+ base = "";
1382
+ glob = str;
1383
+ } else base = str;
1384
+ if (base && base !== "" && base !== "/" && base !== str) {
1385
+ if (isPathSeparator(base.charCodeAt(base.length - 1))) base = base.slice(0, -1);
1386
+ }
1387
+ if (opts.unescape === true) {
1388
+ if (glob) glob = utils.removeBackslashes(glob);
1389
+ if (base && backslashes === true) base = utils.removeBackslashes(base);
1390
+ }
1391
+ const state = {
1392
+ prefix,
1393
+ input,
1394
+ start,
1395
+ base,
1396
+ glob,
1397
+ isBrace,
1398
+ isBracket,
1399
+ isGlob,
1400
+ isExtglob,
1401
+ isGlobstar,
1402
+ negated,
1403
+ negatedExtglob
1404
+ };
1405
+ if (opts.tokens === true) {
1406
+ state.maxDepth = 0;
1407
+ if (!isPathSeparator(code)) tokens.push(token);
1408
+ state.tokens = tokens;
1409
+ }
1410
+ if (opts.parts === true || opts.tokens === true) {
1411
+ let prevIndex;
1412
+ for (let idx = 0; idx < slashes.length; idx++) {
1413
+ const n = prevIndex ? prevIndex + 1 : start;
1414
+ const i = slashes[idx];
1415
+ const value = input.slice(n, i);
1416
+ if (opts.tokens) {
1417
+ if (idx === 0 && start !== 0) {
1418
+ tokens[idx].isPrefix = true;
1419
+ tokens[idx].value = prefix;
1420
+ } else tokens[idx].value = value;
1421
+ depth(tokens[idx]);
1422
+ state.maxDepth += tokens[idx].depth;
1423
+ }
1424
+ if (idx !== 0 || value !== "") parts.push(value);
1425
+ prevIndex = i;
1426
+ }
1427
+ if (prevIndex && prevIndex + 1 < input.length) {
1428
+ const value = input.slice(prevIndex + 1);
1429
+ parts.push(value);
1430
+ if (opts.tokens) {
1431
+ tokens[tokens.length - 1].value = value;
1432
+ depth(tokens[tokens.length - 1]);
1433
+ state.maxDepth += tokens[tokens.length - 1].depth;
1434
+ }
1435
+ }
1436
+ state.slashes = slashes;
1437
+ state.parts = parts;
1438
+ }
1439
+ return state;
1440
+ };
1441
+ module.exports = scan;
1442
+ }));
1443
+ //#endregion
1444
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/parse.js
1445
+ var require_parse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
1446
+ const constants = require_constants();
1447
+ const utils = require_utils();
1448
+ /**
1449
+ * Constants
1450
+ */
1451
+ const { MAX_LENGTH, POSIX_REGEX_SOURCE, REGEX_NON_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_BACKREF, REPLACEMENTS } = constants;
1452
+ /**
1453
+ * Helpers
1454
+ */
1455
+ const expandRange = (args, options) => {
1456
+ if (typeof options.expandRange === "function") return options.expandRange(...args, options);
1457
+ args.sort();
1458
+ const value = `[${args.join("-")}]`;
1459
+ try {
1460
+ new RegExp(value);
1461
+ } catch (ex) {
1462
+ return args.map((v) => utils.escapeRegex(v)).join("..");
1463
+ }
1464
+ return value;
1465
+ };
1466
+ /**
1467
+ * Create the message for a syntax error
1468
+ */
1469
+ const syntaxError = (type, char) => {
1470
+ return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
1471
+ };
1472
+ const splitTopLevel = (input) => {
1473
+ const parts = [];
1474
+ let bracket = 0;
1475
+ let paren = 0;
1476
+ let quote = 0;
1477
+ let value = "";
1478
+ let escaped = false;
1479
+ for (const ch of input) {
1480
+ if (escaped === true) {
1481
+ value += ch;
1482
+ escaped = false;
1483
+ continue;
1484
+ }
1485
+ if (ch === "\\") {
1486
+ value += ch;
1487
+ escaped = true;
1488
+ continue;
1489
+ }
1490
+ if (ch === "\"") {
1491
+ quote = quote === 1 ? 0 : 1;
1492
+ value += ch;
1493
+ continue;
1494
+ }
1495
+ if (quote === 0) {
1496
+ if (ch === "[") bracket++;
1497
+ else if (ch === "]" && bracket > 0) bracket--;
1498
+ else if (bracket === 0) {
1499
+ if (ch === "(") paren++;
1500
+ else if (ch === ")" && paren > 0) paren--;
1501
+ else if (ch === "|" && paren === 0) {
1502
+ parts.push(value);
1503
+ value = "";
1504
+ continue;
1505
+ }
1506
+ }
1507
+ }
1508
+ value += ch;
1509
+ }
1510
+ parts.push(value);
1511
+ return parts;
1512
+ };
1513
+ const isPlainBranch = (branch) => {
1514
+ let escaped = false;
1515
+ for (const ch of branch) {
1516
+ if (escaped === true) {
1517
+ escaped = false;
1518
+ continue;
1519
+ }
1520
+ if (ch === "\\") {
1521
+ escaped = true;
1522
+ continue;
1523
+ }
1524
+ if (/[?*+@!()[\]{}]/.test(ch)) return false;
1525
+ }
1526
+ return true;
1527
+ };
1528
+ const normalizeSimpleBranch = (branch) => {
1529
+ let value = branch.trim();
1530
+ let changed = true;
1531
+ while (changed === true) {
1532
+ changed = false;
1533
+ if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
1534
+ value = value.slice(2, -1);
1535
+ changed = true;
1536
+ }
1537
+ }
1538
+ if (!isPlainBranch(value)) return;
1539
+ return value.replace(/\\(.)/g, "$1");
1540
+ };
1541
+ const hasRepeatedCharPrefixOverlap = (branches) => {
1542
+ const values = branches.map(normalizeSimpleBranch).filter(Boolean);
1543
+ for (let i = 0; i < values.length; i++) for (let j = i + 1; j < values.length; j++) {
1544
+ const a = values[i];
1545
+ const b = values[j];
1546
+ const char = a[0];
1547
+ if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) continue;
1548
+ if (a === b || a.startsWith(b) || b.startsWith(a)) return true;
1549
+ }
1550
+ return false;
1551
+ };
1552
+ const parseRepeatedExtglob = (pattern, requireEnd = true) => {
1553
+ if (pattern[0] !== "+" && pattern[0] !== "*" || pattern[1] !== "(") return;
1554
+ let bracket = 0;
1555
+ let paren = 0;
1556
+ let quote = 0;
1557
+ let escaped = false;
1558
+ for (let i = 1; i < pattern.length; i++) {
1559
+ const ch = pattern[i];
1560
+ if (escaped === true) {
1561
+ escaped = false;
1562
+ continue;
1563
+ }
1564
+ if (ch === "\\") {
1565
+ escaped = true;
1566
+ continue;
1567
+ }
1568
+ if (ch === "\"") {
1569
+ quote = quote === 1 ? 0 : 1;
1570
+ continue;
1571
+ }
1572
+ if (quote === 1) continue;
1573
+ if (ch === "[") {
1574
+ bracket++;
1575
+ continue;
1576
+ }
1577
+ if (ch === "]" && bracket > 0) {
1578
+ bracket--;
1579
+ continue;
1580
+ }
1581
+ if (bracket > 0) continue;
1582
+ if (ch === "(") {
1583
+ paren++;
1584
+ continue;
1585
+ }
1586
+ if (ch === ")") {
1587
+ paren--;
1588
+ if (paren === 0) {
1589
+ if (requireEnd === true && i !== pattern.length - 1) return;
1590
+ return {
1591
+ type: pattern[0],
1592
+ body: pattern.slice(2, i),
1593
+ end: i
1594
+ };
1595
+ }
1596
+ }
1597
+ }
1598
+ };
1599
+ const getStarExtglobSequenceOutput = (pattern) => {
1600
+ let index = 0;
1601
+ const chars = [];
1602
+ while (index < pattern.length) {
1603
+ const match = parseRepeatedExtglob(pattern.slice(index), false);
1604
+ if (!match || match.type !== "*") return;
1605
+ const branches = splitTopLevel(match.body).map((branch) => branch.trim());
1606
+ if (branches.length !== 1) return;
1607
+ const branch = normalizeSimpleBranch(branches[0]);
1608
+ if (!branch || branch.length !== 1) return;
1609
+ chars.push(branch);
1610
+ index += match.end + 1;
1611
+ }
1612
+ if (chars.length < 1) return;
1613
+ return `${chars.length === 1 ? utils.escapeRegex(chars[0]) : `[${chars.map((ch) => utils.escapeRegex(ch)).join("")}]`}*`;
1614
+ };
1615
+ const repeatedExtglobRecursion = (pattern) => {
1616
+ let depth = 0;
1617
+ let value = pattern.trim();
1618
+ let match = parseRepeatedExtglob(value);
1619
+ while (match) {
1620
+ depth++;
1621
+ value = match.body.trim();
1622
+ match = parseRepeatedExtglob(value);
1623
+ }
1624
+ return depth;
1625
+ };
1626
+ const analyzeRepeatedExtglob = (body, options) => {
1627
+ if (options.maxExtglobRecursion === false) return { risky: false };
1628
+ const max = typeof options.maxExtglobRecursion === "number" ? options.maxExtglobRecursion : constants.DEFAULT_MAX_EXTGLOB_RECURSION;
1629
+ const branches = splitTopLevel(body).map((branch) => branch.trim());
1630
+ if (branches.length > 1) {
1631
+ if (branches.some((branch) => branch === "") || branches.some((branch) => /^[*?]+$/.test(branch)) || hasRepeatedCharPrefixOverlap(branches)) return { risky: true };
1632
+ }
1633
+ for (const branch of branches) {
1634
+ const safeOutput = getStarExtglobSequenceOutput(branch);
1635
+ if (safeOutput) return {
1636
+ risky: true,
1637
+ safeOutput
1638
+ };
1639
+ if (repeatedExtglobRecursion(branch) > max) return { risky: true };
1640
+ }
1641
+ return { risky: false };
1642
+ };
1643
+ /**
1644
+ * Parse the given input string.
1645
+ * @param {String} input
1646
+ * @param {Object} options
1647
+ * @return {Object}
1648
+ */
1649
+ const parse = (input, options) => {
1650
+ if (typeof input !== "string") throw new TypeError("Expected a string");
1651
+ input = REPLACEMENTS[input] || input;
1652
+ const opts = { ...options };
1653
+ const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
1654
+ let len = input.length;
1655
+ if (len > max) throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
1656
+ const bos = {
1657
+ type: "bos",
1658
+ value: "",
1659
+ output: opts.prepend || ""
1660
+ };
1661
+ const tokens = [bos];
1662
+ const capture = opts.capture ? "" : "?:";
1663
+ const PLATFORM_CHARS = constants.globChars(opts.windows);
1664
+ const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);
1665
+ 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;
1666
+ const globstar = (opts) => {
1667
+ return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
1668
+ };
1669
+ const nodot = opts.dot ? "" : NO_DOT;
1670
+ const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
1671
+ let star = opts.bash === true ? globstar(opts) : STAR;
1672
+ if (opts.capture) star = `(${star})`;
1673
+ if (typeof opts.noext === "boolean") opts.noextglob = opts.noext;
1674
+ const state = {
1675
+ input,
1676
+ index: -1,
1677
+ start: 0,
1678
+ dot: opts.dot === true,
1679
+ consumed: "",
1680
+ output: "",
1681
+ prefix: "",
1682
+ backtrack: false,
1683
+ negated: false,
1684
+ brackets: 0,
1685
+ braces: 0,
1686
+ parens: 0,
1687
+ quotes: 0,
1688
+ globstar: false,
1689
+ tokens
1690
+ };
1691
+ input = utils.removePrefix(input, state);
1692
+ len = input.length;
1693
+ const extglobs = [];
1694
+ const braces = [];
1695
+ const stack = [];
1696
+ let prev = bos;
1697
+ let value;
1698
+ /**
1699
+ * Tokenizing helpers
1700
+ */
1701
+ const eos = () => state.index === len - 1;
1702
+ const peek = state.peek = (n = 1) => input[state.index + n];
1703
+ const advance = state.advance = () => input[++state.index] || "";
1704
+ const remaining = () => input.slice(state.index + 1);
1705
+ const consume = (value = "", num = 0) => {
1706
+ state.consumed += value;
1707
+ state.index += num;
1708
+ };
1709
+ const append = (token) => {
1710
+ state.output += token.output != null ? token.output : token.value;
1711
+ consume(token.value);
1712
+ };
1713
+ const negate = () => {
1714
+ let count = 1;
1715
+ while (peek() === "!" && (peek(2) !== "(" || peek(3) === "?")) {
1716
+ advance();
1717
+ state.start++;
1718
+ count++;
1719
+ }
1720
+ if (count % 2 === 0) return false;
1721
+ state.negated = true;
1722
+ state.start++;
1723
+ return true;
1724
+ };
1725
+ const increment = (type) => {
1726
+ state[type]++;
1727
+ stack.push(type);
1728
+ };
1729
+ const decrement = (type) => {
1730
+ state[type]--;
1731
+ stack.pop();
1732
+ };
1733
+ /**
1734
+ * Push tokens onto the tokens array. This helper speeds up
1735
+ * tokenizing by 1) helping us avoid backtracking as much as possible,
1736
+ * and 2) helping us avoid creating extra tokens when consecutive
1737
+ * characters are plain text. This improves performance and simplifies
1738
+ * lookbehinds.
1739
+ */
1740
+ const push = (tok) => {
1741
+ if (prev.type === "globstar") {
1742
+ const isBrace = state.braces > 0 && (tok.type === "comma" || tok.type === "brace");
1743
+ const isExtglob = tok.extglob === true || extglobs.length && (tok.type === "pipe" || tok.type === "paren");
1744
+ if (tok.type !== "slash" && tok.type !== "paren" && !isBrace && !isExtglob) {
1745
+ state.output = state.output.slice(0, -prev.output.length);
1746
+ prev.type = "star";
1747
+ prev.value = "*";
1748
+ prev.output = star;
1749
+ state.output += prev.output;
1750
+ }
1751
+ }
1752
+ if (extglobs.length && tok.type !== "paren") extglobs[extglobs.length - 1].inner += tok.value;
1753
+ if (tok.value || tok.output) append(tok);
1754
+ if (prev && prev.type === "text" && tok.type === "text") {
1755
+ prev.output = (prev.output || prev.value) + tok.value;
1756
+ prev.value += tok.value;
1757
+ return;
1758
+ }
1759
+ tok.prev = prev;
1760
+ tokens.push(tok);
1761
+ prev = tok;
1762
+ };
1763
+ const extglobOpen = (type, value) => {
1764
+ const token = {
1765
+ ...EXTGLOB_CHARS[value],
1766
+ conditions: 1,
1767
+ inner: ""
1768
+ };
1769
+ token.prev = prev;
1770
+ token.parens = state.parens;
1771
+ token.output = state.output;
1772
+ token.startIndex = state.index;
1773
+ token.tokensIndex = tokens.length;
1774
+ const output = (opts.capture ? "(" : "") + token.open;
1775
+ increment("parens");
1776
+ push({
1777
+ type,
1778
+ value,
1779
+ output: state.output ? "" : ONE_CHAR
1780
+ });
1781
+ push({
1782
+ type: "paren",
1783
+ extglob: true,
1784
+ value: advance(),
1785
+ output
1786
+ });
1787
+ extglobs.push(token);
1788
+ };
1789
+ const extglobClose = (token) => {
1790
+ const literal = input.slice(token.startIndex, state.index + 1);
1791
+ const analysis = analyzeRepeatedExtglob(input.slice(token.startIndex + 2, state.index), opts);
1792
+ if ((token.type === "plus" || token.type === "star") && analysis.risky) {
1793
+ const safeOutput = analysis.safeOutput ? (token.output ? "" : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : void 0;
1794
+ const open = tokens[token.tokensIndex];
1795
+ open.type = "text";
1796
+ open.value = literal;
1797
+ open.output = safeOutput || utils.escapeRegex(literal);
1798
+ for (let i = token.tokensIndex + 1; i < tokens.length; i++) {
1799
+ tokens[i].value = "";
1800
+ tokens[i].output = "";
1801
+ delete tokens[i].suffix;
1802
+ }
1803
+ state.output = token.output + open.output;
1804
+ state.backtrack = true;
1805
+ push({
1806
+ type: "paren",
1807
+ extglob: true,
1808
+ value,
1809
+ output: ""
1810
+ });
1811
+ decrement("parens");
1812
+ return;
1813
+ }
1814
+ let output = token.close + (opts.capture ? ")" : "");
1815
+ let rest;
1816
+ if (token.type === "negate") {
1817
+ let extglobStar = star;
1818
+ if (token.inner && token.inner.length > 1 && token.inner.includes("/")) extglobStar = globstar(opts);
1819
+ if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) output = token.close = `)$))${extglobStar}`;
1820
+ if (token.inner.includes("*") && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) output = token.close = `)${parse(rest, {
1821
+ ...options,
1822
+ fastpaths: false
1823
+ }).output})${extglobStar})`;
1824
+ if (token.prev.type === "bos") state.negatedExtglob = true;
1825
+ }
1826
+ push({
1827
+ type: "paren",
1828
+ extglob: true,
1829
+ value,
1830
+ output
1831
+ });
1832
+ decrement("parens");
1833
+ };
1834
+ /**
1835
+ * Fast paths
1836
+ */
1837
+ if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) {
1838
+ let backslashes = false;
1839
+ let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => {
1840
+ if (first === "\\") {
1841
+ backslashes = true;
1842
+ return m;
1843
+ }
1844
+ if (first === "?") {
1845
+ if (esc) return esc + first + (rest ? QMARK.repeat(rest.length) : "");
1846
+ if (index === 0) return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : "");
1847
+ return QMARK.repeat(chars.length);
1848
+ }
1849
+ if (first === ".") return DOT_LITERAL.repeat(chars.length);
1850
+ if (first === "*") {
1851
+ if (esc) return esc + first + (rest ? star : "");
1852
+ return star;
1853
+ }
1854
+ return esc ? m : `\\${m}`;
1855
+ });
1856
+ if (backslashes === true) if (opts.unescape === true) output = output.replace(/\\/g, "");
1857
+ else output = output.replace(/\\+/g, (m) => {
1858
+ return m.length % 2 === 0 ? "\\\\" : m ? "\\" : "";
1859
+ });
1860
+ if (output === input && opts.contains === true) {
1861
+ state.output = input;
1862
+ return state;
1863
+ }
1864
+ state.output = utils.wrapOutput(output, state, options);
1865
+ return state;
1866
+ }
1867
+ /**
1868
+ * Tokenize input until we reach end-of-string
1869
+ */
1870
+ while (!eos()) {
1871
+ value = advance();
1872
+ if (value === "\0") continue;
1873
+ /**
1874
+ * Escaped characters
1875
+ */
1876
+ if (value === "\\") {
1877
+ const next = peek();
1878
+ if (next === "/" && opts.bash !== true) continue;
1879
+ if (next === "." || next === ";") continue;
1880
+ if (!next) {
1881
+ value += "\\";
1882
+ push({
1883
+ type: "text",
1884
+ value
1885
+ });
1886
+ continue;
1887
+ }
1888
+ const match = /^\\+/.exec(remaining());
1889
+ let slashes = 0;
1890
+ if (match && match[0].length > 2) {
1891
+ slashes = match[0].length;
1892
+ state.index += slashes;
1893
+ if (slashes % 2 !== 0) value += "\\";
1894
+ }
1895
+ if (opts.unescape === true) value = advance();
1896
+ else value += advance();
1897
+ if (state.brackets === 0) {
1898
+ push({
1899
+ type: "text",
1900
+ value
1901
+ });
1902
+ continue;
1903
+ }
1904
+ }
1905
+ /**
1906
+ * If we're inside a regex character class, continue
1907
+ * until we reach the closing bracket.
1908
+ */
1909
+ if (state.brackets > 0 && (value !== "]" || prev.value === "[" || prev.value === "[^")) {
1910
+ if (opts.posix !== false && value === ":") {
1911
+ const inner = prev.value.slice(1);
1912
+ if (inner.includes("[")) {
1913
+ prev.posix = true;
1914
+ if (inner.includes(":")) {
1915
+ const idx = prev.value.lastIndexOf("[");
1916
+ const pre = prev.value.slice(0, idx);
1917
+ const posix = POSIX_REGEX_SOURCE[prev.value.slice(idx + 2)];
1918
+ if (posix) {
1919
+ prev.value = pre + posix;
1920
+ state.backtrack = true;
1921
+ advance();
1922
+ if (!bos.output && tokens.indexOf(prev) === 1) bos.output = ONE_CHAR;
1923
+ continue;
1924
+ }
1925
+ }
1926
+ }
1927
+ }
1928
+ if (value === "[" && peek() !== ":" || value === "-" && peek() === "]") value = `\\${value}`;
1929
+ if (value === "]" && (prev.value === "[" || prev.value === "[^")) value = `\\${value}`;
1930
+ if (opts.posix === true && value === "!" && prev.value === "[") value = "^";
1931
+ prev.value += value;
1932
+ append({ value });
1933
+ continue;
1934
+ }
1935
+ /**
1936
+ * If we're inside a quoted string, continue
1937
+ * until we reach the closing double quote.
1938
+ */
1939
+ if (state.quotes === 1 && value !== "\"") {
1940
+ value = utils.escapeRegex(value);
1941
+ prev.value += value;
1942
+ append({ value });
1943
+ continue;
1944
+ }
1945
+ /**
1946
+ * Double quotes
1947
+ */
1948
+ if (value === "\"") {
1949
+ state.quotes = state.quotes === 1 ? 0 : 1;
1950
+ if (opts.keepQuotes === true) push({
1951
+ type: "text",
1952
+ value
1953
+ });
1954
+ continue;
1955
+ }
1956
+ /**
1957
+ * Parentheses
1958
+ */
1959
+ if (value === "(") {
1960
+ increment("parens");
1961
+ push({
1962
+ type: "paren",
1963
+ value
1964
+ });
1965
+ continue;
1966
+ }
1967
+ if (value === ")") {
1968
+ if (state.parens === 0 && opts.strictBrackets === true) throw new SyntaxError(syntaxError("opening", "("));
1969
+ const extglob = extglobs[extglobs.length - 1];
1970
+ if (extglob && state.parens === extglob.parens + 1) {
1971
+ extglobClose(extglobs.pop());
1972
+ continue;
1973
+ }
1974
+ push({
1975
+ type: "paren",
1976
+ value,
1977
+ output: state.parens ? ")" : "\\)"
1978
+ });
1979
+ decrement("parens");
1980
+ continue;
1981
+ }
1982
+ /**
1983
+ * Square brackets
1984
+ */
1985
+ if (value === "[") {
1986
+ if (opts.nobracket === true || !remaining().includes("]")) {
1987
+ if (opts.nobracket !== true && opts.strictBrackets === true) throw new SyntaxError(syntaxError("closing", "]"));
1988
+ value = `\\${value}`;
1989
+ } else increment("brackets");
1990
+ push({
1991
+ type: "bracket",
1992
+ value
1993
+ });
1994
+ continue;
1995
+ }
1996
+ if (value === "]") {
1997
+ if (opts.nobracket === true || prev && prev.type === "bracket" && prev.value.length === 1) {
1998
+ push({
1999
+ type: "text",
2000
+ value,
2001
+ output: `\\${value}`
2002
+ });
2003
+ continue;
2004
+ }
2005
+ if (state.brackets === 0) {
2006
+ if (opts.strictBrackets === true) throw new SyntaxError(syntaxError("opening", "["));
2007
+ push({
2008
+ type: "text",
2009
+ value,
2010
+ output: `\\${value}`
2011
+ });
2012
+ continue;
2013
+ }
2014
+ decrement("brackets");
2015
+ const prevValue = prev.value.slice(1);
2016
+ if (prev.posix !== true && prevValue[0] === "^" && !prevValue.includes("/")) value = `/${value}`;
2017
+ prev.value += value;
2018
+ append({ value });
2019
+ if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) continue;
2020
+ const escaped = utils.escapeRegex(prev.value);
2021
+ state.output = state.output.slice(0, -prev.value.length);
2022
+ if (opts.literalBrackets === true) {
2023
+ state.output += escaped;
2024
+ prev.value = escaped;
2025
+ continue;
2026
+ }
2027
+ prev.value = `(${capture}${escaped}|${prev.value})`;
2028
+ state.output += prev.value;
2029
+ continue;
2030
+ }
2031
+ /**
2032
+ * Braces
2033
+ */
2034
+ if (value === "{" && opts.nobrace !== true) {
2035
+ increment("braces");
2036
+ const open = {
2037
+ type: "brace",
2038
+ value,
2039
+ output: "(",
2040
+ outputIndex: state.output.length,
2041
+ tokensIndex: state.tokens.length
2042
+ };
2043
+ braces.push(open);
2044
+ push(open);
2045
+ continue;
2046
+ }
2047
+ if (value === "}") {
2048
+ const brace = braces[braces.length - 1];
2049
+ if (opts.nobrace === true || !brace) {
2050
+ push({
2051
+ type: "text",
2052
+ value,
2053
+ output: value
2054
+ });
2055
+ continue;
2056
+ }
2057
+ let output = ")";
2058
+ if (brace.dots === true) {
2059
+ const arr = tokens.slice();
2060
+ const range = [];
2061
+ for (let i = arr.length - 1; i >= 0; i--) {
2062
+ tokens.pop();
2063
+ if (arr[i].type === "brace") break;
2064
+ if (arr[i].type !== "dots") range.unshift(arr[i].value);
2065
+ }
2066
+ output = expandRange(range, opts);
2067
+ state.backtrack = true;
2068
+ }
2069
+ if (brace.comma !== true && brace.dots !== true) {
2070
+ const out = state.output.slice(0, brace.outputIndex);
2071
+ const toks = state.tokens.slice(brace.tokensIndex);
2072
+ brace.value = brace.output = "\\{";
2073
+ value = output = "\\}";
2074
+ state.output = out;
2075
+ for (const t of toks) state.output += t.output || t.value;
2076
+ }
2077
+ push({
2078
+ type: "brace",
2079
+ value,
2080
+ output
2081
+ });
2082
+ decrement("braces");
2083
+ braces.pop();
2084
+ continue;
2085
+ }
2086
+ /**
2087
+ * Pipes
2088
+ */
2089
+ if (value === "|") {
2090
+ if (extglobs.length > 0) extglobs[extglobs.length - 1].conditions++;
2091
+ push({
2092
+ type: "text",
2093
+ value
2094
+ });
2095
+ continue;
2096
+ }
2097
+ /**
2098
+ * Commas
2099
+ */
2100
+ if (value === ",") {
2101
+ let output = value;
2102
+ const brace = braces[braces.length - 1];
2103
+ if (brace && stack[stack.length - 1] === "braces") {
2104
+ brace.comma = true;
2105
+ output = "|";
2106
+ }
2107
+ push({
2108
+ type: "comma",
2109
+ value,
2110
+ output
2111
+ });
2112
+ continue;
2113
+ }
2114
+ /**
2115
+ * Slashes
2116
+ */
2117
+ if (value === "/") {
2118
+ if (prev.type === "dot" && state.index === state.start + 1) {
2119
+ state.start = state.index + 1;
2120
+ state.consumed = "";
2121
+ state.output = "";
2122
+ tokens.pop();
2123
+ prev = bos;
2124
+ continue;
2125
+ }
2126
+ push({
2127
+ type: "slash",
2128
+ value,
2129
+ output: SLASH_LITERAL
2130
+ });
2131
+ continue;
2132
+ }
2133
+ /**
2134
+ * Dots
2135
+ */
2136
+ if (value === ".") {
2137
+ if (state.braces > 0 && prev.type === "dot") {
2138
+ if (prev.value === ".") prev.output = DOT_LITERAL;
2139
+ const brace = braces[braces.length - 1];
2140
+ prev.type = "dots";
2141
+ prev.output += value;
2142
+ prev.value += value;
2143
+ brace.dots = true;
2144
+ continue;
2145
+ }
2146
+ if (state.braces + state.parens === 0 && prev.type !== "bos" && prev.type !== "slash") {
2147
+ push({
2148
+ type: "text",
2149
+ value,
2150
+ output: DOT_LITERAL
2151
+ });
2152
+ continue;
2153
+ }
2154
+ push({
2155
+ type: "dot",
2156
+ value,
2157
+ output: DOT_LITERAL
2158
+ });
2159
+ continue;
2160
+ }
2161
+ /**
2162
+ * Question marks
2163
+ */
2164
+ if (value === "?") {
2165
+ if (!(prev && prev.value === "(") && opts.noextglob !== true && peek() === "(" && peek(2) !== "?") {
2166
+ extglobOpen("qmark", value);
2167
+ continue;
2168
+ }
2169
+ if (prev && prev.type === "paren") {
2170
+ const next = peek();
2171
+ let output = value;
2172
+ if (prev.value === "(" && !/[!=<:]/.test(next) || next === "<" && !/<([!=]|\w+>)/.test(remaining())) output = `\\${value}`;
2173
+ push({
2174
+ type: "text",
2175
+ value,
2176
+ output
2177
+ });
2178
+ continue;
2179
+ }
2180
+ if (opts.dot !== true && (prev.type === "slash" || prev.type === "bos")) {
2181
+ push({
2182
+ type: "qmark",
2183
+ value,
2184
+ output: QMARK_NO_DOT
2185
+ });
2186
+ continue;
2187
+ }
2188
+ push({
2189
+ type: "qmark",
2190
+ value,
2191
+ output: QMARK
2192
+ });
2193
+ continue;
2194
+ }
2195
+ /**
2196
+ * Exclamation
2197
+ */
2198
+ if (value === "!") {
2199
+ if (opts.noextglob !== true && peek() === "(") {
2200
+ if (peek(2) !== "?" || !/[!=<:]/.test(peek(3))) {
2201
+ extglobOpen("negate", value);
2202
+ continue;
2203
+ }
2204
+ }
2205
+ if (opts.nonegate !== true && state.index === 0) {
2206
+ negate();
2207
+ continue;
2208
+ }
2209
+ }
2210
+ /**
2211
+ * Plus
2212
+ */
2213
+ if (value === "+") {
2214
+ if (opts.noextglob !== true && peek() === "(" && peek(2) !== "?") {
2215
+ extglobOpen("plus", value);
2216
+ continue;
2217
+ }
2218
+ if (prev && prev.value === "(" || opts.regex === false) {
2219
+ push({
2220
+ type: "plus",
2221
+ value,
2222
+ output: PLUS_LITERAL
2223
+ });
2224
+ continue;
2225
+ }
2226
+ if (prev && (prev.type === "bracket" || prev.type === "paren" || prev.type === "brace") || state.parens > 0) {
2227
+ push({
2228
+ type: "plus",
2229
+ value
2230
+ });
2231
+ continue;
2232
+ }
2233
+ push({
2234
+ type: "plus",
2235
+ value: PLUS_LITERAL
2236
+ });
2237
+ continue;
2238
+ }
2239
+ /**
2240
+ * Plain text
2241
+ */
2242
+ if (value === "@") {
2243
+ if (opts.noextglob !== true && peek() === "(" && peek(2) !== "?") {
2244
+ push({
2245
+ type: "at",
2246
+ extglob: true,
2247
+ value,
2248
+ output: ""
2249
+ });
2250
+ continue;
2251
+ }
2252
+ push({
2253
+ type: "text",
2254
+ value
2255
+ });
2256
+ continue;
2257
+ }
2258
+ /**
2259
+ * Plain text
2260
+ */
2261
+ if (value !== "*") {
2262
+ if (value === "$" || value === "^") value = `\\${value}`;
2263
+ const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
2264
+ if (match) {
2265
+ value += match[0];
2266
+ state.index += match[0].length;
2267
+ }
2268
+ push({
2269
+ type: "text",
2270
+ value
2271
+ });
2272
+ continue;
2273
+ }
2274
+ /**
2275
+ * Stars
2276
+ */
2277
+ if (prev && (prev.type === "globstar" || prev.star === true)) {
2278
+ prev.type = "star";
2279
+ prev.star = true;
2280
+ prev.value += value;
2281
+ prev.output = star;
2282
+ state.backtrack = true;
2283
+ state.globstar = true;
2284
+ consume(value);
2285
+ continue;
2286
+ }
2287
+ let rest = remaining();
2288
+ if (opts.noextglob !== true && /^\([^?]/.test(rest)) {
2289
+ extglobOpen("star", value);
2290
+ continue;
2291
+ }
2292
+ if (prev.type === "star") {
2293
+ if (opts.noglobstar === true) {
2294
+ consume(value);
2295
+ continue;
2296
+ }
2297
+ const prior = prev.prev;
2298
+ const before = prior.prev;
2299
+ const isStart = prior.type === "slash" || prior.type === "bos";
2300
+ const afterStar = before && (before.type === "star" || before.type === "globstar");
2301
+ if (opts.bash === true && (!isStart || rest[0] && rest[0] !== "/")) {
2302
+ push({
2303
+ type: "star",
2304
+ value,
2305
+ output: ""
2306
+ });
2307
+ continue;
2308
+ }
2309
+ const isBrace = state.braces > 0 && (prior.type === "comma" || prior.type === "brace");
2310
+ const isExtglob = extglobs.length && (prior.type === "pipe" || prior.type === "paren");
2311
+ if (!isStart && prior.type !== "paren" && !isBrace && !isExtglob) {
2312
+ push({
2313
+ type: "star",
2314
+ value,
2315
+ output: ""
2316
+ });
2317
+ continue;
2318
+ }
2319
+ while (rest.slice(0, 3) === "/**") {
2320
+ const after = input[state.index + 4];
2321
+ if (after && after !== "/") break;
2322
+ rest = rest.slice(3);
2323
+ consume("/**", 3);
2324
+ }
2325
+ if (prior.type === "bos" && eos()) {
2326
+ prev.type = "globstar";
2327
+ prev.value += value;
2328
+ prev.output = globstar(opts);
2329
+ state.output = prev.output;
2330
+ state.globstar = true;
2331
+ consume(value);
2332
+ continue;
2333
+ }
2334
+ if (prior.type === "slash" && prior.prev.type !== "bos" && !afterStar && eos()) {
2335
+ state.output = state.output.slice(0, -(prior.output + prev.output).length);
2336
+ prior.output = `(?:${prior.output}`;
2337
+ prev.type = "globstar";
2338
+ prev.output = globstar(opts) + (opts.strictSlashes ? ")" : "|$)");
2339
+ prev.value += value;
2340
+ state.globstar = true;
2341
+ state.output += prior.output + prev.output;
2342
+ consume(value);
2343
+ continue;
2344
+ }
2345
+ if (prior.type === "slash" && prior.prev.type !== "bos" && rest[0] === "/") {
2346
+ const end = rest[1] !== void 0 ? "|$" : "";
2347
+ state.output = state.output.slice(0, -(prior.output + prev.output).length);
2348
+ prior.output = `(?:${prior.output}`;
2349
+ prev.type = "globstar";
2350
+ prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
2351
+ prev.value += value;
2352
+ state.output += prior.output + prev.output;
2353
+ state.globstar = true;
2354
+ consume(value + advance());
2355
+ push({
2356
+ type: "slash",
2357
+ value: "/",
2358
+ output: ""
2359
+ });
2360
+ continue;
2361
+ }
2362
+ if (prior.type === "bos" && rest[0] === "/") {
2363
+ prev.type = "globstar";
2364
+ prev.value += value;
2365
+ prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
2366
+ state.output = prev.output;
2367
+ state.globstar = true;
2368
+ consume(value + advance());
2369
+ push({
2370
+ type: "slash",
2371
+ value: "/",
2372
+ output: ""
2373
+ });
2374
+ continue;
2375
+ }
2376
+ state.output = state.output.slice(0, -prev.output.length);
2377
+ prev.type = "globstar";
2378
+ prev.output = globstar(opts);
2379
+ prev.value += value;
2380
+ state.output += prev.output;
2381
+ state.globstar = true;
2382
+ consume(value);
2383
+ continue;
2384
+ }
2385
+ const token = {
2386
+ type: "star",
2387
+ value,
2388
+ output: star
2389
+ };
2390
+ if (opts.bash === true) {
2391
+ token.output = ".*?";
2392
+ if (prev.type === "bos" || prev.type === "slash") token.output = nodot + token.output;
2393
+ push(token);
2394
+ continue;
2395
+ }
2396
+ if (prev && (prev.type === "bracket" || prev.type === "paren") && opts.regex === true) {
2397
+ token.output = value;
2398
+ push(token);
2399
+ continue;
2400
+ }
2401
+ if (state.index === state.start || prev.type === "slash" || prev.type === "dot") {
2402
+ if (prev.type === "dot") {
2403
+ state.output += NO_DOT_SLASH;
2404
+ prev.output += NO_DOT_SLASH;
2405
+ } else if (opts.dot === true) {
2406
+ state.output += NO_DOTS_SLASH;
2407
+ prev.output += NO_DOTS_SLASH;
2408
+ } else {
2409
+ state.output += nodot;
2410
+ prev.output += nodot;
2411
+ }
2412
+ if (peek() !== "*") {
2413
+ state.output += ONE_CHAR;
2414
+ prev.output += ONE_CHAR;
2415
+ }
2416
+ }
2417
+ push(token);
2418
+ }
2419
+ while (state.brackets > 0) {
2420
+ if (opts.strictBrackets === true) throw new SyntaxError(syntaxError("closing", "]"));
2421
+ state.output = utils.escapeLast(state.output, "[");
2422
+ decrement("brackets");
2423
+ }
2424
+ while (state.parens > 0) {
2425
+ if (opts.strictBrackets === true) throw new SyntaxError(syntaxError("closing", ")"));
2426
+ state.output = utils.escapeLast(state.output, "(");
2427
+ decrement("parens");
2428
+ }
2429
+ while (state.braces > 0) {
2430
+ if (opts.strictBrackets === true) throw new SyntaxError(syntaxError("closing", "}"));
2431
+ state.output = utils.escapeLast(state.output, "{");
2432
+ decrement("braces");
2433
+ }
2434
+ if (opts.strictSlashes !== true && (prev.type === "star" || prev.type === "bracket")) push({
2435
+ type: "maybe_slash",
2436
+ value: "",
2437
+ output: `${SLASH_LITERAL}?`
2438
+ });
2439
+ if (state.backtrack === true) {
2440
+ state.output = "";
2441
+ for (const token of state.tokens) {
2442
+ state.output += token.output != null ? token.output : token.value;
2443
+ if (token.suffix) state.output += token.suffix;
2444
+ }
2445
+ }
2446
+ return state;
2447
+ };
2448
+ /**
2449
+ * Fast paths for creating regular expressions for common glob patterns.
2450
+ * This can significantly speed up processing and has very little downside
2451
+ * impact when none of the fast paths match.
2452
+ */
2453
+ parse.fastpaths = (input, options) => {
2454
+ const opts = { ...options };
2455
+ const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
2456
+ const len = input.length;
2457
+ if (len > max) throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
2458
+ input = REPLACEMENTS[input] || input;
2459
+ const { DOT_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOTS, NO_DOTS_SLASH, STAR, START_ANCHOR } = constants.globChars(opts.windows);
2460
+ const nodot = opts.dot ? NO_DOTS : NO_DOT;
2461
+ const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
2462
+ const capture = opts.capture ? "" : "?:";
2463
+ const state = {
2464
+ negated: false,
2465
+ prefix: ""
2466
+ };
2467
+ let star = opts.bash === true ? ".*?" : STAR;
2468
+ if (opts.capture) star = `(${star})`;
2469
+ const globstar = (opts) => {
2470
+ if (opts.noglobstar === true) return star;
2471
+ return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
2472
+ };
2473
+ const create = (str) => {
2474
+ switch (str) {
2475
+ case "*": return `${nodot}${ONE_CHAR}${star}`;
2476
+ case ".*": return `${DOT_LITERAL}${ONE_CHAR}${star}`;
2477
+ case "*.*": return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
2478
+ case "*/*": return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`;
2479
+ case "**": return nodot + globstar(opts);
2480
+ case "**/*": return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`;
2481
+ case "**/*.*": return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
2482
+ case "**/.*": return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`;
2483
+ default: {
2484
+ const match = /^(.*?)\.(\w+)$/.exec(str);
2485
+ if (!match) return;
2486
+ const source = create(match[1]);
2487
+ if (!source) return;
2488
+ return source + DOT_LITERAL + match[2];
2489
+ }
2490
+ }
2491
+ };
2492
+ let source = create(utils.removePrefix(input, state));
2493
+ if (source && opts.strictSlashes !== true) source += `${SLASH_LITERAL}?`;
2494
+ return source;
2495
+ };
2496
+ module.exports = parse;
2497
+ }));
2498
+ //#endregion
2499
+ //#region ../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/picomatch.js
2500
+ var require_picomatch$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2501
+ const scan = require_scan();
2502
+ const parse = require_parse();
2503
+ const utils = require_utils();
2504
+ const constants = require_constants();
2505
+ const isObject = (val) => val && typeof val === "object" && !Array.isArray(val);
2506
+ /**
2507
+ * Creates a matcher function from one or more glob patterns. The
2508
+ * returned function takes a string to match as its first argument,
2509
+ * and returns true if the string is a match. The returned matcher
2510
+ * function also takes a boolean as the second argument that, when true,
2511
+ * returns an object with additional information.
2512
+ *
2513
+ * ```js
2514
+ * const picomatch = require('picomatch');
2515
+ * // picomatch(glob[, options]);
2516
+ *
2517
+ * const isMatch = picomatch('*.!(*a)');
2518
+ * console.log(isMatch('a.a')); //=> false
2519
+ * console.log(isMatch('a.b')); //=> true
2520
+ * ```
2521
+ * @name picomatch
2522
+ * @param {String|Array} `globs` One or more glob patterns.
2523
+ * @param {Object=} `options`
2524
+ * @return {Function=} Returns a matcher function.
2525
+ * @api public
2526
+ */
2527
+ const picomatch = (glob, options, returnState = false) => {
2528
+ if (Array.isArray(glob)) {
2529
+ const fns = glob.map((input) => picomatch(input, options, returnState));
2530
+ const arrayMatcher = (str) => {
2531
+ for (const isMatch of fns) {
2532
+ const state = isMatch(str);
2533
+ if (state) return state;
2534
+ }
2535
+ return false;
2536
+ };
2537
+ return arrayMatcher;
2538
+ }
2539
+ const isState = isObject(glob) && glob.tokens && glob.input;
2540
+ if (glob === "" || typeof glob !== "string" && !isState) throw new TypeError("Expected pattern to be a non-empty string");
2541
+ const opts = options || {};
2542
+ const posix = opts.windows;
2543
+ const regex = isState ? picomatch.compileRe(glob, options) : picomatch.makeRe(glob, options, false, true);
2544
+ const state = regex.state;
2545
+ delete regex.state;
2546
+ let isIgnored = () => false;
2547
+ if (opts.ignore) {
2548
+ const ignoreOpts = {
2549
+ ...options,
2550
+ ignore: null,
2551
+ onMatch: null,
2552
+ onResult: null
2553
+ };
2554
+ isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
2555
+ }
2556
+ const matcher = (input, returnObject = false) => {
2557
+ const { isMatch, match, output } = picomatch.test(input, regex, options, {
2558
+ glob,
2559
+ posix
2560
+ });
2561
+ const result = {
2562
+ glob,
2563
+ state,
2564
+ regex,
2565
+ posix,
2566
+ input,
2567
+ output,
2568
+ match,
2569
+ isMatch
2570
+ };
2571
+ if (typeof opts.onResult === "function") opts.onResult(result);
2572
+ if (isMatch === false) {
2573
+ result.isMatch = false;
2574
+ return returnObject ? result : false;
2575
+ }
2576
+ if (isIgnored(input)) {
2577
+ if (typeof opts.onIgnore === "function") opts.onIgnore(result);
2578
+ result.isMatch = false;
2579
+ return returnObject ? result : false;
2580
+ }
2581
+ if (typeof opts.onMatch === "function") opts.onMatch(result);
2582
+ return returnObject ? result : true;
2583
+ };
2584
+ if (returnState) matcher.state = state;
2585
+ return matcher;
2586
+ };
2587
+ /**
2588
+ * Test `input` with the given `regex`. This is used by the main
2589
+ * `picomatch()` function to test the input string.
2590
+ *
2591
+ * ```js
2592
+ * const picomatch = require('picomatch');
2593
+ * // picomatch.test(input, regex[, options]);
2594
+ *
2595
+ * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
2596
+ * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
2597
+ * ```
2598
+ * @param {String} `input` String to test.
2599
+ * @param {RegExp} `regex`
2600
+ * @return {Object} Returns an object with matching info.
2601
+ * @api public
2602
+ */
2603
+ picomatch.test = (input, regex, options, { glob, posix } = {}) => {
2604
+ if (typeof input !== "string") throw new TypeError("Expected input to be a string");
2605
+ if (input === "") return {
2606
+ isMatch: false,
2607
+ output: ""
2608
+ };
2609
+ const opts = options || {};
2610
+ const format = opts.format || (posix ? utils.toPosixSlashes : null);
2611
+ let match = input === glob;
2612
+ let output = match && format ? format(input) : input;
2613
+ if (match === false) {
2614
+ output = format ? format(input) : input;
2615
+ match = output === glob;
2616
+ }
2617
+ if (match === false || opts.capture === true) if (opts.matchBase === true || opts.basename === true) match = picomatch.matchBase(input, regex, options, posix);
2618
+ else match = regex.exec(output);
2619
+ return {
2620
+ isMatch: Boolean(match),
2621
+ match,
2622
+ output
2623
+ };
2624
+ };
2625
+ /**
2626
+ * Match the basename of a filepath.
2627
+ *
2628
+ * ```js
2629
+ * const picomatch = require('picomatch');
2630
+ * // picomatch.matchBase(input, glob[, options]);
2631
+ * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
2632
+ * ```
2633
+ * @param {String} `input` String to test.
2634
+ * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe).
2635
+ * @return {Boolean}
2636
+ * @api public
2637
+ */
2638
+ picomatch.matchBase = (input, glob, options) => {
2639
+ return (glob instanceof RegExp ? glob : picomatch.makeRe(glob, options)).test(utils.basename(input));
2640
+ };
2641
+ /**
2642
+ * Returns true if **any** of the given glob `patterns` match the specified `string`.
2643
+ *
2644
+ * ```js
2645
+ * const picomatch = require('picomatch');
2646
+ * // picomatch.isMatch(string, patterns[, options]);
2647
+ *
2648
+ * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
2649
+ * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
2650
+ * ```
2651
+ * @param {String|Array} str The string to test.
2652
+ * @param {String|Array} patterns One or more glob patterns to use for matching.
2653
+ * @param {Object} [options] See available [options](#options).
2654
+ * @return {Boolean} Returns true if any patterns match `str`
2655
+ * @api public
2656
+ */
2657
+ picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
2658
+ /**
2659
+ * Parse a glob pattern to create the source string for a regular
2660
+ * expression.
2661
+ *
2662
+ * ```js
2663
+ * const picomatch = require('picomatch');
2664
+ * const result = picomatch.parse(pattern[, options]);
2665
+ * ```
2666
+ * @param {String} `pattern`
2667
+ * @param {Object} `options`
2668
+ * @return {Object} Returns an object with useful properties and output to be used as a regex source string.
2669
+ * @api public
2670
+ */
2671
+ picomatch.parse = (pattern, options) => {
2672
+ if (Array.isArray(pattern)) return pattern.map((p) => picomatch.parse(p, options));
2673
+ return parse(pattern, {
2674
+ ...options,
2675
+ fastpaths: false
2676
+ });
2677
+ };
2678
+ /**
2679
+ * Scan a glob pattern to separate the pattern into segments.
2680
+ *
2681
+ * ```js
2682
+ * const picomatch = require('picomatch');
2683
+ * // picomatch.scan(input[, options]);
2684
+ *
2685
+ * const result = picomatch.scan('!./foo/*.js');
2686
+ * console.log(result);
2687
+ * { prefix: '!./',
2688
+ * input: '!./foo/*.js',
2689
+ * start: 3,
2690
+ * base: 'foo',
2691
+ * glob: '*.js',
2692
+ * isBrace: false,
2693
+ * isBracket: false,
2694
+ * isGlob: true,
2695
+ * isExtglob: false,
2696
+ * isGlobstar: false,
2697
+ * negated: true }
2698
+ * ```
2699
+ * @param {String} `input` Glob pattern to scan.
2700
+ * @param {Object} `options`
2701
+ * @return {Object} Returns an object with
2702
+ * @api public
2703
+ */
2704
+ picomatch.scan = (input, options) => scan(input, options);
2705
+ /**
2706
+ * Compile a regular expression from the `state` object returned by the
2707
+ * [parse()](#parse) method.
2708
+ *
2709
+ * ```js
2710
+ * const picomatch = require('picomatch');
2711
+ * const state = picomatch.parse('*.js');
2712
+ * // picomatch.compileRe(state[, options]);
2713
+ *
2714
+ * console.log(picomatch.compileRe(state));
2715
+ * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
2716
+ * ```
2717
+ * @param {Object} `state`
2718
+ * @param {Object} `options`
2719
+ * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
2720
+ * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
2721
+ * @return {RegExp}
2722
+ * @api public
2723
+ */
2724
+ picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
2725
+ if (returnOutput === true) return state.output;
2726
+ const opts = options || {};
2727
+ const prepend = opts.contains ? "" : "^";
2728
+ const append = opts.contains ? "" : "$";
2729
+ let source = `${prepend}(?:${state.output})${append}`;
2730
+ if (state && state.negated === true) source = `^(?!${source}).*$`;
2731
+ const regex = picomatch.toRegex(source, options);
2732
+ if (returnState === true) regex.state = state;
2733
+ return regex;
2734
+ };
2735
+ /**
2736
+ * Create a regular expression from a parsed glob pattern.
2737
+ *
2738
+ * ```js
2739
+ * const picomatch = require('picomatch');
2740
+ * // picomatch.makeRe(state[, options]);
2741
+ *
2742
+ * const result = picomatch.makeRe('*.js');
2743
+ * console.log(result);
2744
+ * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
2745
+ * ```
2746
+ * @param {String} `state` The object returned from the `.parse` method.
2747
+ * @param {Object} `options`
2748
+ * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result.
2749
+ * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression.
2750
+ * @return {RegExp} Returns a regex created from the given pattern.
2751
+ * @api public
2752
+ */
2753
+ picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => {
2754
+ if (!input || typeof input !== "string") throw new TypeError("Expected a non-empty string");
2755
+ let parsed = {
2756
+ negated: false,
2757
+ fastpaths: true
2758
+ };
2759
+ if (options.fastpaths !== false && (input[0] === "." || input[0] === "*")) parsed.output = parse.fastpaths(input, options);
2760
+ if (!parsed.output) parsed = parse(input, options);
2761
+ return picomatch.compileRe(parsed, options, returnOutput, returnState);
2762
+ };
2763
+ /**
2764
+ * Create a regular expression from the given regex source string.
2765
+ *
2766
+ * ```js
2767
+ * const picomatch = require('picomatch');
2768
+ * // picomatch.toRegex(source[, options]);
2769
+ *
2770
+ * const { output } = picomatch.parse('*.js');
2771
+ * console.log(picomatch.toRegex(output));
2772
+ * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
2773
+ * ```
2774
+ * @param {String} `source` Regular expression source string.
2775
+ * @param {Object} `options`
2776
+ * @return {RegExp}
2777
+ * @api public
2778
+ */
2779
+ picomatch.toRegex = (source, options) => {
2780
+ try {
2781
+ const opts = options || {};
2782
+ return new RegExp(source, opts.flags || (opts.nocase ? "i" : ""));
2783
+ } catch (err) {
2784
+ if (options && options.debug === true) throw err;
2785
+ return /$^/;
2786
+ }
2787
+ };
2788
+ /**
2789
+ * Picomatch constants.
2790
+ * @return {Object}
2791
+ */
2792
+ picomatch.constants = constants;
2793
+ /**
2794
+ * Expose "picomatch"
2795
+ */
2796
+ module.exports = picomatch;
2797
+ }));
2798
+ //#endregion
917
2799
  //#region ../core/dist/index.js
2800
+ var import_picomatch = /* @__PURE__ */ __toESM$1((/* @__PURE__ */ __commonJSMin$1(((exports, module) => {
2801
+ const pico = require_picomatch$1();
2802
+ const utils = require_utils();
2803
+ function picomatch(glob, options, returnState = false) {
2804
+ if (options && (options.windows === null || options.windows === void 0)) options = {
2805
+ ...options,
2806
+ windows: utils.isWindows()
2807
+ };
2808
+ return pico(glob, options, returnState);
2809
+ }
2810
+ Object.assign(picomatch, pico);
2811
+ module.exports = picomatch;
2812
+ })))(), 1);
918
2813
  var __create = Object.create;
919
2814
  var __defProp = Object.defineProperty;
920
2815
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -936,30 +2831,60 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
936
2831
  value: mod,
937
2832
  enumerable: true
938
2833
  }) : target, mod));
939
- const REGEX_SPECIAL_CHARACTERS = /[.+^${}()|[\]\\]/g;
940
- const compileGlobPattern = (pattern) => {
941
- const normalizedPattern = pattern.replace(/\\/g, "/").replace(/^\//, "");
942
- let regexSource = "^";
943
- let characterIndex = 0;
944
- while (characterIndex < normalizedPattern.length) if (normalizedPattern[characterIndex] === "*" && normalizedPattern[characterIndex + 1] === "*") if (normalizedPattern[characterIndex + 2] === "/") {
945
- regexSource += "(?:.+/)?";
946
- characterIndex += 3;
947
- } else {
948
- regexSource += ".*";
949
- characterIndex += 2;
950
- }
951
- else if (normalizedPattern[characterIndex] === "*") {
952
- regexSource += "[^/]*";
953
- characterIndex++;
954
- } else if (normalizedPattern[characterIndex] === "?") {
955
- regexSource += "[^/]";
956
- characterIndex++;
957
- } else {
958
- regexSource += normalizedPattern[characterIndex].replace(REGEX_SPECIAL_CHARACTERS, "\\$&");
959
- characterIndex++;
2834
+ const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
2835
+ const MILLISECONDS_PER_SECOND = 1e3;
2836
+ const SCORE_API_URL = "https://www.react.doctor/api/score";
2837
+ const SHARE_BASE_URL = "https://www.react.doctor/share";
2838
+ const REACT_REVIEW_URL = "https://react.review";
2839
+ const FETCH_TIMEOUT_MS = 1e4;
2840
+ const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
2841
+ const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
2842
+ const OXLINT_NODE_REQUIREMENT = "^20.19.0 || >=22.12.0";
2843
+ const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
2844
+ const CANONICAL_GITHUB_URL = "https://github.com/millionco/react-doctor";
2845
+ const SKILL_NAME = "react-doctor";
2846
+ const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
2847
+ const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
2848
+ var InvalidGlobPatternError = class extends Error {
2849
+ pattern;
2850
+ reason;
2851
+ constructor(pattern, reason) {
2852
+ super(`Invalid glob pattern ${JSON.stringify(pattern)}: ${reason}`);
2853
+ this.name = "InvalidGlobPatternError";
2854
+ this.pattern = pattern;
2855
+ this.reason = reason;
2856
+ }
2857
+ };
2858
+ const assertGlobPattern = (condition, pattern, reason) => {
2859
+ if (!condition) throw new InvalidGlobPatternError(pattern, reason);
2860
+ };
2861
+ const countGlobWildcards = (pattern) => (pattern.match(/[*?]/g) ?? []).length;
2862
+ const normalizeGlobPattern = (pattern) => pattern.replace(/\\/g, "/").replace(/^\//, "");
2863
+ const PICOMATCH_OPTIONS = {
2864
+ dot: true,
2865
+ strictSlashes: false,
2866
+ windows: false
2867
+ };
2868
+ const compileGlobPattern = (rawPattern) => {
2869
+ assertGlobPattern(typeof rawPattern === "string" && rawPattern.length > 0, String(rawPattern), "pattern must be a non-empty string.");
2870
+ assertGlobPattern(rawPattern.length <= MAX_GLOB_PATTERN_LENGTH_CHARS, rawPattern, `pattern length ${rawPattern.length} exceeds the maximum of ${MAX_GLOB_PATTERN_LENGTH_CHARS} characters.`);
2871
+ const wildcardCount = countGlobWildcards(rawPattern);
2872
+ assertGlobPattern(wildcardCount <= 24, rawPattern, `pattern uses ${wildcardCount} wildcards (\`*\` / \`?\`), exceeding the maximum of 24. This guards against catastrophic backtracking from pathological patterns; split the pattern into multiple smaller entries.`);
2873
+ try {
2874
+ return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
2875
+ } catch (caughtError) {
2876
+ throw new InvalidGlobPatternError(rawPattern, caughtError instanceof Error ? caughtError.message : String(caughtError));
960
2877
  }
961
- regexSource += "$";
962
- return new RegExp(regexSource);
2878
+ };
2879
+ const compileGlobPatternsLenient = (patterns, onInvalid) => {
2880
+ const compiled = [];
2881
+ for (const pattern of patterns) try {
2882
+ compiled.push(compileGlobPattern(pattern));
2883
+ } catch (caughtError) {
2884
+ if (!(caughtError instanceof InvalidGlobPatternError)) throw caughtError;
2885
+ onInvalid(caughtError);
2886
+ }
2887
+ return compiled;
963
2888
  };
964
2889
  const toRelativePath = (filePath, rootDirectory) => {
965
2890
  const normalizedFilePath = filePath.replace(/\\/g, "/");
@@ -967,22 +2892,22 @@ const toRelativePath = (filePath, rootDirectory) => {
967
2892
  if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
968
2893
  return normalizedFilePath.replace(/^\.\//, "");
969
2894
  };
970
- const warnConfigField$1 = (message) => {
2895
+ const warnConfigIssue = (message) => {
971
2896
  process.stderr.write(`[react-doctor] ${message}\n`);
972
2897
  };
973
2898
  const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
974
2899
  const collectStringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
975
2900
  const validateOverrideEntry = (entry, index) => {
976
2901
  if (!isPlainObject(entry)) {
977
- warnConfigField$1(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
2902
+ warnConfigIssue(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
978
2903
  return null;
979
2904
  }
980
2905
  if (!isStringArray(entry.files)) {
981
- warnConfigField$1(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
2906
+ warnConfigIssue(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
982
2907
  return null;
983
2908
  }
984
2909
  if (entry.rules !== void 0 && !isStringArray(entry.rules)) {
985
- warnConfigField$1(`ignore.overrides[${index}].rules must be an array of "plugin/rule" strings or omitted; treating as missing (override would suppress every rule for the matched files).`);
2910
+ warnConfigIssue(`ignore.overrides[${index}].rules must be an array of "plugin/rule" strings or omitted; treating as missing (override would suppress every rule for the matched files).`);
986
2911
  return { files: entry.files };
987
2912
  }
988
2913
  return entry.rules === void 0 ? { files: entry.files } : {
@@ -994,13 +2919,13 @@ const compileIgnoreOverrides = (userConfig) => {
994
2919
  const overrides = userConfig?.ignore?.overrides;
995
2920
  if (overrides === void 0) return [];
996
2921
  if (!Array.isArray(overrides)) {
997
- warnConfigField$1(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
2922
+ warnConfigIssue(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
998
2923
  return [];
999
2924
  }
1000
2925
  return overrides.flatMap((entry, index) => {
1001
2926
  const validated = validateOverrideEntry(entry, index);
1002
2927
  if (!validated) return [];
1003
- const filePatterns = collectStringList(validated.files).map(compileGlobPattern);
2928
+ const filePatterns = compileGlobPatternsLenient(collectStringList(validated.files), (error) => warnConfigIssue(`ignore.overrides[${index}]: ${error.message}`));
1004
2929
  if (filePatterns.length === 0) return [];
1005
2930
  return [{
1006
2931
  filePatterns,
@@ -1014,18 +2939,94 @@ const isDiagnosticIgnoredByOverrides = (diagnostic, rootDirectory, overrides) =>
1014
2939
  const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
1015
2940
  return overrides.some((override) => override.filePatterns.some((pattern) => pattern.test(relativeFilePath)) && (override.ruleIds.size === 0 || override.ruleIds.has(ruleIdentifier)));
1016
2941
  };
1017
- const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
1018
- const MILLISECONDS_PER_SECOND = 1e3;
1019
- const SCORE_API_URL = "https://www.react.doctor/api/score";
1020
- const SHARE_BASE_URL = "https://www.react.doctor/share";
1021
- const FETCH_TIMEOUT_MS = 1e4;
1022
- const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
1023
- const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
1024
- const OXLINT_NODE_REQUIREMENT = "^20.19.0 || >=22.12.0";
1025
- const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
1026
- const CANONICAL_GITHUB_URL = "https://github.com/millionco/react-doctor";
1027
- const SKILL_NAME = "react-doctor";
1028
- const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
2942
+ /**
2943
+ * Assembles the internal `RuleSeverityControls` shape from a user
2944
+ * config's top-level `rules` and `categories` fields — the
2945
+ * ESLint / oxlint-shaped severity surface.
2946
+ *
2947
+ * Returns `undefined` when neither field is present so the common
2948
+ * path (no severity config at all) stays allocation-free for
2949
+ * downstream consumers.
2950
+ */
2951
+ const buildRuleSeverityControls = (config) => {
2952
+ if (!config) return void 0;
2953
+ if (config.rules === void 0 && config.categories === void 0) return void 0;
2954
+ return {
2955
+ ...config.rules !== void 0 ? { rules: config.rules } : {},
2956
+ ...config.categories !== void 0 ? { categories: config.categories } : {}
2957
+ };
2958
+ };
2959
+ /**
2960
+ * Projects a diagnostic onto the three axes rule-targeted controls
2961
+ * reason about:
2962
+ *
2963
+ * - `ruleKey` — the fully-qualified `"<plugin>/<rule>"` form users
2964
+ * put in config files (consumed by top-level `rules` severity and
2965
+ * `surfaces.*.{include,exclude}Rules`).
2966
+ * - `category` — the diagnostic's category label (consumed by
2967
+ * top-level `categories` severity and
2968
+ * `surfaces.*.{include,exclude}Categories`).
2969
+ * - `tags` — behavioral tags from the rule registry (consumed by
2970
+ * `ignore.tags` and `surfaces.*.{include,exclude}Tags`). Empty
2971
+ * for non-`react-doctor` plugins.
2972
+ */
2973
+ const getDiagnosticRuleIdentity = (diagnostic) => ({
2974
+ ruleKey: `${diagnostic.plugin}/${diagnostic.rule}`,
2975
+ category: diagnostic.category,
2976
+ tags: diagnostic.plugin === "react-doctor" ? reactDoctorPlugin.rules[diagnostic.rule]?.tags ?? [] : []
2977
+ });
2978
+ /**
2979
+ * Resolves the user-configured severity override for a rule.
2980
+ * Per-rule overrides win over per-category overrides. Returns
2981
+ * `undefined` when neither channel matches — callers should fall
2982
+ * back to the rule's built-in severity.
2983
+ */
2984
+ const resolveRuleSeverityOverride = (input, controls) => {
2985
+ if (!controls) return void 0;
2986
+ return controls.rules?.[input.ruleKey] ?? (input.category !== void 0 ? controls.categories?.[input.category] : void 0);
2987
+ };
2988
+ const SEVERITY_FOR_OVERRIDE = {
2989
+ error: "error",
2990
+ warn: "warning"
2991
+ };
2992
+ const restampSeverity = (diagnostic, override) => {
2993
+ const targetSeverity = SEVERITY_FOR_OVERRIDE[override];
2994
+ if (diagnostic.severity === targetSeverity) return diagnostic;
2995
+ return {
2996
+ ...diagnostic,
2997
+ severity: targetSeverity
2998
+ };
2999
+ };
3000
+ /**
3001
+ * Applies the user's top-level `rules` / `categories` / `tags`
3002
+ * severity config to a post-lint diagnostic list:
3003
+ *
3004
+ * - `"off"` drops the diagnostic entirely. For react-doctor rules
3005
+ * this also happens at lint-registration time; this post-filter
3006
+ * covers external plugins (`react/*`, `jsx-a11y/*`, custom adopted
3007
+ * configs) whose severities the lint config can't reach.
3008
+ * - `"warn"` / `"error"` re-stamps `diagnostic.severity` so downstream
3009
+ * consumers — `--fail-on`, the score input, the CLI summary — see
3010
+ * the user-chosen severity rather than the rule's built-in one.
3011
+ *
3012
+ * Returns the input array by identity when no controls are configured
3013
+ * so the common path stays allocation-free.
3014
+ */
3015
+ const applySeverityControls = (diagnostics, config) => {
3016
+ const controls = buildRuleSeverityControls(config);
3017
+ if (!controls) return diagnostics;
3018
+ const adjusted = [];
3019
+ for (const diagnostic of diagnostics) {
3020
+ const { ruleKey, category } = getDiagnosticRuleIdentity(diagnostic);
3021
+ const override = resolveRuleSeverityOverride({
3022
+ ruleKey,
3023
+ category
3024
+ }, controls);
3025
+ if (override === "off") continue;
3026
+ adjusted.push(override === void 0 ? diagnostic : restampSeverity(diagnostic, override));
3027
+ }
3028
+ return adjusted;
3029
+ };
1029
3030
  const estimateArgsLength = (args) => args.reduce((total, argument) => total + argument.length + 1, 0);
1030
3031
  const batchIncludePaths = (baseArgs, includePaths) => {
1031
3032
  const baseArgsLength = estimateArgsLength(baseArgs);
@@ -1707,7 +3708,7 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
1707
3708
  const compileIgnoredFilePatterns = (userConfig) => {
1708
3709
  const files = userConfig?.ignore?.files;
1709
3710
  if (!Array.isArray(files)) return [];
1710
- return files.filter((entry) => typeof entry === "string").map(compileGlobPattern);
3711
+ return compileGlobPatternsLenient(files.filter((entry) => typeof entry === "string"), (error) => warnConfigIssue(`ignore.files: ${error.message}`));
1711
3712
  };
1712
3713
  const isFileIgnoredByPatterns = (filePath, rootDirectory, patterns) => {
1713
3714
  if (patterns.length === 0) return false;
@@ -1868,8 +3869,8 @@ const shouldAutoSuppress = (diagnostic) => {
1868
3869
  return false;
1869
3870
  };
1870
3871
  const mergeAndFilterDiagnostics = (mergedDiagnostics, directory, userConfig, readFileLinesSync, options = {}) => {
1871
- const autoFiltered = mergedDiagnostics.filter((diagnostic) => !shouldAutoSuppress(diagnostic));
1872
- const filtered = userConfig ? filterIgnoredDiagnostics(autoFiltered, userConfig, directory, readFileLinesSync) : autoFiltered;
3872
+ const severityAdjusted = applySeverityControls(mergedDiagnostics.filter((diagnostic) => !shouldAutoSuppress(diagnostic)), userConfig);
3873
+ const filtered = userConfig ? filterIgnoredDiagnostics(severityAdjusted, userConfig, directory, readFileLinesSync) : severityAdjusted;
1873
3874
  if (options.respectInlineDisables === false) return filtered;
1874
3875
  return filterInlineSuppressions(filtered, directory, readFileLinesSync);
1875
3876
  };
@@ -1924,43 +3925,32 @@ const DEFAULT_SURFACE_EXCLUDED_TAGS = {
1924
3925
  };
1925
3926
  const toStringSet = (values) => {
1926
3927
  if (!values || values.length === 0) return /* @__PURE__ */ new Set();
1927
- const collected = /* @__PURE__ */ new Set();
1928
- for (const value of values) if (typeof value === "string" && value.length > 0) collected.add(value);
1929
- return collected;
3928
+ return new Set(values.filter((value) => typeof value === "string" && value.length > 0));
1930
3929
  };
1931
3930
  const buildResolvedControls = (surface, userControls) => {
1932
- const baseExcludeTags = new Set(DEFAULT_SURFACE_EXCLUDED_TAGS[surface]);
1933
- const userIncludeTags = toStringSet(userControls?.includeTags);
1934
- for (const includedTag of userIncludeTags) baseExcludeTags.delete(includedTag);
1935
- const userExcludeTags = toStringSet(userControls?.excludeTags);
1936
- for (const excludedTag of userExcludeTags) baseExcludeTags.add(excludedTag);
3931
+ const excludeTags = new Set(DEFAULT_SURFACE_EXCLUDED_TAGS[surface]);
3932
+ const includeTags = toStringSet(userControls?.includeTags);
3933
+ for (const tag of includeTags) excludeTags.delete(tag);
3934
+ for (const tag of toStringSet(userControls?.excludeTags)) excludeTags.add(tag);
1937
3935
  return {
1938
- includeTags: userIncludeTags,
1939
- excludeTags: baseExcludeTags,
3936
+ includeTags,
3937
+ excludeTags,
1940
3938
  includeCategories: toStringSet(userControls?.includeCategories),
1941
3939
  excludeCategories: toStringSet(userControls?.excludeCategories),
1942
3940
  includeRuleKeys: toStringSet(userControls?.includeRules),
1943
3941
  excludeRuleKeys: toStringSet(userControls?.excludeRules)
1944
3942
  };
1945
3943
  };
1946
- const getRuleTags = (diagnostic) => {
1947
- if (diagnostic.plugin !== "react-doctor") return [];
1948
- return reactDoctorPlugin.rules[diagnostic.rule]?.tags ?? [];
1949
- };
1950
- const intersectsAny = (values, candidateSet) => {
1951
- for (const value of values) if (candidateSet.has(value)) return true;
1952
- return false;
1953
- };
3944
+ const intersects = (values, candidates) => values.some((value) => candidates.has(value));
1954
3945
  const isDiagnosticOnSurface = (diagnostic, surface, config) => {
1955
3946
  const resolved = buildResolvedControls(surface, config?.surfaces?.[surface]);
1956
- const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;
1957
- const tags = getRuleTags(diagnostic);
3947
+ const { ruleKey, category, tags } = getDiagnosticRuleIdentity(diagnostic);
1958
3948
  if (resolved.includeRuleKeys.has(ruleKey)) return true;
1959
- if (resolved.includeCategories.has(diagnostic.category)) return true;
1960
- if (intersectsAny(tags, resolved.includeTags)) return true;
3949
+ if (resolved.includeCategories.has(category)) return true;
3950
+ if (intersects(tags, resolved.includeTags)) return true;
1961
3951
  if (resolved.excludeRuleKeys.has(ruleKey)) return false;
1962
- if (resolved.excludeCategories.has(diagnostic.category)) return false;
1963
- if (intersectsAny(tags, resolved.excludeTags)) return false;
3952
+ if (resolved.excludeCategories.has(category)) return false;
3953
+ if (intersects(tags, resolved.excludeTags)) return false;
1964
3954
  return true;
1965
3955
  };
1966
3956
  const filterDiagnosticsForSurface = (diagnostics, surface, config) => diagnostics.filter((diagnostic) => isDiagnosticOnSurface(diagnostic, surface, config));
@@ -2081,6 +4071,11 @@ const getDiffInfo = (directory, explicitBaseBranch) => {
2081
4071
  };
2082
4072
  const filterSourceFiles = (filePaths) => filePaths.filter((filePath) => SOURCE_FILE_PATTERN.test(filePath));
2083
4073
  const computeJsxIncludePaths = (includePaths) => includePaths.length > 0 ? includePaths.filter((filePath) => JSX_FILE_PATTERN.test(filePath)) : void 0;
4074
+ const VALID_RULE_SEVERITIES = [
4075
+ "error",
4076
+ "warn",
4077
+ "off"
4078
+ ];
2084
4079
  const BOOLEAN_FIELD_NAMES = [
2085
4080
  "lint",
2086
4081
  "verbose",
@@ -2091,18 +4086,27 @@ const BOOLEAN_FIELD_NAMES = [
2091
4086
  "offline"
2092
4087
  ];
2093
4088
  const STRING_FIELD_NAMES = ["rootDir"];
4089
+ const SURFACE_CONTROL_FIELD_NAMES = [
4090
+ "includeTags",
4091
+ "excludeTags",
4092
+ "includeCategories",
4093
+ "excludeCategories",
4094
+ "includeRules",
4095
+ "excludeRules"
4096
+ ];
4097
+ const SEVERITY_FIELD_NAMES = ["rules", "categories"];
2094
4098
  const warnConfigField = (message) => {
2095
4099
  process.stderr.write(`[react-doctor] ${message}\n`);
2096
4100
  };
4101
+ const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4102
+ const formatType = (value) => typeof value === "string" ? `"${value}"` : typeof value;
4103
+ const isRuleSeverity = (value) => typeof value === "string" && VALID_RULE_SEVERITIES.includes(value);
2097
4104
  const coerceMaybeBooleanString = (fieldName, value) => {
2098
- if (typeof value === "boolean" || value === void 0) return value;
2099
- if (value === "true") {
2100
- warnConfigField(`config field "${fieldName}" is the string "true"; treating as boolean true.`);
2101
- return true;
2102
- }
2103
- if (value === "false") {
2104
- warnConfigField(`config field "${fieldName}" is the string "false"; treating as boolean false.`);
2105
- return false;
4105
+ if (typeof value === "boolean") return value;
4106
+ if (value === "true" || value === "false") {
4107
+ const coerced = value === "true";
4108
+ warnConfigField(`config field "${fieldName}" is the string "${value}"; treating as boolean ${coerced}.`);
4109
+ return coerced;
2106
4110
  }
2107
4111
  warnConfigField(`config field "${fieldName}" must be a boolean (got ${typeof value}); ignoring this field.`);
2108
4112
  };
@@ -2110,47 +4114,32 @@ const validateString = (fieldName, value) => {
2110
4114
  if (typeof value === "string") return value;
2111
4115
  warnConfigField(`config field "${fieldName}" must be a string (got ${typeof value}); ignoring this field.`);
2112
4116
  };
2113
- const SURFACE_CONTROL_FIELD_NAMES = [
2114
- "includeTags",
2115
- "excludeTags",
2116
- "includeCategories",
2117
- "excludeCategories",
2118
- "includeRules",
2119
- "excludeRules"
2120
- ];
2121
4117
  const validateStringArrayField = (fieldName, value) => {
2122
- if (value === void 0) return void 0;
2123
4118
  if (!Array.isArray(value)) {
2124
4119
  warnConfigField(`config field "${fieldName}" must be an array of strings (got ${typeof value}); ignoring this field.`);
2125
4120
  return;
2126
4121
  }
2127
- const collected = [];
2128
- for (const entry of value) {
2129
- if (typeof entry !== "string") {
2130
- warnConfigField(`config field "${fieldName}" contains a non-string entry (${typeof entry}); ignoring the entry.`);
2131
- continue;
2132
- }
2133
- collected.push(entry);
2134
- }
2135
- return collected;
4122
+ return value.filter((entry) => {
4123
+ if (typeof entry === "string") return true;
4124
+ warnConfigField(`config field "${fieldName}" contains a non-string entry (${typeof entry}); ignoring the entry.`);
4125
+ return false;
4126
+ });
2136
4127
  };
2137
4128
  const validateSurfaceControls = (surface, rawControls) => {
2138
- if (rawControls === void 0) return void 0;
2139
- if (typeof rawControls !== "object" || rawControls === null || Array.isArray(rawControls)) {
4129
+ if (!isPlainObject$1(rawControls)) {
2140
4130
  warnConfigField(`config field "surfaces.${surface}" must be an object (got ${typeof rawControls}); ignoring this surface.`);
2141
4131
  return;
2142
4132
  }
2143
4133
  const validated = {};
2144
4134
  for (const fieldName of SURFACE_CONTROL_FIELD_NAMES) {
2145
- const value = rawControls[fieldName];
2146
- const validatedValue = validateStringArrayField(`surfaces.${surface}.${fieldName}`, value);
2147
- if (validatedValue !== void 0) validated[fieldName] = validatedValue;
4135
+ if (rawControls[fieldName] === void 0) continue;
4136
+ const result = validateStringArrayField(`surfaces.${surface}.${fieldName}`, rawControls[fieldName]);
4137
+ if (result !== void 0) validated[fieldName] = result;
2148
4138
  }
2149
4139
  return validated;
2150
4140
  };
2151
4141
  const validateSurfacesField = (rawSurfaces) => {
2152
- if (rawSurfaces === void 0) return void 0;
2153
- if (typeof rawSurfaces !== "object" || rawSurfaces === null || Array.isArray(rawSurfaces)) {
4142
+ if (!isPlainObject$1(rawSurfaces)) {
2154
4143
  warnConfigField(`config field "surfaces" must be an object (got ${typeof rawSurfaces}); ignoring this field.`);
2155
4144
  return;
2156
4145
  }
@@ -2165,27 +4154,38 @@ const validateSurfacesField = (rawSurfaces) => {
2165
4154
  }
2166
4155
  return validated;
2167
4156
  };
4157
+ const validateSeverityMap = (fieldName, rawMap) => {
4158
+ if (!isPlainObject$1(rawMap)) {
4159
+ warnConfigField(`config field "${fieldName}" must be an object (got ${typeof rawMap}); ignoring this field.`);
4160
+ return;
4161
+ }
4162
+ const validated = {};
4163
+ for (const [key, value] of Object.entries(rawMap)) {
4164
+ if (key.length === 0) {
4165
+ warnConfigField(`config field "${fieldName}" has an empty key; ignoring the entry.`);
4166
+ continue;
4167
+ }
4168
+ if (!isRuleSeverity(value)) {
4169
+ warnConfigField(`config field "${fieldName}.${key}" must be one of: ${VALID_RULE_SEVERITIES.join(", ")} (got ${formatType(value)}); ignoring the entry.`);
4170
+ continue;
4171
+ }
4172
+ validated[key] = value;
4173
+ }
4174
+ return validated;
4175
+ };
4176
+ const applyFieldValidator = (config, validated, fieldName, validator) => {
4177
+ const raw = config[fieldName];
4178
+ if (raw === void 0) return;
4179
+ const result = validator(raw);
4180
+ if (result === void 0) delete validated[fieldName];
4181
+ else validated[fieldName] = result;
4182
+ };
2168
4183
  const validateConfigTypes = (config) => {
2169
4184
  const validated = { ...config };
2170
- for (const fieldName of BOOLEAN_FIELD_NAMES) {
2171
- const original = config[fieldName];
2172
- if (original === void 0) continue;
2173
- const coerced = coerceMaybeBooleanString(fieldName, original);
2174
- if (coerced === void 0) delete validated[fieldName];
2175
- else validated[fieldName] = coerced;
2176
- }
2177
- for (const fieldName of STRING_FIELD_NAMES) {
2178
- const original = config[fieldName];
2179
- if (original === void 0) continue;
2180
- const validatedString = validateString(fieldName, original);
2181
- if (validatedString === void 0) delete validated[fieldName];
2182
- else validated[fieldName] = validatedString;
2183
- }
2184
- if (config.surfaces !== void 0) {
2185
- const validatedSurfaces = validateSurfacesField(config.surfaces);
2186
- if (validatedSurfaces === void 0) delete validated.surfaces;
2187
- else validated.surfaces = validatedSurfaces;
2188
- }
4185
+ for (const fieldName of BOOLEAN_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => coerceMaybeBooleanString(fieldName, value));
4186
+ for (const fieldName of STRING_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateString(fieldName, value));
4187
+ applyFieldValidator(config, validated, "surfaces", validateSurfacesField);
4188
+ for (const fieldName of SEVERITY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateSeverityMap(fieldName, value));
2189
4189
  return validated;
2190
4190
  };
2191
4191
  const CONFIG_FILENAME = "react-doctor.config.json";
@@ -2569,69 +4569,11 @@ const filterRulesToAvailable = (rules, pluginNamespace, availableRuleNames) => {
2569
4569
  }
2570
4570
  return filtered;
2571
4571
  };
2572
- const REACT_COMPILER_RULES = {
2573
- "react-hooks-js/set-state-in-render": "error",
2574
- "react-hooks-js/immutability": "error",
2575
- "react-hooks-js/refs": "error",
2576
- "react-hooks-js/purity": "error",
2577
- "react-hooks-js/hooks": "error",
2578
- "react-hooks-js/set-state-in-effect": "error",
2579
- "react-hooks-js/globals": "error",
2580
- "react-hooks-js/error-boundaries": "error",
2581
- "react-hooks-js/preserve-manual-memoization": "error",
2582
- "react-hooks-js/unsupported-syntax": "error",
2583
- "react-hooks-js/component-hook-factories": "error",
2584
- "react-hooks-js/static-components": "error",
2585
- "react-hooks-js/use-memo": "error",
2586
- "react-hooks-js/void-use-memo": "error",
2587
- "react-hooks-js/incompatible-library": "error",
2588
- "react-hooks-js/todo": "error"
2589
- };
2590
- const YOU_MIGHT_NOT_NEED_EFFECT_RULES = {
2591
- "effect/no-derived-state": "warn",
2592
- "effect/no-chain-state-updates": "warn",
2593
- "effect/no-event-handler": "warn",
2594
- "effect/no-adjust-state-on-prop-change": "warn",
2595
- "effect/no-reset-all-state-on-prop-change": "warn",
2596
- "effect/no-pass-live-state-to-parent": "warn",
2597
- "effect/no-pass-data-to-parent": "warn",
2598
- "effect/no-initialize-state": "warn"
2599
- };
2600
- const BUILTIN_REACT_RULES = {
2601
- "react/rules-of-hooks": "error",
2602
- "react/no-direct-mutation-state": "error",
2603
- "react/jsx-no-duplicate-props": "error",
2604
- "react/jsx-key": "error",
2605
- "react/no-children-prop": "warn",
2606
- "react/no-danger": "warn",
2607
- "react/jsx-no-script-url": "error",
2608
- "react/no-render-return-value": "warn",
2609
- "react/no-string-refs": "warn",
2610
- "react/no-is-mounted": "warn",
2611
- "react/require-render-return": "error",
2612
- "react/no-unknown-property": "warn"
2613
- };
2614
- const BUILTIN_A11Y_RULES = {
2615
- "jsx-a11y/alt-text": "error",
2616
- "jsx-a11y/anchor-is-valid": "warn",
2617
- "jsx-a11y/click-events-have-key-events": "warn",
2618
- "jsx-a11y/no-static-element-interactions": "warn",
2619
- "jsx-a11y/role-has-required-aria-props": "error",
2620
- "jsx-a11y/no-autofocus": "warn",
2621
- "jsx-a11y/heading-has-content": "warn",
2622
- "jsx-a11y/html-has-lang": "warn",
2623
- "jsx-a11y/no-redundant-roles": "warn",
2624
- "jsx-a11y/scope": "warn",
2625
- "jsx-a11y/tabindex-no-positive": "warn",
2626
- "jsx-a11y/label-has-associated-control": "warn",
2627
- "jsx-a11y/no-distracting-elements": "error",
2628
- "jsx-a11y/iframe-has-title": "warn"
2629
- };
2630
4572
  const resolveSettingsRootDirectory = (rootDirectory) => {
2631
4573
  if (!fs.existsSync(rootDirectory)) return rootDirectory;
2632
4574
  return fs.realpathSync(rootDirectory);
2633
4575
  };
2634
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames }) => {
4576
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls }) => {
2635
4577
  const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
2636
4578
  const reactCompilerRules = reactHooksJsPlugin ? filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames) : {};
2637
4579
  const youMightNotNeedEffectPlugin = resolveYouMightNotNeedEffectPlugin(customRulesOnly);
@@ -2645,7 +4587,12 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
2645
4587
  const fullKey = `react-doctor/${ruleId}`;
2646
4588
  if (rule.framework !== "global" && !rule.requires) continue;
2647
4589
  if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags)) continue;
2648
- enabledReactDoctorRules[fullKey] = rule.severity;
4590
+ const severity = resolveRuleSeverityOverride({
4591
+ ruleKey: fullKey,
4592
+ category: rule.category
4593
+ }, severityControls) ?? rule.severity;
4594
+ if (severity === "off") continue;
4595
+ enabledReactDoctorRules[fullKey] = severity;
2649
4596
  }
2650
4597
  return {
2651
4598
  ...extendsPaths.length > 0 ? { extends: extendsPaths } : {},
@@ -3179,6 +5126,7 @@ const validateRuleRegistration = () => {
3179
5126
  const runOxlint = async (options) => {
3180
5127
  const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, onPartialFailure } = options;
3181
5128
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
5129
+ const severityControls = buildRuleSeverityControls(userConfig);
3182
5130
  validateRuleRegistration();
3183
5131
  if (includePaths !== void 0 && includePaths.length === 0) return [];
3184
5132
  const configDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
@@ -3191,7 +5139,8 @@ const runOxlint = async (options) => {
3191
5139
  customRulesOnly,
3192
5140
  extendsPaths,
3193
5141
  ignoredTags,
3194
- serverAuthFunctionNames
5142
+ serverAuthFunctionNames,
5143
+ severityControls
3195
5144
  });
3196
5145
  const restoreDisableDirectives = respectInlineDisables ? () => {} : neutralizeDisableDirectives(rootDirectory, includePaths);
3197
5146
  try {
@@ -3259,7 +5208,8 @@ const runOxlint = async (options) => {
3259
5208
  customRulesOnly,
3260
5209
  extendsPaths: [],
3261
5210
  ignoredTags,
3262
- serverAuthFunctionNames
5211
+ serverAuthFunctionNames,
5212
+ severityControls
3263
5213
  }));
3264
5214
  return await spawnLintBatches();
3265
5215
  }
@@ -3624,6 +5574,12 @@ const printNoScoreHeader = (noScoreMessage) => {
3624
5574
  logger.log(` ${highlighter.gray(noScoreMessage)}`);
3625
5575
  logger.break();
3626
5576
  };
5577
+ const printReactReviewCta = () => {
5578
+ logger.log(` ${highlighter.bold("→ Catch these issues on every PR:")} ${highlighter.info(REACT_REVIEW_URL)}`);
5579
+ logger.log(` ${highlighter.dim("React Review is a GitHub App built on React Doctor, and it runs on each pull request,")}`);
5580
+ logger.log(` ${highlighter.dim("posts new issues as inline review comments, and tracks your team's score over time.")}`);
5581
+ logger.break();
5582
+ };
3627
5583
  //#endregion
3628
5584
  //#region src/cli/utils/write-diagnostics-directory.ts
3629
5585
  const writeDiagnosticsDirectory = (diagnostics) => {
@@ -3672,6 +5628,8 @@ const printSummary = (diagnostics, elapsedMilliseconds, scoreResult, projectName
3672
5628
  logger.break();
3673
5629
  const shareUrl = buildShareUrl(diagnostics, scoreResult, projectName);
3674
5630
  logger.log(` ${highlighter.bold("→ Share your results:")} ${highlighter.info(shareUrl)}`);
5631
+ logger.break();
5632
+ printReactReviewCta();
3675
5633
  }
3676
5634
  };
3677
5635
  //#endregion
@@ -3688,7 +5646,7 @@ const shouldSelectAllChoices = (choiceStates) => {
3688
5646
  };
3689
5647
  //#endregion
3690
5648
  //#region src/cli/utils/prompts.ts
3691
- const require = createRequire(import.meta.url);
5649
+ const require$1 = createRequire(import.meta.url);
3692
5650
  const PROMPTS_MULTISELECT_MODULE_PATH = "prompts/lib/elements/multiselect";
3693
5651
  let didPatchMultiselectToggleAll = false;
3694
5652
  let didPatchMultiselectSubmit = false;
@@ -3701,7 +5659,7 @@ const onCancel = () => {
3701
5659
  const patchMultiselectToggleAll = () => {
3702
5660
  if (didPatchMultiselectToggleAll) return;
3703
5661
  didPatchMultiselectToggleAll = true;
3704
- const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);
5662
+ const multiselectPromptConstructor = require$1(PROMPTS_MULTISELECT_MODULE_PATH);
3705
5663
  multiselectPromptConstructor.prototype.toggleAll = function() {
3706
5664
  const isCurrentChoiceDisabled = Boolean(this.value[this.cursor]?.disabled);
3707
5665
  if (this.maxChoices !== void 0 || isCurrentChoiceDisabled) {
@@ -3719,7 +5677,7 @@ const patchMultiselectToggleAll = () => {
3719
5677
  const patchMultiselectSubmit = () => {
3720
5678
  if (didPatchMultiselectSubmit) return;
3721
5679
  didPatchMultiselectSubmit = true;
3722
- const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);
5680
+ const multiselectPromptConstructor = require$1(PROMPTS_MULTISELECT_MODULE_PATH);
3723
5681
  const originalSubmit = multiselectPromptConstructor.prototype.submit;
3724
5682
  multiselectPromptConstructor.prototype.submit = function() {
3725
5683
  if (shouldAutoSelectCurrentChoice(this.value, this.cursor)) this.value[this.cursor].selected = true;
@@ -4019,7 +5977,7 @@ const CI_ENVIRONMENT_VARIABLES = [
4019
5977
  const isCiEnvironment = () => CI_ENVIRONMENT_VARIABLES.some((envVariable) => Boolean(process.env[envVariable])) || process.env.CI === "true";
4020
5978
  //#endregion
4021
5979
  //#region src/cli/utils/version.ts
4022
- const VERSION = "0.2.0-beta.5";
5980
+ const VERSION = "0.2.0";
4023
5981
  //#endregion
4024
5982
  //#region src/cli/utils/json-mode.ts
4025
5983
  let context = null;