sentinel-scanner 1.0.1 → 1.1.0-alpha.2

Sign up to get free protection for your applications and to get access to all the features.
package/build/index.js CHANGED
@@ -1,3118 +1,210 @@
1
- #!/usr/bin/env node
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
- }) : x)(function(x) {
11
- if (typeof require !== "undefined") return require.apply(this, arguments);
12
- throw Error('Dynamic require of "' + x + '" is not supported');
13
- });
14
- var __commonJS = (cb, mod) => function __require2() {
15
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
- };
17
- var __copyProps = (to, from, except, desc) => {
18
- if (from && typeof from === "object" || typeof from === "function") {
19
- for (let key of __getOwnPropNames(from))
20
- if (!__hasOwnProp.call(to, key) && key !== except)
21
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
- }
23
- return to;
24
- };
25
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
- // If the importer is in node compatibility mode or this is not an ESM
27
- // file that has been converted to a CommonJS file using a Babel-
28
- // compatible transform (i.e. "__esModule" has not been set), then set
29
- // "default" to the CommonJS "module.exports" for node compatibility.
30
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
- mod
32
- ));
1
+ // src/modules/spider/index.ts
2
+ import fetch from "isomorphic-fetch";
3
+ import jsdom from "jsdom";
4
+ import UserAgent from "user-agents";
33
5
 
34
- // node_modules/commander/lib/error.js
35
- var require_error = __commonJS({
36
- "node_modules/commander/lib/error.js"(exports) {
37
- var CommanderError2 = class extends Error {
38
- /**
39
- * Constructs the CommanderError class
40
- * @param {number} exitCode suggested exit code which could be used with process.exit
41
- * @param {string} code an id string representing the error
42
- * @param {string} message human-readable description of the error
43
- */
44
- constructor(exitCode, code, message) {
45
- super(message);
46
- Error.captureStackTrace(this, this.constructor);
47
- this.name = this.constructor.name;
48
- this.code = code;
49
- this.exitCode = exitCode;
50
- this.nestedError = void 0;
51
- }
52
- };
53
- var InvalidArgumentError2 = class extends CommanderError2 {
54
- /**
55
- * Constructs the InvalidArgumentError class
56
- * @param {string} [message] explanation of why argument is invalid
57
- */
58
- constructor(message) {
59
- super(1, "commander.invalidArgument", message);
60
- Error.captureStackTrace(this, this.constructor);
61
- this.name = this.constructor.name;
62
- }
63
- };
64
- exports.CommanderError = CommanderError2;
65
- exports.InvalidArgumentError = InvalidArgumentError2;
66
- }
6
+ // src/utils/index.ts
7
+ import winston from "winston";
8
+ var createLogger = (label) => winston.createLogger({
9
+ levels: {
10
+ error: 0,
11
+ warn: 1,
12
+ info: 2,
13
+ http: 3,
14
+ verbose: 4,
15
+ debug: 5,
16
+ silly: 6
17
+ },
18
+ format: winston.format.combine(
19
+ winston.format.label({ label }),
20
+ winston.format.colorize(),
21
+ winston.format.timestamp({
22
+ format: () => {
23
+ return (/* @__PURE__ */ new Date()).toLocaleString("en-US");
24
+ }
25
+ }),
26
+ winston.format.align(),
27
+ winston.format.printf(
28
+ (info) => `\x1B[34m(${info.label})\x1B[0m \x1B[33m${info.timestamp}\x1B[0m [${info.level}]: ${info.message}`
29
+ )
30
+ ),
31
+ transports: [new winston.transports.Console()]
67
32
  });
68
33
 
69
- // node_modules/commander/lib/argument.js
70
- var require_argument = __commonJS({
71
- "node_modules/commander/lib/argument.js"(exports) {
72
- var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
73
- var Argument2 = class {
74
- /**
75
- * Initialize a new command argument with the given name and description.
76
- * The default is that the argument is required, and you can explicitly
77
- * indicate this with <> around the name. Put [] around the name for an optional argument.
78
- *
79
- * @param {string} name
80
- * @param {string} [description]
81
- */
82
- constructor(name, description) {
83
- this.description = description || "";
84
- this.variadic = false;
85
- this.parseArg = void 0;
86
- this.defaultValue = void 0;
87
- this.defaultValueDescription = void 0;
88
- this.argChoices = void 0;
89
- switch (name[0]) {
90
- case "<":
91
- this.required = true;
92
- this._name = name.slice(1, -1);
93
- break;
94
- case "[":
95
- this.required = false;
96
- this._name = name.slice(1, -1);
97
- break;
98
- default:
99
- this.required = true;
100
- this._name = name;
101
- break;
102
- }
103
- if (this._name.length > 3 && this._name.slice(-3) === "...") {
104
- this.variadic = true;
105
- this._name = this._name.slice(0, -3);
106
- }
107
- }
108
- /**
109
- * Return argument name.
110
- *
111
- * @return {string}
112
- */
113
- name() {
114
- return this._name;
115
- }
116
- /**
117
- * @package
118
- */
119
- _concatValue(value, previous) {
120
- if (previous === this.defaultValue || !Array.isArray(previous)) {
121
- return [value];
122
- }
123
- return previous.concat(value);
124
- }
125
- /**
126
- * Set the default value, and optionally supply the description to be displayed in the help.
127
- *
128
- * @param {*} value
129
- * @param {string} [description]
130
- * @return {Argument}
131
- */
132
- default(value, description) {
133
- this.defaultValue = value;
134
- this.defaultValueDescription = description;
135
- return this;
136
- }
137
- /**
138
- * Set the custom handler for processing CLI command arguments into argument values.
139
- *
140
- * @param {Function} [fn]
141
- * @return {Argument}
142
- */
143
- argParser(fn) {
144
- this.parseArg = fn;
145
- return this;
146
- }
147
- /**
148
- * Only allow argument value to be one of choices.
149
- *
150
- * @param {string[]} values
151
- * @return {Argument}
152
- */
153
- choices(values) {
154
- this.argChoices = values.slice();
155
- this.parseArg = (arg, previous) => {
156
- if (!this.argChoices.includes(arg)) {
157
- throw new InvalidArgumentError2(
158
- `Allowed choices are ${this.argChoices.join(", ")}.`
159
- );
160
- }
161
- if (this.variadic) {
162
- return this._concatValue(arg, previous);
163
- }
164
- return arg;
165
- };
166
- return this;
167
- }
168
- /**
169
- * Make argument required.
170
- *
171
- * @returns {Argument}
172
- */
173
- argRequired() {
174
- this.required = true;
175
- return this;
176
- }
177
- /**
178
- * Make argument optional.
179
- *
180
- * @returns {Argument}
181
- */
182
- argOptional() {
183
- this.required = false;
184
- return this;
185
- }
186
- };
187
- function humanReadableArgName(arg) {
188
- const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
189
- return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
34
+ // src/modules/spider/index.ts
35
+ var SpiderScanner = class {
36
+ header = {
37
+ "User-Agent": new UserAgent().toString()
38
+ };
39
+ url;
40
+ logger = createLogger("SpiderScanner");
41
+ depth;
42
+ concurrency;
43
+ retries;
44
+ timeout;
45
+ constructor(url, options = {}) {
46
+ const {
47
+ depth = 250,
48
+ concurrency = 5,
49
+ retries = 3,
50
+ timeout = 5e3
51
+ } = options;
52
+ this.depth = depth;
53
+ this.concurrency = concurrency;
54
+ this.retries = retries;
55
+ this.timeout = timeout;
56
+ try {
57
+ this.url = new URL(url);
58
+ this.logger.info(
59
+ `Initialized with URL: ${url}, User-Agent: ${this.header["User-Agent"]}`
60
+ );
61
+ } catch (error) {
62
+ if (error instanceof TypeError) {
63
+ this.logger.error("Invalid URL");
64
+ throw new Error("Invalid URL");
65
+ }
66
+ this.logger.error(`Unexpected error in constructor: ${error}`);
67
+ throw error;
190
68
  }
191
- exports.Argument = Argument2;
192
- exports.humanReadableArgName = humanReadableArgName;
193
69
  }
194
- });
195
-
196
- // node_modules/commander/lib/help.js
197
- var require_help = __commonJS({
198
- "node_modules/commander/lib/help.js"(exports) {
199
- var { humanReadableArgName } = require_argument();
200
- var Help2 = class {
201
- constructor() {
202
- this.helpWidth = void 0;
203
- this.sortSubcommands = false;
204
- this.sortOptions = false;
205
- this.showGlobalOptions = false;
206
- }
207
- /**
208
- * Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
209
- *
210
- * @param {Command} cmd
211
- * @returns {Command[]}
212
- */
213
- visibleCommands(cmd) {
214
- const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
215
- const helpCommand = cmd._getHelpCommand();
216
- if (helpCommand && !helpCommand._hidden) {
217
- visibleCommands.push(helpCommand);
218
- }
219
- if (this.sortSubcommands) {
220
- visibleCommands.sort((a, b) => {
221
- return a.name().localeCompare(b.name());
222
- });
223
- }
224
- return visibleCommands;
225
- }
226
- /**
227
- * Compare options for sort.
228
- *
229
- * @param {Option} a
230
- * @param {Option} b
231
- * @returns {number}
232
- */
233
- compareOptions(a, b) {
234
- const getSortKey = (option) => {
235
- return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
236
- };
237
- return getSortKey(a).localeCompare(getSortKey(b));
238
- }
239
- /**
240
- * Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
241
- *
242
- * @param {Command} cmd
243
- * @returns {Option[]}
244
- */
245
- visibleOptions(cmd) {
246
- const visibleOptions = cmd.options.filter((option) => !option.hidden);
247
- const helpOption = cmd._getHelpOption();
248
- if (helpOption && !helpOption.hidden) {
249
- const removeShort = helpOption.short && cmd._findOption(helpOption.short);
250
- const removeLong = helpOption.long && cmd._findOption(helpOption.long);
251
- if (!removeShort && !removeLong) {
252
- visibleOptions.push(helpOption);
253
- } else if (helpOption.long && !removeLong) {
254
- visibleOptions.push(
255
- cmd.createOption(helpOption.long, helpOption.description)
256
- );
257
- } else if (helpOption.short && !removeShort) {
258
- visibleOptions.push(
259
- cmd.createOption(helpOption.short, helpOption.description)
260
- );
261
- }
262
- }
263
- if (this.sortOptions) {
264
- visibleOptions.sort(this.compareOptions);
265
- }
266
- return visibleOptions;
267
- }
268
- /**
269
- * Get an array of the visible global options. (Not including help.)
270
- *
271
- * @param {Command} cmd
272
- * @returns {Option[]}
273
- */
274
- visibleGlobalOptions(cmd) {
275
- if (!this.showGlobalOptions) return [];
276
- const globalOptions = [];
277
- for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
278
- const visibleOptions = ancestorCmd.options.filter(
279
- (option) => !option.hidden
280
- );
281
- globalOptions.push(...visibleOptions);
282
- }
283
- if (this.sortOptions) {
284
- globalOptions.sort(this.compareOptions);
285
- }
286
- return globalOptions;
287
- }
288
- /**
289
- * Get an array of the arguments if any have a description.
290
- *
291
- * @param {Command} cmd
292
- * @returns {Argument[]}
293
- */
294
- visibleArguments(cmd) {
295
- if (cmd._argsDescription) {
296
- cmd.registeredArguments.forEach((argument) => {
297
- argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
298
- });
299
- }
300
- if (cmd.registeredArguments.find((argument) => argument.description)) {
301
- return cmd.registeredArguments;
302
- }
303
- return [];
304
- }
305
- /**
306
- * Get the command term to show in the list of subcommands.
307
- *
308
- * @param {Command} cmd
309
- * @returns {string}
310
- */
311
- subcommandTerm(cmd) {
312
- const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
313
- return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + // simplistic check for non-help option
314
- (args ? " " + args : "");
315
- }
316
- /**
317
- * Get the option term to show in the list of options.
318
- *
319
- * @param {Option} option
320
- * @returns {string}
321
- */
322
- optionTerm(option) {
323
- return option.flags;
324
- }
325
- /**
326
- * Get the argument term to show in the list of arguments.
327
- *
328
- * @param {Argument} argument
329
- * @returns {string}
330
- */
331
- argumentTerm(argument) {
332
- return argument.name();
333
- }
334
- /**
335
- * Get the longest command term length.
336
- *
337
- * @param {Command} cmd
338
- * @param {Help} helper
339
- * @returns {number}
340
- */
341
- longestSubcommandTermLength(cmd, helper) {
342
- return helper.visibleCommands(cmd).reduce((max, command) => {
343
- return Math.max(max, helper.subcommandTerm(command).length);
344
- }, 0);
345
- }
346
- /**
347
- * Get the longest option term length.
348
- *
349
- * @param {Command} cmd
350
- * @param {Help} helper
351
- * @returns {number}
352
- */
353
- longestOptionTermLength(cmd, helper) {
354
- return helper.visibleOptions(cmd).reduce((max, option) => {
355
- return Math.max(max, helper.optionTerm(option).length);
356
- }, 0);
357
- }
358
- /**
359
- * Get the longest global option term length.
360
- *
361
- * @param {Command} cmd
362
- * @param {Help} helper
363
- * @returns {number}
364
- */
365
- longestGlobalOptionTermLength(cmd, helper) {
366
- return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
367
- return Math.max(max, helper.optionTerm(option).length);
368
- }, 0);
369
- }
370
- /**
371
- * Get the longest argument term length.
372
- *
373
- * @param {Command} cmd
374
- * @param {Help} helper
375
- * @returns {number}
376
- */
377
- longestArgumentTermLength(cmd, helper) {
378
- return helper.visibleArguments(cmd).reduce((max, argument) => {
379
- return Math.max(max, helper.argumentTerm(argument).length);
380
- }, 0);
381
- }
382
- /**
383
- * Get the command usage to be displayed at the top of the built-in help.
384
- *
385
- * @param {Command} cmd
386
- * @returns {string}
387
- */
388
- commandUsage(cmd) {
389
- let cmdName = cmd._name;
390
- if (cmd._aliases[0]) {
391
- cmdName = cmdName + "|" + cmd._aliases[0];
392
- }
393
- let ancestorCmdNames = "";
394
- for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
395
- ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
396
- }
397
- return ancestorCmdNames + cmdName + " " + cmd.usage();
398
- }
399
- /**
400
- * Get the description for the command.
401
- *
402
- * @param {Command} cmd
403
- * @returns {string}
404
- */
405
- commandDescription(cmd) {
406
- return cmd.description();
407
- }
408
- /**
409
- * Get the subcommand summary to show in the list of subcommands.
410
- * (Fallback to description for backwards compatibility.)
411
- *
412
- * @param {Command} cmd
413
- * @returns {string}
414
- */
415
- subcommandDescription(cmd) {
416
- return cmd.summary() || cmd.description();
417
- }
418
- /**
419
- * Get the option description to show in the list of options.
420
- *
421
- * @param {Option} option
422
- * @return {string}
423
- */
424
- optionDescription(option) {
425
- const extraInfo = [];
426
- if (option.argChoices) {
427
- extraInfo.push(
428
- // use stringify to match the display of the default value
429
- `choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
430
- );
431
- }
432
- if (option.defaultValue !== void 0) {
433
- const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
434
- if (showDefault) {
435
- extraInfo.push(
436
- `default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`
437
- );
438
- }
439
- }
440
- if (option.presetArg !== void 0 && option.optional) {
441
- extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
442
- }
443
- if (option.envVar !== void 0) {
444
- extraInfo.push(`env: ${option.envVar}`);
445
- }
446
- if (extraInfo.length > 0) {
447
- return `${option.description} (${extraInfo.join(", ")})`;
448
- }
449
- return option.description;
450
- }
451
- /**
452
- * Get the argument description to show in the list of arguments.
453
- *
454
- * @param {Argument} argument
455
- * @return {string}
456
- */
457
- argumentDescription(argument) {
458
- const extraInfo = [];
459
- if (argument.argChoices) {
460
- extraInfo.push(
461
- // use stringify to match the display of the default value
462
- `choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
463
- );
464
- }
465
- if (argument.defaultValue !== void 0) {
466
- extraInfo.push(
467
- `default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`
468
- );
469
- }
470
- if (extraInfo.length > 0) {
471
- const extraDescripton = `(${extraInfo.join(", ")})`;
472
- if (argument.description) {
473
- return `${argument.description} ${extraDescripton}`;
474
- }
475
- return extraDescripton;
476
- }
477
- return argument.description;
478
- }
479
- /**
480
- * Generate the built-in help text.
481
- *
482
- * @param {Command} cmd
483
- * @param {Help} helper
484
- * @returns {string}
485
- */
486
- formatHelp(cmd, helper) {
487
- const termWidth = helper.padWidth(cmd, helper);
488
- const helpWidth = helper.helpWidth || 80;
489
- const itemIndentWidth = 2;
490
- const itemSeparatorWidth = 2;
491
- function formatItem(term, description) {
492
- if (description) {
493
- const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
494
- return helper.wrap(
495
- fullText,
496
- helpWidth - itemIndentWidth,
497
- termWidth + itemSeparatorWidth
498
- );
499
- }
500
- return term;
501
- }
502
- function formatList(textArray) {
503
- return textArray.join("\n").replace(/^/gm, " ".repeat(itemIndentWidth));
504
- }
505
- let output = [`Usage: ${helper.commandUsage(cmd)}`, ""];
506
- const commandDescription = helper.commandDescription(cmd);
507
- if (commandDescription.length > 0) {
508
- output = output.concat([
509
- helper.wrap(commandDescription, helpWidth, 0),
510
- ""
511
- ]);
512
- }
513
- const argumentList = helper.visibleArguments(cmd).map((argument) => {
514
- return formatItem(
515
- helper.argumentTerm(argument),
516
- helper.argumentDescription(argument)
517
- );
518
- });
519
- if (argumentList.length > 0) {
520
- output = output.concat(["Arguments:", formatList(argumentList), ""]);
521
- }
522
- const optionList = helper.visibleOptions(cmd).map((option) => {
523
- return formatItem(
524
- helper.optionTerm(option),
525
- helper.optionDescription(option)
526
- );
527
- });
528
- if (optionList.length > 0) {
529
- output = output.concat(["Options:", formatList(optionList), ""]);
530
- }
531
- if (this.showGlobalOptions) {
532
- const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
533
- return formatItem(
534
- helper.optionTerm(option),
535
- helper.optionDescription(option)
536
- );
537
- });
538
- if (globalOptionList.length > 0) {
539
- output = output.concat([
540
- "Global Options:",
541
- formatList(globalOptionList),
542
- ""
543
- ]);
544
- }
545
- }
546
- const commandList = helper.visibleCommands(cmd).map((cmd2) => {
547
- return formatItem(
548
- helper.subcommandTerm(cmd2),
549
- helper.subcommandDescription(cmd2)
550
- );
551
- });
552
- if (commandList.length > 0) {
553
- output = output.concat(["Commands:", formatList(commandList), ""]);
554
- }
555
- return output.join("\n");
556
- }
557
- /**
558
- * Calculate the pad width from the maximum term length.
559
- *
560
- * @param {Command} cmd
561
- * @param {Help} helper
562
- * @returns {number}
563
- */
564
- padWidth(cmd, helper) {
565
- return Math.max(
566
- helper.longestOptionTermLength(cmd, helper),
567
- helper.longestGlobalOptionTermLength(cmd, helper),
568
- helper.longestSubcommandTermLength(cmd, helper),
569
- helper.longestArgumentTermLength(cmd, helper)
570
- );
571
- }
572
- /**
573
- * Wrap the given string to width characters per line, with lines after the first indented.
574
- * Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted.
575
- *
576
- * @param {string} str
577
- * @param {number} width
578
- * @param {number} indent
579
- * @param {number} [minColumnWidth=40]
580
- * @return {string}
581
- *
582
- */
583
- wrap(str, width, indent, minColumnWidth = 40) {
584
- const indents = " \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF";
585
- const manualIndent = new RegExp(`[\\n][${indents}]+`);
586
- if (str.match(manualIndent)) return str;
587
- const columnWidth = width - indent;
588
- if (columnWidth < minColumnWidth) return str;
589
- const leadingStr = str.slice(0, indent);
590
- const columnText = str.slice(indent).replace("\r\n", "\n");
591
- const indentString = " ".repeat(indent);
592
- const zeroWidthSpace = "\u200B";
593
- const breaks = `\\s${zeroWidthSpace}`;
594
- const regex = new RegExp(
595
- `
596
- |.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`,
597
- "g"
598
- );
599
- const lines = columnText.match(regex) || [];
600
- return leadingStr + lines.map((line, i) => {
601
- if (line === "\n") return "";
602
- return (i > 0 ? indentString : "") + line.trimEnd();
603
- }).join("\n");
604
- }
605
- };
606
- exports.Help = Help2;
70
+ normalizeDomain(domain) {
71
+ return domain.startsWith("www.") ? domain.slice(4) : domain;
607
72
  }
608
- });
609
-
610
- // node_modules/commander/lib/option.js
611
- var require_option = __commonJS({
612
- "node_modules/commander/lib/option.js"(exports) {
613
- var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
614
- var Option2 = class {
615
- /**
616
- * Initialize a new `Option` with the given `flags` and `description`.
617
- *
618
- * @param {string} flags
619
- * @param {string} [description]
620
- */
621
- constructor(flags, description) {
622
- this.flags = flags;
623
- this.description = description || "";
624
- this.required = flags.includes("<");
625
- this.optional = flags.includes("[");
626
- this.variadic = /\w\.\.\.[>\]]$/.test(flags);
627
- this.mandatory = false;
628
- const optionFlags = splitOptionFlags(flags);
629
- this.short = optionFlags.shortFlag;
630
- this.long = optionFlags.longFlag;
631
- this.negate = false;
632
- if (this.long) {
633
- this.negate = this.long.startsWith("--no-");
634
- }
635
- this.defaultValue = void 0;
636
- this.defaultValueDescription = void 0;
637
- this.presetArg = void 0;
638
- this.envVar = void 0;
639
- this.parseArg = void 0;
640
- this.hidden = false;
641
- this.argChoices = void 0;
642
- this.conflictsWith = [];
643
- this.implied = void 0;
644
- }
645
- /**
646
- * Set the default value, and optionally supply the description to be displayed in the help.
647
- *
648
- * @param {*} value
649
- * @param {string} [description]
650
- * @return {Option}
651
- */
652
- default(value, description) {
653
- this.defaultValue = value;
654
- this.defaultValueDescription = description;
655
- return this;
656
- }
657
- /**
658
- * Preset to use when option used without option-argument, especially optional but also boolean and negated.
659
- * The custom processing (parseArg) is called.
660
- *
661
- * @example
662
- * new Option('--color').default('GREYSCALE').preset('RGB');
663
- * new Option('--donate [amount]').preset('20').argParser(parseFloat);
664
- *
665
- * @param {*} arg
666
- * @return {Option}
667
- */
668
- preset(arg) {
669
- this.presetArg = arg;
670
- return this;
671
- }
672
- /**
673
- * Add option name(s) that conflict with this option.
674
- * An error will be displayed if conflicting options are found during parsing.
675
- *
676
- * @example
677
- * new Option('--rgb').conflicts('cmyk');
678
- * new Option('--js').conflicts(['ts', 'jsx']);
679
- *
680
- * @param {(string | string[])} names
681
- * @return {Option}
682
- */
683
- conflicts(names) {
684
- this.conflictsWith = this.conflictsWith.concat(names);
685
- return this;
686
- }
687
- /**
688
- * Specify implied option values for when this option is set and the implied options are not.
689
- *
690
- * The custom processing (parseArg) is not called on the implied values.
691
- *
692
- * @example
693
- * program
694
- * .addOption(new Option('--log', 'write logging information to file'))
695
- * .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
696
- *
697
- * @param {object} impliedOptionValues
698
- * @return {Option}
699
- */
700
- implies(impliedOptionValues) {
701
- let newImplied = impliedOptionValues;
702
- if (typeof impliedOptionValues === "string") {
703
- newImplied = { [impliedOptionValues]: true };
704
- }
705
- this.implied = Object.assign(this.implied || {}, newImplied);
706
- return this;
707
- }
708
- /**
709
- * Set environment variable to check for option value.
710
- *
711
- * An environment variable is only used if when processed the current option value is
712
- * undefined, or the source of the current value is 'default' or 'config' or 'env'.
713
- *
714
- * @param {string} name
715
- * @return {Option}
716
- */
717
- env(name) {
718
- this.envVar = name;
719
- return this;
720
- }
721
- /**
722
- * Set the custom handler for processing CLI option arguments into option values.
723
- *
724
- * @param {Function} [fn]
725
- * @return {Option}
726
- */
727
- argParser(fn) {
728
- this.parseArg = fn;
729
- return this;
730
- }
731
- /**
732
- * Whether the option is mandatory and must have a value after parsing.
733
- *
734
- * @param {boolean} [mandatory=true]
735
- * @return {Option}
736
- */
737
- makeOptionMandatory(mandatory = true) {
738
- this.mandatory = !!mandatory;
739
- return this;
740
- }
741
- /**
742
- * Hide option in help.
743
- *
744
- * @param {boolean} [hide=true]
745
- * @return {Option}
746
- */
747
- hideHelp(hide = true) {
748
- this.hidden = !!hide;
749
- return this;
750
- }
751
- /**
752
- * @package
753
- */
754
- _concatValue(value, previous) {
755
- if (previous === this.defaultValue || !Array.isArray(previous)) {
756
- return [value];
757
- }
758
- return previous.concat(value);
759
- }
760
- /**
761
- * Only allow option value to be one of choices.
762
- *
763
- * @param {string[]} values
764
- * @return {Option}
765
- */
766
- choices(values) {
767
- this.argChoices = values.slice();
768
- this.parseArg = (arg, previous) => {
769
- if (!this.argChoices.includes(arg)) {
770
- throw new InvalidArgumentError2(
771
- `Allowed choices are ${this.argChoices.join(", ")}.`
772
- );
773
- }
774
- if (this.variadic) {
775
- return this._concatValue(arg, previous);
776
- }
777
- return arg;
778
- };
779
- return this;
780
- }
781
- /**
782
- * Return option name.
783
- *
784
- * @return {string}
785
- */
786
- name() {
787
- if (this.long) {
788
- return this.long.replace(/^--/, "");
789
- }
790
- return this.short.replace(/^-/, "");
791
- }
792
- /**
793
- * Return option name, in a camelcase format that can be used
794
- * as a object attribute key.
795
- *
796
- * @return {string}
797
- */
798
- attributeName() {
799
- return camelcase(this.name().replace(/^no-/, ""));
800
- }
801
- /**
802
- * Check if `arg` matches the short or long flag.
803
- *
804
- * @param {string} arg
805
- * @return {boolean}
806
- * @package
807
- */
808
- is(arg) {
809
- return this.short === arg || this.long === arg;
810
- }
811
- /**
812
- * Return whether a boolean option.
813
- *
814
- * Options are one of boolean, negated, required argument, or optional argument.
815
- *
816
- * @return {boolean}
817
- * @package
818
- */
819
- isBoolean() {
820
- return !this.required && !this.optional && !this.negate;
821
- }
822
- };
823
- var DualOptions = class {
824
- /**
825
- * @param {Option[]} options
826
- */
827
- constructor(options2) {
828
- this.positiveOptions = /* @__PURE__ */ new Map();
829
- this.negativeOptions = /* @__PURE__ */ new Map();
830
- this.dualOptions = /* @__PURE__ */ new Set();
831
- options2.forEach((option) => {
832
- if (option.negate) {
833
- this.negativeOptions.set(option.attributeName(), option);
834
- } else {
835
- this.positiveOptions.set(option.attributeName(), option);
836
- }
837
- });
838
- this.negativeOptions.forEach((value, key) => {
839
- if (this.positiveOptions.has(key)) {
840
- this.dualOptions.add(key);
841
- }
842
- });
843
- }
844
- /**
845
- * Did the value come from the option, and not from possible matching dual option?
846
- *
847
- * @param {*} value
848
- * @param {Option} option
849
- * @returns {boolean}
850
- */
851
- valueFromOption(value, option) {
852
- const optionKey = option.attributeName();
853
- if (!this.dualOptions.has(optionKey)) return true;
854
- const preset = this.negativeOptions.get(optionKey).presetArg;
855
- const negativeValue = preset !== void 0 ? preset : false;
856
- return option.negate === (negativeValue === value);
857
- }
858
- };
859
- function camelcase(str) {
860
- return str.split("-").reduce((str2, word) => {
861
- return str2 + word[0].toUpperCase() + word.slice(1);
862
- });
863
- }
864
- function splitOptionFlags(flags) {
865
- let shortFlag;
866
- let longFlag;
867
- const flagParts = flags.split(/[ |,]+/);
868
- if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
869
- shortFlag = flagParts.shift();
870
- longFlag = flagParts.shift();
871
- if (!shortFlag && /^-[^-]$/.test(longFlag)) {
872
- shortFlag = longFlag;
873
- longFlag = void 0;
874
- }
875
- return { shortFlag, longFlag };
876
- }
877
- exports.Option = Option2;
878
- exports.DualOptions = DualOptions;
73
+ convertRelativeUrlToAbsolute(url) {
74
+ return new URL(url, this.url.toString()).toString();
879
75
  }
880
- });
881
-
882
- // node_modules/commander/lib/suggestSimilar.js
883
- var require_suggestSimilar = __commonJS({
884
- "node_modules/commander/lib/suggestSimilar.js"(exports) {
885
- var maxDistance = 3;
886
- function editDistance(a, b) {
887
- if (Math.abs(a.length - b.length) > maxDistance)
888
- return Math.max(a.length, b.length);
889
- const d = [];
890
- for (let i = 0; i <= a.length; i++) {
891
- d[i] = [i];
892
- }
893
- for (let j = 0; j <= b.length; j++) {
894
- d[0][j] = j;
895
- }
896
- for (let j = 1; j <= b.length; j++) {
897
- for (let i = 1; i <= a.length; i++) {
898
- let cost = 1;
899
- if (a[i - 1] === b[j - 1]) {
900
- cost = 0;
901
- } else {
902
- cost = 1;
903
- }
904
- d[i][j] = Math.min(
905
- d[i - 1][j] + 1,
906
- // deletion
907
- d[i][j - 1] + 1,
908
- // insertion
909
- d[i - 1][j - 1] + cost
910
- // substitution
911
- );
912
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
913
- d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
914
- }
915
- }
916
- }
917
- return d[a.length][b.length];
76
+ isInternalLink(url) {
77
+ try {
78
+ const parsedUrl = new URL(url, this.url.href);
79
+ if (!["http:", "https:"].includes(parsedUrl.protocol)) {
80
+ return false;
81
+ }
82
+ const baseDomain = this.normalizeDomain(this.url.hostname);
83
+ const parsedDomain = this.normalizeDomain(parsedUrl.hostname);
84
+ return parsedDomain === baseDomain;
85
+ } catch (error) {
86
+ this.logger.warn(`Error parsing URL: ${url} - ${error}`);
87
+ return false;
918
88
  }
919
- function suggestSimilar(word, candidates) {
920
- if (!candidates || candidates.length === 0) return "";
921
- candidates = Array.from(new Set(candidates));
922
- const searchingOptions = word.startsWith("--");
923
- if (searchingOptions) {
924
- word = word.slice(2);
925
- candidates = candidates.map((candidate) => candidate.slice(2));
926
- }
927
- let similar = [];
928
- let bestDistance = maxDistance;
929
- const minSimilarity = 0.4;
930
- candidates.forEach((candidate) => {
931
- if (candidate.length <= 1) return;
932
- const distance = editDistance(word, candidate);
933
- const length = Math.max(word.length, candidate.length);
934
- const similarity = (length - distance) / length;
935
- if (similarity > minSimilarity) {
936
- if (distance < bestDistance) {
937
- bestDistance = distance;
938
- similar = [candidate];
939
- } else if (distance === bestDistance) {
940
- similar.push(candidate);
941
- }
942
- }
943
- });
944
- similar.sort((a, b) => a.localeCompare(b));
945
- if (searchingOptions) {
946
- similar = similar.map((candidate) => `--${candidate}`);
947
- }
948
- if (similar.length > 1) {
949
- return `
950
- (Did you mean one of ${similar.join(", ")}?)`;
951
- }
952
- if (similar.length === 1) {
953
- return `
954
- (Did you mean ${similar[0]}?)`;
955
- }
956
- return "";
957
- }
958
- exports.suggestSimilar = suggestSimilar;
959
89
  }
960
- });
961
-
962
- // node_modules/commander/lib/command.js
963
- var require_command = __commonJS({
964
- "node_modules/commander/lib/command.js"(exports) {
965
- var EventEmitter = __require("node:events").EventEmitter;
966
- var childProcess = __require("node:child_process");
967
- var path = __require("node:path");
968
- var fs = __require("node:fs");
969
- var process2 = __require("node:process");
970
- var { Argument: Argument2, humanReadableArgName } = require_argument();
971
- var { CommanderError: CommanderError2 } = require_error();
972
- var { Help: Help2 } = require_help();
973
- var { Option: Option2, DualOptions } = require_option();
974
- var { suggestSimilar } = require_suggestSimilar();
975
- var Command2 = class _Command extends EventEmitter {
976
- /**
977
- * Initialize a new `Command`.
978
- *
979
- * @param {string} [name]
980
- */
981
- constructor(name) {
982
- super();
983
- this.commands = [];
984
- this.options = [];
985
- this.parent = null;
986
- this._allowUnknownOption = false;
987
- this._allowExcessArguments = true;
988
- this.registeredArguments = [];
989
- this._args = this.registeredArguments;
990
- this.args = [];
991
- this.rawArgs = [];
992
- this.processedArgs = [];
993
- this._scriptPath = null;
994
- this._name = name || "";
995
- this._optionValues = {};
996
- this._optionValueSources = {};
997
- this._storeOptionsAsProperties = false;
998
- this._actionHandler = null;
999
- this._executableHandler = false;
1000
- this._executableFile = null;
1001
- this._executableDir = null;
1002
- this._defaultCommandName = null;
1003
- this._exitCallback = null;
1004
- this._aliases = [];
1005
- this._combineFlagAndOptionalValue = true;
1006
- this._description = "";
1007
- this._summary = "";
1008
- this._argsDescription = void 0;
1009
- this._enablePositionalOptions = false;
1010
- this._passThroughOptions = false;
1011
- this._lifeCycleHooks = {};
1012
- this._showHelpAfterError = false;
1013
- this._showSuggestionAfterError = true;
1014
- this._outputConfiguration = {
1015
- writeOut: (str) => process2.stdout.write(str),
1016
- writeErr: (str) => process2.stderr.write(str),
1017
- getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : void 0,
1018
- getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : void 0,
1019
- outputError: (str, write) => write(str)
1020
- };
1021
- this._hidden = false;
1022
- this._helpOption = void 0;
1023
- this._addImplicitHelpCommand = void 0;
1024
- this._helpCommand = void 0;
1025
- this._helpConfiguration = {};
1026
- }
1027
- /**
1028
- * Copy settings that are useful to have in common across root command and subcommands.
1029
- *
1030
- * (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)
1031
- *
1032
- * @param {Command} sourceCommand
1033
- * @return {Command} `this` command for chaining
1034
- */
1035
- copyInheritedSettings(sourceCommand) {
1036
- this._outputConfiguration = sourceCommand._outputConfiguration;
1037
- this._helpOption = sourceCommand._helpOption;
1038
- this._helpCommand = sourceCommand._helpCommand;
1039
- this._helpConfiguration = sourceCommand._helpConfiguration;
1040
- this._exitCallback = sourceCommand._exitCallback;
1041
- this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
1042
- this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
1043
- this._allowExcessArguments = sourceCommand._allowExcessArguments;
1044
- this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
1045
- this._showHelpAfterError = sourceCommand._showHelpAfterError;
1046
- this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
1047
- return this;
1048
- }
1049
- /**
1050
- * @returns {Command[]}
1051
- * @private
1052
- */
1053
- _getCommandAndAncestors() {
1054
- const result = [];
1055
- for (let command = this; command; command = command.parent) {
1056
- result.push(command);
1057
- }
1058
- return result;
1059
- }
1060
- /**
1061
- * Define a command.
1062
- *
1063
- * There are two styles of command: pay attention to where to put the description.
1064
- *
1065
- * @example
1066
- * // Command implemented using action handler (description is supplied separately to `.command`)
1067
- * program
1068
- * .command('clone <source> [destination]')
1069
- * .description('clone a repository into a newly created directory')
1070
- * .action((source, destination) => {
1071
- * console.log('clone command called');
1072
- * });
1073
- *
1074
- * // Command implemented using separate executable file (description is second parameter to `.command`)
1075
- * program
1076
- * .command('start <service>', 'start named service')
1077
- * .command('stop [service]', 'stop named service, or all if no name supplied');
1078
- *
1079
- * @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
1080
- * @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
1081
- * @param {object} [execOpts] - configuration options (for executable)
1082
- * @return {Command} returns new command for action handler, or `this` for executable command
1083
- */
1084
- command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
1085
- let desc = actionOptsOrExecDesc;
1086
- let opts = execOpts;
1087
- if (typeof desc === "object" && desc !== null) {
1088
- opts = desc;
1089
- desc = null;
1090
- }
1091
- opts = opts || {};
1092
- const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
1093
- const cmd = this.createCommand(name);
1094
- if (desc) {
1095
- cmd.description(desc);
1096
- cmd._executableHandler = true;
1097
- }
1098
- if (opts.isDefault) this._defaultCommandName = cmd._name;
1099
- cmd._hidden = !!(opts.noHelp || opts.hidden);
1100
- cmd._executableFile = opts.executableFile || null;
1101
- if (args) cmd.arguments(args);
1102
- this._registerCommand(cmd);
1103
- cmd.parent = this;
1104
- cmd.copyInheritedSettings(this);
1105
- if (desc) return this;
1106
- return cmd;
1107
- }
1108
- /**
1109
- * Factory routine to create a new unattached command.
1110
- *
1111
- * See .command() for creating an attached subcommand, which uses this routine to
1112
- * create the command. You can override createCommand to customise subcommands.
1113
- *
1114
- * @param {string} [name]
1115
- * @return {Command} new command
1116
- */
1117
- createCommand(name) {
1118
- return new _Command(name);
1119
- }
1120
- /**
1121
- * You can customise the help with a subclass of Help by overriding createHelp,
1122
- * or by overriding Help properties using configureHelp().
1123
- *
1124
- * @return {Help}
1125
- */
1126
- createHelp() {
1127
- return Object.assign(new Help2(), this.configureHelp());
1128
- }
1129
- /**
1130
- * You can customise the help by overriding Help properties using configureHelp(),
1131
- * or with a subclass of Help by overriding createHelp().
1132
- *
1133
- * @param {object} [configuration] - configuration options
1134
- * @return {(Command | object)} `this` command for chaining, or stored configuration
1135
- */
1136
- configureHelp(configuration) {
1137
- if (configuration === void 0) return this._helpConfiguration;
1138
- this._helpConfiguration = configuration;
1139
- return this;
1140
- }
1141
- /**
1142
- * The default output goes to stdout and stderr. You can customise this for special
1143
- * applications. You can also customise the display of errors by overriding outputError.
1144
- *
1145
- * The configuration properties are all functions:
1146
- *
1147
- * // functions to change where being written, stdout and stderr
1148
- * writeOut(str)
1149
- * writeErr(str)
1150
- * // matching functions to specify width for wrapping help
1151
- * getOutHelpWidth()
1152
- * getErrHelpWidth()
1153
- * // functions based on what is being written out
1154
- * outputError(str, write) // used for displaying errors, and not used for displaying help
1155
- *
1156
- * @param {object} [configuration] - configuration options
1157
- * @return {(Command | object)} `this` command for chaining, or stored configuration
1158
- */
1159
- configureOutput(configuration) {
1160
- if (configuration === void 0) return this._outputConfiguration;
1161
- Object.assign(this._outputConfiguration, configuration);
1162
- return this;
1163
- }
1164
- /**
1165
- * Display the help or a custom message after an error occurs.
1166
- *
1167
- * @param {(boolean|string)} [displayHelp]
1168
- * @return {Command} `this` command for chaining
1169
- */
1170
- showHelpAfterError(displayHelp = true) {
1171
- if (typeof displayHelp !== "string") displayHelp = !!displayHelp;
1172
- this._showHelpAfterError = displayHelp;
1173
- return this;
1174
- }
1175
- /**
1176
- * Display suggestion of similar commands for unknown commands, or options for unknown options.
1177
- *
1178
- * @param {boolean} [displaySuggestion]
1179
- * @return {Command} `this` command for chaining
1180
- */
1181
- showSuggestionAfterError(displaySuggestion = true) {
1182
- this._showSuggestionAfterError = !!displaySuggestion;
1183
- return this;
1184
- }
1185
- /**
1186
- * Add a prepared subcommand.
1187
- *
1188
- * See .command() for creating an attached subcommand which inherits settings from its parent.
1189
- *
1190
- * @param {Command} cmd - new subcommand
1191
- * @param {object} [opts] - configuration options
1192
- * @return {Command} `this` command for chaining
1193
- */
1194
- addCommand(cmd, opts) {
1195
- if (!cmd._name) {
1196
- throw new Error(`Command passed to .addCommand() must have a name
1197
- - specify the name in Command constructor or using .name()`);
1198
- }
1199
- opts = opts || {};
1200
- if (opts.isDefault) this._defaultCommandName = cmd._name;
1201
- if (opts.noHelp || opts.hidden) cmd._hidden = true;
1202
- this._registerCommand(cmd);
1203
- cmd.parent = this;
1204
- cmd._checkForBrokenPassThrough();
1205
- return this;
1206
- }
1207
- /**
1208
- * Factory routine to create a new unattached argument.
1209
- *
1210
- * See .argument() for creating an attached argument, which uses this routine to
1211
- * create the argument. You can override createArgument to return a custom argument.
1212
- *
1213
- * @param {string} name
1214
- * @param {string} [description]
1215
- * @return {Argument} new argument
1216
- */
1217
- createArgument(name, description) {
1218
- return new Argument2(name, description);
1219
- }
1220
- /**
1221
- * Define argument syntax for command.
1222
- *
1223
- * The default is that the argument is required, and you can explicitly
1224
- * indicate this with <> around the name. Put [] around the name for an optional argument.
1225
- *
1226
- * @example
1227
- * program.argument('<input-file>');
1228
- * program.argument('[output-file]');
1229
- *
1230
- * @param {string} name
1231
- * @param {string} [description]
1232
- * @param {(Function|*)} [fn] - custom argument processing function
1233
- * @param {*} [defaultValue]
1234
- * @return {Command} `this` command for chaining
1235
- */
1236
- argument(name, description, fn, defaultValue) {
1237
- const argument = this.createArgument(name, description);
1238
- if (typeof fn === "function") {
1239
- argument.default(defaultValue).argParser(fn);
1240
- } else {
1241
- argument.default(fn);
1242
- }
1243
- this.addArgument(argument);
1244
- return this;
1245
- }
1246
- /**
1247
- * Define argument syntax for command, adding multiple at once (without descriptions).
1248
- *
1249
- * See also .argument().
1250
- *
1251
- * @example
1252
- * program.arguments('<cmd> [env]');
1253
- *
1254
- * @param {string} names
1255
- * @return {Command} `this` command for chaining
1256
- */
1257
- arguments(names) {
1258
- names.trim().split(/ +/).forEach((detail) => {
1259
- this.argument(detail);
1260
- });
1261
- return this;
1262
- }
1263
- /**
1264
- * Define argument syntax for command, adding a prepared argument.
1265
- *
1266
- * @param {Argument} argument
1267
- * @return {Command} `this` command for chaining
1268
- */
1269
- addArgument(argument) {
1270
- const previousArgument = this.registeredArguments.slice(-1)[0];
1271
- if (previousArgument && previousArgument.variadic) {
1272
- throw new Error(
1273
- `only the last argument can be variadic '${previousArgument.name()}'`
1274
- );
1275
- }
1276
- if (argument.required && argument.defaultValue !== void 0 && argument.parseArg === void 0) {
1277
- throw new Error(
1278
- `a default value for a required argument is never used: '${argument.name()}'`
1279
- );
1280
- }
1281
- this.registeredArguments.push(argument);
1282
- return this;
1283
- }
1284
- /**
1285
- * Customise or override default help command. By default a help command is automatically added if your command has subcommands.
1286
- *
1287
- * @example
1288
- * program.helpCommand('help [cmd]');
1289
- * program.helpCommand('help [cmd]', 'show help');
1290
- * program.helpCommand(false); // suppress default help command
1291
- * program.helpCommand(true); // add help command even if no subcommands
1292
- *
1293
- * @param {string|boolean} enableOrNameAndArgs - enable with custom name and/or arguments, or boolean to override whether added
1294
- * @param {string} [description] - custom description
1295
- * @return {Command} `this` command for chaining
1296
- */
1297
- helpCommand(enableOrNameAndArgs, description) {
1298
- if (typeof enableOrNameAndArgs === "boolean") {
1299
- this._addImplicitHelpCommand = enableOrNameAndArgs;
1300
- return this;
1301
- }
1302
- enableOrNameAndArgs = enableOrNameAndArgs ?? "help [command]";
1303
- const [, helpName, helpArgs] = enableOrNameAndArgs.match(/([^ ]+) *(.*)/);
1304
- const helpDescription = description ?? "display help for command";
1305
- const helpCommand = this.createCommand(helpName);
1306
- helpCommand.helpOption(false);
1307
- if (helpArgs) helpCommand.arguments(helpArgs);
1308
- if (helpDescription) helpCommand.description(helpDescription);
1309
- this._addImplicitHelpCommand = true;
1310
- this._helpCommand = helpCommand;
1311
- return this;
1312
- }
1313
- /**
1314
- * Add prepared custom help command.
1315
- *
1316
- * @param {(Command|string|boolean)} helpCommand - custom help command, or deprecated enableOrNameAndArgs as for `.helpCommand()`
1317
- * @param {string} [deprecatedDescription] - deprecated custom description used with custom name only
1318
- * @return {Command} `this` command for chaining
1319
- */
1320
- addHelpCommand(helpCommand, deprecatedDescription) {
1321
- if (typeof helpCommand !== "object") {
1322
- this.helpCommand(helpCommand, deprecatedDescription);
1323
- return this;
1324
- }
1325
- this._addImplicitHelpCommand = true;
1326
- this._helpCommand = helpCommand;
1327
- return this;
1328
- }
1329
- /**
1330
- * Lazy create help command.
1331
- *
1332
- * @return {(Command|null)}
1333
- * @package
1334
- */
1335
- _getHelpCommand() {
1336
- const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help"));
1337
- if (hasImplicitHelpCommand) {
1338
- if (this._helpCommand === void 0) {
1339
- this.helpCommand(void 0, void 0);
1340
- }
1341
- return this._helpCommand;
1342
- }
1343
- return null;
1344
- }
1345
- /**
1346
- * Add hook for life cycle event.
1347
- *
1348
- * @param {string} event
1349
- * @param {Function} listener
1350
- * @return {Command} `this` command for chaining
1351
- */
1352
- hook(event, listener) {
1353
- const allowedValues = ["preSubcommand", "preAction", "postAction"];
1354
- if (!allowedValues.includes(event)) {
1355
- throw new Error(`Unexpected value for event passed to hook : '${event}'.
1356
- Expecting one of '${allowedValues.join("', '")}'`);
1357
- }
1358
- if (this._lifeCycleHooks[event]) {
1359
- this._lifeCycleHooks[event].push(listener);
1360
- } else {
1361
- this._lifeCycleHooks[event] = [listener];
1362
- }
1363
- return this;
1364
- }
1365
- /**
1366
- * Register callback to use as replacement for calling process.exit.
1367
- *
1368
- * @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing
1369
- * @return {Command} `this` command for chaining
1370
- */
1371
- exitOverride(fn) {
1372
- if (fn) {
1373
- this._exitCallback = fn;
90
+ async fetchWithRetries(url, retries) {
91
+ for (let attempt = 1; attempt <= retries; attempt++) {
92
+ const controller = new AbortController();
93
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
94
+ try {
95
+ this.logger.debug(`Fetching URL (Attempt ${attempt}): ${url}`);
96
+ const randomUserAgent = new UserAgent().toString();
97
+ this.logger.info(`Changing User-Agent to: ${randomUserAgent}`);
98
+ this.header["User-Agent"] = randomUserAgent;
99
+ const response = await fetch(url, {
100
+ headers: this.header,
101
+ signal: controller.signal,
102
+ redirect: "follow"
103
+ });
104
+ clearTimeout(timeoutId);
105
+ if (response.ok) {
106
+ this.logger.info(`Successfully fetched URL: ${url}`);
107
+ return await response.text();
108
+ }
109
+ this.logger.warn(`Failed to fetch URL (${response.status}): ${url}`);
110
+ } catch (error) {
111
+ if (error.name === "AbortError") {
112
+ this.logger.warn(`Fetch timed out: ${url}`);
1374
113
  } else {
1375
- this._exitCallback = (err) => {
1376
- if (err.code !== "commander.executeSubCommandAsync") {
1377
- throw err;
1378
- } else {
1379
- }
1380
- };
1381
- }
1382
- return this;
1383
- }
1384
- /**
1385
- * Call process.exit, and _exitCallback if defined.
1386
- *
1387
- * @param {number} exitCode exit code for using with process.exit
1388
- * @param {string} code an id string representing the error
1389
- * @param {string} message human-readable description of the error
1390
- * @return never
1391
- * @private
1392
- */
1393
- _exit(exitCode, code, message) {
1394
- if (this._exitCallback) {
1395
- this._exitCallback(new CommanderError2(exitCode, code, message));
1396
- }
1397
- process2.exit(exitCode);
1398
- }
1399
- /**
1400
- * Register callback `fn` for the command.
1401
- *
1402
- * @example
1403
- * program
1404
- * .command('serve')
1405
- * .description('start service')
1406
- * .action(function() {
1407
- * // do work here
1408
- * });
1409
- *
1410
- * @param {Function} fn
1411
- * @return {Command} `this` command for chaining
1412
- */
1413
- action(fn) {
1414
- const listener = (args) => {
1415
- const expectedArgsCount = this.registeredArguments.length;
1416
- const actionArgs = args.slice(0, expectedArgsCount);
1417
- if (this._storeOptionsAsProperties) {
1418
- actionArgs[expectedArgsCount] = this;
1419
- } else {
1420
- actionArgs[expectedArgsCount] = this.opts();
1421
- }
1422
- actionArgs.push(this);
1423
- return fn.apply(this, actionArgs);
1424
- };
1425
- this._actionHandler = listener;
1426
- return this;
1427
- }
1428
- /**
1429
- * Factory routine to create a new unattached option.
1430
- *
1431
- * See .option() for creating an attached option, which uses this routine to
1432
- * create the option. You can override createOption to return a custom option.
1433
- *
1434
- * @param {string} flags
1435
- * @param {string} [description]
1436
- * @return {Option} new option
1437
- */
1438
- createOption(flags, description) {
1439
- return new Option2(flags, description);
1440
- }
1441
- /**
1442
- * Wrap parseArgs to catch 'commander.invalidArgument'.
1443
- *
1444
- * @param {(Option | Argument)} target
1445
- * @param {string} value
1446
- * @param {*} previous
1447
- * @param {string} invalidArgumentMessage
1448
- * @private
1449
- */
1450
- _callParseArg(target, value, previous, invalidArgumentMessage) {
1451
- try {
1452
- return target.parseArg(value, previous);
1453
- } catch (err) {
1454
- if (err.code === "commander.invalidArgument") {
1455
- const message = `${invalidArgumentMessage} ${err.message}`;
1456
- this.error(message, { exitCode: err.exitCode, code: err.code });
1457
- }
1458
- throw err;
1459
- }
1460
- }
1461
- /**
1462
- * Check for option flag conflicts.
1463
- * Register option if no conflicts found, or throw on conflict.
1464
- *
1465
- * @param {Option} option
1466
- * @private
1467
- */
1468
- _registerOption(option) {
1469
- const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long);
1470
- if (matchingOption) {
1471
- const matchingFlag = option.long && this._findOption(option.long) ? option.long : option.short;
1472
- throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
1473
- - already used by option '${matchingOption.flags}'`);
114
+ this.logger.error(`Error fetching URL: ${url} - ${error}`);
1474
115
  }
1475
- this.options.push(option);
1476
116
  }
1477
- /**
1478
- * Check for command name and alias conflicts with existing commands.
1479
- * Register command if no conflicts found, or throw on conflict.
1480
- *
1481
- * @param {Command} command
1482
- * @private
1483
- */
1484
- _registerCommand(command) {
1485
- const knownBy = (cmd) => {
1486
- return [cmd.name()].concat(cmd.aliases());
1487
- };
1488
- const alreadyUsed = knownBy(command).find(
1489
- (name) => this._findCommand(name)
1490
- );
1491
- if (alreadyUsed) {
1492
- const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
1493
- const newCmd = knownBy(command).join("|");
1494
- throw new Error(
1495
- `cannot add command '${newCmd}' as already have command '${existingCmd}'`
1496
- );
1497
- }
1498
- this.commands.push(command);
1499
- }
1500
- /**
1501
- * Add an option.
1502
- *
1503
- * @param {Option} option
1504
- * @return {Command} `this` command for chaining
1505
- */
1506
- addOption(option) {
1507
- this._registerOption(option);
1508
- const oname = option.name();
1509
- const name = option.attributeName();
1510
- if (option.negate) {
1511
- const positiveLongFlag = option.long.replace(/^--no-/, "--");
1512
- if (!this._findOption(positiveLongFlag)) {
1513
- this.setOptionValueWithSource(
1514
- name,
1515
- option.defaultValue === void 0 ? true : option.defaultValue,
1516
- "default"
1517
- );
1518
- }
1519
- } else if (option.defaultValue !== void 0) {
1520
- this.setOptionValueWithSource(name, option.defaultValue, "default");
1521
- }
1522
- const handleOptionValue = (val, invalidValueMessage, valueSource) => {
1523
- if (val == null && option.presetArg !== void 0) {
1524
- val = option.presetArg;
1525
- }
1526
- const oldValue = this.getOptionValue(name);
1527
- if (val !== null && option.parseArg) {
1528
- val = this._callParseArg(option, val, oldValue, invalidValueMessage);
1529
- } else if (val !== null && option.variadic) {
1530
- val = option._concatValue(val, oldValue);
1531
- }
1532
- if (val == null) {
1533
- if (option.negate) {
1534
- val = false;
1535
- } else if (option.isBoolean() || option.optional) {
1536
- val = true;
1537
- } else {
1538
- val = "";
1539
- }
1540
- }
1541
- this.setOptionValueWithSource(name, val, valueSource);
1542
- };
1543
- this.on("option:" + oname, (val) => {
1544
- const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;
1545
- handleOptionValue(val, invalidValueMessage, "cli");
1546
- });
1547
- if (option.envVar) {
1548
- this.on("optionEnv:" + oname, (val) => {
1549
- const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;
1550
- handleOptionValue(val, invalidValueMessage, "env");
1551
- });
1552
- }
1553
- return this;
1554
- }
1555
- /**
1556
- * Internal implementation shared by .option() and .requiredOption()
1557
- *
1558
- * @return {Command} `this` command for chaining
1559
- * @private
1560
- */
1561
- _optionEx(config, flags, description, fn, defaultValue) {
1562
- if (typeof flags === "object" && flags instanceof Option2) {
1563
- throw new Error(
1564
- "To add an Option object use addOption() instead of option() or requiredOption()"
1565
- );
1566
- }
1567
- const option = this.createOption(flags, description);
1568
- option.makeOptionMandatory(!!config.mandatory);
1569
- if (typeof fn === "function") {
1570
- option.default(defaultValue).argParser(fn);
1571
- } else if (fn instanceof RegExp) {
1572
- const regex = fn;
1573
- fn = (val, def) => {
1574
- const m = regex.exec(val);
1575
- return m ? m[0] : def;
1576
- };
1577
- option.default(defaultValue).argParser(fn);
1578
- } else {
1579
- option.default(fn);
1580
- }
1581
- return this.addOption(option);
1582
- }
1583
- /**
1584
- * Define option with `flags`, `description`, and optional argument parsing function or `defaultValue` or both.
1585
- *
1586
- * The `flags` string contains the short and/or long flags, separated by comma, a pipe or space. A required
1587
- * option-argument is indicated by `<>` and an optional option-argument by `[]`.
1588
- *
1589
- * See the README for more details, and see also addOption() and requiredOption().
1590
- *
1591
- * @example
1592
- * program
1593
- * .option('-p, --pepper', 'add pepper')
1594
- * .option('-p, --pizza-type <TYPE>', 'type of pizza') // required option-argument
1595
- * .option('-c, --cheese [CHEESE]', 'add extra cheese', 'mozzarella') // optional option-argument with default
1596
- * .option('-t, --tip <VALUE>', 'add tip to purchase cost', parseFloat) // custom parse function
1597
- *
1598
- * @param {string} flags
1599
- * @param {string} [description]
1600
- * @param {(Function|*)} [parseArg] - custom option processing function or default value
1601
- * @param {*} [defaultValue]
1602
- * @return {Command} `this` command for chaining
1603
- */
1604
- option(flags, description, parseArg, defaultValue) {
1605
- return this._optionEx({}, flags, description, parseArg, defaultValue);
1606
- }
1607
- /**
1608
- * Add a required option which must have a value after parsing. This usually means
1609
- * the option must be specified on the command line. (Otherwise the same as .option().)
1610
- *
1611
- * The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
1612
- *
1613
- * @param {string} flags
1614
- * @param {string} [description]
1615
- * @param {(Function|*)} [parseArg] - custom option processing function or default value
1616
- * @param {*} [defaultValue]
1617
- * @return {Command} `this` command for chaining
1618
- */
1619
- requiredOption(flags, description, parseArg, defaultValue) {
1620
- return this._optionEx(
1621
- { mandatory: true },
1622
- flags,
1623
- description,
1624
- parseArg,
1625
- defaultValue
1626
- );
1627
- }
1628
- /**
1629
- * Alter parsing of short flags with optional values.
1630
- *
1631
- * @example
1632
- * // for `.option('-f,--flag [value]'):
1633
- * program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
1634
- * program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
1635
- *
1636
- * @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
1637
- * @return {Command} `this` command for chaining
1638
- */
1639
- combineFlagAndOptionalValue(combine = true) {
1640
- this._combineFlagAndOptionalValue = !!combine;
1641
- return this;
1642
- }
1643
- /**
1644
- * Allow unknown options on the command line.
1645
- *
1646
- * @param {boolean} [allowUnknown] - if `true` or omitted, no error will be thrown for unknown options.
1647
- * @return {Command} `this` command for chaining
1648
- */
1649
- allowUnknownOption(allowUnknown = true) {
1650
- this._allowUnknownOption = !!allowUnknown;
1651
- return this;
1652
- }
1653
- /**
1654
- * Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
1655
- *
1656
- * @param {boolean} [allowExcess] - if `true` or omitted, no error will be thrown for excess arguments.
1657
- * @return {Command} `this` command for chaining
1658
- */
1659
- allowExcessArguments(allowExcess = true) {
1660
- this._allowExcessArguments = !!allowExcess;
1661
- return this;
1662
- }
1663
- /**
1664
- * Enable positional options. Positional means global options are specified before subcommands which lets
1665
- * subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
1666
- * The default behaviour is non-positional and global options may appear anywhere on the command line.
1667
- *
1668
- * @param {boolean} [positional]
1669
- * @return {Command} `this` command for chaining
1670
- */
1671
- enablePositionalOptions(positional = true) {
1672
- this._enablePositionalOptions = !!positional;
1673
- return this;
1674
- }
1675
- /**
1676
- * Pass through options that come after command-arguments rather than treat them as command-options,
1677
- * so actual command-options come before command-arguments. Turning this on for a subcommand requires
1678
- * positional options to have been enabled on the program (parent commands).
1679
- * The default behaviour is non-positional and options may appear before or after command-arguments.
1680
- *
1681
- * @param {boolean} [passThrough] for unknown options.
1682
- * @return {Command} `this` command for chaining
1683
- */
1684
- passThroughOptions(passThrough = true) {
1685
- this._passThroughOptions = !!passThrough;
1686
- this._checkForBrokenPassThrough();
1687
- return this;
1688
- }
1689
- /**
1690
- * @private
1691
- */
1692
- _checkForBrokenPassThrough() {
1693
- if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
1694
- throw new Error(
1695
- `passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`
1696
- );
1697
- }
1698
- }
1699
- /**
1700
- * Whether to store option values as properties on command object,
1701
- * or store separately (specify false). In both cases the option values can be accessed using .opts().
1702
- *
1703
- * @param {boolean} [storeAsProperties=true]
1704
- * @return {Command} `this` command for chaining
1705
- */
1706
- storeOptionsAsProperties(storeAsProperties = true) {
1707
- if (this.options.length) {
1708
- throw new Error("call .storeOptionsAsProperties() before adding options");
1709
- }
1710
- if (Object.keys(this._optionValues).length) {
1711
- throw new Error(
1712
- "call .storeOptionsAsProperties() before setting option values"
1713
- );
1714
- }
1715
- this._storeOptionsAsProperties = !!storeAsProperties;
1716
- return this;
1717
- }
1718
- /**
1719
- * Retrieve option value.
1720
- *
1721
- * @param {string} key
1722
- * @return {object} value
1723
- */
1724
- getOptionValue(key) {
1725
- if (this._storeOptionsAsProperties) {
1726
- return this[key];
1727
- }
1728
- return this._optionValues[key];
1729
- }
1730
- /**
1731
- * Store option value.
1732
- *
1733
- * @param {string} key
1734
- * @param {object} value
1735
- * @return {Command} `this` command for chaining
1736
- */
1737
- setOptionValue(key, value) {
1738
- return this.setOptionValueWithSource(key, value, void 0);
1739
- }
1740
- /**
1741
- * Store option value and where the value came from.
1742
- *
1743
- * @param {string} key
1744
- * @param {object} value
1745
- * @param {string} source - expected values are default/config/env/cli/implied
1746
- * @return {Command} `this` command for chaining
1747
- */
1748
- setOptionValueWithSource(key, value, source) {
1749
- if (this._storeOptionsAsProperties) {
1750
- this[key] = value;
1751
- } else {
1752
- this._optionValues[key] = value;
1753
- }
1754
- this._optionValueSources[key] = source;
1755
- return this;
1756
- }
1757
- /**
1758
- * Get source of option value.
1759
- * Expected values are default | config | env | cli | implied
1760
- *
1761
- * @param {string} key
1762
- * @return {string}
1763
- */
1764
- getOptionValueSource(key) {
1765
- return this._optionValueSources[key];
1766
- }
1767
- /**
1768
- * Get source of option value. See also .optsWithGlobals().
1769
- * Expected values are default | config | env | cli | implied
1770
- *
1771
- * @param {string} key
1772
- * @return {string}
1773
- */
1774
- getOptionValueSourceWithGlobals(key) {
1775
- let source;
1776
- this._getCommandAndAncestors().forEach((cmd) => {
1777
- if (cmd.getOptionValueSource(key) !== void 0) {
1778
- source = cmd.getOptionValueSource(key);
1779
- }
1780
- });
1781
- return source;
1782
- }
1783
- /**
1784
- * Get user arguments from implied or explicit arguments.
1785
- * Side-effects: set _scriptPath if args included script. Used for default program name, and subcommand searches.
1786
- *
1787
- * @private
1788
- */
1789
- _prepareUserArgs(argv, parseOptions) {
1790
- if (argv !== void 0 && !Array.isArray(argv)) {
1791
- throw new Error("first parameter to parse must be array or undefined");
1792
- }
1793
- parseOptions = parseOptions || {};
1794
- if (argv === void 0 && parseOptions.from === void 0) {
1795
- if (process2.versions?.electron) {
1796
- parseOptions.from = "electron";
1797
- }
1798
- const execArgv = process2.execArgv ?? [];
1799
- if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
1800
- parseOptions.from = "eval";
1801
- }
1802
- }
1803
- if (argv === void 0) {
1804
- argv = process2.argv;
1805
- }
1806
- this.rawArgs = argv.slice();
1807
- let userArgs;
1808
- switch (parseOptions.from) {
1809
- case void 0:
1810
- case "node":
1811
- this._scriptPath = argv[1];
1812
- userArgs = argv.slice(2);
1813
- break;
1814
- case "electron":
1815
- if (process2.defaultApp) {
1816
- this._scriptPath = argv[1];
1817
- userArgs = argv.slice(2);
1818
- } else {
1819
- userArgs = argv.slice(1);
1820
- }
1821
- break;
1822
- case "user":
1823
- userArgs = argv.slice(0);
1824
- break;
1825
- case "eval":
1826
- userArgs = argv.slice(1);
1827
- break;
1828
- default:
1829
- throw new Error(
1830
- `unexpected parse option { from: '${parseOptions.from}' }`
1831
- );
1832
- }
1833
- if (!this._name && this._scriptPath)
1834
- this.nameFromFilename(this._scriptPath);
1835
- this._name = this._name || "program";
1836
- return userArgs;
1837
- }
1838
- /**
1839
- * Parse `argv`, setting options and invoking commands when defined.
1840
- *
1841
- * Use parseAsync instead of parse if any of your action handlers are async.
1842
- *
1843
- * Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
1844
- *
1845
- * Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
1846
- * - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
1847
- * - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
1848
- * - `'user'`: just user arguments
1849
- *
1850
- * @example
1851
- * program.parse(); // parse process.argv and auto-detect electron and special node flags
1852
- * program.parse(process.argv); // assume argv[0] is app and argv[1] is script
1853
- * program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
1854
- *
1855
- * @param {string[]} [argv] - optional, defaults to process.argv
1856
- * @param {object} [parseOptions] - optionally specify style of options with from: node/user/electron
1857
- * @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
1858
- * @return {Command} `this` command for chaining
1859
- */
1860
- parse(argv, parseOptions) {
1861
- const userArgs = this._prepareUserArgs(argv, parseOptions);
1862
- this._parseCommand([], userArgs);
1863
- return this;
1864
- }
1865
- /**
1866
- * Parse `argv`, setting options and invoking commands when defined.
1867
- *
1868
- * Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
1869
- *
1870
- * Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
1871
- * - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
1872
- * - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
1873
- * - `'user'`: just user arguments
1874
- *
1875
- * @example
1876
- * await program.parseAsync(); // parse process.argv and auto-detect electron and special node flags
1877
- * await program.parseAsync(process.argv); // assume argv[0] is app and argv[1] is script
1878
- * await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
1879
- *
1880
- * @param {string[]} [argv]
1881
- * @param {object} [parseOptions]
1882
- * @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
1883
- * @return {Promise}
1884
- */
1885
- async parseAsync(argv, parseOptions) {
1886
- const userArgs = this._prepareUserArgs(argv, parseOptions);
1887
- await this._parseCommand([], userArgs);
1888
- return this;
1889
- }
1890
- /**
1891
- * Execute a sub-command executable.
1892
- *
1893
- * @private
1894
- */
1895
- _executeSubCommand(subcommand, args) {
1896
- args = args.slice();
1897
- let launchWithNode = false;
1898
- const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1899
- function findFile(baseDir, baseName) {
1900
- const localBin = path.resolve(baseDir, baseName);
1901
- if (fs.existsSync(localBin)) return localBin;
1902
- if (sourceExt.includes(path.extname(baseName))) return void 0;
1903
- const foundExt = sourceExt.find(
1904
- (ext) => fs.existsSync(`${localBin}${ext}`)
1905
- );
1906
- if (foundExt) return `${localBin}${foundExt}`;
1907
- return void 0;
1908
- }
1909
- this._checkForMissingMandatoryOptions();
1910
- this._checkForConflictingOptions();
1911
- let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
1912
- let executableDir = this._executableDir || "";
1913
- if (this._scriptPath) {
1914
- let resolvedScriptPath;
1915
- try {
1916
- resolvedScriptPath = fs.realpathSync(this._scriptPath);
1917
- } catch (err) {
1918
- resolvedScriptPath = this._scriptPath;
1919
- }
1920
- executableDir = path.resolve(
1921
- path.dirname(resolvedScriptPath),
1922
- executableDir
1923
- );
1924
- }
1925
- if (executableDir) {
1926
- let localFile = findFile(executableDir, executableFile);
1927
- if (!localFile && !subcommand._executableFile && this._scriptPath) {
1928
- const legacyName = path.basename(
1929
- this._scriptPath,
1930
- path.extname(this._scriptPath)
1931
- );
1932
- if (legacyName !== this._name) {
1933
- localFile = findFile(
1934
- executableDir,
1935
- `${legacyName}-${subcommand._name}`
1936
- );
1937
- }
1938
- }
1939
- executableFile = localFile || executableFile;
1940
- }
1941
- launchWithNode = sourceExt.includes(path.extname(executableFile));
1942
- let proc;
1943
- if (process2.platform !== "win32") {
1944
- if (launchWithNode) {
1945
- args.unshift(executableFile);
1946
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1947
- proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
1948
- } else {
1949
- proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
1950
- }
1951
- } else {
1952
- args.unshift(executableFile);
1953
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1954
- proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
1955
- }
1956
- if (!proc.killed) {
1957
- const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
1958
- signals.forEach((signal) => {
1959
- process2.on(signal, () => {
1960
- if (proc.killed === false && proc.exitCode === null) {
1961
- proc.kill(signal);
1962
- }
1963
- });
1964
- });
1965
- }
1966
- const exitCallback = this._exitCallback;
1967
- proc.on("close", (code) => {
1968
- code = code ?? 1;
1969
- if (!exitCallback) {
1970
- process2.exit(code);
1971
- } else {
1972
- exitCallback(
1973
- new CommanderError2(
1974
- code,
1975
- "commander.executeSubCommandAsync",
1976
- "(close)"
1977
- )
1978
- );
1979
- }
1980
- });
1981
- proc.on("error", (err) => {
1982
- if (err.code === "ENOENT") {
1983
- const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
1984
- const executableMissing = `'${executableFile}' does not exist
1985
- - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
1986
- - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
1987
- - ${executableDirMessage}`;
1988
- throw new Error(executableMissing);
1989
- } else if (err.code === "EACCES") {
1990
- throw new Error(`'${executableFile}' not executable`);
1991
- }
1992
- if (!exitCallback) {
1993
- process2.exit(1);
1994
- } else {
1995
- const wrappedError = new CommanderError2(
1996
- 1,
1997
- "commander.executeSubCommandAsync",
1998
- "(error)"
1999
- );
2000
- wrappedError.nestedError = err;
2001
- exitCallback(wrappedError);
2002
- }
2003
- });
2004
- this.runningCommand = proc;
2005
- }
2006
- /**
2007
- * @private
2008
- */
2009
- _dispatchSubcommand(commandName, operands, unknown) {
2010
- const subCommand = this._findCommand(commandName);
2011
- if (!subCommand) this.help({ error: true });
2012
- let promiseChain;
2013
- promiseChain = this._chainOrCallSubCommandHook(
2014
- promiseChain,
2015
- subCommand,
2016
- "preSubcommand"
2017
- );
2018
- promiseChain = this._chainOrCall(promiseChain, () => {
2019
- if (subCommand._executableHandler) {
2020
- this._executeSubCommand(subCommand, operands.concat(unknown));
2021
- } else {
2022
- return subCommand._parseCommand(operands, unknown);
2023
- }
2024
- });
2025
- return promiseChain;
2026
- }
2027
- /**
2028
- * Invoke help directly if possible, or dispatch if necessary.
2029
- * e.g. help foo
2030
- *
2031
- * @private
2032
- */
2033
- _dispatchHelpCommand(subcommandName) {
2034
- if (!subcommandName) {
2035
- this.help();
2036
- }
2037
- const subCommand = this._findCommand(subcommandName);
2038
- if (subCommand && !subCommand._executableHandler) {
2039
- subCommand.help();
2040
- }
2041
- return this._dispatchSubcommand(
2042
- subcommandName,
2043
- [],
2044
- [this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]
2045
- );
2046
- }
2047
- /**
2048
- * Check this.args against expected this.registeredArguments.
2049
- *
2050
- * @private
2051
- */
2052
- _checkNumberOfArguments() {
2053
- this.registeredArguments.forEach((arg, i) => {
2054
- if (arg.required && this.args[i] == null) {
2055
- this.missingArgument(arg.name());
2056
- }
2057
- });
2058
- if (this.registeredArguments.length > 0 && this.registeredArguments[this.registeredArguments.length - 1].variadic) {
2059
- return;
2060
- }
2061
- if (this.args.length > this.registeredArguments.length) {
2062
- this._excessArguments(this.args);
2063
- }
2064
- }
2065
- /**
2066
- * Process this.args using this.registeredArguments and save as this.processedArgs!
2067
- *
2068
- * @private
2069
- */
2070
- _processArguments() {
2071
- const myParseArg = (argument, value, previous) => {
2072
- let parsedValue = value;
2073
- if (value !== null && argument.parseArg) {
2074
- const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
2075
- parsedValue = this._callParseArg(
2076
- argument,
2077
- value,
2078
- previous,
2079
- invalidValueMessage
2080
- );
2081
- }
2082
- return parsedValue;
2083
- };
2084
- this._checkNumberOfArguments();
2085
- const processedArgs = [];
2086
- this.registeredArguments.forEach((declaredArg, index) => {
2087
- let value = declaredArg.defaultValue;
2088
- if (declaredArg.variadic) {
2089
- if (index < this.args.length) {
2090
- value = this.args.slice(index);
2091
- if (declaredArg.parseArg) {
2092
- value = value.reduce((processed, v) => {
2093
- return myParseArg(declaredArg, v, processed);
2094
- }, declaredArg.defaultValue);
2095
- }
2096
- } else if (value === void 0) {
2097
- value = [];
2098
- }
2099
- } else if (index < this.args.length) {
2100
- value = this.args[index];
2101
- if (declaredArg.parseArg) {
2102
- value = myParseArg(declaredArg, value, declaredArg.defaultValue);
2103
- }
2104
- }
2105
- processedArgs[index] = value;
2106
- });
2107
- this.processedArgs = processedArgs;
2108
- }
2109
- /**
2110
- * Once we have a promise we chain, but call synchronously until then.
2111
- *
2112
- * @param {(Promise|undefined)} promise
2113
- * @param {Function} fn
2114
- * @return {(Promise|undefined)}
2115
- * @private
2116
- */
2117
- _chainOrCall(promise, fn) {
2118
- if (promise && promise.then && typeof promise.then === "function") {
2119
- return promise.then(() => fn());
2120
- }
2121
- return fn();
2122
- }
2123
- /**
2124
- *
2125
- * @param {(Promise|undefined)} promise
2126
- * @param {string} event
2127
- * @return {(Promise|undefined)}
2128
- * @private
2129
- */
2130
- _chainOrCallHooks(promise, event) {
2131
- let result = promise;
2132
- const hooks = [];
2133
- this._getCommandAndAncestors().reverse().filter((cmd) => cmd._lifeCycleHooks[event] !== void 0).forEach((hookedCommand) => {
2134
- hookedCommand._lifeCycleHooks[event].forEach((callback) => {
2135
- hooks.push({ hookedCommand, callback });
2136
- });
2137
- });
2138
- if (event === "postAction") {
2139
- hooks.reverse();
2140
- }
2141
- hooks.forEach((hookDetail) => {
2142
- result = this._chainOrCall(result, () => {
2143
- return hookDetail.callback(hookDetail.hookedCommand, this);
2144
- });
2145
- });
2146
- return result;
2147
- }
2148
- /**
2149
- *
2150
- * @param {(Promise|undefined)} promise
2151
- * @param {Command} subCommand
2152
- * @param {string} event
2153
- * @return {(Promise|undefined)}
2154
- * @private
2155
- */
2156
- _chainOrCallSubCommandHook(promise, subCommand, event) {
2157
- let result = promise;
2158
- if (this._lifeCycleHooks[event] !== void 0) {
2159
- this._lifeCycleHooks[event].forEach((hook) => {
2160
- result = this._chainOrCall(result, () => {
2161
- return hook(this, subCommand);
2162
- });
2163
- });
2164
- }
2165
- return result;
2166
- }
2167
- /**
2168
- * Process arguments in context of this command.
2169
- * Returns action result, in case it is a promise.
2170
- *
2171
- * @private
2172
- */
2173
- _parseCommand(operands, unknown) {
2174
- const parsed = this.parseOptions(unknown);
2175
- this._parseOptionsEnv();
2176
- this._parseOptionsImplied();
2177
- operands = operands.concat(parsed.operands);
2178
- unknown = parsed.unknown;
2179
- this.args = operands.concat(unknown);
2180
- if (operands && this._findCommand(operands[0])) {
2181
- return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
2182
- }
2183
- if (this._getHelpCommand() && operands[0] === this._getHelpCommand().name()) {
2184
- return this._dispatchHelpCommand(operands[1]);
2185
- }
2186
- if (this._defaultCommandName) {
2187
- this._outputHelpIfRequested(unknown);
2188
- return this._dispatchSubcommand(
2189
- this._defaultCommandName,
2190
- operands,
2191
- unknown
2192
- );
2193
- }
2194
- if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
2195
- this.help({ error: true });
2196
- }
2197
- this._outputHelpIfRequested(parsed.unknown);
2198
- this._checkForMissingMandatoryOptions();
2199
- this._checkForConflictingOptions();
2200
- const checkForUnknownOptions = () => {
2201
- if (parsed.unknown.length > 0) {
2202
- this.unknownOption(parsed.unknown[0]);
2203
- }
2204
- };
2205
- const commandEvent = `command:${this.name()}`;
2206
- if (this._actionHandler) {
2207
- checkForUnknownOptions();
2208
- this._processArguments();
2209
- let promiseChain;
2210
- promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
2211
- promiseChain = this._chainOrCall(
2212
- promiseChain,
2213
- () => this._actionHandler(this.processedArgs)
2214
- );
2215
- if (this.parent) {
2216
- promiseChain = this._chainOrCall(promiseChain, () => {
2217
- this.parent.emit(commandEvent, operands, unknown);
2218
- });
2219
- }
2220
- promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
2221
- return promiseChain;
2222
- }
2223
- if (this.parent && this.parent.listenerCount(commandEvent)) {
2224
- checkForUnknownOptions();
2225
- this._processArguments();
2226
- this.parent.emit(commandEvent, operands, unknown);
2227
- } else if (operands.length) {
2228
- if (this._findCommand("*")) {
2229
- return this._dispatchSubcommand("*", operands, unknown);
2230
- }
2231
- if (this.listenerCount("command:*")) {
2232
- this.emit("command:*", operands, unknown);
2233
- } else if (this.commands.length) {
2234
- this.unknownCommand();
2235
- } else {
2236
- checkForUnknownOptions();
2237
- this._processArguments();
2238
- }
2239
- } else if (this.commands.length) {
2240
- checkForUnknownOptions();
2241
- this.help({ error: true });
2242
- } else {
2243
- checkForUnknownOptions();
2244
- this._processArguments();
2245
- }
2246
- }
2247
- /**
2248
- * Find matching command.
2249
- *
2250
- * @private
2251
- * @return {Command | undefined}
2252
- */
2253
- _findCommand(name) {
2254
- if (!name) return void 0;
2255
- return this.commands.find(
2256
- (cmd) => cmd._name === name || cmd._aliases.includes(name)
2257
- );
2258
- }
2259
- /**
2260
- * Return an option matching `arg` if any.
2261
- *
2262
- * @param {string} arg
2263
- * @return {Option}
2264
- * @package
2265
- */
2266
- _findOption(arg) {
2267
- return this.options.find((option) => option.is(arg));
2268
- }
2269
- /**
2270
- * Display an error message if a mandatory option does not have a value.
2271
- * Called after checking for help flags in leaf subcommand.
2272
- *
2273
- * @private
2274
- */
2275
- _checkForMissingMandatoryOptions() {
2276
- this._getCommandAndAncestors().forEach((cmd) => {
2277
- cmd.options.forEach((anOption) => {
2278
- if (anOption.mandatory && cmd.getOptionValue(anOption.attributeName()) === void 0) {
2279
- cmd.missingMandatoryOptionValue(anOption);
2280
- }
2281
- });
2282
- });
2283
- }
2284
- /**
2285
- * Display an error message if conflicting options are used together in this.
2286
- *
2287
- * @private
2288
- */
2289
- _checkForConflictingLocalOptions() {
2290
- const definedNonDefaultOptions = this.options.filter((option) => {
2291
- const optionKey = option.attributeName();
2292
- if (this.getOptionValue(optionKey) === void 0) {
2293
- return false;
2294
- }
2295
- return this.getOptionValueSource(optionKey) !== "default";
2296
- });
2297
- const optionsWithConflicting = definedNonDefaultOptions.filter(
2298
- (option) => option.conflictsWith.length > 0
2299
- );
2300
- optionsWithConflicting.forEach((option) => {
2301
- const conflictingAndDefined = definedNonDefaultOptions.find(
2302
- (defined) => option.conflictsWith.includes(defined.attributeName())
2303
- );
2304
- if (conflictingAndDefined) {
2305
- this._conflictingOption(option, conflictingAndDefined);
2306
- }
2307
- });
2308
- }
2309
- /**
2310
- * Display an error message if conflicting options are used together.
2311
- * Called after checking for help flags in leaf subcommand.
2312
- *
2313
- * @private
2314
- */
2315
- _checkForConflictingOptions() {
2316
- this._getCommandAndAncestors().forEach((cmd) => {
2317
- cmd._checkForConflictingLocalOptions();
2318
- });
2319
- }
2320
- /**
2321
- * Parse options from `argv` removing known options,
2322
- * and return argv split into operands and unknown arguments.
2323
- *
2324
- * Examples:
2325
- *
2326
- * argv => operands, unknown
2327
- * --known kkk op => [op], []
2328
- * op --known kkk => [op], []
2329
- * sub --unknown uuu op => [sub], [--unknown uuu op]
2330
- * sub -- --unknown uuu op => [sub --unknown uuu op], []
2331
- *
2332
- * @param {string[]} argv
2333
- * @return {{operands: string[], unknown: string[]}}
2334
- */
2335
- parseOptions(argv) {
2336
- const operands = [];
2337
- const unknown = [];
2338
- let dest = operands;
2339
- const args = argv.slice();
2340
- function maybeOption(arg) {
2341
- return arg.length > 1 && arg[0] === "-";
2342
- }
2343
- let activeVariadicOption = null;
2344
- while (args.length) {
2345
- const arg = args.shift();
2346
- if (arg === "--") {
2347
- if (dest === unknown) dest.push(arg);
2348
- dest.push(...args);
2349
- break;
2350
- }
2351
- if (activeVariadicOption && !maybeOption(arg)) {
2352
- this.emit(`option:${activeVariadicOption.name()}`, arg);
2353
- continue;
2354
- }
2355
- activeVariadicOption = null;
2356
- if (maybeOption(arg)) {
2357
- const option = this._findOption(arg);
2358
- if (option) {
2359
- if (option.required) {
2360
- const value = args.shift();
2361
- if (value === void 0) this.optionMissingArgument(option);
2362
- this.emit(`option:${option.name()}`, value);
2363
- } else if (option.optional) {
2364
- let value = null;
2365
- if (args.length > 0 && !maybeOption(args[0])) {
2366
- value = args.shift();
2367
- }
2368
- this.emit(`option:${option.name()}`, value);
2369
- } else {
2370
- this.emit(`option:${option.name()}`);
2371
- }
2372
- activeVariadicOption = option.variadic ? option : null;
2373
- continue;
2374
- }
2375
- }
2376
- if (arg.length > 2 && arg[0] === "-" && arg[1] !== "-") {
2377
- const option = this._findOption(`-${arg[1]}`);
2378
- if (option) {
2379
- if (option.required || option.optional && this._combineFlagAndOptionalValue) {
2380
- this.emit(`option:${option.name()}`, arg.slice(2));
2381
- } else {
2382
- this.emit(`option:${option.name()}`);
2383
- args.unshift(`-${arg.slice(2)}`);
2384
- }
2385
- continue;
2386
- }
2387
- }
2388
- if (/^--[^=]+=/.test(arg)) {
2389
- const index = arg.indexOf("=");
2390
- const option = this._findOption(arg.slice(0, index));
2391
- if (option && (option.required || option.optional)) {
2392
- this.emit(`option:${option.name()}`, arg.slice(index + 1));
2393
- continue;
2394
- }
2395
- }
2396
- if (maybeOption(arg)) {
2397
- dest = unknown;
2398
- }
2399
- if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
2400
- if (this._findCommand(arg)) {
2401
- operands.push(arg);
2402
- if (args.length > 0) unknown.push(...args);
2403
- break;
2404
- } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
2405
- operands.push(arg);
2406
- if (args.length > 0) operands.push(...args);
2407
- break;
2408
- } else if (this._defaultCommandName) {
2409
- unknown.push(arg);
2410
- if (args.length > 0) unknown.push(...args);
2411
- break;
2412
- }
2413
- }
2414
- if (this._passThroughOptions) {
2415
- dest.push(arg);
2416
- if (args.length > 0) dest.push(...args);
2417
- break;
2418
- }
2419
- dest.push(arg);
2420
- }
2421
- return { operands, unknown };
2422
- }
2423
- /**
2424
- * Return an object containing local option values as key-value pairs.
2425
- *
2426
- * @return {object}
2427
- */
2428
- opts() {
2429
- if (this._storeOptionsAsProperties) {
2430
- const result = {};
2431
- const len = this.options.length;
2432
- for (let i = 0; i < len; i++) {
2433
- const key = this.options[i].attributeName();
2434
- result[key] = key === this._versionOptionName ? this._version : this[key];
2435
- }
2436
- return result;
2437
- }
2438
- return this._optionValues;
2439
- }
2440
- /**
2441
- * Return an object containing merged local and global option values as key-value pairs.
2442
- *
2443
- * @return {object}
2444
- */
2445
- optsWithGlobals() {
2446
- return this._getCommandAndAncestors().reduce(
2447
- (combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()),
2448
- {}
2449
- );
2450
- }
2451
- /**
2452
- * Display error message and exit (or call exitOverride).
2453
- *
2454
- * @param {string} message
2455
- * @param {object} [errorOptions]
2456
- * @param {string} [errorOptions.code] - an id string representing the error
2457
- * @param {number} [errorOptions.exitCode] - used with process.exit
2458
- */
2459
- error(message, errorOptions) {
2460
- this._outputConfiguration.outputError(
2461
- `${message}
2462
- `,
2463
- this._outputConfiguration.writeErr
2464
- );
2465
- if (typeof this._showHelpAfterError === "string") {
2466
- this._outputConfiguration.writeErr(`${this._showHelpAfterError}
2467
- `);
2468
- } else if (this._showHelpAfterError) {
2469
- this._outputConfiguration.writeErr("\n");
2470
- this.outputHelp({ error: true });
2471
- }
2472
- const config = errorOptions || {};
2473
- const exitCode = config.exitCode || 1;
2474
- const code = config.code || "commander.error";
2475
- this._exit(exitCode, code, message);
2476
- }
2477
- /**
2478
- * Apply any option related environment variables, if option does
2479
- * not have a value from cli or client code.
2480
- *
2481
- * @private
2482
- */
2483
- _parseOptionsEnv() {
2484
- this.options.forEach((option) => {
2485
- if (option.envVar && option.envVar in process2.env) {
2486
- const optionKey = option.attributeName();
2487
- if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
2488
- this.getOptionValueSource(optionKey)
2489
- )) {
2490
- if (option.required || option.optional) {
2491
- this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
2492
- } else {
2493
- this.emit(`optionEnv:${option.name()}`);
2494
- }
2495
- }
2496
- }
2497
- });
2498
- }
2499
- /**
2500
- * Apply any implied option values, if option is undefined or default value.
2501
- *
2502
- * @private
2503
- */
2504
- _parseOptionsImplied() {
2505
- const dualHelper = new DualOptions(this.options);
2506
- const hasCustomOptionValue = (optionKey) => {
2507
- return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
2508
- };
2509
- this.options.filter(
2510
- (option) => option.implied !== void 0 && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(
2511
- this.getOptionValue(option.attributeName()),
2512
- option
2513
- )
2514
- ).forEach((option) => {
2515
- Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
2516
- this.setOptionValueWithSource(
2517
- impliedKey,
2518
- option.implied[impliedKey],
2519
- "implied"
2520
- );
2521
- });
2522
- });
2523
- }
2524
- /**
2525
- * Argument `name` is missing.
2526
- *
2527
- * @param {string} name
2528
- * @private
2529
- */
2530
- missingArgument(name) {
2531
- const message = `error: missing required argument '${name}'`;
2532
- this.error(message, { code: "commander.missingArgument" });
2533
- }
2534
- /**
2535
- * `Option` is missing an argument.
2536
- *
2537
- * @param {Option} option
2538
- * @private
2539
- */
2540
- optionMissingArgument(option) {
2541
- const message = `error: option '${option.flags}' argument missing`;
2542
- this.error(message, { code: "commander.optionMissingArgument" });
2543
- }
2544
- /**
2545
- * `Option` does not have a value, and is a mandatory option.
2546
- *
2547
- * @param {Option} option
2548
- * @private
2549
- */
2550
- missingMandatoryOptionValue(option) {
2551
- const message = `error: required option '${option.flags}' not specified`;
2552
- this.error(message, { code: "commander.missingMandatoryOptionValue" });
2553
- }
2554
- /**
2555
- * `Option` conflicts with another option.
2556
- *
2557
- * @param {Option} option
2558
- * @param {Option} conflictingOption
2559
- * @private
2560
- */
2561
- _conflictingOption(option, conflictingOption) {
2562
- const findBestOptionFromValue = (option2) => {
2563
- const optionKey = option2.attributeName();
2564
- const optionValue = this.getOptionValue(optionKey);
2565
- const negativeOption = this.options.find(
2566
- (target) => target.negate && optionKey === target.attributeName()
2567
- );
2568
- const positiveOption = this.options.find(
2569
- (target) => !target.negate && optionKey === target.attributeName()
2570
- );
2571
- if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
2572
- return negativeOption;
2573
- }
2574
- return positiveOption || option2;
2575
- };
2576
- const getErrorMessage = (option2) => {
2577
- const bestOption = findBestOptionFromValue(option2);
2578
- const optionKey = bestOption.attributeName();
2579
- const source = this.getOptionValueSource(optionKey);
2580
- if (source === "env") {
2581
- return `environment variable '${bestOption.envVar}'`;
2582
- }
2583
- return `option '${bestOption.flags}'`;
2584
- };
2585
- const message = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
2586
- this.error(message, { code: "commander.conflictingOption" });
2587
- }
2588
- /**
2589
- * Unknown option `flag`.
2590
- *
2591
- * @param {string} flag
2592
- * @private
2593
- */
2594
- unknownOption(flag) {
2595
- if (this._allowUnknownOption) return;
2596
- let suggestion = "";
2597
- if (flag.startsWith("--") && this._showSuggestionAfterError) {
2598
- let candidateFlags = [];
2599
- let command = this;
2600
- do {
2601
- const moreFlags = command.createHelp().visibleOptions(command).filter((option) => option.long).map((option) => option.long);
2602
- candidateFlags = candidateFlags.concat(moreFlags);
2603
- command = command.parent;
2604
- } while (command && !command._enablePositionalOptions);
2605
- suggestion = suggestSimilar(flag, candidateFlags);
2606
- }
2607
- const message = `error: unknown option '${flag}'${suggestion}`;
2608
- this.error(message, { code: "commander.unknownOption" });
2609
- }
2610
- /**
2611
- * Excess arguments, more than expected.
2612
- *
2613
- * @param {string[]} receivedArgs
2614
- * @private
2615
- */
2616
- _excessArguments(receivedArgs) {
2617
- if (this._allowExcessArguments) return;
2618
- const expected = this.registeredArguments.length;
2619
- const s = expected === 1 ? "" : "s";
2620
- const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
2621
- const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
2622
- this.error(message, { code: "commander.excessArguments" });
2623
- }
2624
- /**
2625
- * Unknown command.
2626
- *
2627
- * @private
2628
- */
2629
- unknownCommand() {
2630
- const unknownName = this.args[0];
2631
- let suggestion = "";
2632
- if (this._showSuggestionAfterError) {
2633
- const candidateNames = [];
2634
- this.createHelp().visibleCommands(this).forEach((command) => {
2635
- candidateNames.push(command.name());
2636
- if (command.alias()) candidateNames.push(command.alias());
2637
- });
2638
- suggestion = suggestSimilar(unknownName, candidateNames);
2639
- }
2640
- const message = `error: unknown command '${unknownName}'${suggestion}`;
2641
- this.error(message, { code: "commander.unknownCommand" });
2642
- }
2643
- /**
2644
- * Get or set the program version.
2645
- *
2646
- * This method auto-registers the "-V, --version" option which will print the version number.
2647
- *
2648
- * You can optionally supply the flags and description to override the defaults.
2649
- *
2650
- * @param {string} [str]
2651
- * @param {string} [flags]
2652
- * @param {string} [description]
2653
- * @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
2654
- */
2655
- version(str, flags, description) {
2656
- if (str === void 0) return this._version;
2657
- this._version = str;
2658
- flags = flags || "-V, --version";
2659
- description = description || "output the version number";
2660
- const versionOption = this.createOption(flags, description);
2661
- this._versionOptionName = versionOption.attributeName();
2662
- this._registerOption(versionOption);
2663
- this.on("option:" + versionOption.name(), () => {
2664
- this._outputConfiguration.writeOut(`${str}
2665
- `);
2666
- this._exit(0, "commander.version", str);
2667
- });
2668
- return this;
2669
- }
2670
- /**
2671
- * Set the description.
2672
- *
2673
- * @param {string} [str]
2674
- * @param {object} [argsDescription]
2675
- * @return {(string|Command)}
2676
- */
2677
- description(str, argsDescription) {
2678
- if (str === void 0 && argsDescription === void 0)
2679
- return this._description;
2680
- this._description = str;
2681
- if (argsDescription) {
2682
- this._argsDescription = argsDescription;
2683
- }
2684
- return this;
2685
- }
2686
- /**
2687
- * Set the summary. Used when listed as subcommand of parent.
2688
- *
2689
- * @param {string} [str]
2690
- * @return {(string|Command)}
2691
- */
2692
- summary(str) {
2693
- if (str === void 0) return this._summary;
2694
- this._summary = str;
2695
- return this;
2696
- }
2697
- /**
2698
- * Set an alias for the command.
2699
- *
2700
- * You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
2701
- *
2702
- * @param {string} [alias]
2703
- * @return {(string|Command)}
2704
- */
2705
- alias(alias) {
2706
- if (alias === void 0) return this._aliases[0];
2707
- let command = this;
2708
- if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
2709
- command = this.commands[this.commands.length - 1];
2710
- }
2711
- if (alias === command._name)
2712
- throw new Error("Command alias can't be the same as its name");
2713
- const matchingCommand = this.parent?._findCommand(alias);
2714
- if (matchingCommand) {
2715
- const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
2716
- throw new Error(
2717
- `cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`
2718
- );
2719
- }
2720
- command._aliases.push(alias);
2721
- return this;
2722
- }
2723
- /**
2724
- * Set aliases for the command.
2725
- *
2726
- * Only the first alias is shown in the auto-generated help.
2727
- *
2728
- * @param {string[]} [aliases]
2729
- * @return {(string[]|Command)}
2730
- */
2731
- aliases(aliases) {
2732
- if (aliases === void 0) return this._aliases;
2733
- aliases.forEach((alias) => this.alias(alias));
2734
- return this;
2735
- }
2736
- /**
2737
- * Set / get the command usage `str`.
2738
- *
2739
- * @param {string} [str]
2740
- * @return {(string|Command)}
2741
- */
2742
- usage(str) {
2743
- if (str === void 0) {
2744
- if (this._usage) return this._usage;
2745
- const args = this.registeredArguments.map((arg) => {
2746
- return humanReadableArgName(arg);
2747
- });
2748
- return [].concat(
2749
- this.options.length || this._helpOption !== null ? "[options]" : [],
2750
- this.commands.length ? "[command]" : [],
2751
- this.registeredArguments.length ? args : []
2752
- ).join(" ");
2753
- }
2754
- this._usage = str;
2755
- return this;
2756
- }
2757
- /**
2758
- * Get or set the name of the command.
2759
- *
2760
- * @param {string} [str]
2761
- * @return {(string|Command)}
2762
- */
2763
- name(str) {
2764
- if (str === void 0) return this._name;
2765
- this._name = str;
2766
- return this;
2767
- }
2768
- /**
2769
- * Set the name of the command from script filename, such as process.argv[1],
2770
- * or require.main.filename, or __filename.
2771
- *
2772
- * (Used internally and public although not documented in README.)
2773
- *
2774
- * @example
2775
- * program.nameFromFilename(require.main.filename);
2776
- *
2777
- * @param {string} filename
2778
- * @return {Command}
2779
- */
2780
- nameFromFilename(filename) {
2781
- this._name = path.basename(filename, path.extname(filename));
2782
- return this;
2783
- }
2784
- /**
2785
- * Get or set the directory for searching for executable subcommands of this command.
2786
- *
2787
- * @example
2788
- * program.executableDir(__dirname);
2789
- * // or
2790
- * program.executableDir('subcommands');
2791
- *
2792
- * @param {string} [path]
2793
- * @return {(string|null|Command)}
2794
- */
2795
- executableDir(path2) {
2796
- if (path2 === void 0) return this._executableDir;
2797
- this._executableDir = path2;
2798
- return this;
2799
- }
2800
- /**
2801
- * Return program help documentation.
2802
- *
2803
- * @param {{ error: boolean }} [contextOptions] - pass {error:true} to wrap for stderr instead of stdout
2804
- * @return {string}
2805
- */
2806
- helpInformation(contextOptions) {
2807
- const helper = this.createHelp();
2808
- if (helper.helpWidth === void 0) {
2809
- helper.helpWidth = contextOptions && contextOptions.error ? this._outputConfiguration.getErrHelpWidth() : this._outputConfiguration.getOutHelpWidth();
2810
- }
2811
- return helper.formatHelp(this, helper);
2812
- }
2813
- /**
2814
- * @private
2815
- */
2816
- _getHelpContext(contextOptions) {
2817
- contextOptions = contextOptions || {};
2818
- const context = { error: !!contextOptions.error };
2819
- let write;
2820
- if (context.error) {
2821
- write = (arg) => this._outputConfiguration.writeErr(arg);
2822
- } else {
2823
- write = (arg) => this._outputConfiguration.writeOut(arg);
2824
- }
2825
- context.write = contextOptions.write || write;
2826
- context.command = this;
2827
- return context;
2828
- }
2829
- /**
2830
- * Output help information for this command.
2831
- *
2832
- * Outputs built-in help, and custom text added using `.addHelpText()`.
2833
- *
2834
- * @param {{ error: boolean } | Function} [contextOptions] - pass {error:true} to write to stderr instead of stdout
2835
- */
2836
- outputHelp(contextOptions) {
2837
- let deprecatedCallback;
2838
- if (typeof contextOptions === "function") {
2839
- deprecatedCallback = contextOptions;
2840
- contextOptions = void 0;
2841
- }
2842
- const context = this._getHelpContext(contextOptions);
2843
- this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", context));
2844
- this.emit("beforeHelp", context);
2845
- let helpInformation = this.helpInformation(context);
2846
- if (deprecatedCallback) {
2847
- helpInformation = deprecatedCallback(helpInformation);
2848
- if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
2849
- throw new Error("outputHelp callback must return a string or a Buffer");
2850
- }
2851
- }
2852
- context.write(helpInformation);
2853
- if (this._getHelpOption()?.long) {
2854
- this.emit(this._getHelpOption().long);
2855
- }
2856
- this.emit("afterHelp", context);
2857
- this._getCommandAndAncestors().forEach(
2858
- (command) => command.emit("afterAllHelp", context)
2859
- );
2860
- }
2861
- /**
2862
- * You can pass in flags and a description to customise the built-in help option.
2863
- * Pass in false to disable the built-in help option.
2864
- *
2865
- * @example
2866
- * program.helpOption('-?, --help' 'show help'); // customise
2867
- * program.helpOption(false); // disable
2868
- *
2869
- * @param {(string | boolean)} flags
2870
- * @param {string} [description]
2871
- * @return {Command} `this` command for chaining
2872
- */
2873
- helpOption(flags, description) {
2874
- if (typeof flags === "boolean") {
2875
- if (flags) {
2876
- this._helpOption = this._helpOption ?? void 0;
2877
- } else {
2878
- this._helpOption = null;
2879
- }
2880
- return this;
2881
- }
2882
- flags = flags ?? "-h, --help";
2883
- description = description ?? "display help for command";
2884
- this._helpOption = this.createOption(flags, description);
2885
- return this;
2886
- }
2887
- /**
2888
- * Lazy create help option.
2889
- * Returns null if has been disabled with .helpOption(false).
2890
- *
2891
- * @returns {(Option | null)} the help option
2892
- * @package
2893
- */
2894
- _getHelpOption() {
2895
- if (this._helpOption === void 0) {
2896
- this.helpOption(void 0, void 0);
2897
- }
2898
- return this._helpOption;
2899
- }
2900
- /**
2901
- * Supply your own option to use for the built-in help option.
2902
- * This is an alternative to using helpOption() to customise the flags and description etc.
2903
- *
2904
- * @param {Option} option
2905
- * @return {Command} `this` command for chaining
2906
- */
2907
- addHelpOption(option) {
2908
- this._helpOption = option;
2909
- return this;
2910
- }
2911
- /**
2912
- * Output help information and exit.
2913
- *
2914
- * Outputs built-in help, and custom text added using `.addHelpText()`.
2915
- *
2916
- * @param {{ error: boolean }} [contextOptions] - pass {error:true} to write to stderr instead of stdout
2917
- */
2918
- help(contextOptions) {
2919
- this.outputHelp(contextOptions);
2920
- let exitCode = process2.exitCode || 0;
2921
- if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
2922
- exitCode = 1;
2923
- }
2924
- this._exit(exitCode, "commander.help", "(outputHelp)");
2925
- }
2926
- /**
2927
- * Add additional text to be displayed with the built-in help.
2928
- *
2929
- * Position is 'before' or 'after' to affect just this command,
2930
- * and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
2931
- *
2932
- * @param {string} position - before or after built-in help
2933
- * @param {(string | Function)} text - string to add, or a function returning a string
2934
- * @return {Command} `this` command for chaining
2935
- */
2936
- addHelpText(position, text) {
2937
- const allowedValues = ["beforeAll", "before", "after", "afterAll"];
2938
- if (!allowedValues.includes(position)) {
2939
- throw new Error(`Unexpected value for position to addHelpText.
2940
- Expecting one of '${allowedValues.join("', '")}'`);
2941
- }
2942
- const helpEvent = `${position}Help`;
2943
- this.on(helpEvent, (context) => {
2944
- let helpStr;
2945
- if (typeof text === "function") {
2946
- helpStr = text({ error: context.error, command: context.command });
2947
- } else {
2948
- helpStr = text;
2949
- }
2950
- if (helpStr) {
2951
- context.write(`${helpStr}
2952
- `);
2953
- }
2954
- });
2955
- return this;
2956
- }
2957
- /**
2958
- * Output help information if help flags specified
2959
- *
2960
- * @param {Array} args - array of options to search for help flags
2961
- * @private
2962
- */
2963
- _outputHelpIfRequested(args) {
2964
- const helpOption = this._getHelpOption();
2965
- const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
2966
- if (helpRequested) {
2967
- this.outputHelp();
2968
- this._exit(0, "commander.helpDisplayed", "(outputHelp)");
2969
- }
2970
- }
2971
- };
2972
- function incrementNodeInspectorPort(args) {
2973
- return args.map((arg) => {
2974
- if (!arg.startsWith("--inspect")) {
2975
- return arg;
2976
- }
2977
- let debugOption;
2978
- let debugHost = "127.0.0.1";
2979
- let debugPort = "9229";
2980
- let match;
2981
- if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
2982
- debugOption = match[1];
2983
- } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
2984
- debugOption = match[1];
2985
- if (/^\d+$/.test(match[3])) {
2986
- debugPort = match[3];
2987
- } else {
2988
- debugHost = match[3];
2989
- }
2990
- } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
2991
- debugOption = match[1];
2992
- debugHost = match[3];
2993
- debugPort = match[4];
2994
- }
2995
- if (debugOption && debugPort !== "0") {
2996
- return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
2997
- }
2998
- return arg;
2999
- });
3000
117
  }
3001
- exports.Command = Command2;
118
+ return null;
3002
119
  }
3003
- });
3004
-
3005
- // node_modules/commander/index.js
3006
- var require_commander = __commonJS({
3007
- "node_modules/commander/index.js"(exports) {
3008
- var { Argument: Argument2 } = require_argument();
3009
- var { Command: Command2 } = require_command();
3010
- var { CommanderError: CommanderError2, InvalidArgumentError: InvalidArgumentError2 } = require_error();
3011
- var { Help: Help2 } = require_help();
3012
- var { Option: Option2 } = require_option();
3013
- exports.program = new Command2();
3014
- exports.createCommand = (name) => new Command2(name);
3015
- exports.createOption = (flags, description) => new Option2(flags, description);
3016
- exports.createArgument = (name, description) => new Argument2(name, description);
3017
- exports.Command = Command2;
3018
- exports.Option = Option2;
3019
- exports.Argument = Argument2;
3020
- exports.Help = Help2;
3021
- exports.CommanderError = CommanderError2;
3022
- exports.InvalidArgumentError = InvalidArgumentError2;
3023
- exports.InvalidOptionArgumentError = InvalidArgumentError2;
120
+ extractLinks(html) {
121
+ const { JSDOM } = jsdom;
122
+ const dom = new JSDOM(html);
123
+ const links = Array.from(dom.window.document.querySelectorAll("a"));
124
+ const hrefs = links.map((link) => link.href);
125
+ const internalLinks = hrefs.filter((href) => this.isInternalLink(href));
126
+ this.logger.debug(
127
+ `Extracted ${internalLinks.length} internal links from HTML content`
128
+ );
129
+ return internalLinks.map((link) => this.convertRelativeUrlToAbsolute(link));
3024
130
  }
3025
- });
3026
-
3027
- // node_modules/commander/esm.mjs
3028
- var import_index = __toESM(require_commander(), 1);
3029
- var {
3030
- program,
3031
- createCommand,
3032
- createArgument,
3033
- createOption,
3034
- CommanderError,
3035
- InvalidArgumentError,
3036
- InvalidOptionArgumentError,
3037
- // deprecated old name
3038
- Command,
3039
- Argument,
3040
- Option,
3041
- Help
3042
- } = import_index.default;
3043
-
3044
- // package.json
3045
- var package_default = {
3046
- name: "sentinel-scanner",
3047
- description: "[WIP] An open-source web app vulnerability scanner developed by Rebackk.",
3048
- version: "0.0.0-development",
3049
- exports: "./build/index.js",
3050
- types: "./build/index.d.ts",
3051
- bin: "./build/index.js",
3052
- main: "./build/index.js",
3053
- license: "Apache-2.0",
3054
- engines: {
3055
- node: "^22.11.0",
3056
- npm: "^10.5.0"
3057
- },
3058
- volta: {
3059
- node: "22.8.0",
3060
- npm: "10.9.0"
3061
- },
3062
- publishConfig: {
3063
- access: "public"
3064
- },
3065
- scripts: {
3066
- build: "node --disable-warning=ExperimentalWarning --experimental-strip-types ./scripts/build.ts",
3067
- clean: "rimraf build coverage",
3068
- "type:check": "tsc --noEmit",
3069
- lint: "biome check . --write --unsafe",
3070
- "lint:check": "biome ci .",
3071
- test: "node --disable-warning=ExperimentalWarning --experimental-strip-types ./scripts/test.ts test",
3072
- "test:watch": "node --disable-warning=ExperimentalWarning --experimental-strip-types ./scripts/test.ts test:watch",
3073
- "test:coverage": "node --disable-warning=ExperimentalWarning --experimental-strip-types ./scripts/test.ts test:coverage",
3074
- "spell:check": 'cspell "{README.md,CODE_OF_CONDUCT.md,CONTRIBUTING.md,.github/*.md,src/**/*.ts}"',
3075
- cz: "cz",
3076
- "semantic-release": "semantic-release"
3077
- },
3078
- devDependencies: {
3079
- "@biomejs/biome": "^1.9.4",
3080
- "@microsoft/api-extractor": "^7.47.11",
3081
- "@ryansonshine/commitizen": "^4.2.8",
3082
- "@ryansonshine/cz-conventional-changelog": "^3.3.4",
3083
- "@semantic-release/changelog": "^6.0.3",
3084
- "@semantic-release/commit-analyzer": "^13.0.0",
3085
- "@semantic-release/github": "^10.3.5",
3086
- "@semantic-release/npm": "^12.0.1",
3087
- "@semantic-release/release-notes-generator": "^14.0.1",
3088
- "@types/commander": "^2.12.0",
3089
- "@types/node": "^22.9.0",
3090
- "@types/prompts": "^2.4.9",
3091
- c8: "^10.1.2",
3092
- cspell: "^8.15.7",
3093
- "cz-conventional-changelog": "^3.3.0",
3094
- esbuild: "^0.23.1",
3095
- rimraf: "^6.0.1",
3096
- "semantic-release": "^24.2.0",
3097
- typescript: "^5.6.3"
3098
- },
3099
- config: {
3100
- commitizen: {
3101
- path: "./node_modules/cz-conventional-changelog"
131
+ async crawl() {
132
+ const visited = /* @__PURE__ */ new Set();
133
+ const queue = /* @__PURE__ */ new Set([this.url.href]);
134
+ const resultLinks = /* @__PURE__ */ new Set();
135
+ const assetExtensions = [
136
+ ".css",
137
+ ".js",
138
+ ".png",
139
+ ".jpg",
140
+ ".jpeg",
141
+ ".gif",
142
+ ".svg",
143
+ ".ico",
144
+ ".webp",
145
+ ".mp4",
146
+ ".mp3",
147
+ ".wav",
148
+ ".avi",
149
+ ".mov",
150
+ ".webm",
151
+ ".pdf",
152
+ ".doc",
153
+ ".docx",
154
+ ".xls",
155
+ ".xlsx",
156
+ ".ppt",
157
+ ".pptx",
158
+ ".zip",
159
+ ".rar",
160
+ ".tar",
161
+ ".gz"
162
+ ];
163
+ const fetchAndExtract = async (currentUrl) => {
164
+ if (visited.has(currentUrl)) {
165
+ this.logger.debug(`Skipping already visited URL: ${currentUrl}`);
166
+ return;
167
+ }
168
+ visited.add(currentUrl);
169
+ this.logger.info(`Visiting URL: ${currentUrl}`);
170
+ const html = await this.fetchWithRetries(currentUrl, this.retries);
171
+ if (!html) return;
172
+ const links = this.extractLinks(html);
173
+ for (const link of links) {
174
+ if (assetExtensions.some((ext) => link.endsWith(ext))) {
175
+ this.logger.debug(`Ignoring asset link: ${link}`);
176
+ continue;
177
+ }
178
+ this.logger.debug(`Found link: ${link}`);
179
+ }
180
+ for (const link of links) {
181
+ if (!visited.has(link) && queue.size < this.depth) {
182
+ queue.add(link);
183
+ this.logger.debug(`Added to queue: ${link}`);
184
+ }
185
+ }
186
+ resultLinks.add(currentUrl);
187
+ };
188
+ const processBatch = async () => {
189
+ const batch = Array.from(queue).slice(0, this.concurrency);
190
+ for (const url of batch) {
191
+ queue.delete(url);
192
+ }
193
+ await Promise.allSettled(batch.map((url) => fetchAndExtract(url)));
194
+ };
195
+ this.logger.info(
196
+ `Starting crawl with depth: ${this.depth}, concurrency: ${this.concurrency}`
197
+ );
198
+ while (queue.size > 0 && visited.size < this.depth) {
199
+ await processBatch();
3102
200
  }
3103
- },
3104
- dependencies: {
3105
- commander: "^12.1.0"
201
+ this.logger.info(
202
+ `Crawling completed. Total pages visited: ${resultLinks.size}`
203
+ );
204
+ return Array.from(resultLinks);
3106
205
  }
3107
206
  };
3108
-
3109
- // src/index.ts
3110
- var program2 = new Command();
3111
- program2.version(package_default.version).name(package_default.name).description(package_default.description);
3112
- program2.helpOption("-h, --help", "Display help for command");
3113
- program2.parse(process.argv);
3114
- var options = program2.opts();
3115
- if (Object.keys(options).length === 0) {
3116
- program2.help();
3117
- }
207
+ export {
208
+ SpiderScanner
209
+ };
3118
210
  //# sourceMappingURL=index.js.map