roast-my-codebase 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -6,1758 +6,12 @@ import {
|
|
|
6
6
|
LARGE_FILE_THRESHOLDS,
|
|
7
7
|
SAFE_GLOB_OPTIONS,
|
|
8
8
|
SOURCE_EXTENSIONS,
|
|
9
|
-
__commonJS,
|
|
10
|
-
__require,
|
|
11
|
-
__toESM,
|
|
12
9
|
buildIgnorePatterns
|
|
13
|
-
} from "./chunk-
|
|
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) {
|
|
@@ -10388,7 +8816,7 @@ function getScoreColor3(score) {
|
|
|
10388
8816
|
if (score >= 60) return chalk4.rgb(255, 165, 0);
|
|
10389
8817
|
return chalk4.red;
|
|
10390
8818
|
}
|
|
10391
|
-
function
|
|
8819
|
+
function renderHealthBar2(score) {
|
|
10392
8820
|
const width = 30;
|
|
10393
8821
|
const filled = Math.round(score / 100 * width);
|
|
10394
8822
|
const empty = width - filled;
|
|
@@ -10533,7 +8961,7 @@ function renderWatchSummary(health, delta, findingCounts2) {
|
|
|
10533
8961
|
}
|
|
10534
8962
|
|
|
10535
8963
|
// src/compare/index.ts
|
|
10536
|
-
import
|
|
8964
|
+
import path19 from "path";
|
|
10537
8965
|
import fs33 from "fs";
|
|
10538
8966
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
10539
8967
|
import { randomBytes } from "crypto";
|
|
@@ -10562,7 +8990,7 @@ async function compareWithBranch(rootDir, branchName, scanFunc) {
|
|
|
10562
8990
|
console.log(chalk6.dim(`Scanning current working directory...`));
|
|
10563
8991
|
const currentResult = await scanFunc(rootDir);
|
|
10564
8992
|
const randomId = randomBytes(8).toString("hex");
|
|
10565
|
-
const worktreePath =
|
|
8993
|
+
const worktreePath = path19.join(tmpdir(), `.roast-worktree-${randomId}`);
|
|
10566
8994
|
console.log(chalk6.dim(`Checking out ${branchName} to temporary worktree...`));
|
|
10567
8995
|
let cleanupAttempted = false;
|
|
10568
8996
|
const cleanupWorktree = async (retries = 3) => {
|
|
@@ -10655,7 +9083,7 @@ function renderComparison(comparison, branchName) {
|
|
|
10655
9083
|
|
|
10656
9084
|
// src/config/index.ts
|
|
10657
9085
|
import fs34 from "fs";
|
|
10658
|
-
import
|
|
9086
|
+
import path20 from "path";
|
|
10659
9087
|
|
|
10660
9088
|
// src/config/validation.ts
|
|
10661
9089
|
function validateConfig(userConfig) {
|
|
@@ -10801,7 +9229,7 @@ function safeJsonParse(content) {
|
|
|
10801
9229
|
return cleaned;
|
|
10802
9230
|
}
|
|
10803
9231
|
return parsed;
|
|
10804
|
-
} catch
|
|
9232
|
+
} catch {
|
|
10805
9233
|
return null;
|
|
10806
9234
|
}
|
|
10807
9235
|
}
|
|
@@ -10826,7 +9254,7 @@ var DEFAULT_CONFIG = {
|
|
|
10826
9254
|
notify: void 0
|
|
10827
9255
|
};
|
|
10828
9256
|
function loadConfig(rootDir) {
|
|
10829
|
-
const configPath =
|
|
9257
|
+
const configPath = path20.join(rootDir, ".roastrc.json");
|
|
10830
9258
|
if (!fs34.existsSync(configPath)) {
|
|
10831
9259
|
return DEFAULT_CONFIG;
|
|
10832
9260
|
}
|
|
@@ -10898,7 +9326,7 @@ import chalk7 from "chalk";
|
|
|
10898
9326
|
|
|
10899
9327
|
// src/interactive/fixes.ts
|
|
10900
9328
|
import fs35 from "fs";
|
|
10901
|
-
import
|
|
9329
|
+
import path21 from "path";
|
|
10902
9330
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
10903
9331
|
async function applyAutoFix(finding, fix, rootDir, dryRun = false) {
|
|
10904
9332
|
switch (finding.category) {
|
|
@@ -10979,7 +9407,7 @@ function fixTodoComment(finding, rootDir, dryRun) {
|
|
|
10979
9407
|
message: "No file specified for TODO fix"
|
|
10980
9408
|
};
|
|
10981
9409
|
}
|
|
10982
|
-
const filePath =
|
|
9410
|
+
const filePath = path21.join(rootDir, finding.file);
|
|
10983
9411
|
try {
|
|
10984
9412
|
const content = fs35.readFileSync(filePath, "utf-8");
|
|
10985
9413
|
const lines = content.split("\n");
|
|
@@ -11036,7 +9464,7 @@ function fixDeadExport(finding, rootDir, dryRun) {
|
|
|
11036
9464
|
};
|
|
11037
9465
|
}
|
|
11038
9466
|
const exportName = match[1];
|
|
11039
|
-
const filePath =
|
|
9467
|
+
const filePath = path21.join(rootDir, finding.file);
|
|
11040
9468
|
try {
|
|
11041
9469
|
const content = fs35.readFileSync(filePath, "utf-8");
|
|
11042
9470
|
const lines = content.split("\n");
|
|
@@ -11080,7 +9508,7 @@ function fixNextjsClientServer(finding, rootDir, dryRun) {
|
|
|
11080
9508
|
if (!finding.file) {
|
|
11081
9509
|
return { success: false, message: "No file specified for nextjs-client-server fix" };
|
|
11082
9510
|
}
|
|
11083
|
-
const filePath =
|
|
9511
|
+
const filePath = path21.join(rootDir, finding.file);
|
|
11084
9512
|
try {
|
|
11085
9513
|
const content = fs35.readFileSync(filePath, "utf-8");
|
|
11086
9514
|
if (content.includes("'use client'") || content.includes('"use client"')) {
|
|
@@ -11104,7 +9532,7 @@ function fixNextjsMetadata(finding, rootDir, dryRun) {
|
|
|
11104
9532
|
if (!finding.file) {
|
|
11105
9533
|
return { success: false, message: "No file specified for nextjs-metadata fix" };
|
|
11106
9534
|
}
|
|
11107
|
-
const filePath =
|
|
9535
|
+
const filePath = path21.join(rootDir, finding.file);
|
|
11108
9536
|
try {
|
|
11109
9537
|
const content = fs35.readFileSync(filePath, "utf-8");
|
|
11110
9538
|
if (/export.*metadata/.test(content)) {
|
|
@@ -11124,7 +9552,7 @@ function fixNextjsMetadata(finding, rootDir, dryRun) {
|
|
|
11124
9552
|
}
|
|
11125
9553
|
}
|
|
11126
9554
|
function fixGitignoreEntry(rootDir, filename, dryRun) {
|
|
11127
|
-
const gitignorePath =
|
|
9555
|
+
const gitignorePath = path21.join(rootDir, ".gitignore");
|
|
11128
9556
|
try {
|
|
11129
9557
|
let existing = "";
|
|
11130
9558
|
if (fs35.existsSync(gitignorePath)) {
|
|
@@ -11151,7 +9579,7 @@ function fixEnvInGit(finding, rootDir, dryRun) {
|
|
|
11151
9579
|
if (!finding.file) {
|
|
11152
9580
|
return { success: false, message: "No file specified for env-in-git fix" };
|
|
11153
9581
|
}
|
|
11154
|
-
const filename =
|
|
9582
|
+
const filename = path21.basename(finding.file);
|
|
11155
9583
|
const result = fixGitignoreEntry(rootDir, filename, dryRun);
|
|
11156
9584
|
if (result.success) {
|
|
11157
9585
|
return {
|
|
@@ -11168,7 +9596,7 @@ function fixTypeSafety(finding, rootDir, dryRun) {
|
|
|
11168
9596
|
if (!finding.file) {
|
|
11169
9597
|
return { success: false, message: "No file specified for type-safety fix" };
|
|
11170
9598
|
}
|
|
11171
|
-
const filePath =
|
|
9599
|
+
const filePath = path21.join(rootDir, finding.file);
|
|
11172
9600
|
try {
|
|
11173
9601
|
const content = fs35.readFileSync(filePath, "utf-8");
|
|
11174
9602
|
const lines = content.split("\n");
|
|
@@ -11207,11 +9635,11 @@ function fixTestCoverage(finding, rootDir, dryRun) {
|
|
|
11207
9635
|
}
|
|
11208
9636
|
const srcRelative = finding.file.replace(/^src\//, "");
|
|
11209
9637
|
const testRelative = `tests/${srcRelative.replace(/\.tsx?$/, ".test.ts")}`;
|
|
11210
|
-
const testPath =
|
|
9638
|
+
const testPath = path21.join(rootDir, testRelative);
|
|
11211
9639
|
if (fs35.existsSync(testPath)) {
|
|
11212
9640
|
return { success: false, message: `Test file already exists: ${testRelative}` };
|
|
11213
9641
|
}
|
|
11214
|
-
const baseName =
|
|
9642
|
+
const baseName = path21.basename(finding.file, path21.extname(finding.file));
|
|
11215
9643
|
const skeleton = `import { describe, it, expect } from 'vitest';
|
|
11216
9644
|
|
|
11217
9645
|
describe('${baseName}', () => {
|
|
@@ -11225,7 +9653,7 @@ describe('${baseName}', () => {
|
|
|
11225
9653
|
return { success: true, message: `Would create test file: ${testRelative}` };
|
|
11226
9654
|
}
|
|
11227
9655
|
try {
|
|
11228
|
-
fs35.mkdirSync(
|
|
9656
|
+
fs35.mkdirSync(path21.dirname(testPath), { recursive: true });
|
|
11229
9657
|
fs35.writeFileSync(testPath, skeleton, "utf-8");
|
|
11230
9658
|
return { success: true, message: `Created test file: ${testRelative}` };
|
|
11231
9659
|
} catch (error) {
|
|
@@ -11239,7 +9667,7 @@ function fixSecrets(finding, rootDir, dryRun) {
|
|
|
11239
9667
|
if (!finding.file) {
|
|
11240
9668
|
return { success: false, message: "No file specified for secrets fix" };
|
|
11241
9669
|
}
|
|
11242
|
-
const filename =
|
|
9670
|
+
const filename = path21.basename(finding.file);
|
|
11243
9671
|
const result = fixGitignoreEntry(rootDir, filename, dryRun);
|
|
11244
9672
|
const warning = " WARNING: The secret may already be in git history \u2014 consider rotating it and running: git filter-branch or git-filter-repo";
|
|
11245
9673
|
if (result.success) {
|
|
@@ -11525,11 +9953,11 @@ function getSeverityBadge(severity) {
|
|
|
11525
9953
|
|
|
11526
9954
|
// src/history/index.ts
|
|
11527
9955
|
import fs36 from "fs";
|
|
11528
|
-
import
|
|
9956
|
+
import path22 from "path";
|
|
11529
9957
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
11530
9958
|
var HISTORY_FILE = ".roast-history.json";
|
|
11531
9959
|
function loadHistory(rootDir) {
|
|
11532
|
-
const historyPath =
|
|
9960
|
+
const historyPath = path22.join(rootDir, HISTORY_FILE);
|
|
11533
9961
|
if (!fs36.existsSync(historyPath)) {
|
|
11534
9962
|
return null;
|
|
11535
9963
|
}
|
|
@@ -11542,7 +9970,7 @@ function loadHistory(rootDir) {
|
|
|
11542
9970
|
}
|
|
11543
9971
|
}
|
|
11544
9972
|
function saveHistory(rootDir, history) {
|
|
11545
|
-
const historyPath =
|
|
9973
|
+
const historyPath = path22.join(rootDir, HISTORY_FILE);
|
|
11546
9974
|
try {
|
|
11547
9975
|
fs36.writeFileSync(historyPath, JSON.stringify(history, null, 2), "utf-8");
|
|
11548
9976
|
} catch (error) {
|
|
@@ -11860,7 +10288,7 @@ function getTrendColor(trend) {
|
|
|
11860
10288
|
// src/incremental/index.ts
|
|
11861
10289
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
11862
10290
|
import fs37 from "fs";
|
|
11863
|
-
import
|
|
10291
|
+
import path23 from "path";
|
|
11864
10292
|
function getChangedFiles(rootDir, baseRef) {
|
|
11865
10293
|
const gitCheck = spawnSync7("git", ["rev-parse", "--git-dir"], {
|
|
11866
10294
|
cwd: rootDir,
|
|
@@ -11878,7 +10306,7 @@ function getChangedFiles(rootDir, baseRef) {
|
|
|
11878
10306
|
if (diffResult.status !== 0) {
|
|
11879
10307
|
return { changedFiles: [], isIncremental: true, baseRef };
|
|
11880
10308
|
}
|
|
11881
|
-
const files = parseGitOutput(diffResult.stdout).map((f) =>
|
|
10309
|
+
const files = parseGitOutput(diffResult.stdout).map((f) => path23.join(rootDir, f)).filter((f) => fs37.existsSync(f));
|
|
11882
10310
|
return { changedFiles: files, isIncremental: true, baseRef };
|
|
11883
10311
|
}
|
|
11884
10312
|
const unstagedResult = spawnSync7(
|
|
@@ -11894,7 +10322,7 @@ function getChangedFiles(rootDir, baseRef) {
|
|
|
11894
10322
|
const unstagedFiles = unstagedResult.status === 0 ? parseGitOutput(unstagedResult.stdout) : [];
|
|
11895
10323
|
const stagedFiles = stagedResult.status === 0 ? parseGitOutput(stagedResult.stdout) : [];
|
|
11896
10324
|
const merged = Array.from(/* @__PURE__ */ new Set([...unstagedFiles, ...stagedFiles]));
|
|
11897
|
-
const changedFiles = merged.map((f) =>
|
|
10325
|
+
const changedFiles = merged.map((f) => path23.join(rootDir, f)).filter((f) => fs37.existsSync(f));
|
|
11898
10326
|
return { changedFiles, isIncremental: true, baseRef: "HEAD" };
|
|
11899
10327
|
}
|
|
11900
10328
|
function parseGitOutput(stdout) {
|
|
@@ -11905,13 +10333,13 @@ function filterFindingsByFiles(findings, changedFiles, rootDir) {
|
|
|
11905
10333
|
return findings.filter((f) => !f.file);
|
|
11906
10334
|
}
|
|
11907
10335
|
const normalizedChanged = new Set(
|
|
11908
|
-
changedFiles.map((f) =>
|
|
10336
|
+
changedFiles.map((f) => path23.normalize(f))
|
|
11909
10337
|
);
|
|
11910
10338
|
return findings.filter((finding) => {
|
|
11911
10339
|
if (!finding.file) {
|
|
11912
10340
|
return true;
|
|
11913
10341
|
}
|
|
11914
|
-
const findingAbsolute =
|
|
10342
|
+
const findingAbsolute = path23.isAbsolute(finding.file) ? path23.normalize(finding.file) : path23.normalize(path23.join(rootDir, finding.file));
|
|
11915
10343
|
const findingForward = findingAbsolute.replace(/\\/g, "/");
|
|
11916
10344
|
const findingBackward = findingAbsolute.replace(/\//g, "\\");
|
|
11917
10345
|
if (normalizedChanged.has(findingAbsolute)) {
|
|
@@ -11987,10 +10415,10 @@ function filterFindingsByChangedLines(findings, changedRanges) {
|
|
|
11987
10415
|
|
|
11988
10416
|
// src/ci/index.ts
|
|
11989
10417
|
import fs38 from "fs";
|
|
11990
|
-
import
|
|
10418
|
+
import path24 from "path";
|
|
11991
10419
|
function detectPackageManager(rootDir) {
|
|
11992
|
-
if (fs38.existsSync(
|
|
11993
|
-
if (fs38.existsSync(
|
|
10420
|
+
if (fs38.existsSync(path24.join(rootDir, "yarn.lock"))) return "yarn";
|
|
10421
|
+
if (fs38.existsSync(path24.join(rootDir, "pnpm-lock.yaml"))) return "pnpm";
|
|
11994
10422
|
return "npm";
|
|
11995
10423
|
}
|
|
11996
10424
|
function generateCIWorkflow(config) {
|
|
@@ -12046,9 +10474,9 @@ ${permissionsBlock}
|
|
|
12046
10474
|
`;
|
|
12047
10475
|
}
|
|
12048
10476
|
function writeCIWorkflow(rootDir, config) {
|
|
12049
|
-
const workflowsDir =
|
|
12050
|
-
const filePath =
|
|
12051
|
-
const displayPath = filePath.split(
|
|
10477
|
+
const workflowsDir = path24.join(rootDir, ".github", "workflows");
|
|
10478
|
+
const filePath = path24.join(workflowsDir, "roast.yml");
|
|
10479
|
+
const displayPath = filePath.split(path24.sep).join("/");
|
|
12052
10480
|
if (fs38.existsSync(filePath)) {
|
|
12053
10481
|
return { path: displayPath, alreadyExists: true };
|
|
12054
10482
|
}
|
|
@@ -12185,13 +10613,13 @@ function formatTrendResult(result) {
|
|
|
12185
10613
|
|
|
12186
10614
|
// src/hooks/index.ts
|
|
12187
10615
|
import fs39 from "fs";
|
|
12188
|
-
import
|
|
10616
|
+
import path25 from "path";
|
|
12189
10617
|
function detectHuskySetup(rootDir) {
|
|
12190
|
-
const huskyDir =
|
|
10618
|
+
const huskyDir = path25.join(rootDir, ".husky");
|
|
12191
10619
|
if (fs39.existsSync(huskyDir) && fs39.statSync(huskyDir).isDirectory()) {
|
|
12192
10620
|
return true;
|
|
12193
10621
|
}
|
|
12194
|
-
const pkgPath =
|
|
10622
|
+
const pkgPath = path25.join(rootDir, "package.json");
|
|
12195
10623
|
if (fs39.existsSync(pkgPath)) {
|
|
12196
10624
|
try {
|
|
12197
10625
|
const pkg = JSON.parse(fs39.readFileSync(pkgPath, "utf-8"));
|
|
@@ -12212,8 +10640,8 @@ function installPreCommitHook(rootDir, threshold) {
|
|
|
12212
10640
|
}
|
|
12213
10641
|
}
|
|
12214
10642
|
function _installHuskyHook(rootDir, threshold) {
|
|
12215
|
-
const huskyDir =
|
|
12216
|
-
const hookPath =
|
|
10643
|
+
const huskyDir = path25.join(rootDir, ".husky");
|
|
10644
|
+
const hookPath = path25.join(huskyDir, "pre-commit");
|
|
12217
10645
|
try {
|
|
12218
10646
|
if (!fs39.existsSync(huskyDir)) {
|
|
12219
10647
|
fs39.mkdirSync(huskyDir, { recursive: true });
|
|
@@ -12260,9 +10688,9 @@ function _installHuskyHook(rootDir, threshold) {
|
|
|
12260
10688
|
}
|
|
12261
10689
|
}
|
|
12262
10690
|
function _installGitHook(rootDir, threshold) {
|
|
12263
|
-
const gitDir =
|
|
12264
|
-
const hooksDir =
|
|
12265
|
-
const hookPath =
|
|
10691
|
+
const gitDir = path25.join(rootDir, ".git");
|
|
10692
|
+
const hooksDir = path25.join(gitDir, "hooks");
|
|
10693
|
+
const hookPath = path25.join(hooksDir, "pre-commit");
|
|
12266
10694
|
if (!fs39.existsSync(gitDir) || !fs39.statSync(gitDir).isDirectory()) {
|
|
12267
10695
|
return {
|
|
12268
10696
|
success: false,
|
|
@@ -12325,8 +10753,8 @@ function _installGitHook(rootDir, threshold) {
|
|
|
12325
10753
|
}
|
|
12326
10754
|
}
|
|
12327
10755
|
function uninstallPreCommitHook(rootDir) {
|
|
12328
|
-
const huskyHook =
|
|
12329
|
-
const gitHook =
|
|
10756
|
+
const huskyHook = path25.join(rootDir, ".husky", "pre-commit");
|
|
10757
|
+
const gitHook = path25.join(rootDir, ".git", "hooks", "pre-commit");
|
|
12330
10758
|
let targetPath = null;
|
|
12331
10759
|
if (fs39.existsSync(huskyHook)) {
|
|
12332
10760
|
const content = fs39.readFileSync(huskyHook, "utf-8");
|
|
@@ -13236,9 +11664,9 @@ function generateDashboardHtml(report) {
|
|
|
13236
11664
|
</html>`;
|
|
13237
11665
|
}
|
|
13238
11666
|
function startDashboard(report, port = 7777, options) {
|
|
13239
|
-
let
|
|
11667
|
+
let _currentReport = report;
|
|
13240
11668
|
let currentHtml = generateDashboardHtml(report);
|
|
13241
|
-
let
|
|
11669
|
+
let _currentReportJson = JSON.stringify(report);
|
|
13242
11670
|
const sseClients = /* @__PURE__ */ new Set();
|
|
13243
11671
|
let isRescanning = false;
|
|
13244
11672
|
function broadcast(data) {
|
|
@@ -13274,9 +11702,9 @@ function startDashboard(report, port = 7777, options) {
|
|
|
13274
11702
|
isRescanning = true;
|
|
13275
11703
|
broadcast({ type: "scanning", file: "manual" });
|
|
13276
11704
|
options.rescan().then((newReport) => {
|
|
13277
|
-
|
|
11705
|
+
_currentReport = newReport;
|
|
13278
11706
|
currentHtml = generateDashboardHtml(newReport);
|
|
13279
|
-
|
|
11707
|
+
_currentReportJson = JSON.stringify(newReport);
|
|
13280
11708
|
broadcast({ type: "update", report: newReport });
|
|
13281
11709
|
isRescanning = false;
|
|
13282
11710
|
}).catch(() => {
|
|
@@ -13291,7 +11719,7 @@ function startDashboard(report, port = 7777, options) {
|
|
|
13291
11719
|
res.end(currentHtml);
|
|
13292
11720
|
} else if (req.method === "GET" && url === "/api/report") {
|
|
13293
11721
|
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
13294
|
-
res.end(
|
|
11722
|
+
res.end(_currentReportJson);
|
|
13295
11723
|
} else if (req.method === "GET" && url === "/health") {
|
|
13296
11724
|
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
13297
11725
|
res.end('{"ok":true}');
|
|
@@ -13338,12 +11766,12 @@ function startDashboard(report, port = 7777, options) {
|
|
|
13338
11766
|
broadcast({ type: "scanning", file: changedPath });
|
|
13339
11767
|
try {
|
|
13340
11768
|
const newReport = await options.rescan();
|
|
13341
|
-
|
|
11769
|
+
_currentReport = newReport;
|
|
13342
11770
|
currentHtml = generateDashboardHtml(newReport);
|
|
13343
|
-
|
|
11771
|
+
_currentReportJson = JSON.stringify(newReport);
|
|
13344
11772
|
broadcast({ type: "update", report: newReport });
|
|
13345
11773
|
console.log(` \u21BB Dashboard updated (${changedPath})`);
|
|
13346
|
-
} catch
|
|
11774
|
+
} catch {
|
|
13347
11775
|
broadcast({ type: "error", message: "Rescan failed" });
|
|
13348
11776
|
} finally {
|
|
13349
11777
|
isRescanning = false;
|
|
@@ -13379,11 +11807,11 @@ function startDashboard(report, port = 7777, options) {
|
|
|
13379
11807
|
|
|
13380
11808
|
// src/readme/index.ts
|
|
13381
11809
|
import fs40 from "fs";
|
|
13382
|
-
import
|
|
11810
|
+
import path26 from "path";
|
|
13383
11811
|
function findReadmePath(rootDir) {
|
|
13384
11812
|
const candidates = ["README.md", "readme.md", "README.MD", "Readme.md"];
|
|
13385
11813
|
for (const name of candidates) {
|
|
13386
|
-
const fullPath =
|
|
11814
|
+
const fullPath = path26.join(rootDir, name);
|
|
13387
11815
|
if (fs40.existsSync(fullPath)) {
|
|
13388
11816
|
return fullPath;
|
|
13389
11817
|
}
|
|
@@ -13403,7 +11831,7 @@ function updateReadmeBadge(rootDir, health) {
|
|
|
13403
11831
|
${badgeLine}
|
|
13404
11832
|
<!-- roast-score-end -->`;
|
|
13405
11833
|
const newContent2 = previousContent.replace(blockPattern, replacement);
|
|
13406
|
-
validateOutputPath(rootDir,
|
|
11834
|
+
validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
|
|
13407
11835
|
fs40.writeFileSync(readmePath, newContent2, "utf-8");
|
|
13408
11836
|
return { updated: true, method: "html-comment", previousContent };
|
|
13409
11837
|
}
|
|
@@ -13414,7 +11842,7 @@ ${badgeLine}
|
|
|
13414
11842
|
if (badgeLineIndex !== -1) {
|
|
13415
11843
|
lines[badgeLineIndex] = badgeLine;
|
|
13416
11844
|
const newContent2 = lines.join("\n");
|
|
13417
|
-
validateOutputPath(rootDir,
|
|
11845
|
+
validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
|
|
13418
11846
|
fs40.writeFileSync(readmePath, newContent2, "utf-8");
|
|
13419
11847
|
return { updated: true, method: "badge-line", previousContent };
|
|
13420
11848
|
}
|
|
@@ -13427,7 +11855,7 @@ ${badgeLine}
|
|
|
13427
11855
|
Generated by [roast-my-codebase](https://github.com/rahuldk1105/roast-my-codebase)
|
|
13428
11856
|
<!-- roast-score-end -->`;
|
|
13429
11857
|
const newContent = previousContent + appendBlock;
|
|
13430
|
-
validateOutputPath(rootDir,
|
|
11858
|
+
validateOutputPath(rootDir, path26.relative(rootDir, readmePath));
|
|
13431
11859
|
fs40.writeFileSync(readmePath, newContent, "utf-8");
|
|
13432
11860
|
return { updated: true, method: "appended", previousContent };
|
|
13433
11861
|
}
|
|
@@ -14309,14 +12737,14 @@ var EXIT_CODES = {
|
|
|
14309
12737
|
// src/cli/index.ts
|
|
14310
12738
|
function loadPackageVersion() {
|
|
14311
12739
|
const __filename = fileURLToPath(import.meta.url);
|
|
14312
|
-
let dir =
|
|
14313
|
-
while (dir !==
|
|
14314
|
-
const pkgPath =
|
|
12740
|
+
let dir = path27.dirname(__filename);
|
|
12741
|
+
while (dir !== path27.dirname(dir)) {
|
|
12742
|
+
const pkgPath = path27.join(dir, "package.json");
|
|
14315
12743
|
if (fs41.existsSync(pkgPath)) {
|
|
14316
12744
|
const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf-8"));
|
|
14317
12745
|
if (pkg.name === "roast-my-codebase") return pkg.version;
|
|
14318
12746
|
}
|
|
14319
|
-
dir =
|
|
12747
|
+
dir = path27.dirname(dir);
|
|
14320
12748
|
}
|
|
14321
12749
|
return "1.0.0";
|
|
14322
12750
|
}
|
|
@@ -14327,7 +12755,7 @@ function createCli() {
|
|
|
14327
12755
|
"Exit with code 1 if health score is below threshold (use with --json)",
|
|
14328
12756
|
parseInt
|
|
14329
12757
|
).action(async (targetPath, options) => {
|
|
14330
|
-
const rootDir =
|
|
12758
|
+
const rootDir = path27.resolve(targetPath);
|
|
14331
12759
|
if (options.explain !== void 0) {
|
|
14332
12760
|
if (options.explain === true || options.explain === "") {
|
|
14333
12761
|
console.log(chalk12.bold("\n Available categories:\n"));
|
|
@@ -14441,7 +12869,7 @@ function createCli() {
|
|
|
14441
12869
|
process.exit(1);
|
|
14442
12870
|
}
|
|
14443
12871
|
try {
|
|
14444
|
-
fs41.mkdirSync(
|
|
12872
|
+
fs41.mkdirSync(path27.join(pluginDir, "src"), { recursive: false });
|
|
14445
12873
|
} catch (e) {
|
|
14446
12874
|
if (e.code === "EEXIST") {
|
|
14447
12875
|
console.log(chalk12.yellow(`
|
|
@@ -14449,9 +12877,9 @@ function createCli() {
|
|
|
14449
12877
|
`));
|
|
14450
12878
|
process.exit(1);
|
|
14451
12879
|
}
|
|
14452
|
-
fs41.mkdirSync(
|
|
12880
|
+
fs41.mkdirSync(path27.join(pluginDir, "src"), { recursive: true });
|
|
14453
12881
|
}
|
|
14454
|
-
fs41.writeFileSync(
|
|
12882
|
+
fs41.writeFileSync(path27.join(pluginDir, "package.json"), JSON.stringify({
|
|
14455
12883
|
name: fullName,
|
|
14456
12884
|
version: "0.1.0",
|
|
14457
12885
|
description: "A roast-my-codebase plugin",
|
|
@@ -14462,7 +12890,7 @@ function createCli() {
|
|
|
14462
12890
|
devDependencies: { typescript: "^5.0.0" }
|
|
14463
12891
|
}, null, 2));
|
|
14464
12892
|
fs41.writeFileSync(
|
|
14465
|
-
|
|
12893
|
+
path27.join(pluginDir, "src", "index.ts"),
|
|
14466
12894
|
`import type { Scanner, ScanResult, Finding } from 'roast-my-codebase/types';
|
|
14467
12895
|
|
|
14468
12896
|
export default {
|
|
@@ -14479,7 +12907,7 @@ export default {
|
|
|
14479
12907
|
};
|
|
14480
12908
|
`
|
|
14481
12909
|
);
|
|
14482
|
-
fs41.writeFileSync(
|
|
12910
|
+
fs41.writeFileSync(path27.join(pluginDir, "tsconfig.json"), JSON.stringify({
|
|
14483
12911
|
compilerOptions: {
|
|
14484
12912
|
target: "ES2022",
|
|
14485
12913
|
module: "NodeNext",
|
|
@@ -14506,7 +12934,7 @@ export default {
|
|
|
14506
12934
|
console.error(`Error: "${rootDir}" does not exist.`);
|
|
14507
12935
|
process.exit(1);
|
|
14508
12936
|
}
|
|
14509
|
-
const { BundleSizeScanner: BundleSizeScannerDynamic } = await import("./bundle-
|
|
12937
|
+
const { BundleSizeScanner: BundleSizeScannerDynamic } = await import("./bundle-U2Y5OE4Z.js");
|
|
14510
12938
|
const scanner = new BundleSizeScannerDynamic();
|
|
14511
12939
|
const result = await scanner.scan(rootDir);
|
|
14512
12940
|
const stats = result.stats;
|
|
@@ -14544,9 +12972,9 @@ export default {
|
|
|
14544
12972
|
process.exit(1);
|
|
14545
12973
|
}
|
|
14546
12974
|
if (options.file) {
|
|
14547
|
-
const targetFile =
|
|
14548
|
-
const normalizedRootForFile =
|
|
14549
|
-
if (!targetFile.startsWith(normalizedRootForFile +
|
|
12975
|
+
const targetFile = path27.resolve(rootDir, options.file);
|
|
12976
|
+
const normalizedRootForFile = path27.resolve(rootDir);
|
|
12977
|
+
if (!targetFile.startsWith(normalizedRootForFile + path27.sep) && targetFile !== normalizedRootForFile) {
|
|
14550
12978
|
console.error(chalk12.red(`
|
|
14551
12979
|
Security: --file path must be within the project directory.
|
|
14552
12980
|
`));
|
|
@@ -14596,7 +13024,7 @@ ${options.file} is a directory. Use --file with a specific file.
|
|
|
14596
13024
|
...fileDuplicateResult.findings,
|
|
14597
13025
|
...fileDeadExportResult.findings
|
|
14598
13026
|
);
|
|
14599
|
-
const fileExt =
|
|
13027
|
+
const fileExt = path27.extname(targetFile).toLowerCase();
|
|
14600
13028
|
if (fileExt === ".py") {
|
|
14601
13029
|
const pyResults = await Promise.all([
|
|
14602
13030
|
new PythonComplexityScanner().scan(rootDir),
|
|
@@ -14625,7 +13053,7 @@ ${options.file} is a directory. Use --file with a specific file.
|
|
|
14625
13053
|
fileAllFindings.push(...rsResults.flatMap((r) => r.findings));
|
|
14626
13054
|
}
|
|
14627
13055
|
fileSpinner.stop();
|
|
14628
|
-
const relFilePath =
|
|
13056
|
+
const relFilePath = path27.relative(rootDir, targetFile).replace(/\\/g, "/");
|
|
14629
13057
|
const fileFindings = fileAllFindings.filter(
|
|
14630
13058
|
(f) => f.file && (f.file === relFilePath || f.file.replace(/\\/g, "/") === relFilePath)
|
|
14631
13059
|
);
|
|
@@ -15217,9 +13645,9 @@ Warning: Custom rules scanner failed: ${error instanceof Error ? error.message :
|
|
|
15217
13645
|
return;
|
|
15218
13646
|
}
|
|
15219
13647
|
if (options.outputDir) {
|
|
15220
|
-
const resolvedOutputDir =
|
|
15221
|
-
const normalizedRoot =
|
|
15222
|
-
if (!resolvedOutputDir.startsWith(normalizedRoot +
|
|
13648
|
+
const resolvedOutputDir = path27.resolve(rootDir, options.outputDir);
|
|
13649
|
+
const normalizedRoot = path27.resolve(rootDir);
|
|
13650
|
+
if (!resolvedOutputDir.startsWith(normalizedRoot + path27.sep) && resolvedOutputDir !== normalizedRoot) {
|
|
15223
13651
|
console.error(chalk12.red(`
|
|
15224
13652
|
Error: --output-dir path "${options.outputDir}" escapes the project directory.
|
|
15225
13653
|
`));
|
|
@@ -15231,7 +13659,7 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
|
|
|
15231
13659
|
\u2713 Reports saved to ${options.outputDir}/
|
|
15232
13660
|
`));
|
|
15233
13661
|
for (const file of outputResult.files) {
|
|
15234
|
-
console.log(chalk12.dim(` ${
|
|
13662
|
+
console.log(chalk12.dim(` ${path27.basename(file)}`));
|
|
15235
13663
|
}
|
|
15236
13664
|
console.log();
|
|
15237
13665
|
} else {
|
|
@@ -15391,7 +13819,7 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
|
|
|
15391
13819
|
console.error("Analysis failed:", sanitizeError(error));
|
|
15392
13820
|
if (process.env.DEBUG) {
|
|
15393
13821
|
try {
|
|
15394
|
-
const debugPath =
|
|
13822
|
+
const debugPath = path27.join(rootDir, ".roast-debug.log");
|
|
15395
13823
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15396
13824
|
const errorStr = error instanceof Error ? error.stack : String(error);
|
|
15397
13825
|
fs41.appendFileSync(debugPath, `${timestamp}: ${errorStr}
|
|
@@ -15406,12 +13834,12 @@ Error: --output-dir path "${options.outputDir}" escapes the project directory.
|
|
|
15406
13834
|
return program2;
|
|
15407
13835
|
}
|
|
15408
13836
|
function getProjectName(rootDir) {
|
|
15409
|
-
const pkgPath =
|
|
13837
|
+
const pkgPath = path27.join(rootDir, "package.json");
|
|
15410
13838
|
try {
|
|
15411
13839
|
const pkg = JSON.parse(fs41.readFileSync(pkgPath, "utf-8"));
|
|
15412
|
-
return pkg.name ||
|
|
13840
|
+
return pkg.name || path27.basename(rootDir);
|
|
15413
13841
|
} catch {
|
|
15414
|
-
return
|
|
13842
|
+
return path27.basename(rootDir);
|
|
15415
13843
|
}
|
|
15416
13844
|
}
|
|
15417
13845
|
|