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-
|
|
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
|
|
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) => (
|
|
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
|
|
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 [
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1736
|
+
} catch {
|
|
3483
1737
|
continue;
|
|
3484
1738
|
}
|
|
3485
1739
|
}
|
|
@@ -3507,7 +1761,7 @@ var FrameworkScanner = class {
|
|
|
3507
1761
|
});
|
|
3508
1762
|
}
|
|
3509
1763
|
}
|
|
3510
|
-
} catch
|
|
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
|
|
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
|
|
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
|
|
1890
|
+
} catch {
|
|
3637
1891
|
continue;
|
|
3638
1892
|
}
|
|
3639
1893
|
}
|
|
@@ -3670,7 +1924,7 @@ var FrameworkScanner = class {
|
|
|
3670
1924
|
});
|
|
3671
1925
|
}
|
|
3672
1926
|
}
|
|
3673
|
-
} catch
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
7121
|
+
import path16 from "path";
|
|
8867
7122
|
function escapeHtml(text) {
|
|
8868
7123
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
8869
7124
|
}
|
|
@@ -9587,7 +7842,7 @@ function renderHtmlReport(report) {
|
|
|
9587
7842
|
</html>`;
|
|
9588
7843
|
}
|
|
9589
7844
|
function saveHtmlReport(html, rootDir) {
|
|
9590
|
-
const outputPath =
|
|
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,
|
|
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:
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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 =
|
|
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
|
|
10456
|
+
import path24 from "path";
|
|
11991
10457
|
function detectPackageManager(rootDir) {
|
|
11992
|
-
if (fs38.existsSync(
|
|
11993
|
-
if (fs38.existsSync(
|
|
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 =
|
|
12050
|
-
const filePath =
|
|
12051
|
-
const displayPath = filePath.split(
|
|
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
|
|
10654
|
+
import path25 from "path";
|
|
12189
10655
|
function detectHuskySetup(rootDir) {
|
|
12190
|
-
const huskyDir =
|
|
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 =
|
|
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 =
|
|
12216
|
-
const hookPath =
|
|
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 =
|
|
12264
|
-
const hooksDir =
|
|
12265
|
-
const hookPath =
|
|
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 =
|
|
12329
|
-
const gitHook =
|
|
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
|
|
11705
|
+
let _currentReport = report;
|
|
13240
11706
|
let currentHtml = generateDashboardHtml(report);
|
|
13241
|
-
let
|
|
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
|
-
|
|
11743
|
+
_currentReport = newReport;
|
|
13278
11744
|
currentHtml = generateDashboardHtml(newReport);
|
|
13279
|
-
|
|
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(
|
|
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
|
-
|
|
11807
|
+
_currentReport = newReport;
|
|
13342
11808
|
currentHtml = generateDashboardHtml(newReport);
|
|
13343
|
-
|
|
11809
|
+
_currentReportJson = JSON.stringify(newReport);
|
|
13344
11810
|
broadcast({ type: "update", report: newReport });
|
|
13345
11811
|
console.log(` \u21BB Dashboard updated (${changedPath})`);
|
|
13346
|
-
} catch
|
|
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
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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 =
|
|
14313
|
-
while (dir !==
|
|
14314
|
-
const pkgPath =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
12918
|
+
fs41.mkdirSync(path27.join(pluginDir, "src"), { recursive: true });
|
|
14453
12919
|
}
|
|
14454
|
-
fs41.writeFileSync(
|
|
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
|
-
|
|
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(
|
|
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-
|
|
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 =
|
|
14548
|
-
const normalizedRootForFile =
|
|
14549
|
-
if (!targetFile.startsWith(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 =
|
|
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 =
|
|
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 =
|
|
15221
|
-
const normalizedRoot =
|
|
15222
|
-
if (!resolvedOutputDir.startsWith(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(` ${
|
|
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 =
|
|
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 =
|
|
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 ||
|
|
13878
|
+
return pkg.name || path27.basename(rootDir);
|
|
15413
13879
|
} catch {
|
|
15414
|
-
return
|
|
13880
|
+
return path27.basename(rootDir);
|
|
15415
13881
|
}
|
|
15416
13882
|
}
|
|
15417
13883
|
|