roast-my-codebase 1.3.0 → 1.3.2

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) {
@@ -10305,6 +8733,34 @@ function renderReport(report, options) {
10305
8733
  ` ${chalk4.cyan("Dev Dependencies")} ${report.stats.devDependencies}`
10306
8734
  );
10307
8735
  sections.push("");
8736
+ const FINDING_TO_ROAST_CATEGORY = {
8737
+ "unused-deps": "dependencies",
8738
+ "nextjs-metadata": "framework",
8739
+ "nextjs-client-server": "framework",
8740
+ "react-error-boundary": "framework",
8741
+ "secrets": "security",
8742
+ "env-in-git": "security",
8743
+ "eval-usage": "security",
8744
+ "npm-audit": "npm-audit",
8745
+ "dep-outdated": "dep-outdated",
8746
+ "ruby-style": "ruby-issues",
8747
+ "php-smell": "php-issues",
8748
+ "swift-async": "swift-issues",
8749
+ "kotlin-coroutine": "kotlin-issues",
8750
+ "db-n-plus-one": "database",
8751
+ "db-sql-injection": "database",
8752
+ "db-over-fetch": "database",
8753
+ "db-destructive": "database"
8754
+ };
8755
+ const roastByFile = /* @__PURE__ */ new Map();
8756
+ const roastByCategory = /* @__PURE__ */ new Map();
8757
+ for (const roast of report.roasts) {
8758
+ if (roast.target === "codebase") continue;
8759
+ roastByCategory.set(roast.category, roast.message);
8760
+ if (roast.target.includes("/") || roast.target.includes(".") && !roast.target.includes(" ")) {
8761
+ roastByFile.set(roast.target, roast.message);
8762
+ }
8763
+ }
10308
8764
  const warnings = report.findings.filter((f) => f.severity === "warning");
10309
8765
  const criticals = report.findings.filter((f) => f.severity === "critical");
10310
8766
  const infos = report.findings.filter((f) => f.severity === "info");
@@ -10325,27 +8781,37 @@ function renderReport(report, options) {
10325
8781
  sections.push(` ${chalk4.blue("\u25CF")} ${chalk4.blue(`${infos.length} info`)}`);
10326
8782
  }
10327
8783
  sections.push("");
8784
+ const shownRoastKeys = /* @__PURE__ */ new Set();
10328
8785
  const keyFindings = [...criticals, ...warnings].slice(0, 8);
10329
8786
  for (const finding of keyFindings) {
10330
8787
  const icon = finding.severity === "critical" ? chalk4.red("\u2717") : chalk4.yellow("\u26A0");
10331
8788
  sections.push(` ${icon} ${chalk4.white(finding.message)}`);
8789
+ let roastMsg;
8790
+ let roastKey;
8791
+ if (finding.file && roastByFile.has(finding.file)) {
8792
+ roastKey = `file:${finding.file}`;
8793
+ if (!shownRoastKeys.has(roastKey)) {
8794
+ roastMsg = roastByFile.get(finding.file);
8795
+ }
8796
+ }
8797
+ if (!roastMsg) {
8798
+ const resolvedCategory = FINDING_TO_ROAST_CATEGORY[finding.category] ?? finding.category;
8799
+ roastKey = `cat:${resolvedCategory}`;
8800
+ if (!shownRoastKeys.has(roastKey)) {
8801
+ roastMsg = roastByCategory.get(resolvedCategory);
8802
+ }
8803
+ }
8804
+ if (roastMsg && roastKey) {
8805
+ sections.push(` ${chalk4.italic.dim(roastMsg)}`);
8806
+ shownRoastKeys.add(roastKey);
8807
+ }
10332
8808
  }
10333
8809
  sections.push("");
10334
8810
  }
10335
- if (report.roasts.length > 0) {
10336
- sections.push(
10337
- boxen(chalk4.bold.yellow(" Roast Time ") + " " + flame(), {
10338
- padding: { top: 0, bottom: 0, left: 1, right: 1 },
10339
- borderStyle: "round",
10340
- borderColor: "yellow"
10341
- })
10342
- );
8811
+ const comboRoast = report.roasts.find((r) => r.target === "codebase");
8812
+ if (comboRoast) {
8813
+ sections.push(chalk4.italic.yellow(` ${comboRoast.message}`));
10343
8814
  sections.push("");
10344
- for (const roast of report.roasts) {
10345
- sections.push(` ${chalk4.bold.white(roast.target)}`);
10346
- sections.push(` ${chalk4.yellow(roast.message)}`);
10347
- sections.push("");
10348
- }
10349
8815
  }
10350
8816
  if (report.fixes && report.fixes.length > 0) {
10351
8817
  sections.push(
@@ -10388,7 +8854,7 @@ function getScoreColor3(score) {
10388
8854
  if (score >= 60) return chalk4.rgb(255, 165, 0);
10389
8855
  return chalk4.red;
10390
8856
  }
10391
- function renderHealthBar(score) {
8857
+ function renderHealthBar2(score) {
10392
8858
  const width = 30;
10393
8859
  const filled = Math.round(score / 100 * width);
10394
8860
  const empty = width - filled;
@@ -10533,7 +8999,7 @@ function renderWatchSummary(health, delta, findingCounts2) {
10533
8999
  }
10534
9000
 
10535
9001
  // src/compare/index.ts
10536
- import path17 from "path";
9002
+ import path19 from "path";
10537
9003
  import fs33 from "fs";
10538
9004
  import { spawnSync as spawnSync4 } from "child_process";
10539
9005
  import { randomBytes } from "crypto";
@@ -10562,7 +9028,7 @@ async function compareWithBranch(rootDir, branchName, scanFunc) {
10562
9028
  console.log(chalk6.dim(`Scanning current working directory...`));
10563
9029
  const currentResult = await scanFunc(rootDir);
10564
9030
  const randomId = randomBytes(8).toString("hex");
10565
- const worktreePath = path17.join(tmpdir(), `.roast-worktree-${randomId}`);
9031
+ const worktreePath = path19.join(tmpdir(), `.roast-worktree-${randomId}`);
10566
9032
  console.log(chalk6.dim(`Checking out ${branchName} to temporary worktree...`));
10567
9033
  let cleanupAttempted = false;
10568
9034
  const cleanupWorktree = async (retries = 3) => {
@@ -10655,7 +9121,7 @@ function renderComparison(comparison, branchName) {
10655
9121
 
10656
9122
  // src/config/index.ts
10657
9123
  import fs34 from "fs";
10658
- import path18 from "path";
9124
+ import path20 from "path";
10659
9125
 
10660
9126
  // src/config/validation.ts
10661
9127
  function validateConfig(userConfig) {
@@ -10801,7 +9267,7 @@ function safeJsonParse(content) {
10801
9267
  return cleaned;
10802
9268
  }
10803
9269
  return parsed;
10804
- } catch (_error) {
9270
+ } catch {
10805
9271
  return null;
10806
9272
  }
10807
9273
  }
@@ -10826,7 +9292,7 @@ var DEFAULT_CONFIG = {
10826
9292
  notify: void 0
10827
9293
  };
10828
9294
  function loadConfig(rootDir) {
10829
- const configPath = path18.join(rootDir, ".roastrc.json");
9295
+ const configPath = path20.join(rootDir, ".roastrc.json");
10830
9296
  if (!fs34.existsSync(configPath)) {
10831
9297
  return DEFAULT_CONFIG;
10832
9298
  }
@@ -10898,7 +9364,7 @@ import chalk7 from "chalk";
10898
9364
 
10899
9365
  // src/interactive/fixes.ts
10900
9366
  import fs35 from "fs";
10901
- import path19 from "path";
9367
+ import path21 from "path";
10902
9368
  import { spawnSync as spawnSync5 } from "child_process";
10903
9369
  async function applyAutoFix(finding, fix, rootDir, dryRun = false) {
10904
9370
  switch (finding.category) {
@@ -10979,7 +9445,7 @@ function fixTodoComment(finding, rootDir, dryRun) {
10979
9445
  message: "No file specified for TODO fix"
10980
9446
  };
10981
9447
  }
10982
- const filePath = path19.join(rootDir, finding.file);
9448
+ const filePath = path21.join(rootDir, finding.file);
10983
9449
  try {
10984
9450
  const content = fs35.readFileSync(filePath, "utf-8");
10985
9451
  const lines = content.split("\n");
@@ -11036,7 +9502,7 @@ function fixDeadExport(finding, rootDir, dryRun) {
11036
9502
  };
11037
9503
  }
11038
9504
  const exportName = match[1];
11039
- const filePath = path19.join(rootDir, finding.file);
9505
+ const filePath = path21.join(rootDir, finding.file);
11040
9506
  try {
11041
9507
  const content = fs35.readFileSync(filePath, "utf-8");
11042
9508
  const lines = content.split("\n");
@@ -11080,7 +9546,7 @@ function fixNextjsClientServer(finding, rootDir, dryRun) {
11080
9546
  if (!finding.file) {
11081
9547
  return { success: false, message: "No file specified for nextjs-client-server fix" };
11082
9548
  }
11083
- const filePath = path19.join(rootDir, finding.file);
9549
+ const filePath = path21.join(rootDir, finding.file);
11084
9550
  try {
11085
9551
  const content = fs35.readFileSync(filePath, "utf-8");
11086
9552
  if (content.includes("'use client'") || content.includes('"use client"')) {
@@ -11104,7 +9570,7 @@ function fixNextjsMetadata(finding, rootDir, dryRun) {
11104
9570
  if (!finding.file) {
11105
9571
  return { success: false, message: "No file specified for nextjs-metadata fix" };
11106
9572
  }
11107
- const filePath = path19.join(rootDir, finding.file);
9573
+ const filePath = path21.join(rootDir, finding.file);
11108
9574
  try {
11109
9575
  const content = fs35.readFileSync(filePath, "utf-8");
11110
9576
  if (/export.*metadata/.test(content)) {
@@ -11124,7 +9590,7 @@ function fixNextjsMetadata(finding, rootDir, dryRun) {
11124
9590
  }
11125
9591
  }
11126
9592
  function fixGitignoreEntry(rootDir, filename, dryRun) {
11127
- const gitignorePath = path19.join(rootDir, ".gitignore");
9593
+ const gitignorePath = path21.join(rootDir, ".gitignore");
11128
9594
  try {
11129
9595
  let existing = "";
11130
9596
  if (fs35.existsSync(gitignorePath)) {
@@ -11151,7 +9617,7 @@ function fixEnvInGit(finding, rootDir, dryRun) {
11151
9617
  if (!finding.file) {
11152
9618
  return { success: false, message: "No file specified for env-in-git fix" };
11153
9619
  }
11154
- const filename = path19.basename(finding.file);
9620
+ const filename = path21.basename(finding.file);
11155
9621
  const result = fixGitignoreEntry(rootDir, filename, dryRun);
11156
9622
  if (result.success) {
11157
9623
  return {
@@ -11168,7 +9634,7 @@ function fixTypeSafety(finding, rootDir, dryRun) {
11168
9634
  if (!finding.file) {
11169
9635
  return { success: false, message: "No file specified for type-safety fix" };
11170
9636
  }
11171
- const filePath = path19.join(rootDir, finding.file);
9637
+ const filePath = path21.join(rootDir, finding.file);
11172
9638
  try {
11173
9639
  const content = fs35.readFileSync(filePath, "utf-8");
11174
9640
  const lines = content.split("\n");
@@ -11207,11 +9673,11 @@ function fixTestCoverage(finding, rootDir, dryRun) {
11207
9673
  }
11208
9674
  const srcRelative = finding.file.replace(/^src\//, "");
11209
9675
  const testRelative = `tests/${srcRelative.replace(/\.tsx?$/, ".test.ts")}`;
11210
- const testPath = path19.join(rootDir, testRelative);
9676
+ const testPath = path21.join(rootDir, testRelative);
11211
9677
  if (fs35.existsSync(testPath)) {
11212
9678
  return { success: false, message: `Test file already exists: ${testRelative}` };
11213
9679
  }
11214
- const baseName = path19.basename(finding.file, path19.extname(finding.file));
9680
+ const baseName = path21.basename(finding.file, path21.extname(finding.file));
11215
9681
  const skeleton = `import { describe, it, expect } from 'vitest';
11216
9682
 
11217
9683
  describe('${baseName}', () => {
@@ -11225,7 +9691,7 @@ describe('${baseName}', () => {
11225
9691
  return { success: true, message: `Would create test file: ${testRelative}` };
11226
9692
  }
11227
9693
  try {
11228
- fs35.mkdirSync(path19.dirname(testPath), { recursive: true });
9694
+ fs35.mkdirSync(path21.dirname(testPath), { recursive: true });
11229
9695
  fs35.writeFileSync(testPath, skeleton, "utf-8");
11230
9696
  return { success: true, message: `Created test file: ${testRelative}` };
11231
9697
  } catch (error) {
@@ -11239,7 +9705,7 @@ function fixSecrets(finding, rootDir, dryRun) {
11239
9705
  if (!finding.file) {
11240
9706
  return { success: false, message: "No file specified for secrets fix" };
11241
9707
  }
11242
- const filename = path19.basename(finding.file);
9708
+ const filename = path21.basename(finding.file);
11243
9709
  const result = fixGitignoreEntry(rootDir, filename, dryRun);
11244
9710
  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
9711
  if (result.success) {
@@ -11525,11 +9991,11 @@ function getSeverityBadge(severity) {
11525
9991
 
11526
9992
  // src/history/index.ts
11527
9993
  import fs36 from "fs";
11528
- import path20 from "path";
9994
+ import path22 from "path";
11529
9995
  import { spawnSync as spawnSync6 } from "child_process";
11530
9996
  var HISTORY_FILE = ".roast-history.json";
11531
9997
  function loadHistory(rootDir) {
11532
- const historyPath = path20.join(rootDir, HISTORY_FILE);
9998
+ const historyPath = path22.join(rootDir, HISTORY_FILE);
11533
9999
  if (!fs36.existsSync(historyPath)) {
11534
10000
  return null;
11535
10001
  }
@@ -11542,7 +10008,7 @@ function loadHistory(rootDir) {
11542
10008
  }
11543
10009
  }
11544
10010
  function saveHistory(rootDir, history) {
11545
- const historyPath = path20.join(rootDir, HISTORY_FILE);
10011
+ const historyPath = path22.join(rootDir, HISTORY_FILE);
11546
10012
  try {
11547
10013
  fs36.writeFileSync(historyPath, JSON.stringify(history, null, 2), "utf-8");
11548
10014
  } catch (error) {
@@ -11860,7 +10326,7 @@ function getTrendColor(trend) {
11860
10326
  // src/incremental/index.ts
11861
10327
  import { spawnSync as spawnSync7 } from "child_process";
11862
10328
  import fs37 from "fs";
11863
- import path21 from "path";
10329
+ import path23 from "path";
11864
10330
  function getChangedFiles(rootDir, baseRef) {
11865
10331
  const gitCheck = spawnSync7("git", ["rev-parse", "--git-dir"], {
11866
10332
  cwd: rootDir,
@@ -11878,7 +10344,7 @@ function getChangedFiles(rootDir, baseRef) {
11878
10344
  if (diffResult.status !== 0) {
11879
10345
  return { changedFiles: [], isIncremental: true, baseRef };
11880
10346
  }
11881
- const files = parseGitOutput(diffResult.stdout).map((f) => path21.join(rootDir, f)).filter((f) => fs37.existsSync(f));
10347
+ const files = parseGitOutput(diffResult.stdout).map((f) => path23.join(rootDir, f)).filter((f) => fs37.existsSync(f));
11882
10348
  return { changedFiles: files, isIncremental: true, baseRef };
11883
10349
  }
11884
10350
  const unstagedResult = spawnSync7(
@@ -11894,7 +10360,7 @@ function getChangedFiles(rootDir, baseRef) {
11894
10360
  const unstagedFiles = unstagedResult.status === 0 ? parseGitOutput(unstagedResult.stdout) : [];
11895
10361
  const stagedFiles = stagedResult.status === 0 ? parseGitOutput(stagedResult.stdout) : [];
11896
10362
  const merged = Array.from(/* @__PURE__ */ new Set([...unstagedFiles, ...stagedFiles]));
11897
- const changedFiles = merged.map((f) => path21.join(rootDir, f)).filter((f) => fs37.existsSync(f));
10363
+ const changedFiles = merged.map((f) => path23.join(rootDir, f)).filter((f) => fs37.existsSync(f));
11898
10364
  return { changedFiles, isIncremental: true, baseRef: "HEAD" };
11899
10365
  }
11900
10366
  function parseGitOutput(stdout) {
@@ -11905,13 +10371,13 @@ function filterFindingsByFiles(findings, changedFiles, rootDir) {
11905
10371
  return findings.filter((f) => !f.file);
11906
10372
  }
11907
10373
  const normalizedChanged = new Set(
11908
- changedFiles.map((f) => path21.normalize(f))
10374
+ changedFiles.map((f) => path23.normalize(f))
11909
10375
  );
11910
10376
  return findings.filter((finding) => {
11911
10377
  if (!finding.file) {
11912
10378
  return true;
11913
10379
  }
11914
- const findingAbsolute = path21.isAbsolute(finding.file) ? path21.normalize(finding.file) : path21.normalize(path21.join(rootDir, finding.file));
10380
+ const findingAbsolute = path23.isAbsolute(finding.file) ? path23.normalize(finding.file) : path23.normalize(path23.join(rootDir, finding.file));
11915
10381
  const findingForward = findingAbsolute.replace(/\\/g, "/");
11916
10382
  const findingBackward = findingAbsolute.replace(/\//g, "\\");
11917
10383
  if (normalizedChanged.has(findingAbsolute)) {
@@ -11987,10 +10453,10 @@ function filterFindingsByChangedLines(findings, changedRanges) {
11987
10453
 
11988
10454
  // src/ci/index.ts
11989
10455
  import fs38 from "fs";
11990
- import path22 from "path";
10456
+ import path24 from "path";
11991
10457
  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";
10458
+ if (fs38.existsSync(path24.join(rootDir, "yarn.lock"))) return "yarn";
10459
+ if (fs38.existsSync(path24.join(rootDir, "pnpm-lock.yaml"))) return "pnpm";
11994
10460
  return "npm";
11995
10461
  }
11996
10462
  function generateCIWorkflow(config) {
@@ -12046,9 +10512,9 @@ ${permissionsBlock}
12046
10512
  `;
12047
10513
  }
12048
10514
  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("/");
10515
+ const workflowsDir = path24.join(rootDir, ".github", "workflows");
10516
+ const filePath = path24.join(workflowsDir, "roast.yml");
10517
+ const displayPath = filePath.split(path24.sep).join("/");
12052
10518
  if (fs38.existsSync(filePath)) {
12053
10519
  return { path: displayPath, alreadyExists: true };
12054
10520
  }
@@ -12185,13 +10651,13 @@ function formatTrendResult(result) {
12185
10651
 
12186
10652
  // src/hooks/index.ts
12187
10653
  import fs39 from "fs";
12188
- import path23 from "path";
10654
+ import path25 from "path";
12189
10655
  function detectHuskySetup(rootDir) {
12190
- const huskyDir = path23.join(rootDir, ".husky");
10656
+ const huskyDir = path25.join(rootDir, ".husky");
12191
10657
  if (fs39.existsSync(huskyDir) && fs39.statSync(huskyDir).isDirectory()) {
12192
10658
  return true;
12193
10659
  }
12194
- const pkgPath = path23.join(rootDir, "package.json");
10660
+ const pkgPath = path25.join(rootDir, "package.json");
12195
10661
  if (fs39.existsSync(pkgPath)) {
12196
10662
  try {
12197
10663
  const pkg = JSON.parse(fs39.readFileSync(pkgPath, "utf-8"));
@@ -12212,8 +10678,8 @@ function installPreCommitHook(rootDir, threshold) {
12212
10678
  }
12213
10679
  }
12214
10680
  function _installHuskyHook(rootDir, threshold) {
12215
- const huskyDir = path23.join(rootDir, ".husky");
12216
- const hookPath = path23.join(huskyDir, "pre-commit");
10681
+ const huskyDir = path25.join(rootDir, ".husky");
10682
+ const hookPath = path25.join(huskyDir, "pre-commit");
12217
10683
  try {
12218
10684
  if (!fs39.existsSync(huskyDir)) {
12219
10685
  fs39.mkdirSync(huskyDir, { recursive: true });
@@ -12260,9 +10726,9 @@ function _installHuskyHook(rootDir, threshold) {
12260
10726
  }
12261
10727
  }
12262
10728
  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");
10729
+ const gitDir = path25.join(rootDir, ".git");
10730
+ const hooksDir = path25.join(gitDir, "hooks");
10731
+ const hookPath = path25.join(hooksDir, "pre-commit");
12266
10732
  if (!fs39.existsSync(gitDir) || !fs39.statSync(gitDir).isDirectory()) {
12267
10733
  return {
12268
10734
  success: false,
@@ -12325,8 +10791,8 @@ function _installGitHook(rootDir, threshold) {
12325
10791
  }
12326
10792
  }
12327
10793
  function uninstallPreCommitHook(rootDir) {
12328
- const huskyHook = path23.join(rootDir, ".husky", "pre-commit");
12329
- const gitHook = path23.join(rootDir, ".git", "hooks", "pre-commit");
10794
+ const huskyHook = path25.join(rootDir, ".husky", "pre-commit");
10795
+ const gitHook = path25.join(rootDir, ".git", "hooks", "pre-commit");
12330
10796
  let targetPath = null;
12331
10797
  if (fs39.existsSync(huskyHook)) {
12332
10798
  const content = fs39.readFileSync(huskyHook, "utf-8");
@@ -13236,9 +11702,9 @@ function generateDashboardHtml(report) {
13236
11702
  </html>`;
13237
11703
  }
13238
11704
  function startDashboard(report, port = 7777, options) {
13239
- let currentReport = report;
11705
+ let _currentReport = report;
13240
11706
  let currentHtml = generateDashboardHtml(report);
13241
- let currentReportJson = JSON.stringify(report);
11707
+ let _currentReportJson = JSON.stringify(report);
13242
11708
  const sseClients = /* @__PURE__ */ new Set();
13243
11709
  let isRescanning = false;
13244
11710
  function broadcast(data) {
@@ -13274,9 +11740,9 @@ function startDashboard(report, port = 7777, options) {
13274
11740
  isRescanning = true;
13275
11741
  broadcast({ type: "scanning", file: "manual" });
13276
11742
  options.rescan().then((newReport) => {
13277
- currentReport = newReport;
11743
+ _currentReport = newReport;
13278
11744
  currentHtml = generateDashboardHtml(newReport);
13279
- currentReportJson = JSON.stringify(newReport);
11745
+ _currentReportJson = JSON.stringify(newReport);
13280
11746
  broadcast({ type: "update", report: newReport });
13281
11747
  isRescanning = false;
13282
11748
  }).catch(() => {
@@ -13291,7 +11757,7 @@ function startDashboard(report, port = 7777, options) {
13291
11757
  res.end(currentHtml);
13292
11758
  } else if (req.method === "GET" && url === "/api/report") {
13293
11759
  res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
13294
- res.end(currentReportJson);
11760
+ res.end(_currentReportJson);
13295
11761
  } else if (req.method === "GET" && url === "/health") {
13296
11762
  res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
13297
11763
  res.end('{"ok":true}');
@@ -13338,12 +11804,12 @@ function startDashboard(report, port = 7777, options) {
13338
11804
  broadcast({ type: "scanning", file: changedPath });
13339
11805
  try {
13340
11806
  const newReport = await options.rescan();
13341
- currentReport = newReport;
11807
+ _currentReport = newReport;
13342
11808
  currentHtml = generateDashboardHtml(newReport);
13343
- currentReportJson = JSON.stringify(newReport);
11809
+ _currentReportJson = JSON.stringify(newReport);
13344
11810
  broadcast({ type: "update", report: newReport });
13345
11811
  console.log(` \u21BB Dashboard updated (${changedPath})`);
13346
- } catch (err) {
11812
+ } catch {
13347
11813
  broadcast({ type: "error", message: "Rescan failed" });
13348
11814
  } finally {
13349
11815
  isRescanning = false;
@@ -13379,11 +11845,11 @@ function startDashboard(report, port = 7777, options) {
13379
11845
 
13380
11846
  // src/readme/index.ts
13381
11847
  import fs40 from "fs";
13382
- import path24 from "path";
11848
+ import path26 from "path";
13383
11849
  function findReadmePath(rootDir) {
13384
11850
  const candidates = ["README.md", "readme.md", "README.MD", "Readme.md"];
13385
11851
  for (const name of candidates) {
13386
- const fullPath = path24.join(rootDir, name);
11852
+ const fullPath = path26.join(rootDir, name);
13387
11853
  if (fs40.existsSync(fullPath)) {
13388
11854
  return fullPath;
13389
11855
  }
@@ -13403,7 +11869,7 @@ function updateReadmeBadge(rootDir, health) {
13403
11869
  ${badgeLine}
13404
11870
  <!-- roast-score-end -->`;
13405
11871
  const newContent2 = previousContent.replace(blockPattern, replacement);
13406
- validateOutputPath(rootDir, path24.relative(rootDir, readmePath));
11872
+ validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
13407
11873
  fs40.writeFileSync(readmePath, newContent2, "utf-8");
13408
11874
  return { updated: true, method: "html-comment", previousContent };
13409
11875
  }
@@ -13414,7 +11880,7 @@ ${badgeLine}
13414
11880
  if (badgeLineIndex !== -1) {
13415
11881
  lines[badgeLineIndex] = badgeLine;
13416
11882
  const newContent2 = lines.join("\n");
13417
- validateOutputPath(rootDir, path24.relative(rootDir, readmePath));
11883
+ validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
13418
11884
  fs40.writeFileSync(readmePath, newContent2, "utf-8");
13419
11885
  return { updated: true, method: "badge-line", previousContent };
13420
11886
  }
@@ -13427,7 +11893,7 @@ ${badgeLine}
13427
11893
  Generated by [roast-my-codebase](https://github.com/rahuldk1105/roast-my-codebase)
13428
11894
  <!-- roast-score-end -->`;
13429
11895
  const newContent = previousContent + appendBlock;
13430
- validateOutputPath(rootDir, path24.relative(rootDir, readmePath));
11896
+ validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
13431
11897
  fs40.writeFileSync(readmePath, newContent, "utf-8");
13432
11898
  return { updated: true, method: "appended", previousContent };
13433
11899
  }
@@ -14309,14 +12775,14 @@ var EXIT_CODES = {
14309
12775
  // src/cli/index.ts
14310
12776
  function loadPackageVersion() {
14311
12777
  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");
12778
+ let dir = path27.dirname(__filename);
12779
+ while (dir !== path27.dirname(dir)) {
12780
+ const pkgPath = path27.join(dir, "package.json");
14315
12781
  if (fs41.existsSync(pkgPath)) {
14316
12782
  const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf-8"));
14317
12783
  if (pkg.name === "roast-my-codebase") return pkg.version;
14318
12784
  }
14319
- dir = path25.dirname(dir);
12785
+ dir = path27.dirname(dir);
14320
12786
  }
14321
12787
  return "1.0.0";
14322
12788
  }
@@ -14327,7 +12793,7 @@ function createCli() {
14327
12793
  "Exit with code 1 if health score is below threshold (use with --json)",
14328
12794
  parseInt
14329
12795
  ).action(async (targetPath, options) => {
14330
- const rootDir = path25.resolve(targetPath);
12796
+ const rootDir = path27.resolve(targetPath);
14331
12797
  if (options.explain !== void 0) {
14332
12798
  if (options.explain === true || options.explain === "") {
14333
12799
  console.log(chalk12.bold("\n Available categories:\n"));
@@ -14441,7 +12907,7 @@ function createCli() {
14441
12907
  process.exit(1);
14442
12908
  }
14443
12909
  try {
14444
- fs41.mkdirSync(path25.join(pluginDir, "src"), { recursive: false });
12910
+ fs41.mkdirSync(path27.join(pluginDir, "src"), { recursive: false });
14445
12911
  } catch (e) {
14446
12912
  if (e.code === "EEXIST") {
14447
12913
  console.log(chalk12.yellow(`
@@ -14449,9 +12915,9 @@ function createCli() {
14449
12915
  `));
14450
12916
  process.exit(1);
14451
12917
  }
14452
- fs41.mkdirSync(path25.join(pluginDir, "src"), { recursive: true });
12918
+ fs41.mkdirSync(path27.join(pluginDir, "src"), { recursive: true });
14453
12919
  }
14454
- fs41.writeFileSync(path25.join(pluginDir, "package.json"), JSON.stringify({
12920
+ fs41.writeFileSync(path27.join(pluginDir, "package.json"), JSON.stringify({
14455
12921
  name: fullName,
14456
12922
  version: "0.1.0",
14457
12923
  description: "A roast-my-codebase plugin",
@@ -14462,7 +12928,7 @@ function createCli() {
14462
12928
  devDependencies: { typescript: "^5.0.0" }
14463
12929
  }, null, 2));
14464
12930
  fs41.writeFileSync(
14465
- path25.join(pluginDir, "src", "index.ts"),
12931
+ path27.join(pluginDir, "src", "index.ts"),
14466
12932
  `import type { Scanner, ScanResult, Finding } from 'roast-my-codebase/types';
14467
12933
 
14468
12934
  export default {
@@ -14479,7 +12945,7 @@ export default {
14479
12945
  };
14480
12946
  `
14481
12947
  );
14482
- fs41.writeFileSync(path25.join(pluginDir, "tsconfig.json"), JSON.stringify({
12948
+ fs41.writeFileSync(path27.join(pluginDir, "tsconfig.json"), JSON.stringify({
14483
12949
  compilerOptions: {
14484
12950
  target: "ES2022",
14485
12951
  module: "NodeNext",
@@ -14506,7 +12972,7 @@ export default {
14506
12972
  console.error(`Error: "${rootDir}" does not exist.`);
14507
12973
  process.exit(1);
14508
12974
  }
14509
- const { BundleSizeScanner: BundleSizeScannerDynamic } = await import("./bundle-OG535XKC.js");
12975
+ const { BundleSizeScanner: BundleSizeScannerDynamic } = await import("./bundle-U2Y5OE4Z.js");
14510
12976
  const scanner = new BundleSizeScannerDynamic();
14511
12977
  const result = await scanner.scan(rootDir);
14512
12978
  const stats = result.stats;
@@ -14544,9 +13010,9 @@ export default {
14544
13010
  process.exit(1);
14545
13011
  }
14546
13012
  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) {
13013
+ const targetFile = path27.resolve(rootDir, options.file);
13014
+ const normalizedRootForFile = path27.resolve(rootDir);
13015
+ if (!targetFile.startsWith(normalizedRootForFile + path27.sep) && targetFile !== normalizedRootForFile) {
14550
13016
  console.error(chalk12.red(`
14551
13017
  Security: --file path must be within the project directory.
14552
13018
  `));
@@ -14596,7 +13062,7 @@ ${options.file} is a directory. Use --file with a specific file.
14596
13062
  ...fileDuplicateResult.findings,
14597
13063
  ...fileDeadExportResult.findings
14598
13064
  );
14599
- const fileExt = path25.extname(targetFile).toLowerCase();
13065
+ const fileExt = path27.extname(targetFile).toLowerCase();
14600
13066
  if (fileExt === ".py") {
14601
13067
  const pyResults = await Promise.all([
14602
13068
  new PythonComplexityScanner().scan(rootDir),
@@ -14625,7 +13091,7 @@ ${options.file} is a directory. Use --file with a specific file.
14625
13091
  fileAllFindings.push(...rsResults.flatMap((r) => r.findings));
14626
13092
  }
14627
13093
  fileSpinner.stop();
14628
- const relFilePath = path25.relative(rootDir, targetFile).replace(/\\/g, "/");
13094
+ const relFilePath = path27.relative(rootDir, targetFile).replace(/\\/g, "/");
14629
13095
  const fileFindings = fileAllFindings.filter(
14630
13096
  (f) => f.file && (f.file === relFilePath || f.file.replace(/\\/g, "/") === relFilePath)
14631
13097
  );
@@ -15217,9 +13683,9 @@ Warning: Custom rules scanner failed: ${error instanceof Error ? error.message :
15217
13683
  return;
15218
13684
  }
15219
13685
  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) {
13686
+ const resolvedOutputDir = path27.resolve(rootDir, options.outputDir);
13687
+ const normalizedRoot = path27.resolve(rootDir);
13688
+ if (!resolvedOutputDir.startsWith(normalizedRoot + path27.sep) && resolvedOutputDir !== normalizedRoot) {
15223
13689
  console.error(chalk12.red(`
15224
13690
  Error: --output-dir path "${options.outputDir}" escapes the project directory.
15225
13691
  `));
@@ -15231,7 +13697,7 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
15231
13697
  \u2713 Reports saved to ${options.outputDir}/
15232
13698
  `));
15233
13699
  for (const file of outputResult.files) {
15234
- console.log(chalk12.dim(` ${path25.basename(file)}`));
13700
+ console.log(chalk12.dim(` ${path27.basename(file)}`));
15235
13701
  }
15236
13702
  console.log();
15237
13703
  } else {
@@ -15391,7 +13857,7 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
15391
13857
  console.error("Analysis failed:", sanitizeError(error));
15392
13858
  if (process.env.DEBUG) {
15393
13859
  try {
15394
- const debugPath = path25.join(rootDir, ".roast-debug.log");
13860
+ const debugPath = path27.join(rootDir, ".roast-debug.log");
15395
13861
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
15396
13862
  const errorStr = error instanceof Error ? error.stack : String(error);
15397
13863
  fs41.appendFileSync(debugPath, `${timestamp}: ${errorStr}
@@ -15406,12 +13872,12 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
15406
13872
  return program2;
15407
13873
  }
15408
13874
  function getProjectName(rootDir) {
15409
- const pkgPath = path25.join(rootDir, "package.json");
13875
+ const pkgPath = path27.join(rootDir, "package.json");
15410
13876
  try {
15411
13877
  const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf-8"));
15412
- return pkg.name || path25.basename(rootDir);
13878
+ return pkg.name || path27.basename(rootDir);
15413
13879
  } catch {
15414
- return path25.basename(rootDir);
13880
+ return path27.basename(rootDir);
15415
13881
  }
15416
13882
  }
15417
13883