roast-my-codebase 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,1758 +6,12 @@ import {
6
6
  LARGE_FILE_THRESHOLDS,
7
7
  SAFE_GLOB_OPTIONS,
8
8
  SOURCE_EXTENSIONS,
9
- __commonJS,
10
- __require,
11
- __toESM,
12
9
  buildIgnorePatterns
13
- } from "./chunk-4KMMPANT.js";
14
-
15
- // node_modules/picomatch/lib/constants.js
16
- var require_constants = __commonJS({
17
- "node_modules/picomatch/lib/constants.js"(exports, module) {
18
- "use strict";
19
- var path26 = __require("path");
20
- var WIN_SLASH = "\\\\/";
21
- var WIN_NO_SLASH = `[^${WIN_SLASH}]`;
22
- var DEFAULT_MAX_EXTGLOB_RECURSION = 0;
23
- var DOT_LITERAL = "\\.";
24
- var PLUS_LITERAL = "\\+";
25
- var QMARK_LITERAL = "\\?";
26
- var SLASH_LITERAL = "\\/";
27
- var ONE_CHAR = "(?=.)";
28
- var QMARK = "[^/]";
29
- var END_ANCHOR = `(?:${SLASH_LITERAL}|$)`;
30
- var START_ANCHOR = `(?:^|${SLASH_LITERAL})`;
31
- var DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`;
32
- var NO_DOT = `(?!${DOT_LITERAL})`;
33
- var NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`;
34
- var NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`;
35
- var NO_DOTS_SLASH = `(?!${DOTS_SLASH})`;
36
- var QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`;
37
- var STAR = `${QMARK}*?`;
38
- var POSIX_CHARS = {
39
- DOT_LITERAL,
40
- PLUS_LITERAL,
41
- QMARK_LITERAL,
42
- SLASH_LITERAL,
43
- ONE_CHAR,
44
- QMARK,
45
- END_ANCHOR,
46
- DOTS_SLASH,
47
- NO_DOT,
48
- NO_DOTS,
49
- NO_DOT_SLASH,
50
- NO_DOTS_SLASH,
51
- QMARK_NO_DOT,
52
- STAR,
53
- START_ANCHOR
54
- };
55
- var WINDOWS_CHARS = {
56
- ...POSIX_CHARS,
57
- SLASH_LITERAL: `[${WIN_SLASH}]`,
58
- QMARK: WIN_NO_SLASH,
59
- STAR: `${WIN_NO_SLASH}*?`,
60
- DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`,
61
- NO_DOT: `(?!${DOT_LITERAL})`,
62
- NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
63
- NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`,
64
- NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
65
- QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
66
- START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
67
- END_ANCHOR: `(?:[${WIN_SLASH}]|$)`
68
- };
69
- var POSIX_REGEX_SOURCE = {
70
- __proto__: null,
71
- alnum: "a-zA-Z0-9",
72
- alpha: "a-zA-Z",
73
- ascii: "\\x00-\\x7F",
74
- blank: " \\t",
75
- cntrl: "\\x00-\\x1F\\x7F",
76
- digit: "0-9",
77
- graph: "\\x21-\\x7E",
78
- lower: "a-z",
79
- print: "\\x20-\\x7E ",
80
- punct: "\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",
81
- space: " \\t\\r\\n\\v\\f",
82
- upper: "A-Z",
83
- word: "A-Za-z0-9_",
84
- xdigit: "A-Fa-f0-9"
85
- };
86
- module.exports = {
87
- DEFAULT_MAX_EXTGLOB_RECURSION,
88
- MAX_LENGTH: 1024 * 64,
89
- POSIX_REGEX_SOURCE,
90
- // regular expressions
91
- REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g,
92
- REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/,
93
- REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/,
94
- REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g,
95
- REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g,
96
- REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g,
97
- // Replace globs with equivalent patterns to reduce parsing time.
98
- REPLACEMENTS: {
99
- __proto__: null,
100
- "***": "*",
101
- "**/**": "**",
102
- "**/**/**": "**"
103
- },
104
- // Digits
105
- CHAR_0: 48,
106
- /* 0 */
107
- CHAR_9: 57,
108
- /* 9 */
109
- // Alphabet chars.
110
- CHAR_UPPERCASE_A: 65,
111
- /* A */
112
- CHAR_LOWERCASE_A: 97,
113
- /* a */
114
- CHAR_UPPERCASE_Z: 90,
115
- /* Z */
116
- CHAR_LOWERCASE_Z: 122,
117
- /* z */
118
- CHAR_LEFT_PARENTHESES: 40,
119
- /* ( */
120
- CHAR_RIGHT_PARENTHESES: 41,
121
- /* ) */
122
- CHAR_ASTERISK: 42,
123
- /* * */
124
- // Non-alphabetic chars.
125
- CHAR_AMPERSAND: 38,
126
- /* & */
127
- CHAR_AT: 64,
128
- /* @ */
129
- CHAR_BACKWARD_SLASH: 92,
130
- /* \ */
131
- CHAR_CARRIAGE_RETURN: 13,
132
- /* \r */
133
- CHAR_CIRCUMFLEX_ACCENT: 94,
134
- /* ^ */
135
- CHAR_COLON: 58,
136
- /* : */
137
- CHAR_COMMA: 44,
138
- /* , */
139
- CHAR_DOT: 46,
140
- /* . */
141
- CHAR_DOUBLE_QUOTE: 34,
142
- /* " */
143
- CHAR_EQUAL: 61,
144
- /* = */
145
- CHAR_EXCLAMATION_MARK: 33,
146
- /* ! */
147
- CHAR_FORM_FEED: 12,
148
- /* \f */
149
- CHAR_FORWARD_SLASH: 47,
150
- /* / */
151
- CHAR_GRAVE_ACCENT: 96,
152
- /* ` */
153
- CHAR_HASH: 35,
154
- /* # */
155
- CHAR_HYPHEN_MINUS: 45,
156
- /* - */
157
- CHAR_LEFT_ANGLE_BRACKET: 60,
158
- /* < */
159
- CHAR_LEFT_CURLY_BRACE: 123,
160
- /* { */
161
- CHAR_LEFT_SQUARE_BRACKET: 91,
162
- /* [ */
163
- CHAR_LINE_FEED: 10,
164
- /* \n */
165
- CHAR_NO_BREAK_SPACE: 160,
166
- /* \u00A0 */
167
- CHAR_PERCENT: 37,
168
- /* % */
169
- CHAR_PLUS: 43,
170
- /* + */
171
- CHAR_QUESTION_MARK: 63,
172
- /* ? */
173
- CHAR_RIGHT_ANGLE_BRACKET: 62,
174
- /* > */
175
- CHAR_RIGHT_CURLY_BRACE: 125,
176
- /* } */
177
- CHAR_RIGHT_SQUARE_BRACKET: 93,
178
- /* ] */
179
- CHAR_SEMICOLON: 59,
180
- /* ; */
181
- CHAR_SINGLE_QUOTE: 39,
182
- /* ' */
183
- CHAR_SPACE: 32,
184
- /* */
185
- CHAR_TAB: 9,
186
- /* \t */
187
- CHAR_UNDERSCORE: 95,
188
- /* _ */
189
- CHAR_VERTICAL_LINE: 124,
190
- /* | */
191
- CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279,
192
- /* \uFEFF */
193
- SEP: path26.sep,
194
- /**
195
- * Create EXTGLOB_CHARS
196
- */
197
- extglobChars(chars) {
198
- return {
199
- "!": { type: "negate", open: "(?:(?!(?:", close: `))${chars.STAR})` },
200
- "?": { type: "qmark", open: "(?:", close: ")?" },
201
- "+": { type: "plus", open: "(?:", close: ")+" },
202
- "*": { type: "star", open: "(?:", close: ")*" },
203
- "@": { type: "at", open: "(?:", close: ")" }
204
- };
205
- },
206
- /**
207
- * Create GLOB_CHARS
208
- */
209
- globChars(win32) {
210
- return win32 === true ? WINDOWS_CHARS : POSIX_CHARS;
211
- }
212
- };
213
- }
214
- });
215
-
216
- // node_modules/picomatch/lib/utils.js
217
- var require_utils = __commonJS({
218
- "node_modules/picomatch/lib/utils.js"(exports) {
219
- "use strict";
220
- var path26 = __require("path");
221
- var win32 = process.platform === "win32";
222
- var {
223
- REGEX_BACKSLASH,
224
- REGEX_REMOVE_BACKSLASH,
225
- REGEX_SPECIAL_CHARS,
226
- REGEX_SPECIAL_CHARS_GLOBAL
227
- } = require_constants();
228
- exports.isObject = (val) => val !== null && typeof val === "object" && !Array.isArray(val);
229
- exports.hasRegexChars = (str) => REGEX_SPECIAL_CHARS.test(str);
230
- exports.isRegexChar = (str) => str.length === 1 && exports.hasRegexChars(str);
231
- exports.escapeRegex = (str) => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, "\\$1");
232
- exports.toPosixSlashes = (str) => str.replace(REGEX_BACKSLASH, "/");
233
- exports.removeBackslashes = (str) => {
234
- return str.replace(REGEX_REMOVE_BACKSLASH, (match) => {
235
- return match === "\\" ? "" : match;
236
- });
237
- };
238
- exports.supportsLookbehinds = () => {
239
- const segs = process.version.slice(1).split(".").map(Number);
240
- if (segs.length === 3 && segs[0] >= 9 || segs[0] === 8 && segs[1] >= 10) {
241
- return true;
242
- }
243
- return false;
244
- };
245
- exports.isWindows = (options) => {
246
- if (options && typeof options.windows === "boolean") {
247
- return options.windows;
248
- }
249
- return win32 === true || path26.sep === "\\";
250
- };
251
- exports.escapeLast = (input2, char, lastIdx) => {
252
- const idx = input2.lastIndexOf(char, lastIdx);
253
- if (idx === -1) return input2;
254
- if (input2[idx - 1] === "\\") return exports.escapeLast(input2, char, idx - 1);
255
- return `${input2.slice(0, idx)}\\${input2.slice(idx)}`;
256
- };
257
- exports.removePrefix = (input2, state = {}) => {
258
- let output = input2;
259
- if (output.startsWith("./")) {
260
- output = output.slice(2);
261
- state.prefix = "./";
262
- }
263
- return output;
264
- };
265
- exports.wrapOutput = (input2, state = {}, options = {}) => {
266
- const prepend = options.contains ? "" : "^";
267
- const append = options.contains ? "" : "$";
268
- let output = `${prepend}(?:${input2})${append}`;
269
- if (state.negated === true) {
270
- output = `(?:^(?!${output}).*$)`;
271
- }
272
- return output;
273
- };
274
- }
275
- });
276
-
277
- // node_modules/picomatch/lib/scan.js
278
- var require_scan = __commonJS({
279
- "node_modules/picomatch/lib/scan.js"(exports, module) {
280
- "use strict";
281
- var utils = require_utils();
282
- var {
283
- CHAR_ASTERISK,
284
- /* * */
285
- CHAR_AT,
286
- /* @ */
287
- CHAR_BACKWARD_SLASH,
288
- /* \ */
289
- CHAR_COMMA,
290
- /* , */
291
- CHAR_DOT,
292
- /* . */
293
- CHAR_EXCLAMATION_MARK,
294
- /* ! */
295
- CHAR_FORWARD_SLASH,
296
- /* / */
297
- CHAR_LEFT_CURLY_BRACE,
298
- /* { */
299
- CHAR_LEFT_PARENTHESES,
300
- /* ( */
301
- CHAR_LEFT_SQUARE_BRACKET,
302
- /* [ */
303
- CHAR_PLUS,
304
- /* + */
305
- CHAR_QUESTION_MARK,
306
- /* ? */
307
- CHAR_RIGHT_CURLY_BRACE,
308
- /* } */
309
- CHAR_RIGHT_PARENTHESES,
310
- /* ) */
311
- CHAR_RIGHT_SQUARE_BRACKET
312
- /* ] */
313
- } = require_constants();
314
- var isPathSeparator = (code) => {
315
- return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
316
- };
317
- var depth = (token) => {
318
- if (token.isPrefix !== true) {
319
- token.depth = token.isGlobstar ? Infinity : 1;
320
- }
321
- };
322
- var scan = (input2, options) => {
323
- const opts = options || {};
324
- const length = input2.length - 1;
325
- const scanToEnd = opts.parts === true || opts.scanToEnd === true;
326
- const slashes = [];
327
- const tokens = [];
328
- const parts = [];
329
- let str = input2;
330
- let index = -1;
331
- let start = 0;
332
- let lastIndex = 0;
333
- let isBrace = false;
334
- let isBracket = false;
335
- let isGlob = false;
336
- let isExtglob = false;
337
- let isGlobstar = false;
338
- let braceEscaped = false;
339
- let backslashes = false;
340
- let negated = false;
341
- let negatedExtglob = false;
342
- let finished = false;
343
- let braces = 0;
344
- let prev;
345
- let code;
346
- let token = { value: "", depth: 0, isGlob: false };
347
- const eos = () => index >= length;
348
- const peek = () => str.charCodeAt(index + 1);
349
- const advance = () => {
350
- prev = code;
351
- return str.charCodeAt(++index);
352
- };
353
- while (index < length) {
354
- code = advance();
355
- let next;
356
- if (code === CHAR_BACKWARD_SLASH) {
357
- backslashes = token.backslashes = true;
358
- code = advance();
359
- if (code === CHAR_LEFT_CURLY_BRACE) {
360
- braceEscaped = true;
361
- }
362
- continue;
363
- }
364
- if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) {
365
- braces++;
366
- while (eos() !== true && (code = advance())) {
367
- if (code === CHAR_BACKWARD_SLASH) {
368
- backslashes = token.backslashes = true;
369
- advance();
370
- continue;
371
- }
372
- if (code === CHAR_LEFT_CURLY_BRACE) {
373
- braces++;
374
- continue;
375
- }
376
- if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) {
377
- isBrace = token.isBrace = true;
378
- isGlob = token.isGlob = true;
379
- finished = true;
380
- if (scanToEnd === true) {
381
- continue;
382
- }
383
- break;
384
- }
385
- if (braceEscaped !== true && code === CHAR_COMMA) {
386
- isBrace = token.isBrace = true;
387
- isGlob = token.isGlob = true;
388
- finished = true;
389
- if (scanToEnd === true) {
390
- continue;
391
- }
392
- break;
393
- }
394
- if (code === CHAR_RIGHT_CURLY_BRACE) {
395
- braces--;
396
- if (braces === 0) {
397
- braceEscaped = false;
398
- isBrace = token.isBrace = true;
399
- finished = true;
400
- break;
401
- }
402
- }
403
- }
404
- if (scanToEnd === true) {
405
- continue;
406
- }
407
- break;
408
- }
409
- if (code === CHAR_FORWARD_SLASH) {
410
- slashes.push(index);
411
- tokens.push(token);
412
- token = { value: "", depth: 0, isGlob: false };
413
- if (finished === true) continue;
414
- if (prev === CHAR_DOT && index === start + 1) {
415
- start += 2;
416
- continue;
417
- }
418
- lastIndex = index + 1;
419
- continue;
420
- }
421
- if (opts.noext !== true) {
422
- const isExtglobChar = code === CHAR_PLUS || code === CHAR_AT || code === CHAR_ASTERISK || code === CHAR_QUESTION_MARK || code === CHAR_EXCLAMATION_MARK;
423
- if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) {
424
- isGlob = token.isGlob = true;
425
- isExtglob = token.isExtglob = true;
426
- finished = true;
427
- if (code === CHAR_EXCLAMATION_MARK && index === start) {
428
- negatedExtglob = true;
429
- }
430
- if (scanToEnd === true) {
431
- while (eos() !== true && (code = advance())) {
432
- if (code === CHAR_BACKWARD_SLASH) {
433
- backslashes = token.backslashes = true;
434
- code = advance();
435
- continue;
436
- }
437
- if (code === CHAR_RIGHT_PARENTHESES) {
438
- isGlob = token.isGlob = true;
439
- finished = true;
440
- break;
441
- }
442
- }
443
- continue;
444
- }
445
- break;
446
- }
447
- }
448
- if (code === CHAR_ASTERISK) {
449
- if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true;
450
- isGlob = token.isGlob = true;
451
- finished = true;
452
- if (scanToEnd === true) {
453
- continue;
454
- }
455
- break;
456
- }
457
- if (code === CHAR_QUESTION_MARK) {
458
- isGlob = token.isGlob = true;
459
- finished = true;
460
- if (scanToEnd === true) {
461
- continue;
462
- }
463
- break;
464
- }
465
- if (code === CHAR_LEFT_SQUARE_BRACKET) {
466
- while (eos() !== true && (next = advance())) {
467
- if (next === CHAR_BACKWARD_SLASH) {
468
- backslashes = token.backslashes = true;
469
- advance();
470
- continue;
471
- }
472
- if (next === CHAR_RIGHT_SQUARE_BRACKET) {
473
- isBracket = token.isBracket = true;
474
- isGlob = token.isGlob = true;
475
- finished = true;
476
- break;
477
- }
478
- }
479
- if (scanToEnd === true) {
480
- continue;
481
- }
482
- break;
483
- }
484
- if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) {
485
- negated = token.negated = true;
486
- start++;
487
- continue;
488
- }
489
- if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) {
490
- isGlob = token.isGlob = true;
491
- if (scanToEnd === true) {
492
- while (eos() !== true && (code = advance())) {
493
- if (code === CHAR_LEFT_PARENTHESES) {
494
- backslashes = token.backslashes = true;
495
- code = advance();
496
- continue;
497
- }
498
- if (code === CHAR_RIGHT_PARENTHESES) {
499
- finished = true;
500
- break;
501
- }
502
- }
503
- continue;
504
- }
505
- break;
506
- }
507
- if (isGlob === true) {
508
- finished = true;
509
- if (scanToEnd === true) {
510
- continue;
511
- }
512
- break;
513
- }
514
- }
515
- if (opts.noext === true) {
516
- isExtglob = false;
517
- isGlob = false;
518
- }
519
- let base = str;
520
- let prefix = "";
521
- let glob = "";
522
- if (start > 0) {
523
- prefix = str.slice(0, start);
524
- str = str.slice(start);
525
- lastIndex -= start;
526
- }
527
- if (base && isGlob === true && lastIndex > 0) {
528
- base = str.slice(0, lastIndex);
529
- glob = str.slice(lastIndex);
530
- } else if (isGlob === true) {
531
- base = "";
532
- glob = str;
533
- } else {
534
- base = str;
535
- }
536
- if (base && base !== "" && base !== "/" && base !== str) {
537
- if (isPathSeparator(base.charCodeAt(base.length - 1))) {
538
- base = base.slice(0, -1);
539
- }
540
- }
541
- if (opts.unescape === true) {
542
- if (glob) glob = utils.removeBackslashes(glob);
543
- if (base && backslashes === true) {
544
- base = utils.removeBackslashes(base);
545
- }
546
- }
547
- const state = {
548
- prefix,
549
- input: input2,
550
- start,
551
- base,
552
- glob,
553
- isBrace,
554
- isBracket,
555
- isGlob,
556
- isExtglob,
557
- isGlobstar,
558
- negated,
559
- negatedExtglob
560
- };
561
- if (opts.tokens === true) {
562
- state.maxDepth = 0;
563
- if (!isPathSeparator(code)) {
564
- tokens.push(token);
565
- }
566
- state.tokens = tokens;
567
- }
568
- if (opts.parts === true || opts.tokens === true) {
569
- let prevIndex;
570
- for (let idx = 0; idx < slashes.length; idx++) {
571
- const n = prevIndex ? prevIndex + 1 : start;
572
- const i = slashes[idx];
573
- const value = input2.slice(n, i);
574
- if (opts.tokens) {
575
- if (idx === 0 && start !== 0) {
576
- tokens[idx].isPrefix = true;
577
- tokens[idx].value = prefix;
578
- } else {
579
- tokens[idx].value = value;
580
- }
581
- depth(tokens[idx]);
582
- state.maxDepth += tokens[idx].depth;
583
- }
584
- if (idx !== 0 || value !== "") {
585
- parts.push(value);
586
- }
587
- prevIndex = i;
588
- }
589
- if (prevIndex && prevIndex + 1 < input2.length) {
590
- const value = input2.slice(prevIndex + 1);
591
- parts.push(value);
592
- if (opts.tokens) {
593
- tokens[tokens.length - 1].value = value;
594
- depth(tokens[tokens.length - 1]);
595
- state.maxDepth += tokens[tokens.length - 1].depth;
596
- }
597
- }
598
- state.slashes = slashes;
599
- state.parts = parts;
600
- }
601
- return state;
602
- };
603
- module.exports = scan;
604
- }
605
- });
606
-
607
- // node_modules/picomatch/lib/parse.js
608
- var require_parse = __commonJS({
609
- "node_modules/picomatch/lib/parse.js"(exports, module) {
610
- "use strict";
611
- var constants = require_constants();
612
- var utils = require_utils();
613
- var {
614
- MAX_LENGTH,
615
- POSIX_REGEX_SOURCE,
616
- REGEX_NON_SPECIAL_CHARS,
617
- REGEX_SPECIAL_CHARS_BACKREF,
618
- REPLACEMENTS
619
- } = constants;
620
- var expandRange = (args, options) => {
621
- if (typeof options.expandRange === "function") {
622
- return options.expandRange(...args, options);
623
- }
624
- args.sort();
625
- const value = `[${args.join("-")}]`;
626
- try {
627
- new RegExp(value);
628
- } catch (ex) {
629
- return args.map((v) => utils.escapeRegex(v)).join("..");
630
- }
631
- return value;
632
- };
633
- var syntaxError = (type, char) => {
634
- return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
635
- };
636
- var splitTopLevel = (input2) => {
637
- const parts = [];
638
- let bracket = 0;
639
- let paren = 0;
640
- let quote = 0;
641
- let value = "";
642
- let escaped = false;
643
- for (const ch of input2) {
644
- if (escaped === true) {
645
- value += ch;
646
- escaped = false;
647
- continue;
648
- }
649
- if (ch === "\\") {
650
- value += ch;
651
- escaped = true;
652
- continue;
653
- }
654
- if (ch === '"') {
655
- quote = quote === 1 ? 0 : 1;
656
- value += ch;
657
- continue;
658
- }
659
- if (quote === 0) {
660
- if (ch === "[") {
661
- bracket++;
662
- } else if (ch === "]" && bracket > 0) {
663
- bracket--;
664
- } else if (bracket === 0) {
665
- if (ch === "(") {
666
- paren++;
667
- } else if (ch === ")" && paren > 0) {
668
- paren--;
669
- } else if (ch === "|" && paren === 0) {
670
- parts.push(value);
671
- value = "";
672
- continue;
673
- }
674
- }
675
- }
676
- value += ch;
677
- }
678
- parts.push(value);
679
- return parts;
680
- };
681
- var isPlainBranch = (branch) => {
682
- let escaped = false;
683
- for (const ch of branch) {
684
- if (escaped === true) {
685
- escaped = false;
686
- continue;
687
- }
688
- if (ch === "\\") {
689
- escaped = true;
690
- continue;
691
- }
692
- if (/[?*+@!()[\]{}]/.test(ch)) {
693
- return false;
694
- }
695
- }
696
- return true;
697
- };
698
- var normalizeSimpleBranch = (branch) => {
699
- let value = branch.trim();
700
- let changed = true;
701
- while (changed === true) {
702
- changed = false;
703
- if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
704
- value = value.slice(2, -1);
705
- changed = true;
706
- }
707
- }
708
- if (!isPlainBranch(value)) {
709
- return;
710
- }
711
- return value.replace(/\\(.)/g, "$1");
712
- };
713
- var hasRepeatedCharPrefixOverlap = (branches) => {
714
- const values = branches.map(normalizeSimpleBranch).filter(Boolean);
715
- for (let i = 0; i < values.length; i++) {
716
- for (let j = i + 1; j < values.length; j++) {
717
- const a = values[i];
718
- const b = values[j];
719
- const char = a[0];
720
- if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) {
721
- continue;
722
- }
723
- if (a === b || a.startsWith(b) || b.startsWith(a)) {
724
- return true;
725
- }
726
- }
727
- }
728
- return false;
729
- };
730
- var parseRepeatedExtglob = (pattern, requireEnd = true) => {
731
- if (pattern[0] !== "+" && pattern[0] !== "*" || pattern[1] !== "(") {
732
- return;
733
- }
734
- let bracket = 0;
735
- let paren = 0;
736
- let quote = 0;
737
- let escaped = false;
738
- for (let i = 1; i < pattern.length; i++) {
739
- const ch = pattern[i];
740
- if (escaped === true) {
741
- escaped = false;
742
- continue;
743
- }
744
- if (ch === "\\") {
745
- escaped = true;
746
- continue;
747
- }
748
- if (ch === '"') {
749
- quote = quote === 1 ? 0 : 1;
750
- continue;
751
- }
752
- if (quote === 1) {
753
- continue;
754
- }
755
- if (ch === "[") {
756
- bracket++;
757
- continue;
758
- }
759
- if (ch === "]" && bracket > 0) {
760
- bracket--;
761
- continue;
762
- }
763
- if (bracket > 0) {
764
- continue;
765
- }
766
- if (ch === "(") {
767
- paren++;
768
- continue;
769
- }
770
- if (ch === ")") {
771
- paren--;
772
- if (paren === 0) {
773
- if (requireEnd === true && i !== pattern.length - 1) {
774
- return;
775
- }
776
- return {
777
- type: pattern[0],
778
- body: pattern.slice(2, i),
779
- end: i
780
- };
781
- }
782
- }
783
- }
784
- };
785
- var getStarExtglobSequenceOutput = (pattern) => {
786
- let index = 0;
787
- const chars = [];
788
- while (index < pattern.length) {
789
- const match = parseRepeatedExtglob(pattern.slice(index), false);
790
- if (!match || match.type !== "*") {
791
- return;
792
- }
793
- const branches = splitTopLevel(match.body).map((branch2) => branch2.trim());
794
- if (branches.length !== 1) {
795
- return;
796
- }
797
- const branch = normalizeSimpleBranch(branches[0]);
798
- if (!branch || branch.length !== 1) {
799
- return;
800
- }
801
- chars.push(branch);
802
- index += match.end + 1;
803
- }
804
- if (chars.length < 1) {
805
- return;
806
- }
807
- const source = chars.length === 1 ? utils.escapeRegex(chars[0]) : `[${chars.map((ch) => utils.escapeRegex(ch)).join("")}]`;
808
- return `${source}*`;
809
- };
810
- var repeatedExtglobRecursion = (pattern) => {
811
- let depth = 0;
812
- let value = pattern.trim();
813
- let match = parseRepeatedExtglob(value);
814
- while (match) {
815
- depth++;
816
- value = match.body.trim();
817
- match = parseRepeatedExtglob(value);
818
- }
819
- return depth;
820
- };
821
- var analyzeRepeatedExtglob = (body, options) => {
822
- if (options.maxExtglobRecursion === false) {
823
- return { risky: false };
824
- }
825
- const max = typeof options.maxExtglobRecursion === "number" ? options.maxExtglobRecursion : constants.DEFAULT_MAX_EXTGLOB_RECURSION;
826
- const branches = splitTopLevel(body).map((branch) => branch.trim());
827
- if (branches.length > 1) {
828
- if (branches.some((branch) => branch === "") || branches.some((branch) => /^[*?]+$/.test(branch)) || hasRepeatedCharPrefixOverlap(branches)) {
829
- return { risky: true };
830
- }
831
- }
832
- for (const branch of branches) {
833
- const safeOutput = getStarExtglobSequenceOutput(branch);
834
- if (safeOutput) {
835
- return { risky: true, safeOutput };
836
- }
837
- if (repeatedExtglobRecursion(branch) > max) {
838
- return { risky: true };
839
- }
840
- }
841
- return { risky: false };
842
- };
843
- var parse = (input2, options) => {
844
- if (typeof input2 !== "string") {
845
- throw new TypeError("Expected a string");
846
- }
847
- input2 = REPLACEMENTS[input2] || input2;
848
- const opts = { ...options };
849
- const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
850
- let len = input2.length;
851
- if (len > max) {
852
- throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
853
- }
854
- const bos = { type: "bos", value: "", output: opts.prepend || "" };
855
- const tokens = [bos];
856
- const capture = opts.capture ? "" : "?:";
857
- const win32 = utils.isWindows(options);
858
- const PLATFORM_CHARS = constants.globChars(win32);
859
- const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);
860
- const {
861
- DOT_LITERAL,
862
- PLUS_LITERAL,
863
- SLASH_LITERAL,
864
- ONE_CHAR,
865
- DOTS_SLASH,
866
- NO_DOT,
867
- NO_DOT_SLASH,
868
- NO_DOTS_SLASH,
869
- QMARK,
870
- QMARK_NO_DOT,
871
- STAR,
872
- START_ANCHOR
873
- } = PLATFORM_CHARS;
874
- const globstar = (opts2) => {
875
- return `(${capture}(?:(?!${START_ANCHOR}${opts2.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
876
- };
877
- const nodot = opts.dot ? "" : NO_DOT;
878
- const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
879
- let star = opts.bash === true ? globstar(opts) : STAR;
880
- if (opts.capture) {
881
- star = `(${star})`;
882
- }
883
- if (typeof opts.noext === "boolean") {
884
- opts.noextglob = opts.noext;
885
- }
886
- const state = {
887
- input: input2,
888
- index: -1,
889
- start: 0,
890
- dot: opts.dot === true,
891
- consumed: "",
892
- output: "",
893
- prefix: "",
894
- backtrack: false,
895
- negated: false,
896
- brackets: 0,
897
- braces: 0,
898
- parens: 0,
899
- quotes: 0,
900
- globstar: false,
901
- tokens
902
- };
903
- input2 = utils.removePrefix(input2, state);
904
- len = input2.length;
905
- const extglobs = [];
906
- const braces = [];
907
- const stack = [];
908
- let prev = bos;
909
- let value;
910
- const eos = () => state.index === len - 1;
911
- const peek = state.peek = (n = 1) => input2[state.index + n];
912
- const advance = state.advance = () => input2[++state.index] || "";
913
- const remaining = () => input2.slice(state.index + 1);
914
- const consume = (value2 = "", num = 0) => {
915
- state.consumed += value2;
916
- state.index += num;
917
- };
918
- const append = (token) => {
919
- state.output += token.output != null ? token.output : token.value;
920
- consume(token.value);
921
- };
922
- const negate = () => {
923
- let count = 1;
924
- while (peek() === "!" && (peek(2) !== "(" || peek(3) === "?")) {
925
- advance();
926
- state.start++;
927
- count++;
928
- }
929
- if (count % 2 === 0) {
930
- return false;
931
- }
932
- state.negated = true;
933
- state.start++;
934
- return true;
935
- };
936
- const increment = (type) => {
937
- state[type]++;
938
- stack.push(type);
939
- };
940
- const decrement = (type) => {
941
- state[type]--;
942
- stack.pop();
943
- };
944
- const push = (tok) => {
945
- if (prev.type === "globstar") {
946
- const isBrace = state.braces > 0 && (tok.type === "comma" || tok.type === "brace");
947
- const isExtglob = tok.extglob === true || extglobs.length && (tok.type === "pipe" || tok.type === "paren");
948
- if (tok.type !== "slash" && tok.type !== "paren" && !isBrace && !isExtglob) {
949
- state.output = state.output.slice(0, -prev.output.length);
950
- prev.type = "star";
951
- prev.value = "*";
952
- prev.output = star;
953
- state.output += prev.output;
954
- }
955
- }
956
- if (extglobs.length && tok.type !== "paren") {
957
- extglobs[extglobs.length - 1].inner += tok.value;
958
- }
959
- if (tok.value || tok.output) append(tok);
960
- if (prev && prev.type === "text" && tok.type === "text") {
961
- prev.value += tok.value;
962
- prev.output = (prev.output || "") + tok.value;
963
- return;
964
- }
965
- tok.prev = prev;
966
- tokens.push(tok);
967
- prev = tok;
968
- };
969
- const extglobOpen = (type, value2) => {
970
- const token = { ...EXTGLOB_CHARS[value2], conditions: 1, inner: "" };
971
- token.prev = prev;
972
- token.parens = state.parens;
973
- token.output = state.output;
974
- token.startIndex = state.index;
975
- token.tokensIndex = tokens.length;
976
- const output = (opts.capture ? "(" : "") + token.open;
977
- increment("parens");
978
- push({ type, value: value2, output: state.output ? "" : ONE_CHAR });
979
- push({ type: "paren", extglob: true, value: advance(), output });
980
- extglobs.push(token);
981
- };
982
- const extglobClose = (token) => {
983
- const literal = input2.slice(token.startIndex, state.index + 1);
984
- const body = input2.slice(token.startIndex + 2, state.index);
985
- const analysis = analyzeRepeatedExtglob(body, opts);
986
- if ((token.type === "plus" || token.type === "star") && analysis.risky) {
987
- const safeOutput = analysis.safeOutput ? (token.output ? "" : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : void 0;
988
- const open = tokens[token.tokensIndex];
989
- open.type = "text";
990
- open.value = literal;
991
- open.output = safeOutput || utils.escapeRegex(literal);
992
- for (let i = token.tokensIndex + 1; i < tokens.length; i++) {
993
- tokens[i].value = "";
994
- tokens[i].output = "";
995
- delete tokens[i].suffix;
996
- }
997
- state.output = token.output + open.output;
998
- state.backtrack = true;
999
- push({ type: "paren", extglob: true, value, output: "" });
1000
- decrement("parens");
1001
- return;
1002
- }
1003
- let output = token.close + (opts.capture ? ")" : "");
1004
- let rest;
1005
- if (token.type === "negate") {
1006
- let extglobStar = star;
1007
- if (token.inner && token.inner.length > 1 && token.inner.includes("/")) {
1008
- extglobStar = globstar(opts);
1009
- }
1010
- if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) {
1011
- output = token.close = `)$))${extglobStar}`;
1012
- }
1013
- if (token.inner.includes("*") && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
1014
- const expression = parse(rest, { ...options, fastpaths: false }).output;
1015
- output = token.close = `)${expression})${extglobStar})`;
1016
- }
1017
- if (token.prev.type === "bos") {
1018
- state.negatedExtglob = true;
1019
- }
1020
- }
1021
- push({ type: "paren", extglob: true, value, output });
1022
- decrement("parens");
1023
- };
1024
- if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input2)) {
1025
- let backslashes = false;
1026
- let output = input2.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => {
1027
- if (first === "\\") {
1028
- backslashes = true;
1029
- return m;
1030
- }
1031
- if (first === "?") {
1032
- if (esc) {
1033
- return esc + first + (rest ? QMARK.repeat(rest.length) : "");
1034
- }
1035
- if (index === 0) {
1036
- return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : "");
1037
- }
1038
- return QMARK.repeat(chars.length);
1039
- }
1040
- if (first === ".") {
1041
- return DOT_LITERAL.repeat(chars.length);
1042
- }
1043
- if (first === "*") {
1044
- if (esc) {
1045
- return esc + first + (rest ? star : "");
1046
- }
1047
- return star;
1048
- }
1049
- return esc ? m : `\\${m}`;
1050
- });
1051
- if (backslashes === true) {
1052
- if (opts.unescape === true) {
1053
- output = output.replace(/\\/g, "");
1054
- } else {
1055
- output = output.replace(/\\+/g, (m) => {
1056
- return m.length % 2 === 0 ? "\\\\" : m ? "\\" : "";
1057
- });
1058
- }
1059
- }
1060
- if (output === input2 && opts.contains === true) {
1061
- state.output = input2;
1062
- return state;
1063
- }
1064
- state.output = utils.wrapOutput(output, state, options);
1065
- return state;
1066
- }
1067
- while (!eos()) {
1068
- value = advance();
1069
- if (value === "\0") {
1070
- continue;
1071
- }
1072
- if (value === "\\") {
1073
- const next = peek();
1074
- if (next === "/" && opts.bash !== true) {
1075
- continue;
1076
- }
1077
- if (next === "." || next === ";") {
1078
- continue;
1079
- }
1080
- if (!next) {
1081
- value += "\\";
1082
- push({ type: "text", value });
1083
- continue;
1084
- }
1085
- const match = /^\\+/.exec(remaining());
1086
- let slashes = 0;
1087
- if (match && match[0].length > 2) {
1088
- slashes = match[0].length;
1089
- state.index += slashes;
1090
- if (slashes % 2 !== 0) {
1091
- value += "\\";
1092
- }
1093
- }
1094
- if (opts.unescape === true) {
1095
- value = advance();
1096
- } else {
1097
- value += advance();
1098
- }
1099
- if (state.brackets === 0) {
1100
- push({ type: "text", value });
1101
- continue;
1102
- }
1103
- }
1104
- if (state.brackets > 0 && (value !== "]" || prev.value === "[" || prev.value === "[^")) {
1105
- if (opts.posix !== false && value === ":") {
1106
- const inner = prev.value.slice(1);
1107
- if (inner.includes("[")) {
1108
- prev.posix = true;
1109
- if (inner.includes(":")) {
1110
- const idx = prev.value.lastIndexOf("[");
1111
- const pre = prev.value.slice(0, idx);
1112
- const rest2 = prev.value.slice(idx + 2);
1113
- const posix = POSIX_REGEX_SOURCE[rest2];
1114
- if (posix) {
1115
- prev.value = pre + posix;
1116
- state.backtrack = true;
1117
- advance();
1118
- if (!bos.output && tokens.indexOf(prev) === 1) {
1119
- bos.output = ONE_CHAR;
1120
- }
1121
- continue;
1122
- }
1123
- }
1124
- }
1125
- }
1126
- if (value === "[" && peek() !== ":" || value === "-" && peek() === "]") {
1127
- value = `\\${value}`;
1128
- }
1129
- if (value === "]" && (prev.value === "[" || prev.value === "[^")) {
1130
- value = `\\${value}`;
1131
- }
1132
- if (opts.posix === true && value === "!" && prev.value === "[") {
1133
- value = "^";
1134
- }
1135
- prev.value += value;
1136
- append({ value });
1137
- continue;
1138
- }
1139
- if (state.quotes === 1 && value !== '"') {
1140
- value = utils.escapeRegex(value);
1141
- prev.value += value;
1142
- append({ value });
1143
- continue;
1144
- }
1145
- if (value === '"') {
1146
- state.quotes = state.quotes === 1 ? 0 : 1;
1147
- if (opts.keepQuotes === true) {
1148
- push({ type: "text", value });
1149
- }
1150
- continue;
1151
- }
1152
- if (value === "(") {
1153
- increment("parens");
1154
- push({ type: "paren", value });
1155
- continue;
1156
- }
1157
- if (value === ")") {
1158
- if (state.parens === 0 && opts.strictBrackets === true) {
1159
- throw new SyntaxError(syntaxError("opening", "("));
1160
- }
1161
- const extglob = extglobs[extglobs.length - 1];
1162
- if (extglob && state.parens === extglob.parens + 1) {
1163
- extglobClose(extglobs.pop());
1164
- continue;
1165
- }
1166
- push({ type: "paren", value, output: state.parens ? ")" : "\\)" });
1167
- decrement("parens");
1168
- continue;
1169
- }
1170
- if (value === "[") {
1171
- if (opts.nobracket === true || !remaining().includes("]")) {
1172
- if (opts.nobracket !== true && opts.strictBrackets === true) {
1173
- throw new SyntaxError(syntaxError("closing", "]"));
1174
- }
1175
- value = `\\${value}`;
1176
- } else {
1177
- increment("brackets");
1178
- }
1179
- push({ type: "bracket", value });
1180
- continue;
1181
- }
1182
- if (value === "]") {
1183
- if (opts.nobracket === true || prev && prev.type === "bracket" && prev.value.length === 1) {
1184
- push({ type: "text", value, output: `\\${value}` });
1185
- continue;
1186
- }
1187
- if (state.brackets === 0) {
1188
- if (opts.strictBrackets === true) {
1189
- throw new SyntaxError(syntaxError("opening", "["));
1190
- }
1191
- push({ type: "text", value, output: `\\${value}` });
1192
- continue;
1193
- }
1194
- decrement("brackets");
1195
- const prevValue = prev.value.slice(1);
1196
- if (prev.posix !== true && prevValue[0] === "^" && !prevValue.includes("/")) {
1197
- value = `/${value}`;
1198
- }
1199
- prev.value += value;
1200
- append({ value });
1201
- if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) {
1202
- continue;
1203
- }
1204
- const escaped = utils.escapeRegex(prev.value);
1205
- state.output = state.output.slice(0, -prev.value.length);
1206
- if (opts.literalBrackets === true) {
1207
- state.output += escaped;
1208
- prev.value = escaped;
1209
- continue;
1210
- }
1211
- prev.value = `(${capture}${escaped}|${prev.value})`;
1212
- state.output += prev.value;
1213
- continue;
1214
- }
1215
- if (value === "{" && opts.nobrace !== true) {
1216
- increment("braces");
1217
- const open = {
1218
- type: "brace",
1219
- value,
1220
- output: "(",
1221
- outputIndex: state.output.length,
1222
- tokensIndex: state.tokens.length
1223
- };
1224
- braces.push(open);
1225
- push(open);
1226
- continue;
1227
- }
1228
- if (value === "}") {
1229
- const brace = braces[braces.length - 1];
1230
- if (opts.nobrace === true || !brace) {
1231
- push({ type: "text", value, output: value });
1232
- continue;
1233
- }
1234
- let output = ")";
1235
- if (brace.dots === true) {
1236
- const arr = tokens.slice();
1237
- const range = [];
1238
- for (let i = arr.length - 1; i >= 0; i--) {
1239
- tokens.pop();
1240
- if (arr[i].type === "brace") {
1241
- break;
1242
- }
1243
- if (arr[i].type !== "dots") {
1244
- range.unshift(arr[i].value);
1245
- }
1246
- }
1247
- output = expandRange(range, opts);
1248
- state.backtrack = true;
1249
- }
1250
- if (brace.comma !== true && brace.dots !== true) {
1251
- const out = state.output.slice(0, brace.outputIndex);
1252
- const toks = state.tokens.slice(brace.tokensIndex);
1253
- brace.value = brace.output = "\\{";
1254
- value = output = "\\}";
1255
- state.output = out;
1256
- for (const t of toks) {
1257
- state.output += t.output || t.value;
1258
- }
1259
- }
1260
- push({ type: "brace", value, output });
1261
- decrement("braces");
1262
- braces.pop();
1263
- continue;
1264
- }
1265
- if (value === "|") {
1266
- if (extglobs.length > 0) {
1267
- extglobs[extglobs.length - 1].conditions++;
1268
- }
1269
- push({ type: "text", value });
1270
- continue;
1271
- }
1272
- if (value === ",") {
1273
- let output = value;
1274
- const brace = braces[braces.length - 1];
1275
- if (brace && stack[stack.length - 1] === "braces") {
1276
- brace.comma = true;
1277
- output = "|";
1278
- }
1279
- push({ type: "comma", value, output });
1280
- continue;
1281
- }
1282
- if (value === "/") {
1283
- if (prev.type === "dot" && state.index === state.start + 1) {
1284
- state.start = state.index + 1;
1285
- state.consumed = "";
1286
- state.output = "";
1287
- tokens.pop();
1288
- prev = bos;
1289
- continue;
1290
- }
1291
- push({ type: "slash", value, output: SLASH_LITERAL });
1292
- continue;
1293
- }
1294
- if (value === ".") {
1295
- if (state.braces > 0 && prev.type === "dot") {
1296
- if (prev.value === ".") prev.output = DOT_LITERAL;
1297
- const brace = braces[braces.length - 1];
1298
- prev.type = "dots";
1299
- prev.output += value;
1300
- prev.value += value;
1301
- brace.dots = true;
1302
- continue;
1303
- }
1304
- if (state.braces + state.parens === 0 && prev.type !== "bos" && prev.type !== "slash") {
1305
- push({ type: "text", value, output: DOT_LITERAL });
1306
- continue;
1307
- }
1308
- push({ type: "dot", value, output: DOT_LITERAL });
1309
- continue;
1310
- }
1311
- if (value === "?") {
1312
- const isGroup = prev && prev.value === "(";
1313
- if (!isGroup && opts.noextglob !== true && peek() === "(" && peek(2) !== "?") {
1314
- extglobOpen("qmark", value);
1315
- continue;
1316
- }
1317
- if (prev && prev.type === "paren") {
1318
- const next = peek();
1319
- let output = value;
1320
- if (next === "<" && !utils.supportsLookbehinds()) {
1321
- throw new Error("Node.js v10 or higher is required for regex lookbehinds");
1322
- }
1323
- if (prev.value === "(" && !/[!=<:]/.test(next) || next === "<" && !/<([!=]|\w+>)/.test(remaining())) {
1324
- output = `\\${value}`;
1325
- }
1326
- push({ type: "text", value, output });
1327
- continue;
1328
- }
1329
- if (opts.dot !== true && (prev.type === "slash" || prev.type === "bos")) {
1330
- push({ type: "qmark", value, output: QMARK_NO_DOT });
1331
- continue;
1332
- }
1333
- push({ type: "qmark", value, output: QMARK });
1334
- continue;
1335
- }
1336
- if (value === "!") {
1337
- if (opts.noextglob !== true && peek() === "(") {
1338
- if (peek(2) !== "?" || !/[!=<:]/.test(peek(3))) {
1339
- extglobOpen("negate", value);
1340
- continue;
1341
- }
1342
- }
1343
- if (opts.nonegate !== true && state.index === 0) {
1344
- negate();
1345
- continue;
1346
- }
1347
- }
1348
- if (value === "+") {
1349
- if (opts.noextglob !== true && peek() === "(" && peek(2) !== "?") {
1350
- extglobOpen("plus", value);
1351
- continue;
1352
- }
1353
- if (prev && prev.value === "(" || opts.regex === false) {
1354
- push({ type: "plus", value, output: PLUS_LITERAL });
1355
- continue;
1356
- }
1357
- if (prev && (prev.type === "bracket" || prev.type === "paren" || prev.type === "brace") || state.parens > 0) {
1358
- push({ type: "plus", value });
1359
- continue;
1360
- }
1361
- push({ type: "plus", value: PLUS_LITERAL });
1362
- continue;
1363
- }
1364
- if (value === "@") {
1365
- if (opts.noextglob !== true && peek() === "(" && peek(2) !== "?") {
1366
- push({ type: "at", extglob: true, value, output: "" });
1367
- continue;
1368
- }
1369
- push({ type: "text", value });
1370
- continue;
1371
- }
1372
- if (value !== "*") {
1373
- if (value === "$" || value === "^") {
1374
- value = `\\${value}`;
1375
- }
1376
- const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
1377
- if (match) {
1378
- value += match[0];
1379
- state.index += match[0].length;
1380
- }
1381
- push({ type: "text", value });
1382
- continue;
1383
- }
1384
- if (prev && (prev.type === "globstar" || prev.star === true)) {
1385
- prev.type = "star";
1386
- prev.star = true;
1387
- prev.value += value;
1388
- prev.output = star;
1389
- state.backtrack = true;
1390
- state.globstar = true;
1391
- consume(value);
1392
- continue;
1393
- }
1394
- let rest = remaining();
1395
- if (opts.noextglob !== true && /^\([^?]/.test(rest)) {
1396
- extglobOpen("star", value);
1397
- continue;
1398
- }
1399
- if (prev.type === "star") {
1400
- if (opts.noglobstar === true) {
1401
- consume(value);
1402
- continue;
1403
- }
1404
- const prior = prev.prev;
1405
- const before = prior.prev;
1406
- const isStart = prior.type === "slash" || prior.type === "bos";
1407
- const afterStar = before && (before.type === "star" || before.type === "globstar");
1408
- if (opts.bash === true && (!isStart || rest[0] && rest[0] !== "/")) {
1409
- push({ type: "star", value, output: "" });
1410
- continue;
1411
- }
1412
- const isBrace = state.braces > 0 && (prior.type === "comma" || prior.type === "brace");
1413
- const isExtglob = extglobs.length && (prior.type === "pipe" || prior.type === "paren");
1414
- if (!isStart && prior.type !== "paren" && !isBrace && !isExtglob) {
1415
- push({ type: "star", value, output: "" });
1416
- continue;
1417
- }
1418
- while (rest.slice(0, 3) === "/**") {
1419
- const after = input2[state.index + 4];
1420
- if (after && after !== "/") {
1421
- break;
1422
- }
1423
- rest = rest.slice(3);
1424
- consume("/**", 3);
1425
- }
1426
- if (prior.type === "bos" && eos()) {
1427
- prev.type = "globstar";
1428
- prev.value += value;
1429
- prev.output = globstar(opts);
1430
- state.output = prev.output;
1431
- state.globstar = true;
1432
- consume(value);
1433
- continue;
1434
- }
1435
- if (prior.type === "slash" && prior.prev.type !== "bos" && !afterStar && eos()) {
1436
- state.output = state.output.slice(0, -(prior.output + prev.output).length);
1437
- prior.output = `(?:${prior.output}`;
1438
- prev.type = "globstar";
1439
- prev.output = globstar(opts) + (opts.strictSlashes ? ")" : "|$)");
1440
- prev.value += value;
1441
- state.globstar = true;
1442
- state.output += prior.output + prev.output;
1443
- consume(value);
1444
- continue;
1445
- }
1446
- if (prior.type === "slash" && prior.prev.type !== "bos" && rest[0] === "/") {
1447
- const end = rest[1] !== void 0 ? "|$" : "";
1448
- state.output = state.output.slice(0, -(prior.output + prev.output).length);
1449
- prior.output = `(?:${prior.output}`;
1450
- prev.type = "globstar";
1451
- prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
1452
- prev.value += value;
1453
- state.output += prior.output + prev.output;
1454
- state.globstar = true;
1455
- consume(value + advance());
1456
- push({ type: "slash", value: "/", output: "" });
1457
- continue;
1458
- }
1459
- if (prior.type === "bos" && rest[0] === "/") {
1460
- prev.type = "globstar";
1461
- prev.value += value;
1462
- prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
1463
- state.output = prev.output;
1464
- state.globstar = true;
1465
- consume(value + advance());
1466
- push({ type: "slash", value: "/", output: "" });
1467
- continue;
1468
- }
1469
- state.output = state.output.slice(0, -prev.output.length);
1470
- prev.type = "globstar";
1471
- prev.output = globstar(opts);
1472
- prev.value += value;
1473
- state.output += prev.output;
1474
- state.globstar = true;
1475
- consume(value);
1476
- continue;
1477
- }
1478
- const token = { type: "star", value, output: star };
1479
- if (opts.bash === true) {
1480
- token.output = ".*?";
1481
- if (prev.type === "bos" || prev.type === "slash") {
1482
- token.output = nodot + token.output;
1483
- }
1484
- push(token);
1485
- continue;
1486
- }
1487
- if (prev && (prev.type === "bracket" || prev.type === "paren") && opts.regex === true) {
1488
- token.output = value;
1489
- push(token);
1490
- continue;
1491
- }
1492
- if (state.index === state.start || prev.type === "slash" || prev.type === "dot") {
1493
- if (prev.type === "dot") {
1494
- state.output += NO_DOT_SLASH;
1495
- prev.output += NO_DOT_SLASH;
1496
- } else if (opts.dot === true) {
1497
- state.output += NO_DOTS_SLASH;
1498
- prev.output += NO_DOTS_SLASH;
1499
- } else {
1500
- state.output += nodot;
1501
- prev.output += nodot;
1502
- }
1503
- if (peek() !== "*") {
1504
- state.output += ONE_CHAR;
1505
- prev.output += ONE_CHAR;
1506
- }
1507
- }
1508
- push(token);
1509
- }
1510
- while (state.brackets > 0) {
1511
- if (opts.strictBrackets === true) throw new SyntaxError(syntaxError("closing", "]"));
1512
- state.output = utils.escapeLast(state.output, "[");
1513
- decrement("brackets");
1514
- }
1515
- while (state.parens > 0) {
1516
- if (opts.strictBrackets === true) throw new SyntaxError(syntaxError("closing", ")"));
1517
- state.output = utils.escapeLast(state.output, "(");
1518
- decrement("parens");
1519
- }
1520
- while (state.braces > 0) {
1521
- if (opts.strictBrackets === true) throw new SyntaxError(syntaxError("closing", "}"));
1522
- state.output = utils.escapeLast(state.output, "{");
1523
- decrement("braces");
1524
- }
1525
- if (opts.strictSlashes !== true && (prev.type === "star" || prev.type === "bracket")) {
1526
- push({ type: "maybe_slash", value: "", output: `${SLASH_LITERAL}?` });
1527
- }
1528
- if (state.backtrack === true) {
1529
- state.output = "";
1530
- for (const token of state.tokens) {
1531
- state.output += token.output != null ? token.output : token.value;
1532
- if (token.suffix) {
1533
- state.output += token.suffix;
1534
- }
1535
- }
1536
- }
1537
- return state;
1538
- };
1539
- parse.fastpaths = (input2, options) => {
1540
- const opts = { ...options };
1541
- const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
1542
- const len = input2.length;
1543
- if (len > max) {
1544
- throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
1545
- }
1546
- input2 = REPLACEMENTS[input2] || input2;
1547
- const win32 = utils.isWindows(options);
1548
- const {
1549
- DOT_LITERAL,
1550
- SLASH_LITERAL,
1551
- ONE_CHAR,
1552
- DOTS_SLASH,
1553
- NO_DOT,
1554
- NO_DOTS,
1555
- NO_DOTS_SLASH,
1556
- STAR,
1557
- START_ANCHOR
1558
- } = constants.globChars(win32);
1559
- const nodot = opts.dot ? NO_DOTS : NO_DOT;
1560
- const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
1561
- const capture = opts.capture ? "" : "?:";
1562
- const state = { negated: false, prefix: "" };
1563
- let star = opts.bash === true ? ".*?" : STAR;
1564
- if (opts.capture) {
1565
- star = `(${star})`;
1566
- }
1567
- const globstar = (opts2) => {
1568
- if (opts2.noglobstar === true) return star;
1569
- return `(${capture}(?:(?!${START_ANCHOR}${opts2.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
1570
- };
1571
- const create = (str) => {
1572
- switch (str) {
1573
- case "*":
1574
- return `${nodot}${ONE_CHAR}${star}`;
1575
- case ".*":
1576
- return `${DOT_LITERAL}${ONE_CHAR}${star}`;
1577
- case "*.*":
1578
- return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
1579
- case "*/*":
1580
- return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`;
1581
- case "**":
1582
- return nodot + globstar(opts);
1583
- case "**/*":
1584
- return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`;
1585
- case "**/*.*":
1586
- return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
1587
- case "**/.*":
1588
- return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`;
1589
- default: {
1590
- const match = /^(.*?)\.(\w+)$/.exec(str);
1591
- if (!match) return;
1592
- const source2 = create(match[1]);
1593
- if (!source2) return;
1594
- return source2 + DOT_LITERAL + match[2];
1595
- }
1596
- }
1597
- };
1598
- const output = utils.removePrefix(input2, state);
1599
- let source = create(output);
1600
- if (source && opts.strictSlashes !== true) {
1601
- source += `${SLASH_LITERAL}?`;
1602
- }
1603
- return source;
1604
- };
1605
- module.exports = parse;
1606
- }
1607
- });
1608
-
1609
- // node_modules/picomatch/lib/picomatch.js
1610
- var require_picomatch = __commonJS({
1611
- "node_modules/picomatch/lib/picomatch.js"(exports, module) {
1612
- "use strict";
1613
- var path26 = __require("path");
1614
- var scan = require_scan();
1615
- var parse = require_parse();
1616
- var utils = require_utils();
1617
- var constants = require_constants();
1618
- var isObject = (val) => val && typeof val === "object" && !Array.isArray(val);
1619
- var picomatch2 = (glob, options, returnState = false) => {
1620
- if (Array.isArray(glob)) {
1621
- const fns = glob.map((input2) => picomatch2(input2, options, returnState));
1622
- const arrayMatcher = (str) => {
1623
- for (const isMatch of fns) {
1624
- const state2 = isMatch(str);
1625
- if (state2) return state2;
1626
- }
1627
- return false;
1628
- };
1629
- return arrayMatcher;
1630
- }
1631
- const isState = isObject(glob) && glob.tokens && glob.input;
1632
- if (glob === "" || typeof glob !== "string" && !isState) {
1633
- throw new TypeError("Expected pattern to be a non-empty string");
1634
- }
1635
- const opts = options || {};
1636
- const posix = utils.isWindows(options);
1637
- const regex = isState ? picomatch2.compileRe(glob, options) : picomatch2.makeRe(glob, options, false, true);
1638
- const state = regex.state;
1639
- delete regex.state;
1640
- let isIgnored = () => false;
1641
- if (opts.ignore) {
1642
- const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null };
1643
- isIgnored = picomatch2(opts.ignore, ignoreOpts, returnState);
1644
- }
1645
- const matcher = (input2, returnObject = false) => {
1646
- const { isMatch, match, output } = picomatch2.test(input2, regex, options, { glob, posix });
1647
- const result = { glob, state, regex, posix, input: input2, output, match, isMatch };
1648
- if (typeof opts.onResult === "function") {
1649
- opts.onResult(result);
1650
- }
1651
- if (isMatch === false) {
1652
- result.isMatch = false;
1653
- return returnObject ? result : false;
1654
- }
1655
- if (isIgnored(input2)) {
1656
- if (typeof opts.onIgnore === "function") {
1657
- opts.onIgnore(result);
1658
- }
1659
- result.isMatch = false;
1660
- return returnObject ? result : false;
1661
- }
1662
- if (typeof opts.onMatch === "function") {
1663
- opts.onMatch(result);
1664
- }
1665
- return returnObject ? result : true;
1666
- };
1667
- if (returnState) {
1668
- matcher.state = state;
1669
- }
1670
- return matcher;
1671
- };
1672
- picomatch2.test = (input2, regex, options, { glob, posix } = {}) => {
1673
- if (typeof input2 !== "string") {
1674
- throw new TypeError("Expected input to be a string");
1675
- }
1676
- if (input2 === "") {
1677
- return { isMatch: false, output: "" };
1678
- }
1679
- const opts = options || {};
1680
- const format = opts.format || (posix ? utils.toPosixSlashes : null);
1681
- let match = input2 === glob;
1682
- let output = match && format ? format(input2) : input2;
1683
- if (match === false) {
1684
- output = format ? format(input2) : input2;
1685
- match = output === glob;
1686
- }
1687
- if (match === false || opts.capture === true) {
1688
- if (opts.matchBase === true || opts.basename === true) {
1689
- match = picomatch2.matchBase(input2, regex, options, posix);
1690
- } else {
1691
- match = regex.exec(output);
1692
- }
1693
- }
1694
- return { isMatch: Boolean(match), match, output };
1695
- };
1696
- picomatch2.matchBase = (input2, glob, options, posix = utils.isWindows(options)) => {
1697
- const regex = glob instanceof RegExp ? glob : picomatch2.makeRe(glob, options);
1698
- return regex.test(path26.basename(input2));
1699
- };
1700
- picomatch2.isMatch = (str, patterns, options) => picomatch2(patterns, options)(str);
1701
- picomatch2.parse = (pattern, options) => {
1702
- if (Array.isArray(pattern)) return pattern.map((p) => picomatch2.parse(p, options));
1703
- return parse(pattern, { ...options, fastpaths: false });
1704
- };
1705
- picomatch2.scan = (input2, options) => scan(input2, options);
1706
- picomatch2.compileRe = (state, options, returnOutput = false, returnState = false) => {
1707
- if (returnOutput === true) {
1708
- return state.output;
1709
- }
1710
- const opts = options || {};
1711
- const prepend = opts.contains ? "" : "^";
1712
- const append = opts.contains ? "" : "$";
1713
- let source = `${prepend}(?:${state.output})${append}`;
1714
- if (state && state.negated === true) {
1715
- source = `^(?!${source}).*$`;
1716
- }
1717
- const regex = picomatch2.toRegex(source, options);
1718
- if (returnState === true) {
1719
- regex.state = state;
1720
- }
1721
- return regex;
1722
- };
1723
- picomatch2.makeRe = (input2, options = {}, returnOutput = false, returnState = false) => {
1724
- if (!input2 || typeof input2 !== "string") {
1725
- throw new TypeError("Expected a non-empty string");
1726
- }
1727
- let parsed = { negated: false, fastpaths: true };
1728
- if (options.fastpaths !== false && (input2[0] === "." || input2[0] === "*")) {
1729
- parsed.output = parse.fastpaths(input2, options);
1730
- }
1731
- if (!parsed.output) {
1732
- parsed = parse(input2, options);
1733
- }
1734
- return picomatch2.compileRe(parsed, options, returnOutput, returnState);
1735
- };
1736
- picomatch2.toRegex = (source, options) => {
1737
- try {
1738
- const opts = options || {};
1739
- return new RegExp(source, opts.flags || (opts.nocase ? "i" : ""));
1740
- } catch (err) {
1741
- if (options && options.debug === true) throw err;
1742
- return /$^/;
1743
- }
1744
- };
1745
- picomatch2.constants = constants;
1746
- module.exports = picomatch2;
1747
- }
1748
- });
1749
-
1750
- // node_modules/picomatch/index.js
1751
- var require_picomatch2 = __commonJS({
1752
- "node_modules/picomatch/index.js"(exports, module) {
1753
- "use strict";
1754
- module.exports = require_picomatch();
1755
- }
1756
- });
10
+ } from "./chunk-32UIGL7K.js";
1757
11
 
1758
12
  // src/cli/index.ts
1759
13
  import { Command } from "commander";
1760
- import path25 from "path";
14
+ import path27 from "path";
1761
15
  import fs41 from "fs";
1762
16
  import { fileURLToPath } from "url";
1763
17
  import { performance } from "perf_hooks";
@@ -1769,9 +23,9 @@ import fg from "fast-glob";
1769
23
  import path2 from "path";
1770
24
 
1771
25
  // src/utils/files.ts
1772
- var import_picomatch = __toESM(require_picomatch2(), 1);
1773
26
  import fs from "fs";
1774
27
  import path from "path";
28
+ import picomatch from "picomatch";
1775
29
  function readFileLines(filePath) {
1776
30
  try {
1777
31
  return fs.readFileSync(filePath, "utf-8").split("\n");
@@ -1839,7 +93,7 @@ function convertIgnorePattern(pattern) {
1839
93
  }
1840
94
  function filterIgnoredFindings(findings, ignorePatterns, _rootDir) {
1841
95
  if (ignorePatterns.length === 0) return findings;
1842
- const matchers = ignorePatterns.map((p) => (0, import_picomatch.default)(p, { dot: true }));
96
+ const matchers = ignorePatterns.map((p) => picomatch(p, { dot: true }));
1843
97
  return findings.filter((finding) => {
1844
98
  if (!finding.file) return true;
1845
99
  const normalized = finding.file.replace(/\\/g, "/");
@@ -1947,7 +201,7 @@ var TodoScanner = class {
1947
201
  let totalHacks = 0;
1948
202
  for (const file of files) {
1949
203
  const lines = readFileLines(file);
1950
- const rel = relativePath(rootDir, file);
204
+ const _rel = relativePath(rootDir, file);
1951
205
  for (let i = 0; i < lines.length; i++) {
1952
206
  const line = lines[i];
1953
207
  if (/\bTODO\b/.test(line)) totalTodos++;
@@ -2556,7 +810,7 @@ var DuplicateScanner = class {
2556
810
  }
2557
811
  }
2558
812
  const duplicates = [];
2559
- for (const [hash, locations] of hashMap) {
813
+ for (const [_hash, locations] of hashMap) {
2560
814
  if (locations.length < 2) continue;
2561
815
  const uniqueLocations = this.filterUniqueLocations(locations);
2562
816
  if (uniqueLocations.length < 2) continue;
@@ -2621,7 +875,7 @@ var DuplicateScanner = class {
2621
875
  }
2622
876
  return unique;
2623
877
  }
2624
- calculateBlockSize(locations, files, rootDir) {
878
+ calculateBlockSize(_locations, _files, _rootDir) {
2625
879
  return WINDOW_SIZE;
2626
880
  }
2627
881
  hashString(str) {
@@ -3430,7 +1684,7 @@ var FrameworkScanner = class {
3430
1684
  isAngular = !!(pkg.dependencies?.["@angular/core"] || pkg.devDependencies?.["@angular/core"]);
3431
1685
  isSvelte = !!(pkg.dependencies?.svelte || pkg.devDependencies?.svelte);
3432
1686
  isExpress = !!(pkg.dependencies?.express || pkg.devDependencies?.express);
3433
- } catch (error) {
1687
+ } catch {
3434
1688
  return { findings: [], stats: { isNextJS: false, isReact: false } };
3435
1689
  }
3436
1690
  }
@@ -3443,7 +1697,7 @@ var FrameworkScanner = class {
3443
1697
  if (content.toLowerCase().includes("fastapi")) {
3444
1698
  isFastAPI = true;
3445
1699
  }
3446
- } catch (error) {
1700
+ } catch {
3447
1701
  }
3448
1702
  }
3449
1703
  if (!isFastAPI && fs9.existsSync(pyprojectPath)) {
@@ -3452,7 +1706,7 @@ var FrameworkScanner = class {
3452
1706
  if (content.toLowerCase().includes("fastapi")) {
3453
1707
  isFastAPI = true;
3454
1708
  }
3455
- } catch (error) {
1709
+ } catch {
3456
1710
  }
3457
1711
  }
3458
1712
  if (!isNextJS && !isReact && !isVue && !isAngular && !isSvelte && !isExpress && !isFastAPI) {
@@ -3479,7 +1733,7 @@ var FrameworkScanner = class {
3479
1733
  file: rel
3480
1734
  });
3481
1735
  }
3482
- } catch (error) {
1736
+ } catch {
3483
1737
  continue;
3484
1738
  }
3485
1739
  }
@@ -3507,7 +1761,7 @@ var FrameworkScanner = class {
3507
1761
  });
3508
1762
  }
3509
1763
  }
3510
- } catch (error) {
1764
+ } catch {
3511
1765
  continue;
3512
1766
  }
3513
1767
  }
@@ -3543,7 +1797,7 @@ var FrameworkScanner = class {
3543
1797
  file: rel
3544
1798
  });
3545
1799
  }
3546
- } catch (error) {
1800
+ } catch {
3547
1801
  continue;
3548
1802
  }
3549
1803
  }
@@ -3590,7 +1844,7 @@ var FrameworkScanner = class {
3590
1844
  file: rel
3591
1845
  });
3592
1846
  }
3593
- } catch (error) {
1847
+ } catch {
3594
1848
  continue;
3595
1849
  }
3596
1850
  }
@@ -3633,7 +1887,7 @@ var FrameworkScanner = class {
3633
1887
  file: rel
3634
1888
  });
3635
1889
  }
3636
- } catch (error) {
1890
+ } catch {
3637
1891
  continue;
3638
1892
  }
3639
1893
  }
@@ -3670,7 +1924,7 @@ var FrameworkScanner = class {
3670
1924
  });
3671
1925
  }
3672
1926
  }
3673
- } catch (error) {
1927
+ } catch {
3674
1928
  continue;
3675
1929
  }
3676
1930
  }
@@ -3694,7 +1948,7 @@ var FrameworkScanner = class {
3694
1948
  if (/app\.(get|post|put|delete|patch)\s*\(/.test(content)) {
3695
1949
  routeFiles.push(filePath);
3696
1950
  }
3697
- } catch (error) {
1951
+ } catch {
3698
1952
  continue;
3699
1953
  }
3700
1954
  }
@@ -3714,7 +1968,7 @@ var FrameworkScanner = class {
3714
1968
  hasRateLimit = true;
3715
1969
  break;
3716
1970
  }
3717
- } catch (error) {
1971
+ } catch {
3718
1972
  continue;
3719
1973
  }
3720
1974
  }
@@ -3739,7 +1993,7 @@ var FrameworkScanner = class {
3739
1993
  file: rel
3740
1994
  });
3741
1995
  }
3742
- } catch (error) {
1996
+ } catch {
3743
1997
  continue;
3744
1998
  }
3745
1999
  }
@@ -3794,7 +2048,7 @@ var FrameworkScanner = class {
3794
2048
  break;
3795
2049
  }
3796
2050
  }
3797
- } catch (error) {
2051
+ } catch {
3798
2052
  continue;
3799
2053
  }
3800
2054
  }
@@ -3918,7 +2172,7 @@ var PythonTypeHintsScanner = class {
3918
2172
  for (const file of files) {
3919
2173
  try {
3920
2174
  const content = fs10.readFileSync(file, "utf-8");
3921
- const rel = relativePath(rootDir, file);
2175
+ const _rel = relativePath(rootDir, file);
3922
2176
  const funcPattern = /def\s+(\w+)\s*\([^)]{0,500}\)(?:\s*->\s*\w+)?:/g;
3923
2177
  const functions = Array.from(content.matchAll(funcPattern));
3924
2178
  for (const match of functions) {
@@ -7285,6 +5539,7 @@ var DatabaseScanner = class {
7285
5539
  };
7286
5540
 
7287
5541
  // src/languages/index.ts
5542
+ import path14 from "path";
7288
5543
  var LANGUAGE_CONFIGS = {
7289
5544
  javascript: {
7290
5545
  name: "JavaScript",
@@ -7374,7 +5629,7 @@ function detectProjectLanguage(rootDir, fs42) {
7374
5629
  const detectedLanguages = [];
7375
5630
  for (const [lang, config] of Object.entries(LANGUAGE_CONFIGS)) {
7376
5631
  for (const packageFile of config.packageFiles) {
7377
- const fullPath = __require("path").join(rootDir, packageFile);
5632
+ const fullPath = path14.join(rootDir, packageFile);
7378
5633
  if (fs42.existsSync(fullPath)) {
7379
5634
  detectedLanguages.push(lang);
7380
5635
  break;
@@ -7557,7 +5812,7 @@ function getLabel(score) {
7557
5812
  // src/ai/index.ts
7558
5813
  import Anthropic from "@anthropic-ai/sdk";
7559
5814
  import fs25 from "fs";
7560
- import path14 from "path";
5815
+ import path15 from "path";
7561
5816
  import crypto from "crypto";
7562
5817
  var DEFAULT_MODEL = "claude-3-5-sonnet-20241022";
7563
5818
  var DEFAULT_MAX_TOKENS = 150;
@@ -7661,7 +5916,7 @@ function getFindingHash(finding) {
7661
5916
  return crypto.createHash("md5").update(key).digest("hex");
7662
5917
  }
7663
5918
  function getCachedRoast(finding, rootDir, cachePath) {
7664
- const cacheFile = path14.join(rootDir, cachePath || CACHE_FILE);
5919
+ const cacheFile = path15.join(rootDir, cachePath || CACHE_FILE);
7665
5920
  if (!fs25.existsSync(cacheFile)) {
7666
5921
  return null;
7667
5922
  }
@@ -7679,7 +5934,7 @@ function getCachedRoast(finding, rootDir, cachePath) {
7679
5934
  }
7680
5935
  }
7681
5936
  function cacheRoast(finding, roast, rootDir, cachePath) {
7682
- const cacheFile = path14.join(rootDir, cachePath || CACHE_FILE);
5937
+ const cacheFile = path15.join(rootDir, cachePath || CACHE_FILE);
7683
5938
  try {
7684
5939
  let cache = [];
7685
5940
  if (fs25.existsSync(cacheFile)) {
@@ -7699,7 +5954,7 @@ function cacheRoast(finding, roast, rootDir, cachePath) {
7699
5954
  cache = cache.slice(-100);
7700
5955
  }
7701
5956
  fs25.writeFileSync(cacheFile, JSON.stringify(cache, null, 2), "utf-8");
7702
- } catch (error) {
5957
+ } catch {
7703
5958
  }
7704
5959
  }
7705
5960
 
@@ -8289,7 +6544,7 @@ async function generateRoasts(findings, aiConfig, rootDir) {
8289
6544
  aiConfig,
8290
6545
  rootDir
8291
6546
  );
8292
- } catch (error) {
6547
+ } catch {
8293
6548
  console.warn("Warning: AI roast generation failed, using predefined roasts");
8294
6549
  }
8295
6550
  }
@@ -8863,7 +7118,7 @@ function renderMarkdownReport(report) {
8863
7118
 
8864
7119
  // src/report/html.ts
8865
7120
  import fs27 from "fs";
8866
- import path15 from "path";
7121
+ import path16 from "path";
8867
7122
  function escapeHtml(text) {
8868
7123
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
8869
7124
  }
@@ -9587,7 +7842,7 @@ function renderHtmlReport(report) {
9587
7842
  </html>`;
9588
7843
  }
9589
7844
  function saveHtmlReport(html, rootDir) {
9590
- const outputPath = path15.join(rootDir, ".roast-report.html");
7845
+ const outputPath = path16.join(rootDir, ".roast-report.html");
9591
7846
  fs27.writeFileSync(outputPath, html, "utf-8");
9592
7847
  }
9593
7848
 
@@ -9694,13 +7949,13 @@ function formatPRComment(report) {
9694
7949
  }
9695
7950
  return comment;
9696
7951
  }
9697
- function githubRequest(method, path26, token, body) {
7952
+ function githubRequest(method, path28, token, body) {
9698
7953
  return new Promise((resolve, reject) => {
9699
7954
  const data = body ? JSON.stringify(body) : void 0;
9700
7955
  const req = https.request(
9701
7956
  {
9702
7957
  hostname: "api.github.com",
9703
- path: path26,
7958
+ path: path28,
9704
7959
  method,
9705
7960
  headers: {
9706
7961
  Authorization: `Bearer ${token}`,
@@ -10016,7 +8271,180 @@ function saveJUnitReport(xml, rootDir) {
10016
8271
  }
10017
8272
 
10018
8273
  // src/report/hotmap.ts
8274
+ import path17 from "path";
10019
8275
  import chalk3 from "chalk";
8276
+ function normalizePath(filePath) {
8277
+ return filePath.replace(/\\/g, "/");
8278
+ }
8279
+ function emptyNode(name, nodePath) {
8280
+ return {
8281
+ name,
8282
+ path: nodePath,
8283
+ criticalCount: 0,
8284
+ warningCount: 0,
8285
+ infoCount: 0,
8286
+ totalCount: 0,
8287
+ score: 100,
8288
+ children: [],
8289
+ fileCount: 0
8290
+ };
8291
+ }
8292
+ function calculateScore(criticalCount, warningCount, infoCount) {
8293
+ const raw = 100 - (criticalCount * 5 + warningCount * 2 + infoCount * 0.5);
8294
+ return Math.max(0, Math.min(100, raw));
8295
+ }
8296
+ function buildFolderTree(findings, rootDir) {
8297
+ const rootName = path17.basename(rootDir);
8298
+ const root = emptyNode(rootName, "");
8299
+ const fileFindings = findings.filter((f) => f.file !== void 0 && f.file !== "");
8300
+ const nodeMap = /* @__PURE__ */ new Map();
8301
+ nodeMap.set("", root);
8302
+ const filesPerNode = /* @__PURE__ */ new Map();
8303
+ filesPerNode.set("", /* @__PURE__ */ new Set());
8304
+ for (const finding of fileFindings) {
8305
+ const rawFile = finding.file;
8306
+ let relFile = normalizePath(rawFile);
8307
+ const normalizedRoot = normalizePath(rootDir);
8308
+ if (relFile.startsWith(normalizedRoot + "/")) {
8309
+ relFile = relFile.slice(normalizedRoot.length + 1);
8310
+ }
8311
+ const dirPart = relFile.includes("/") ? relFile.substring(0, relFile.lastIndexOf("/")) : "";
8312
+ const segments = dirPart === "" ? [] : dirPart.split("/");
8313
+ let currentPath = "";
8314
+ for (let i = 0; i < segments.length; i++) {
8315
+ const seg = segments[i];
8316
+ const parentPath = currentPath;
8317
+ currentPath = currentPath === "" ? seg : `${currentPath}/${seg}`;
8318
+ if (!nodeMap.has(currentPath)) {
8319
+ const newNode = emptyNode(seg, currentPath);
8320
+ nodeMap.set(currentPath, newNode);
8321
+ filesPerNode.set(currentPath, /* @__PURE__ */ new Set());
8322
+ const parent = nodeMap.get(parentPath);
8323
+ parent.children.push(newNode);
8324
+ }
8325
+ }
8326
+ const leafNode = nodeMap.get(currentPath);
8327
+ if (finding.severity === "critical") leafNode.criticalCount++;
8328
+ else if (finding.severity === "warning") leafNode.warningCount++;
8329
+ else if (finding.severity === "info") leafNode.infoCount++;
8330
+ leafNode.totalCount++;
8331
+ let trackPath = currentPath;
8332
+ while (true) {
8333
+ const set = filesPerNode.get(trackPath);
8334
+ if (set) set.add(relFile);
8335
+ if (trackPath === "") break;
8336
+ trackPath = trackPath.includes("/") ? trackPath.substring(0, trackPath.lastIndexOf("/")) : "";
8337
+ }
8338
+ }
8339
+ function aggregate(node) {
8340
+ for (const child of node.children) {
8341
+ aggregate(child);
8342
+ node.criticalCount += child.criticalCount;
8343
+ node.warningCount += child.warningCount;
8344
+ node.infoCount += child.infoCount;
8345
+ node.totalCount += child.totalCount;
8346
+ }
8347
+ node.score = calculateScore(node.criticalCount, node.warningCount, node.infoCount);
8348
+ node.fileCount = filesPerNode.get(node.path)?.size ?? 0;
8349
+ }
8350
+ aggregate(root);
8351
+ return root;
8352
+ }
8353
+ function renderHealthBar(score) {
8354
+ const width = 10;
8355
+ const filled = Math.round(score / 100 * width);
8356
+ const empty = width - filled;
8357
+ return "[" + "\u2588".repeat(filled) + "\u2591".repeat(empty) + "]";
8358
+ }
8359
+ function colorScore(score) {
8360
+ const bar = renderHealthBar(score);
8361
+ const scoreStr = String(Math.round(score));
8362
+ if (score >= 80) {
8363
+ return chalk3.green(bar) + " " + chalk3.green(scoreStr);
8364
+ } else if (score >= 60) {
8365
+ return chalk3.yellow(bar) + " " + chalk3.yellow(scoreStr);
8366
+ } else {
8367
+ return chalk3.red(bar) + " " + chalk3.red(scoreStr);
8368
+ }
8369
+ }
8370
+ function folderIcon(node) {
8371
+ if (node.criticalCount > 0) return "\u{1F534}";
8372
+ if (node.warningCount > 0) return "\u26A0\uFE0F ";
8373
+ return "\u2713 ";
8374
+ }
8375
+ function renderFolderSuffix(node) {
8376
+ if (node.totalCount === 0) {
8377
+ return chalk3.dim("\u2713 0 issues");
8378
+ }
8379
+ const icon = folderIcon(node);
8380
+ const countStr = ` ${node.totalCount} issue${node.totalCount !== 1 ? "s" : ""}`;
8381
+ const bar = " " + colorScore(node.score);
8382
+ let issuesPart;
8383
+ if (node.criticalCount > 0) {
8384
+ issuesPart = chalk3.red(icon) + chalk3.red(countStr);
8385
+ } else if (node.warningCount > 0) {
8386
+ issuesPart = chalk3.yellow(icon) + chalk3.yellow(countStr);
8387
+ } else {
8388
+ issuesPart = chalk3.dim(icon) + chalk3.dim(countStr);
8389
+ }
8390
+ return issuesPart + bar;
8391
+ }
8392
+ function renderHotmap(root, maxDepth = 4) {
8393
+ const lines = [];
8394
+ const totalIssues = root.totalCount;
8395
+ const folderCount = countFoldersWithIssues(root);
8396
+ lines.push(
8397
+ chalk3.bold(" Complexity Hotmap") + chalk3.dim(` \u2014 ${totalIssues} total issue${totalIssues !== 1 ? "s" : ""} across ${folderCount} folder${folderCount !== 1 ? "s" : ""}`)
8398
+ );
8399
+ const hotFolders = getHottestFolders(root, 3);
8400
+ if (hotFolders.length > 0) {
8401
+ const hottestStr = hotFolders.map((n) => chalk3.yellow(`${n.path || root.name} (${n.totalCount} issues)`)).join(", ");
8402
+ lines.push(chalk3.dim(" Hottest folders: ") + hottestStr);
8403
+ }
8404
+ lines.push("");
8405
+ lines.push(chalk3.bold(root.name + "/") + " " + renderFolderSuffix(root));
8406
+ function renderChildren(node, prefix, depth) {
8407
+ if (depth > maxDepth) return;
8408
+ const visibleChildren = node.children.filter((c) => c.totalCount > 0);
8409
+ const childrenToRender = visibleChildren.length > 0 ? visibleChildren : node.children;
8410
+ for (let i = 0; i < childrenToRender.length; i++) {
8411
+ const child = childrenToRender[i];
8412
+ const isLast = i === childrenToRender.length - 1;
8413
+ const connector = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
8414
+ const childPrefix = prefix + (isLast ? " " : "\u2502 ");
8415
+ lines.push(
8416
+ prefix + connector + " " + chalk3.bold(child.name + "/") + " " + renderFolderSuffix(child)
8417
+ );
8418
+ if (depth < maxDepth) {
8419
+ renderChildren(child, childPrefix, depth + 1);
8420
+ }
8421
+ }
8422
+ }
8423
+ renderChildren(root, "", 1);
8424
+ lines.push("");
8425
+ lines.push(
8426
+ chalk3.dim(" \u{1F534} critical \u26A0\uFE0F warning \u2713 clean ") + chalk3.green("[\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588]") + chalk3.dim(" health bar")
8427
+ );
8428
+ return lines.join("\n");
8429
+ }
8430
+ function countFoldersWithIssues(root) {
8431
+ let count = 0;
8432
+ function walk(node) {
8433
+ if (node.totalCount > 0) count++;
8434
+ for (const child of node.children) walk(child);
8435
+ }
8436
+ walk(root);
8437
+ return count;
8438
+ }
8439
+ function getHottestFolders(root, topN) {
8440
+ const all = [];
8441
+ function collect(node) {
8442
+ if (node.path !== "" && node.totalCount > 0) all.push(node);
8443
+ for (const child of node.children) collect(child);
8444
+ }
8445
+ collect(root);
8446
+ return all.sort((a, b) => b.totalCount - a.totalCount).slice(0, topN);
8447
+ }
10020
8448
 
10021
8449
  // src/report/github-summary.ts
10022
8450
  import fs31 from "fs";
@@ -10227,7 +8655,7 @@ function calculateScoreBreakdown(findings, finalScore) {
10227
8655
 
10228
8656
  // src/report/output-dir.ts
10229
8657
  import fs32 from "fs";
10230
- import path16 from "path";
8658
+ import path18 from "path";
10231
8659
  async function saveAllReports(report, outputDir, rootDir) {
10232
8660
  const result = { dir: outputDir, files: [], errors: [] };
10233
8661
  try {
@@ -10244,7 +8672,7 @@ async function saveAllReports(report, outputDir, rootDir) {
10244
8672
  { name: "roast-results", content: renderJUnitReport(report, rootDir), ext: ".xml" }
10245
8673
  ];
10246
8674
  for (const { name, content, ext } of reports) {
10247
- const filePath = path16.join(outputDir, name + ext);
8675
+ const filePath = path18.join(outputDir, name + ext);
10248
8676
  try {
10249
8677
  fs32.writeFileSync(filePath, content, "utf-8");
10250
8678
  result.files.push(filePath);
@@ -10280,7 +8708,7 @@ function renderReport(report, options) {
10280
8708
  )
10281
8709
  );
10282
8710
  sections.push("");
10283
- sections.push(renderHealthBar(report.health.score));
8711
+ sections.push(renderHealthBar2(report.health.score));
10284
8712
  sections.push("");
10285
8713
  const openingLine = generateOpeningLine(report.health.score, report.findings.length);
10286
8714
  if (openingLine) {
@@ -10388,7 +8816,7 @@ function getScoreColor3(score) {
10388
8816
  if (score >= 60) return chalk4.rgb(255, 165, 0);
10389
8817
  return chalk4.red;
10390
8818
  }
10391
- function renderHealthBar(score) {
8819
+ function renderHealthBar2(score) {
10392
8820
  const width = 30;
10393
8821
  const filled = Math.round(score / 100 * width);
10394
8822
  const empty = width - filled;
@@ -10533,7 +8961,7 @@ function renderWatchSummary(health, delta, findingCounts2) {
10533
8961
  }
10534
8962
 
10535
8963
  // src/compare/index.ts
10536
- import path17 from "path";
8964
+ import path19 from "path";
10537
8965
  import fs33 from "fs";
10538
8966
  import { spawnSync as spawnSync4 } from "child_process";
10539
8967
  import { randomBytes } from "crypto";
@@ -10562,7 +8990,7 @@ async function compareWithBranch(rootDir, branchName, scanFunc) {
10562
8990
  console.log(chalk6.dim(`Scanning current working directory...`));
10563
8991
  const currentResult = await scanFunc(rootDir);
10564
8992
  const randomId = randomBytes(8).toString("hex");
10565
- const worktreePath = path17.join(tmpdir(), `.roast-worktree-${randomId}`);
8993
+ const worktreePath = path19.join(tmpdir(), `.roast-worktree-${randomId}`);
10566
8994
  console.log(chalk6.dim(`Checking out ${branchName} to temporary worktree...`));
10567
8995
  let cleanupAttempted = false;
10568
8996
  const cleanupWorktree = async (retries = 3) => {
@@ -10655,7 +9083,7 @@ function renderComparison(comparison, branchName) {
10655
9083
 
10656
9084
  // src/config/index.ts
10657
9085
  import fs34 from "fs";
10658
- import path18 from "path";
9086
+ import path20 from "path";
10659
9087
 
10660
9088
  // src/config/validation.ts
10661
9089
  function validateConfig(userConfig) {
@@ -10801,7 +9229,7 @@ function safeJsonParse(content) {
10801
9229
  return cleaned;
10802
9230
  }
10803
9231
  return parsed;
10804
- } catch (_error) {
9232
+ } catch {
10805
9233
  return null;
10806
9234
  }
10807
9235
  }
@@ -10826,7 +9254,7 @@ var DEFAULT_CONFIG = {
10826
9254
  notify: void 0
10827
9255
  };
10828
9256
  function loadConfig(rootDir) {
10829
- const configPath = path18.join(rootDir, ".roastrc.json");
9257
+ const configPath = path20.join(rootDir, ".roastrc.json");
10830
9258
  if (!fs34.existsSync(configPath)) {
10831
9259
  return DEFAULT_CONFIG;
10832
9260
  }
@@ -10898,7 +9326,7 @@ import chalk7 from "chalk";
10898
9326
 
10899
9327
  // src/interactive/fixes.ts
10900
9328
  import fs35 from "fs";
10901
- import path19 from "path";
9329
+ import path21 from "path";
10902
9330
  import { spawnSync as spawnSync5 } from "child_process";
10903
9331
  async function applyAutoFix(finding, fix, rootDir, dryRun = false) {
10904
9332
  switch (finding.category) {
@@ -10979,7 +9407,7 @@ function fixTodoComment(finding, rootDir, dryRun) {
10979
9407
  message: "No file specified for TODO fix"
10980
9408
  };
10981
9409
  }
10982
- const filePath = path19.join(rootDir, finding.file);
9410
+ const filePath = path21.join(rootDir, finding.file);
10983
9411
  try {
10984
9412
  const content = fs35.readFileSync(filePath, "utf-8");
10985
9413
  const lines = content.split("\n");
@@ -11036,7 +9464,7 @@ function fixDeadExport(finding, rootDir, dryRun) {
11036
9464
  };
11037
9465
  }
11038
9466
  const exportName = match[1];
11039
- const filePath = path19.join(rootDir, finding.file);
9467
+ const filePath = path21.join(rootDir, finding.file);
11040
9468
  try {
11041
9469
  const content = fs35.readFileSync(filePath, "utf-8");
11042
9470
  const lines = content.split("\n");
@@ -11080,7 +9508,7 @@ function fixNextjsClientServer(finding, rootDir, dryRun) {
11080
9508
  if (!finding.file) {
11081
9509
  return { success: false, message: "No file specified for nextjs-client-server fix" };
11082
9510
  }
11083
- const filePath = path19.join(rootDir, finding.file);
9511
+ const filePath = path21.join(rootDir, finding.file);
11084
9512
  try {
11085
9513
  const content = fs35.readFileSync(filePath, "utf-8");
11086
9514
  if (content.includes("'use client'") || content.includes('"use client"')) {
@@ -11104,7 +9532,7 @@ function fixNextjsMetadata(finding, rootDir, dryRun) {
11104
9532
  if (!finding.file) {
11105
9533
  return { success: false, message: "No file specified for nextjs-metadata fix" };
11106
9534
  }
11107
- const filePath = path19.join(rootDir, finding.file);
9535
+ const filePath = path21.join(rootDir, finding.file);
11108
9536
  try {
11109
9537
  const content = fs35.readFileSync(filePath, "utf-8");
11110
9538
  if (/export.*metadata/.test(content)) {
@@ -11124,7 +9552,7 @@ function fixNextjsMetadata(finding, rootDir, dryRun) {
11124
9552
  }
11125
9553
  }
11126
9554
  function fixGitignoreEntry(rootDir, filename, dryRun) {
11127
- const gitignorePath = path19.join(rootDir, ".gitignore");
9555
+ const gitignorePath = path21.join(rootDir, ".gitignore");
11128
9556
  try {
11129
9557
  let existing = "";
11130
9558
  if (fs35.existsSync(gitignorePath)) {
@@ -11151,7 +9579,7 @@ function fixEnvInGit(finding, rootDir, dryRun) {
11151
9579
  if (!finding.file) {
11152
9580
  return { success: false, message: "No file specified for env-in-git fix" };
11153
9581
  }
11154
- const filename = path19.basename(finding.file);
9582
+ const filename = path21.basename(finding.file);
11155
9583
  const result = fixGitignoreEntry(rootDir, filename, dryRun);
11156
9584
  if (result.success) {
11157
9585
  return {
@@ -11168,7 +9596,7 @@ function fixTypeSafety(finding, rootDir, dryRun) {
11168
9596
  if (!finding.file) {
11169
9597
  return { success: false, message: "No file specified for type-safety fix" };
11170
9598
  }
11171
- const filePath = path19.join(rootDir, finding.file);
9599
+ const filePath = path21.join(rootDir, finding.file);
11172
9600
  try {
11173
9601
  const content = fs35.readFileSync(filePath, "utf-8");
11174
9602
  const lines = content.split("\n");
@@ -11207,11 +9635,11 @@ function fixTestCoverage(finding, rootDir, dryRun) {
11207
9635
  }
11208
9636
  const srcRelative = finding.file.replace(/^src\//, "");
11209
9637
  const testRelative = `tests/${srcRelative.replace(/\.tsx?$/, ".test.ts")}`;
11210
- const testPath = path19.join(rootDir, testRelative);
9638
+ const testPath = path21.join(rootDir, testRelative);
11211
9639
  if (fs35.existsSync(testPath)) {
11212
9640
  return { success: false, message: `Test file already exists: ${testRelative}` };
11213
9641
  }
11214
- const baseName = path19.basename(finding.file, path19.extname(finding.file));
9642
+ const baseName = path21.basename(finding.file, path21.extname(finding.file));
11215
9643
  const skeleton = `import { describe, it, expect } from 'vitest';
11216
9644
 
11217
9645
  describe('${baseName}', () => {
@@ -11225,7 +9653,7 @@ describe('${baseName}', () => {
11225
9653
  return { success: true, message: `Would create test file: ${testRelative}` };
11226
9654
  }
11227
9655
  try {
11228
- fs35.mkdirSync(path19.dirname(testPath), { recursive: true });
9656
+ fs35.mkdirSync(path21.dirname(testPath), { recursive: true });
11229
9657
  fs35.writeFileSync(testPath, skeleton, "utf-8");
11230
9658
  return { success: true, message: `Created test file: ${testRelative}` };
11231
9659
  } catch (error) {
@@ -11239,7 +9667,7 @@ function fixSecrets(finding, rootDir, dryRun) {
11239
9667
  if (!finding.file) {
11240
9668
  return { success: false, message: "No file specified for secrets fix" };
11241
9669
  }
11242
- const filename = path19.basename(finding.file);
9670
+ const filename = path21.basename(finding.file);
11243
9671
  const result = fixGitignoreEntry(rootDir, filename, dryRun);
11244
9672
  const warning = " WARNING: The secret may already be in git history \u2014 consider rotating it and running: git filter-branch or git-filter-repo";
11245
9673
  if (result.success) {
@@ -11525,11 +9953,11 @@ function getSeverityBadge(severity) {
11525
9953
 
11526
9954
  // src/history/index.ts
11527
9955
  import fs36 from "fs";
11528
- import path20 from "path";
9956
+ import path22 from "path";
11529
9957
  import { spawnSync as spawnSync6 } from "child_process";
11530
9958
  var HISTORY_FILE = ".roast-history.json";
11531
9959
  function loadHistory(rootDir) {
11532
- const historyPath = path20.join(rootDir, HISTORY_FILE);
9960
+ const historyPath = path22.join(rootDir, HISTORY_FILE);
11533
9961
  if (!fs36.existsSync(historyPath)) {
11534
9962
  return null;
11535
9963
  }
@@ -11542,7 +9970,7 @@ function loadHistory(rootDir) {
11542
9970
  }
11543
9971
  }
11544
9972
  function saveHistory(rootDir, history) {
11545
- const historyPath = path20.join(rootDir, HISTORY_FILE);
9973
+ const historyPath = path22.join(rootDir, HISTORY_FILE);
11546
9974
  try {
11547
9975
  fs36.writeFileSync(historyPath, JSON.stringify(history, null, 2), "utf-8");
11548
9976
  } catch (error) {
@@ -11860,7 +10288,7 @@ function getTrendColor(trend) {
11860
10288
  // src/incremental/index.ts
11861
10289
  import { spawnSync as spawnSync7 } from "child_process";
11862
10290
  import fs37 from "fs";
11863
- import path21 from "path";
10291
+ import path23 from "path";
11864
10292
  function getChangedFiles(rootDir, baseRef) {
11865
10293
  const gitCheck = spawnSync7("git", ["rev-parse", "--git-dir"], {
11866
10294
  cwd: rootDir,
@@ -11878,7 +10306,7 @@ function getChangedFiles(rootDir, baseRef) {
11878
10306
  if (diffResult.status !== 0) {
11879
10307
  return { changedFiles: [], isIncremental: true, baseRef };
11880
10308
  }
11881
- const files = parseGitOutput(diffResult.stdout).map((f) => path21.join(rootDir, f)).filter((f) => fs37.existsSync(f));
10309
+ const files = parseGitOutput(diffResult.stdout).map((f) => path23.join(rootDir, f)).filter((f) => fs37.existsSync(f));
11882
10310
  return { changedFiles: files, isIncremental: true, baseRef };
11883
10311
  }
11884
10312
  const unstagedResult = spawnSync7(
@@ -11894,7 +10322,7 @@ function getChangedFiles(rootDir, baseRef) {
11894
10322
  const unstagedFiles = unstagedResult.status === 0 ? parseGitOutput(unstagedResult.stdout) : [];
11895
10323
  const stagedFiles = stagedResult.status === 0 ? parseGitOutput(stagedResult.stdout) : [];
11896
10324
  const merged = Array.from(/* @__PURE__ */ new Set([...unstagedFiles, ...stagedFiles]));
11897
- const changedFiles = merged.map((f) => path21.join(rootDir, f)).filter((f) => fs37.existsSync(f));
10325
+ const changedFiles = merged.map((f) => path23.join(rootDir, f)).filter((f) => fs37.existsSync(f));
11898
10326
  return { changedFiles, isIncremental: true, baseRef: "HEAD" };
11899
10327
  }
11900
10328
  function parseGitOutput(stdout) {
@@ -11905,13 +10333,13 @@ function filterFindingsByFiles(findings, changedFiles, rootDir) {
11905
10333
  return findings.filter((f) => !f.file);
11906
10334
  }
11907
10335
  const normalizedChanged = new Set(
11908
- changedFiles.map((f) => path21.normalize(f))
10336
+ changedFiles.map((f) => path23.normalize(f))
11909
10337
  );
11910
10338
  return findings.filter((finding) => {
11911
10339
  if (!finding.file) {
11912
10340
  return true;
11913
10341
  }
11914
- const findingAbsolute = path21.isAbsolute(finding.file) ? path21.normalize(finding.file) : path21.normalize(path21.join(rootDir, finding.file));
10342
+ const findingAbsolute = path23.isAbsolute(finding.file) ? path23.normalize(finding.file) : path23.normalize(path23.join(rootDir, finding.file));
11915
10343
  const findingForward = findingAbsolute.replace(/\\/g, "/");
11916
10344
  const findingBackward = findingAbsolute.replace(/\//g, "\\");
11917
10345
  if (normalizedChanged.has(findingAbsolute)) {
@@ -11987,10 +10415,10 @@ function filterFindingsByChangedLines(findings, changedRanges) {
11987
10415
 
11988
10416
  // src/ci/index.ts
11989
10417
  import fs38 from "fs";
11990
- import path22 from "path";
10418
+ import path24 from "path";
11991
10419
  function detectPackageManager(rootDir) {
11992
- if (fs38.existsSync(path22.join(rootDir, "yarn.lock"))) return "yarn";
11993
- if (fs38.existsSync(path22.join(rootDir, "pnpm-lock.yaml"))) return "pnpm";
10420
+ if (fs38.existsSync(path24.join(rootDir, "yarn.lock"))) return "yarn";
10421
+ if (fs38.existsSync(path24.join(rootDir, "pnpm-lock.yaml"))) return "pnpm";
11994
10422
  return "npm";
11995
10423
  }
11996
10424
  function generateCIWorkflow(config) {
@@ -12046,9 +10474,9 @@ ${permissionsBlock}
12046
10474
  `;
12047
10475
  }
12048
10476
  function writeCIWorkflow(rootDir, config) {
12049
- const workflowsDir = path22.join(rootDir, ".github", "workflows");
12050
- const filePath = path22.join(workflowsDir, "roast.yml");
12051
- const displayPath = filePath.split(path22.sep).join("/");
10477
+ const workflowsDir = path24.join(rootDir, ".github", "workflows");
10478
+ const filePath = path24.join(workflowsDir, "roast.yml");
10479
+ const displayPath = filePath.split(path24.sep).join("/");
12052
10480
  if (fs38.existsSync(filePath)) {
12053
10481
  return { path: displayPath, alreadyExists: true };
12054
10482
  }
@@ -12185,13 +10613,13 @@ function formatTrendResult(result) {
12185
10613
 
12186
10614
  // src/hooks/index.ts
12187
10615
  import fs39 from "fs";
12188
- import path23 from "path";
10616
+ import path25 from "path";
12189
10617
  function detectHuskySetup(rootDir) {
12190
- const huskyDir = path23.join(rootDir, ".husky");
10618
+ const huskyDir = path25.join(rootDir, ".husky");
12191
10619
  if (fs39.existsSync(huskyDir) && fs39.statSync(huskyDir).isDirectory()) {
12192
10620
  return true;
12193
10621
  }
12194
- const pkgPath = path23.join(rootDir, "package.json");
10622
+ const pkgPath = path25.join(rootDir, "package.json");
12195
10623
  if (fs39.existsSync(pkgPath)) {
12196
10624
  try {
12197
10625
  const pkg = JSON.parse(fs39.readFileSync(pkgPath, "utf-8"));
@@ -12212,8 +10640,8 @@ function installPreCommitHook(rootDir, threshold) {
12212
10640
  }
12213
10641
  }
12214
10642
  function _installHuskyHook(rootDir, threshold) {
12215
- const huskyDir = path23.join(rootDir, ".husky");
12216
- const hookPath = path23.join(huskyDir, "pre-commit");
10643
+ const huskyDir = path25.join(rootDir, ".husky");
10644
+ const hookPath = path25.join(huskyDir, "pre-commit");
12217
10645
  try {
12218
10646
  if (!fs39.existsSync(huskyDir)) {
12219
10647
  fs39.mkdirSync(huskyDir, { recursive: true });
@@ -12260,9 +10688,9 @@ function _installHuskyHook(rootDir, threshold) {
12260
10688
  }
12261
10689
  }
12262
10690
  function _installGitHook(rootDir, threshold) {
12263
- const gitDir = path23.join(rootDir, ".git");
12264
- const hooksDir = path23.join(gitDir, "hooks");
12265
- const hookPath = path23.join(hooksDir, "pre-commit");
10691
+ const gitDir = path25.join(rootDir, ".git");
10692
+ const hooksDir = path25.join(gitDir, "hooks");
10693
+ const hookPath = path25.join(hooksDir, "pre-commit");
12266
10694
  if (!fs39.existsSync(gitDir) || !fs39.statSync(gitDir).isDirectory()) {
12267
10695
  return {
12268
10696
  success: false,
@@ -12325,8 +10753,8 @@ function _installGitHook(rootDir, threshold) {
12325
10753
  }
12326
10754
  }
12327
10755
  function uninstallPreCommitHook(rootDir) {
12328
- const huskyHook = path23.join(rootDir, ".husky", "pre-commit");
12329
- const gitHook = path23.join(rootDir, ".git", "hooks", "pre-commit");
10756
+ const huskyHook = path25.join(rootDir, ".husky", "pre-commit");
10757
+ const gitHook = path25.join(rootDir, ".git", "hooks", "pre-commit");
12330
10758
  let targetPath = null;
12331
10759
  if (fs39.existsSync(huskyHook)) {
12332
10760
  const content = fs39.readFileSync(huskyHook, "utf-8");
@@ -13236,9 +11664,9 @@ function generateDashboardHtml(report) {
13236
11664
  </html>`;
13237
11665
  }
13238
11666
  function startDashboard(report, port = 7777, options) {
13239
- let currentReport = report;
11667
+ let _currentReport = report;
13240
11668
  let currentHtml = generateDashboardHtml(report);
13241
- let currentReportJson = JSON.stringify(report);
11669
+ let _currentReportJson = JSON.stringify(report);
13242
11670
  const sseClients = /* @__PURE__ */ new Set();
13243
11671
  let isRescanning = false;
13244
11672
  function broadcast(data) {
@@ -13274,9 +11702,9 @@ function startDashboard(report, port = 7777, options) {
13274
11702
  isRescanning = true;
13275
11703
  broadcast({ type: "scanning", file: "manual" });
13276
11704
  options.rescan().then((newReport) => {
13277
- currentReport = newReport;
11705
+ _currentReport = newReport;
13278
11706
  currentHtml = generateDashboardHtml(newReport);
13279
- currentReportJson = JSON.stringify(newReport);
11707
+ _currentReportJson = JSON.stringify(newReport);
13280
11708
  broadcast({ type: "update", report: newReport });
13281
11709
  isRescanning = false;
13282
11710
  }).catch(() => {
@@ -13291,7 +11719,7 @@ function startDashboard(report, port = 7777, options) {
13291
11719
  res.end(currentHtml);
13292
11720
  } else if (req.method === "GET" && url === "/api/report") {
13293
11721
  res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
13294
- res.end(currentReportJson);
11722
+ res.end(_currentReportJson);
13295
11723
  } else if (req.method === "GET" && url === "/health") {
13296
11724
  res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
13297
11725
  res.end('{"ok":true}');
@@ -13338,12 +11766,12 @@ function startDashboard(report, port = 7777, options) {
13338
11766
  broadcast({ type: "scanning", file: changedPath });
13339
11767
  try {
13340
11768
  const newReport = await options.rescan();
13341
- currentReport = newReport;
11769
+ _currentReport = newReport;
13342
11770
  currentHtml = generateDashboardHtml(newReport);
13343
- currentReportJson = JSON.stringify(newReport);
11771
+ _currentReportJson = JSON.stringify(newReport);
13344
11772
  broadcast({ type: "update", report: newReport });
13345
11773
  console.log(` \u21BB Dashboard updated (${changedPath})`);
13346
- } catch (err) {
11774
+ } catch {
13347
11775
  broadcast({ type: "error", message: "Rescan failed" });
13348
11776
  } finally {
13349
11777
  isRescanning = false;
@@ -13379,11 +11807,11 @@ function startDashboard(report, port = 7777, options) {
13379
11807
 
13380
11808
  // src/readme/index.ts
13381
11809
  import fs40 from "fs";
13382
- import path24 from "path";
11810
+ import path26 from "path";
13383
11811
  function findReadmePath(rootDir) {
13384
11812
  const candidates = ["README.md", "readme.md", "README.MD", "Readme.md"];
13385
11813
  for (const name of candidates) {
13386
- const fullPath = path24.join(rootDir, name);
11814
+ const fullPath = path26.join(rootDir, name);
13387
11815
  if (fs40.existsSync(fullPath)) {
13388
11816
  return fullPath;
13389
11817
  }
@@ -13403,7 +11831,7 @@ function updateReadmeBadge(rootDir, health) {
13403
11831
  ${badgeLine}
13404
11832
  <!-- roast-score-end -->`;
13405
11833
  const newContent2 = previousContent.replace(blockPattern, replacement);
13406
- validateOutputPath(rootDir, path24.relative(rootDir, readmePath));
11834
+ validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
13407
11835
  fs40.writeFileSync(readmePath, newContent2, "utf-8");
13408
11836
  return { updated: true, method: "html-comment", previousContent };
13409
11837
  }
@@ -13414,7 +11842,7 @@ ${badgeLine}
13414
11842
  if (badgeLineIndex !== -1) {
13415
11843
  lines[badgeLineIndex] = badgeLine;
13416
11844
  const newContent2 = lines.join("\n");
13417
- validateOutputPath(rootDir, path24.relative(rootDir, readmePath));
11845
+ validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
13418
11846
  fs40.writeFileSync(readmePath, newContent2, "utf-8");
13419
11847
  return { updated: true, method: "badge-line", previousContent };
13420
11848
  }
@@ -13427,7 +11855,7 @@ ${badgeLine}
13427
11855
  Generated by [roast-my-codebase](https://github.com/rahuldk1105/roast-my-codebase)
13428
11856
  <!-- roast-score-end -->`;
13429
11857
  const newContent = previousContent + appendBlock;
13430
- validateOutputPath(rootDir, path24.relative(rootDir, readmePath));
11858
+ validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
13431
11859
  fs40.writeFileSync(readmePath, newContent, "utf-8");
13432
11860
  return { updated: true, method: "appended", previousContent };
13433
11861
  }
@@ -14309,14 +12737,14 @@ var EXIT_CODES = {
14309
12737
  // src/cli/index.ts
14310
12738
  function loadPackageVersion() {
14311
12739
  const __filename = fileURLToPath(import.meta.url);
14312
- let dir = path25.dirname(__filename);
14313
- while (dir !== path25.dirname(dir)) {
14314
- const pkgPath = path25.join(dir, "package.json");
12740
+ let dir = path27.dirname(__filename);
12741
+ while (dir !== path27.dirname(dir)) {
12742
+ const pkgPath = path27.join(dir, "package.json");
14315
12743
  if (fs41.existsSync(pkgPath)) {
14316
12744
  const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf-8"));
14317
12745
  if (pkg.name === "roast-my-codebase") return pkg.version;
14318
12746
  }
14319
- dir = path25.dirname(dir);
12747
+ dir = path27.dirname(dir);
14320
12748
  }
14321
12749
  return "1.0.0";
14322
12750
  }
@@ -14327,7 +12755,7 @@ function createCli() {
14327
12755
  "Exit with code 1 if health score is below threshold (use with --json)",
14328
12756
  parseInt
14329
12757
  ).action(async (targetPath, options) => {
14330
- const rootDir = path25.resolve(targetPath);
12758
+ const rootDir = path27.resolve(targetPath);
14331
12759
  if (options.explain !== void 0) {
14332
12760
  if (options.explain === true || options.explain === "") {
14333
12761
  console.log(chalk12.bold("\n Available categories:\n"));
@@ -14441,7 +12869,7 @@ function createCli() {
14441
12869
  process.exit(1);
14442
12870
  }
14443
12871
  try {
14444
- fs41.mkdirSync(path25.join(pluginDir, "src"), { recursive: false });
12872
+ fs41.mkdirSync(path27.join(pluginDir, "src"), { recursive: false });
14445
12873
  } catch (e) {
14446
12874
  if (e.code === "EEXIST") {
14447
12875
  console.log(chalk12.yellow(`
@@ -14449,9 +12877,9 @@ function createCli() {
14449
12877
  `));
14450
12878
  process.exit(1);
14451
12879
  }
14452
- fs41.mkdirSync(path25.join(pluginDir, "src"), { recursive: true });
12880
+ fs41.mkdirSync(path27.join(pluginDir, "src"), { recursive: true });
14453
12881
  }
14454
- fs41.writeFileSync(path25.join(pluginDir, "package.json"), JSON.stringify({
12882
+ fs41.writeFileSync(path27.join(pluginDir, "package.json"), JSON.stringify({
14455
12883
  name: fullName,
14456
12884
  version: "0.1.0",
14457
12885
  description: "A roast-my-codebase plugin",
@@ -14462,7 +12890,7 @@ function createCli() {
14462
12890
  devDependencies: { typescript: "^5.0.0" }
14463
12891
  }, null, 2));
14464
12892
  fs41.writeFileSync(
14465
- path25.join(pluginDir, "src", "index.ts"),
12893
+ path27.join(pluginDir, "src", "index.ts"),
14466
12894
  `import type { Scanner, ScanResult, Finding } from 'roast-my-codebase/types';
14467
12895
 
14468
12896
  export default {
@@ -14479,7 +12907,7 @@ export default {
14479
12907
  };
14480
12908
  `
14481
12909
  );
14482
- fs41.writeFileSync(path25.join(pluginDir, "tsconfig.json"), JSON.stringify({
12910
+ fs41.writeFileSync(path27.join(pluginDir, "tsconfig.json"), JSON.stringify({
14483
12911
  compilerOptions: {
14484
12912
  target: "ES2022",
14485
12913
  module: "NodeNext",
@@ -14506,7 +12934,7 @@ export default {
14506
12934
  console.error(`Error: "${rootDir}" does not exist.`);
14507
12935
  process.exit(1);
14508
12936
  }
14509
- const { BundleSizeScanner: BundleSizeScannerDynamic } = await import("./bundle-OG535XKC.js");
12937
+ const { BundleSizeScanner: BundleSizeScannerDynamic } = await import("./bundle-U2Y5OE4Z.js");
14510
12938
  const scanner = new BundleSizeScannerDynamic();
14511
12939
  const result = await scanner.scan(rootDir);
14512
12940
  const stats = result.stats;
@@ -14544,9 +12972,9 @@ export default {
14544
12972
  process.exit(1);
14545
12973
  }
14546
12974
  if (options.file) {
14547
- const targetFile = path25.resolve(rootDir, options.file);
14548
- const normalizedRootForFile = path25.resolve(rootDir);
14549
- if (!targetFile.startsWith(normalizedRootForFile + path25.sep) && targetFile !== normalizedRootForFile) {
12975
+ const targetFile = path27.resolve(rootDir, options.file);
12976
+ const normalizedRootForFile = path27.resolve(rootDir);
12977
+ if (!targetFile.startsWith(normalizedRootForFile + path27.sep) && targetFile !== normalizedRootForFile) {
14550
12978
  console.error(chalk12.red(`
14551
12979
  Security: --file path must be within the project directory.
14552
12980
  `));
@@ -14596,7 +13024,7 @@ ${options.file} is a directory. Use --file with a specific file.
14596
13024
  ...fileDuplicateResult.findings,
14597
13025
  ...fileDeadExportResult.findings
14598
13026
  );
14599
- const fileExt = path25.extname(targetFile).toLowerCase();
13027
+ const fileExt = path27.extname(targetFile).toLowerCase();
14600
13028
  if (fileExt === ".py") {
14601
13029
  const pyResults = await Promise.all([
14602
13030
  new PythonComplexityScanner().scan(rootDir),
@@ -14625,7 +13053,7 @@ ${options.file} is a directory. Use --file with a specific file.
14625
13053
  fileAllFindings.push(...rsResults.flatMap((r) => r.findings));
14626
13054
  }
14627
13055
  fileSpinner.stop();
14628
- const relFilePath = path25.relative(rootDir, targetFile).replace(/\\/g, "/");
13056
+ const relFilePath = path27.relative(rootDir, targetFile).replace(/\\/g, "/");
14629
13057
  const fileFindings = fileAllFindings.filter(
14630
13058
  (f) => f.file && (f.file === relFilePath || f.file.replace(/\\/g, "/") === relFilePath)
14631
13059
  );
@@ -15217,9 +13645,9 @@ Warning: Custom rules scanner failed: ${error instanceof Error ? error.message :
15217
13645
  return;
15218
13646
  }
15219
13647
  if (options.outputDir) {
15220
- const resolvedOutputDir = path25.resolve(rootDir, options.outputDir);
15221
- const normalizedRoot = path25.resolve(rootDir);
15222
- if (!resolvedOutputDir.startsWith(normalizedRoot + path25.sep) && resolvedOutputDir !== normalizedRoot) {
13648
+ const resolvedOutputDir = path27.resolve(rootDir, options.outputDir);
13649
+ const normalizedRoot = path27.resolve(rootDir);
13650
+ if (!resolvedOutputDir.startsWith(normalizedRoot + path27.sep) && resolvedOutputDir !== normalizedRoot) {
15223
13651
  console.error(chalk12.red(`
15224
13652
  Error: --output-dir path "${options.outputDir}" escapes the project directory.
15225
13653
  `));
@@ -15231,7 +13659,7 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
15231
13659
  \u2713 Reports saved to ${options.outputDir}/
15232
13660
  `));
15233
13661
  for (const file of outputResult.files) {
15234
- console.log(chalk12.dim(` ${path25.basename(file)}`));
13662
+ console.log(chalk12.dim(` ${path27.basename(file)}`));
15235
13663
  }
15236
13664
  console.log();
15237
13665
  } else {
@@ -15391,7 +13819,7 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
15391
13819
  console.error("Analysis failed:", sanitizeError(error));
15392
13820
  if (process.env.DEBUG) {
15393
13821
  try {
15394
- const debugPath = path25.join(rootDir, ".roast-debug.log");
13822
+ const debugPath = path27.join(rootDir, ".roast-debug.log");
15395
13823
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
15396
13824
  const errorStr = error instanceof Error ? error.stack : String(error);
15397
13825
  fs41.appendFileSync(debugPath, `${timestamp}: ${errorStr}
@@ -15406,12 +13834,12 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
15406
13834
  return program2;
15407
13835
  }
15408
13836
  function getProjectName(rootDir) {
15409
- const pkgPath = path25.join(rootDir, "package.json");
13837
+ const pkgPath = path27.join(rootDir, "package.json");
15410
13838
  try {
15411
13839
  const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf-8"));
15412
- return pkg.name || path25.basename(rootDir);
13840
+ return pkg.name || path27.basename(rootDir);
15413
13841
  } catch {
15414
- return path25.basename(rootDir);
13842
+ return path27.basename(rootDir);
15415
13843
  }
15416
13844
  }
15417
13845