bob-core 2.0.0-beta.2 → 2.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +338 -173
  2. package/dist/cjs/package-Bxb7QZU4.cjs +1 -0
  3. package/dist/cjs/src/Cli.d.ts +12 -12
  4. package/dist/cjs/src/Command.d.ts +24 -24
  5. package/dist/cjs/src/CommandIO.d.ts +13 -2
  6. package/dist/cjs/src/CommandParser.d.ts +29 -5
  7. package/dist/cjs/src/CommandRegistry.d.ts +17 -7
  8. package/dist/cjs/src/CommandSignatureParser.d.ts +5 -50
  9. package/dist/cjs/src/CommandWithSignature.d.ts +4 -13
  10. package/dist/cjs/src/ExceptionHandler.d.ts +1 -1
  11. package/dist/cjs/src/Logger.d.ts +2 -3
  12. package/dist/cjs/src/StringSimilarity.d.ts +26 -0
  13. package/dist/cjs/src/commands/HelpCommand.d.ts +1 -1
  14. package/dist/cjs/src/contracts/CommandOption.d.ts +3 -3
  15. package/dist/cjs/src/contracts/LoggerContract.d.ts +1 -2
  16. package/dist/cjs/src/errors/BadCommandOption.d.ts +2 -1
  17. package/dist/cjs/src/errors/BadCommandParameter.d.ts +2 -1
  18. package/dist/cjs/src/errors/CommandNotFoundError.d.ts +2 -1
  19. package/dist/cjs/src/errors/InvalidOption.d.ts +2 -1
  20. package/dist/cjs/src/errors/MissingRequiredArgumentValue.d.ts +2 -1
  21. package/dist/cjs/src/errors/MissingRequiredOptionValue.d.ts +2 -1
  22. package/dist/cjs/src/errors/index.d.ts +0 -2
  23. package/dist/cjs/src/index.d.ts +2 -0
  24. package/dist/cjs/src/index.js +17 -0
  25. package/dist/cjs/src/lib/optionHelpers.d.ts +1 -1
  26. package/dist/cjs/src/lib/types.d.ts +2 -0
  27. package/dist/cjs/src/options/HelpOption.d.ts +1 -1
  28. package/dist/esm/package-DZqOZEXL.js +33 -0
  29. package/dist/esm/src/Cli.d.ts +12 -12
  30. package/dist/esm/src/Command.d.ts +24 -24
  31. package/dist/esm/src/CommandIO.d.ts +13 -2
  32. package/dist/esm/src/CommandParser.d.ts +29 -5
  33. package/dist/esm/src/CommandRegistry.d.ts +17 -7
  34. package/dist/esm/src/CommandSignatureParser.d.ts +5 -50
  35. package/dist/esm/src/CommandWithSignature.d.ts +4 -13
  36. package/dist/esm/src/ExceptionHandler.d.ts +1 -1
  37. package/dist/esm/src/Logger.d.ts +2 -3
  38. package/dist/esm/src/StringSimilarity.d.ts +26 -0
  39. package/dist/esm/src/commands/HelpCommand.d.ts +1 -1
  40. package/dist/esm/src/contracts/CommandOption.d.ts +3 -3
  41. package/dist/esm/src/contracts/LoggerContract.d.ts +1 -2
  42. package/dist/esm/src/errors/BadCommandOption.d.ts +2 -1
  43. package/dist/esm/src/errors/BadCommandParameter.d.ts +2 -1
  44. package/dist/esm/src/errors/CommandNotFoundError.d.ts +2 -1
  45. package/dist/esm/src/errors/InvalidOption.d.ts +2 -1
  46. package/dist/esm/src/errors/MissingRequiredArgumentValue.d.ts +2 -1
  47. package/dist/esm/src/errors/MissingRequiredOptionValue.d.ts +2 -1
  48. package/dist/esm/src/errors/index.d.ts +0 -2
  49. package/dist/esm/src/index.d.ts +2 -0
  50. package/dist/esm/src/index.js +1030 -0
  51. package/dist/esm/src/lib/optionHelpers.d.ts +1 -1
  52. package/dist/esm/src/lib/types.d.ts +2 -0
  53. package/dist/esm/src/options/HelpOption.d.ts +1 -1
  54. package/package.json +27 -20
  55. package/dist/cjs/index.d.ts +0 -2
  56. package/dist/cjs/index.js +0 -9
  57. package/dist/cjs/package-88kG_8yl.cjs +0 -1
  58. package/dist/cjs/src/errors/MissingSignatureArgument.d.ts +0 -8
  59. package/dist/cjs/src/errors/MissingSignatureOption.d.ts +0 -8
  60. package/dist/cjs/src/testFixtures.d.ts +0 -11
  61. package/dist/esm/index.d.ts +0 -2
  62. package/dist/esm/index.js +0 -1066
  63. package/dist/esm/package-COKp1myj.js +0 -31
  64. package/dist/esm/src/errors/MissingSignatureArgument.d.ts +0 -8
  65. package/dist/esm/src/errors/MissingSignatureOption.d.ts +0 -8
  66. package/dist/esm/src/testFixtures.d.ts +0 -11
@@ -0,0 +1,1030 @@
1
+ import y from "prompts";
2
+ import a from "chalk";
3
+ import q from "minimist";
4
+ class S {
5
+ logger;
6
+ constructor(t) {
7
+ this.logger = t.logger;
8
+ }
9
+ /**
10
+ * Logger methods
11
+ */
12
+ log(...t) {
13
+ this.logger.log(...t);
14
+ }
15
+ info(...t) {
16
+ this.logger.info(...t);
17
+ }
18
+ warn(...t) {
19
+ this.logger.warn(...t);
20
+ }
21
+ error(...t) {
22
+ this.logger.error(...t);
23
+ }
24
+ debug(...t) {
25
+ this.logger.debug(...t);
26
+ }
27
+ /**
28
+ * Prompt utils
29
+ */
30
+ async askForConfirmation(t = "Do you want to continue?", e) {
31
+ return (await y({
32
+ type: "confirm",
33
+ name: "value",
34
+ message: t,
35
+ initial: e ?? !1
36
+ })).value;
37
+ }
38
+ async askForInput(t, e, i) {
39
+ return (await y({
40
+ type: "text",
41
+ name: "value",
42
+ message: t,
43
+ initial: e,
44
+ ...i
45
+ }))?.value ?? null;
46
+ }
47
+ async askForDate(t, e, i) {
48
+ return (await y({
49
+ type: "date",
50
+ name: "value",
51
+ message: t,
52
+ initial: e,
53
+ ...i
54
+ }))?.value ?? null;
55
+ }
56
+ async askForList(t, e, i) {
57
+ return (await y({
58
+ type: "list",
59
+ name: "value",
60
+ message: t,
61
+ initial: e,
62
+ ...i
63
+ }))?.value ?? null;
64
+ }
65
+ async askForToggle(t, e, i) {
66
+ return (await y({
67
+ type: "toggle",
68
+ name: "value",
69
+ message: t,
70
+ initial: e,
71
+ ...i
72
+ }))?.value ?? null;
73
+ }
74
+ async askForSelect(t, e, i) {
75
+ if (e.length === 0)
76
+ throw new Error("No options provided");
77
+ const n = [];
78
+ for (const o of e)
79
+ typeof o == "string" ? n.push({ title: o, value: o }) : n.push(o);
80
+ return (await y({
81
+ type: "select",
82
+ name: "value",
83
+ message: t,
84
+ choices: n,
85
+ ...i
86
+ }))?.value ?? null;
87
+ }
88
+ newLoader(t = "", e = ["⠙", "⠘", "⠰", "⠴", "⠤", "⠦", "⠆", "⠃", "⠋", "⠉"], i = 100) {
89
+ let n = t, s = null, o = 0;
90
+ const u = setInterval(function() {
91
+ s && (process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(s.length + 5) + "\r")), s = null), process.stdout.write(new TextEncoder().encode("\r" + e[o++] + " " + n)), o = o % e.length;
92
+ }, i), m = () => {
93
+ clearInterval(u), process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(n.length + 5) + "\r"));
94
+ };
95
+ return {
96
+ [Symbol.dispose]: m,
97
+ [Symbol.asyncDispose]: m,
98
+ updateText: (h) => {
99
+ s = n, n = h;
100
+ },
101
+ stop: m
102
+ };
103
+ }
104
+ }
105
+ class f extends Error {
106
+ }
107
+ function R(r) {
108
+ if (r === "string" || r === "number") return null;
109
+ if (r === "boolean") return !1;
110
+ if (Array.isArray(r) && r.length === 1) {
111
+ if (r[0] === "string") return [];
112
+ if (r[0] === "number") return [];
113
+ }
114
+ throw new Error("Invalid option type: " + r);
115
+ }
116
+ function x(r) {
117
+ return typeof r == "string" || Array.isArray(r) ? R(r) : r.default !== void 0 ? r.default : R(r.type);
118
+ }
119
+ function g(r) {
120
+ return typeof r == "string" || Array.isArray(r) ? {
121
+ alias: [],
122
+ default: x(r),
123
+ description: "",
124
+ required: !1,
125
+ secret: !1,
126
+ type: r,
127
+ variadic: !1
128
+ } : {
129
+ alias: r.alias ? Array.isArray(r.alias) ? r.alias : [r.alias] : [],
130
+ default: r.default ?? x(r.type),
131
+ description: r.description ?? "",
132
+ required: r.required ?? !1,
133
+ secret: r.secret ?? !1,
134
+ type: r.type,
135
+ variadic: r.variadic ?? !1
136
+ };
137
+ }
138
+ class b extends f {
139
+ constructor(t, e = {}) {
140
+ super(`Invalid option ${t} in not recognized`), this.option = t, this.optionsSchema = e;
141
+ }
142
+ pretty(t) {
143
+ const e = Object.entries(this.optionsSchema);
144
+ if (e.length > 0) {
145
+ t.log(`
146
+ ${a.yellow("Available options")}:`);
147
+ for (const [i, n] of e) {
148
+ const s = g(n), o = s.alias ? typeof s.alias == "string" ? [s.alias] : s.alias : [], u = Array.isArray(s.type) ? `[${s.type[0]}]` : s.type, m = `--${i}${o.length > 0 ? o.map((l) => `, -${l}`).join("") : ""}`, h = " ".repeat(30 - m.length);
149
+ t.log(` ${a.green(m)} ${h} ${s.description || "\b"} ${a.white(`(${u})`)}`);
150
+ }
151
+ t.log("");
152
+ }
153
+ t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is not recognized.`);
154
+ }
155
+ }
156
+ class E extends f {
157
+ constructor(t) {
158
+ super(`Argument "${t}" is required.`), this.argument = t;
159
+ }
160
+ pretty(t) {
161
+ t.log(`${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.argument)} is required.`);
162
+ }
163
+ }
164
+ class I extends f {
165
+ constructor(t) {
166
+ super(`Argument "${t}" is required.`), this.option = t;
167
+ }
168
+ pretty(t) {
169
+ t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is required.`);
170
+ }
171
+ }
172
+ class B extends f {
173
+ constructor(t) {
174
+ let e = `Argument "${t.param}" value is invalid.`;
175
+ t.reason ? e += ` Reason: ${t.reason}` : e += ` Value: "${t.value}"`, super(e), this.param = t;
176
+ }
177
+ pretty(t) {
178
+ t.log(` ${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.param.param)} value is invalid. `), (this.param.value || this.param.reason) && t.log(""), this.param.value && t.log(` ${a.blue("Value")}: ${this.param.value}`), this.param.reason && t.log(` ${a.yellow("Reason")}: ${this.param.reason}`);
179
+ }
180
+ }
181
+ class C extends f {
182
+ constructor(t) {
183
+ let e = `Option "${t.option}" value is invalid.`;
184
+ t.reason ? e += ` Reason: ${t.reason}` : e += ` Value: "${t.value}"`, super(e), this.param = t;
185
+ }
186
+ pretty(t) {
187
+ t.log(` ${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.param.option)} value is invalid. `), (this.param.value || this.param.reason) && t.log(""), this.param.value && t.log(` ${a.blue("Value")}: ${this.param.value}`), this.param.reason && t.log(` ${a.yellow("Reason")}: ${this.param.reason}`);
188
+ }
189
+ }
190
+ class V extends f {
191
+ constructor(t) {
192
+ super(`Command "${t}" not found.`), this.command = t;
193
+ }
194
+ pretty(t) {
195
+ t.log(`${a.bgRed(" ERROR ")} Command ${a.yellow(this.command)} not found.`);
196
+ }
197
+ }
198
+ function w(r, t, e, i) {
199
+ if (r == null)
200
+ return i ?? null;
201
+ if (t === "string")
202
+ return String(r);
203
+ if (t === "number") {
204
+ const n = Number(r);
205
+ if (isNaN(n))
206
+ throw new C({
207
+ option: e,
208
+ reason: `Expected a number, got "${r}"`
209
+ });
210
+ return n;
211
+ }
212
+ if (t === "boolean")
213
+ return typeof r == "boolean" ? r : r === "true" || r === "1" ? !0 : r === "false" || r === "0" ? !1 : !!r;
214
+ if (Array.isArray(t)) {
215
+ const n = t[0], s = Array.isArray(r) ? r : [r];
216
+ if (n === "string")
217
+ return s.map((o) => String(o));
218
+ if (n === "number")
219
+ return s.map((o) => {
220
+ const u = Number(o);
221
+ if (isNaN(u))
222
+ throw new C({
223
+ option: e,
224
+ reason: `Expected array of numbers, got "${o}" in array`
225
+ });
226
+ return u;
227
+ });
228
+ }
229
+ return r;
230
+ }
231
+ class k {
232
+ options;
233
+ parsedOptions = null;
234
+ arguments;
235
+ parsedArguments = null;
236
+ io;
237
+ shouldPromptForMissingOptions = !0;
238
+ constructor(t) {
239
+ this.options = t.options, this.arguments = t.arguments, this.io = t.io;
240
+ }
241
+ // === PUBLIC METHODS ===
242
+ /**
243
+ * Parses raw command-line arguments into structured options and arguments
244
+ * @param args - Raw command line arguments (typically from process.argv.slice(2))
245
+ * @returns Object containing parsed options and arguments
246
+ * @throws {InvalidOption} If an naan option is provided
247
+ * @throws {BadCommandOption} If a value cannot be converted to the expected type
248
+ */
249
+ init(t) {
250
+ const { _: e, ...i } = q(t);
251
+ return this.validateUnknownOptions(i), this.parsedOptions = this.handleOptions(i), this.parsedArguments = this.handleArguments(e), {
252
+ options: this.parsedOptions,
253
+ arguments: this.parsedArguments
254
+ };
255
+ }
256
+ /**
257
+ * Validates the parsed options and arguments
258
+ * @throws {Error} If validation fails
259
+ */
260
+ async validate() {
261
+ for (const t in this.options)
262
+ if (g(this.options[t]).required && (this.parsedOptions?.[t] === void 0 || this.parsedOptions?.[t] === null))
263
+ throw new I(t);
264
+ for (const t in this.arguments) {
265
+ const e = g(this.arguments[t]), i = this.parsedArguments?.[t];
266
+ if (e.required && i == null) {
267
+ if (this.shouldPromptForMissingOptions) {
268
+ const n = await this.promptForArgument(t, e);
269
+ if (n && this.parsedArguments) {
270
+ this.parsedArguments[t] = w(n, e.type, t);
271
+ continue;
272
+ }
273
+ }
274
+ throw new E(t);
275
+ }
276
+ if (e.required && e.variadic && Array.isArray(i) && i.length === 0) {
277
+ if (this.shouldPromptForMissingOptions) {
278
+ const n = await this.promptForArgument(t, e);
279
+ if (n && this.parsedArguments) {
280
+ this.parsedArguments[t] = w(n, e.type, t);
281
+ continue;
282
+ }
283
+ }
284
+ throw new E(t);
285
+ }
286
+ }
287
+ }
288
+ /**
289
+ * Retrieves a parsed option value by name
290
+ * @param name - The option name
291
+ * @param defaultValue - Optional default value if option is not set
292
+ * @returns The typed option value
293
+ * @throws {Error} If init() has not been called yet
294
+ */
295
+ option(t, e) {
296
+ if (!this.parsedOptions)
297
+ throw new Error("Options have not been parsed yet. Call init() first.");
298
+ return this.isEmptyValue(this.parsedOptions[t]) && e !== void 0 ? e : this.parsedOptions[t];
299
+ }
300
+ setOption(t, e) {
301
+ if (!this.parsedOptions)
302
+ throw new Error("Options have not been parsed yet. Call init() first.");
303
+ if (!(t in this.options))
304
+ throw new b(t, this.options);
305
+ this.parsedOptions[t] = e;
306
+ }
307
+ /**
308
+ * Retrieves a parsed argument value by name
309
+ * @param name - The argument name
310
+ * @param defaultValue - Optional default value if argument is not set
311
+ * @returns The typed argument value
312
+ * @throws {Error} If init() has not been called yet
313
+ */
314
+ argument(t, e) {
315
+ if (!this.parsedArguments)
316
+ throw new Error("Arguments have not been parsed yet. Call init() first.");
317
+ return this.isEmptyValue(this.parsedArguments[t]) && e !== void 0 ? e : this.parsedArguments[t];
318
+ }
319
+ setArgument(t, e) {
320
+ if (!this.parsedArguments)
321
+ throw new Error("Arguments have not been parsed yet. Call init() first.");
322
+ if (!(t in this.arguments))
323
+ throw new b(t, this.arguments);
324
+ this.parsedArguments[t] = e;
325
+ }
326
+ // === PRIVATE HELPERS ===
327
+ /**
328
+ * Checks if a value should be considered "empty" for default value purposes
329
+ * @param value - The value to check
330
+ * @returns true if the value is null, undefined, or an empty array
331
+ */
332
+ isEmptyValue(t) {
333
+ return t == null || Array.isArray(t) && t.length === 0;
334
+ }
335
+ /**
336
+ * Validates that all provided options are recognized
337
+ * @throws {InvalidOption} If an unknown option is found
338
+ */
339
+ validateUnknownOptions(t) {
340
+ const e = /* @__PURE__ */ new Set();
341
+ for (const i in this.options) {
342
+ e.add(i);
343
+ const n = g(this.options[i]);
344
+ for (const s of n.alias)
345
+ e.add(s);
346
+ }
347
+ for (const i in t)
348
+ if (!e.has(i))
349
+ throw new b(i, this.options);
350
+ }
351
+ /**
352
+ * Processes named options from minimist output
353
+ */
354
+ handleOptions(t) {
355
+ const e = {};
356
+ for (const i in this.options) {
357
+ const n = g(this.options[i]);
358
+ e[i] = this.resolveOptionValue(i, n, t);
359
+ }
360
+ return e;
361
+ }
362
+ /**
363
+ * Processes positional arguments from minimist output
364
+ */
365
+ handleArguments(t) {
366
+ const e = {}, i = [...t];
367
+ for (const n in this.arguments) {
368
+ const s = g(this.arguments[n]);
369
+ if (s.variadic) {
370
+ e[n] = this.handleVariadicArgument(n, s, i);
371
+ continue;
372
+ }
373
+ e[n] = this.resolveArgumentValue(n, s, i.shift());
374
+ }
375
+ return e;
376
+ }
377
+ /**
378
+ * Handles variadic arguments that consume all remaining positional values
379
+ */
380
+ handleVariadicArgument(t, e, i) {
381
+ return i.length ? w(i, e.type, t, e.default) : e.default;
382
+ }
383
+ /**
384
+ * Resolves a single positional argument value with defaults and type conversion
385
+ * Note: Does not validate required arguments - validation happens in subclass validate() methods
386
+ */
387
+ resolveArgumentValue(t, e, i) {
388
+ return i === void 0 ? e.default : w(i, e.type, t, e.default);
389
+ }
390
+ /**
391
+ * Resolves an option value from the parsed option values object
392
+ * Handles alias resolution, defaults, and type conversion
393
+ */
394
+ resolveOptionValue(t, e, i) {
395
+ let n;
396
+ const s = [t, ...e.alias];
397
+ for (const o of s)
398
+ if (o in i) {
399
+ n = i[o];
400
+ break;
401
+ }
402
+ if (n === void 0) {
403
+ if (e.required)
404
+ throw new C({
405
+ option: t,
406
+ reason: "Required option is missing"
407
+ });
408
+ return e.default;
409
+ }
410
+ return w(n, e.type, t, e.default);
411
+ }
412
+ optionDefinitions() {
413
+ const t = {};
414
+ for (const e in this.options)
415
+ t[e] = g(this.options[e]);
416
+ return t;
417
+ }
418
+ argumentDefinitions() {
419
+ const t = {};
420
+ for (const e in this.arguments)
421
+ t[e] = g(this.arguments[e]);
422
+ return t;
423
+ }
424
+ availableOptions() {
425
+ return Object.keys(this.options);
426
+ }
427
+ availableArguments() {
428
+ return Object.keys(this.arguments);
429
+ }
430
+ /**
431
+ * Disables prompting for missing argument values
432
+ * Useful for non-interactive environments
433
+ */
434
+ disablePrompting() {
435
+ return this.shouldPromptForMissingOptions = !1, this;
436
+ }
437
+ /**
438
+ * Prompts the user to provide a missing argument value via CommandIO
439
+ * Used by validate() when shouldPromptForMissingArgs is enabled
440
+ * @param argumentName - The name of the missing argument
441
+ * @param argDef - The argument's definition for type and description
442
+ * @returns The user-provided value, or null if none given
443
+ */
444
+ async promptForArgument(t, e) {
445
+ if (!Array.isArray(e.type) && !["string", "number", "secret"].includes(e.type))
446
+ return null;
447
+ let i = `${a.yellow.bold(t)} is required`;
448
+ return e.description && (i += `: ${a.gray(`(${e.description})`)}`), i += ` ${a.green(`(${e.type}${e.variadic == !0 ? "[]" : ""})`)}
449
+ `, Array.isArray(e.type) ? (i += `Please provide one or more values, separated by commas:
450
+ `, await this.io.askForList(i, void 0, {
451
+ separator: ",",
452
+ validate: (n) => {
453
+ if (!n.length)
454
+ return "Please enter at least one value";
455
+ if (e.type[0] === "number") {
456
+ for (const s of n.split(","))
457
+ if (isNaN(Number(s)))
458
+ return "Please enter only valid numbers";
459
+ }
460
+ return !0;
461
+ }
462
+ })) : await this.io.askForInput(i, void 0, {
463
+ type: e.type === "number" ? "number" : e.secret ? "password" : "text",
464
+ validate: (n) => {
465
+ if (n == null || typeof n == "string" && !n.length)
466
+ return "This value is required";
467
+ if (e.type === "number") {
468
+ const s = Number(n);
469
+ if (isNaN(s))
470
+ return "Please enter a valid number";
471
+ } else if (e.type === "string" && (typeof n != "string" || !n.length))
472
+ return "Please enter a valid text";
473
+ return !0;
474
+ }
475
+ });
476
+ }
477
+ }
478
+ function A(r) {
479
+ return new Array(r + 5).join(" ");
480
+ }
481
+ class P {
482
+ type = "boolean";
483
+ option = "help";
484
+ alias = ["h"];
485
+ default = !1;
486
+ description = `Display help for the given command. When no command is given display help for the ${a.green("list")} command`;
487
+ async handler() {
488
+ const t = this.parser.argumentDefinitions(), e = this.parser.optionDefinitions(), i = Object.entries(t), n = Object.entries(e), s = n.map(([l, d]) => {
489
+ const c = Array.isArray(d.alias) ? d.alias : d.alias ? [d.alias] : [];
490
+ return {
491
+ name: l,
492
+ ...d,
493
+ optionWithAlias: `--${l}${c.map((p) => `, -${p}`).join("")}`
494
+ };
495
+ }), o = i.filter(([, l]) => l.required);
496
+ this.io.log(a.yellow("Description:")), this.io.log(` ${this.description}
497
+ `), this.io.log(a.yellow("Usage:")), this.io.log(` ${this.command} ${o.length > 0 ? o.map(([l]) => `<${l}>`).join(" ") : "\b"} [options]`);
498
+ const u = Math.max(...s.map((l) => l.optionWithAlias.length), 0), m = Math.max(...i.map(([l]) => l.length), 0), h = m > u ? m : u;
499
+ if (i.length > 0) {
500
+ this.io.log(`
501
+ ${a.yellow("Arguments")}:`);
502
+ for (const [l, d] of i) {
503
+ const c = A(h - l.length);
504
+ let p = ` ${a.green(l)} ${c} ${d.description ?? "\b"}`;
505
+ if (d.default !== void 0 && !d.required) {
506
+ const L = (Array.isArray(d.type) ? `[${d.type[0]}]` : d.type) === "array" || Array.isArray(d.type) ? JSON.stringify(d.default) : d.default;
507
+ p += ` ${a.yellow(`[default: ${L}]`)}`;
508
+ }
509
+ d.variadic && (p += ` ${a.white("(variadic)")}`), this.io.log(p);
510
+ }
511
+ }
512
+ if (n.length > 0) {
513
+ this.io.log(`
514
+ ${a.yellow("Options")}:`);
515
+ for (const l of s) {
516
+ const d = A(h - l.optionWithAlias.length);
517
+ let c = `${a.green(l.optionWithAlias)} ${d} ${l.description ?? "\b"}`;
518
+ if (l.type) {
519
+ const p = Array.isArray(l.type) ? `[${l.type[0]}]` : l.type;
520
+ c += ` ${a.white(`(${p})`)}`;
521
+ }
522
+ if (l.default !== void 0 && !l.required) {
523
+ const O = (Array.isArray(l.type) ? `[${l.type[0]}]` : l.type) === "array" || Array.isArray(l.type) ? JSON.stringify(l.default) : l.default;
524
+ c += ` ${a.yellow(`[default: ${O}]`)}`;
525
+ }
526
+ this.io.log(c);
527
+ }
528
+ }
529
+ if (this.commandsExamples.length > 0) {
530
+ this.io.log(`
531
+ ${a.yellow("Examples")}:`);
532
+ let l = process.argv[0].split("/").pop();
533
+ l === "node" && (l += " " + process.argv[1].split("/").pop());
534
+ for (const [d, c] of this.commandsExamples.entries())
535
+ d > 0 && this.io.log(""), this.io.log(` ${c.description}
536
+ `), this.io.log(` ${a.green(`${l} ${c.command}`)}`);
537
+ }
538
+ return -1;
539
+ }
540
+ }
541
+ class v {
542
+ _command;
543
+ description;
544
+ group;
545
+ commandsExamples = [];
546
+ get command() {
547
+ return this._command;
548
+ }
549
+ ctx;
550
+ io;
551
+ parser;
552
+ disablePromptingFlag = !1;
553
+ _preHandler;
554
+ _handler;
555
+ tmp;
556
+ defaultOptions() {
557
+ return [new P()];
558
+ }
559
+ newCommandParser(t) {
560
+ return new k({
561
+ io: t.io,
562
+ options: t.options,
563
+ arguments: t.arguments
564
+ });
565
+ }
566
+ newCommandIO(t) {
567
+ return new S(t);
568
+ }
569
+ constructor(t, e) {
570
+ this._command = t, this.description = e?.description ?? "", this.group = e?.group, this.tmp = {
571
+ options: e?.options ?? {},
572
+ arguments: e?.arguments ?? {}
573
+ };
574
+ const i = this.defaultOptions();
575
+ if (i.length > 0)
576
+ for (const n of i)
577
+ this.tmp.options[n.option] = n;
578
+ }
579
+ disablePrompting() {
580
+ return this.disablePromptingFlag = !0, this;
581
+ }
582
+ preHandler(t) {
583
+ return this._preHandler = t, this;
584
+ }
585
+ handler(t) {
586
+ return this._handler = t, this;
587
+ }
588
+ options(t) {
589
+ return this.tmp = {
590
+ options: {
591
+ ...this.tmp?.options ?? {},
592
+ ...t
593
+ },
594
+ arguments: this.tmp?.arguments ?? {}
595
+ }, this;
596
+ }
597
+ arguments(t) {
598
+ return this.tmp = {
599
+ options: this.tmp?.options ?? {},
600
+ arguments: {
601
+ ...this.tmp?.arguments ?? {},
602
+ ...t
603
+ }
604
+ }, this;
605
+ }
606
+ async run(t) {
607
+ if (!this._handler && !this.handle)
608
+ throw new Error(`No handler defined for command ${this.command || "(unknown)"}`);
609
+ let e;
610
+ if (this.ctx = t.ctx, this.io = this.newCommandIO({
611
+ logger: t.logger
612
+ }), t && "args" in t) {
613
+ const n = this.tmp?.options ?? {};
614
+ for (const s of this.defaultOptions())
615
+ s.option in n || (n[s.option] = s);
616
+ this.parser = this.newCommandParser({
617
+ io: this.io,
618
+ options: n,
619
+ arguments: this.tmp?.arguments ?? {}
620
+ }), e = this.parser.init(t.args);
621
+ for (const s of this.defaultOptions())
622
+ if (e.options[s.option] === !0) {
623
+ const o = await s.handler.call(this);
624
+ if (o && o !== 0)
625
+ return o;
626
+ }
627
+ this.disablePromptingFlag && this.parser.disablePrompting(), await this.parser.validate();
628
+ } else
629
+ e = {
630
+ options: t.options,
631
+ arguments: t.arguments
632
+ };
633
+ if (!this._preHandler && this.preHandle && (this._preHandler = this.preHandle.bind(this)), this._preHandler) {
634
+ const n = await this._preHandler(t.ctx, e);
635
+ if (n && n !== 0)
636
+ return n;
637
+ }
638
+ if (!this._handler && this.handle)
639
+ this._handler = this.handle.bind(this);
640
+ else if (!this._handler)
641
+ throw new Error(`No handler defined for command ${this.command || "(unknown)"}`);
642
+ return await this._handler(t.ctx, e) ?? 0;
643
+ }
644
+ }
645
+ class $ extends k {
646
+ command;
647
+ constructor(t) {
648
+ const e = $.parseSignature(t.signature, t.helperDefinitions, t.defaultOptions);
649
+ super({
650
+ io: t.io,
651
+ options: e.options,
652
+ arguments: e.arguments
653
+ }), this.command = e.command;
654
+ }
655
+ /**
656
+ * Parses command signature string into command name and parameter schemas
657
+ * Example: "migrate {name} {--force}" -> { command: "migrate", arguments: {name: ...}, options: {force: ...} }
658
+ */
659
+ static parseSignature(t, e, i) {
660
+ const [n, ...s] = t.split(/\{(.*?)\}/g).map((m) => m.trim()).filter(Boolean), o = {}, u = {};
661
+ for (const m of s) {
662
+ const { name: h, isOption: l, definition: d } = $.parseParamSignature(m, e);
663
+ l ? o[h] = d : u[h] = d;
664
+ }
665
+ for (const m of i)
666
+ o[m.option] = {
667
+ type: m.type,
668
+ required: m.required,
669
+ alias: m.alias,
670
+ variadic: m.variadic ?? !1,
671
+ description: m.description,
672
+ default: m.default ?? null
673
+ };
674
+ return {
675
+ command: n,
676
+ options: o,
677
+ arguments: u
678
+ };
679
+ }
680
+ /**
681
+ * Parses a single parameter signature like "{name}" or "{--force}" or "{files*}"
682
+ * Extracts name, type, default value, aliases, description, etc.
683
+ *
684
+ * Signature syntax:
685
+ * - {arg} -> required string argument
686
+ * - {arg?} -> optional argument
687
+ * - {arg=default} -> argument with default value
688
+ * - {arg*} -> variadic argument (array)
689
+ * - {arg:desc} -> argument with description
690
+ * - {--opt} -> boolean option
691
+ * - {--opt=} -> string option
692
+ * - {--opt|o} -> option with alias
693
+ */
694
+ static parseParamSignature(t, e) {
695
+ let i = t, n = !1;
696
+ const s = {
697
+ required: !0,
698
+ type: "string",
699
+ description: void 0,
700
+ default: null,
701
+ variadic: !1
702
+ };
703
+ if (i.includes(":")) {
704
+ const [o, u] = i.split(":");
705
+ i = o.trim(), s.description = u.trim();
706
+ }
707
+ if (i.includes("=")) {
708
+ const [o, u] = i.split("=");
709
+ i = o.trim(), s.default = u.trim(), s.required = !1, typeof s.default == "string" && !s.default.length ? s.default = null : s.default === "true" ? (s.default = !0, s.type = "boolean") : s.default === "false" && (s.default = !1, s.type = "boolean");
710
+ } else i.startsWith("--") && (s.required = !1, s.default = !1, s.type = "boolean");
711
+ if (i.includes("|")) {
712
+ const [o, ...u] = i.split("|");
713
+ i = o.trim(), s.alias = u.map((m) => m.trim());
714
+ }
715
+ return i.startsWith("--") && (n = !0, i = i.slice(2)), s.default === "*" && (s.default = [], s.type = ["string"]), i.endsWith("?") && (s.required = !1, i = i.slice(0, -1)), i.endsWith("*") && (s.type = ["string"], s.variadic = !0, s.default = [], i = i.slice(0, -1)), s.description = s.description ?? e[i] ?? e[`--${i}`], { name: i, isOption: n, definition: s };
716
+ }
717
+ }
718
+ class G extends v {
719
+ helperDefinitions = {};
720
+ get command() {
721
+ return this.parser ? this.parser.command : this.signature.split(" ")[0];
722
+ }
723
+ newCommandParser(t) {
724
+ return new $({
725
+ io: t.io,
726
+ signature: this.signature,
727
+ helperDefinitions: this.helperDefinitions,
728
+ defaultOptions: this.defaultOptions()
729
+ });
730
+ }
731
+ constructor() {
732
+ super("");
733
+ }
734
+ option(t, e = null) {
735
+ return this.parser.option(t, e);
736
+ }
737
+ argument(t, e = null) {
738
+ return this.parser.argument(t, e);
739
+ }
740
+ // Prompt utils
741
+ async askForConfirmation(...t) {
742
+ return this.io.askForConfirmation(...t);
743
+ }
744
+ async askForInput(...t) {
745
+ return this.io.askForInput(...t);
746
+ }
747
+ async askForSelect(...t) {
748
+ return this.io.askForSelect(...t);
749
+ }
750
+ newLoader(...t) {
751
+ return this.io.newLoader(...t);
752
+ }
753
+ }
754
+ const F = {};
755
+ class N {
756
+ level;
757
+ constructor(t = {}) {
758
+ this.level = t.level ?? "info";
759
+ }
760
+ shouldLog(t) {
761
+ const e = ["debug", "info", "warn", "error"], i = e.indexOf(this.level);
762
+ return e.indexOf(t) >= i;
763
+ }
764
+ setLevel(t) {
765
+ this.level = t;
766
+ }
767
+ getLevel() {
768
+ return this.level;
769
+ }
770
+ log(...t) {
771
+ console.log(...t);
772
+ }
773
+ info(...t) {
774
+ this.shouldLog("info") && console.log(...t);
775
+ }
776
+ warn(...t) {
777
+ this.shouldLog("warn") && console.warn(...t);
778
+ }
779
+ error(...t) {
780
+ this.shouldLog("error") && console.error(...t);
781
+ }
782
+ debug(...t) {
783
+ this.shouldLog("debug") && console.log(...t);
784
+ }
785
+ }
786
+ class H {
787
+ /**
788
+ * Generate bigrams (character pairs) from a string
789
+ */
790
+ getBigrams(t) {
791
+ const e = [], i = t.toLowerCase();
792
+ for (let n = 0; n < i.length - 1; n++)
793
+ e.push(i.slice(n, n + 2));
794
+ return e;
795
+ }
796
+ /**
797
+ * Calculate Dice's Coefficient similarity between two strings (0-1 scale)
798
+ */
799
+ calculateSimilarity(t, e) {
800
+ if (t === e) return 1;
801
+ if (t.length < 2 || e.length < 2) return 0;
802
+ const i = this.getBigrams(t), n = this.getBigrams(e), s = new Set(n);
803
+ let o = 0;
804
+ for (const u of i)
805
+ s.has(u) && (o++, s.delete(u));
806
+ return 2 * o / (i.length + n.length);
807
+ }
808
+ /**
809
+ * Find best matching string and ratings for all candidates
810
+ */
811
+ findBestMatch(t, e) {
812
+ const i = e.map((o) => ({
813
+ target: o,
814
+ rating: this.calculateSimilarity(t, o)
815
+ }));
816
+ let n = 0, s = i[0]?.rating ?? 0;
817
+ for (let o = 1; o < i.length; o++)
818
+ i[o].rating > s && (s = i[o].rating, n = o);
819
+ return {
820
+ ratings: i,
821
+ bestMatch: i[n],
822
+ bestMatchIndex: n
823
+ };
824
+ }
825
+ }
826
+ class D {
827
+ commands = {};
828
+ io;
829
+ logger;
830
+ stringSimilarity;
831
+ newCommandIO(t) {
832
+ return new S(t);
833
+ }
834
+ constructor(t) {
835
+ this.logger = t?.logger ?? new N(), this.io = this.newCommandIO({
836
+ logger: this.logger
837
+ }), this.stringSimilarity = t?.stringSimilarity ?? new H();
838
+ }
839
+ getAvailableCommands() {
840
+ return Object.keys(this.commands);
841
+ }
842
+ getCommands() {
843
+ return Object.values(this.commands);
844
+ }
845
+ importFile = async (t) => (await import(t)).default;
846
+ commandResolver = async (t) => {
847
+ let e = await this.importFile(t);
848
+ if (!e)
849
+ throw new Error(`The command at path ${t} does not have a default export.`);
850
+ return e && typeof e == "object" && "default" in e && (e = e.default), typeof e == "function" ? new e() : e instanceof v ? e : null;
851
+ };
852
+ withCommandResolver(t) {
853
+ return this.commandResolver = t, this;
854
+ }
855
+ withFileImporter(t) {
856
+ return this.importFile = t, this;
857
+ }
858
+ registerCommand(t, e = !1) {
859
+ const i = t.command;
860
+ if (!i)
861
+ throw new Error("Command signature is invalid, it must have a command name.");
862
+ if (!e && this.commands[i])
863
+ throw new Error(`Command ${i} already registered.`);
864
+ this.commands[i] = t;
865
+ }
866
+ async loadCommandsPath(t) {
867
+ for await (const e of this.listCommandsFiles(t))
868
+ try {
869
+ const i = await this.commandResolver(e);
870
+ i instanceof v && this.registerCommand(i);
871
+ } catch (i) {
872
+ throw new Error(`Command ${e} failed to load. ${i}`, {
873
+ cause: i
874
+ });
875
+ }
876
+ }
877
+ async runCommand(t, e, ...i) {
878
+ const n = typeof e == "string" ? this.commands[e] : e, s = typeof e == "string" ? e : n.command;
879
+ if (!n) {
880
+ const o = await this.suggestCommand(s);
881
+ return o ? await this.runCommand(t, o, ...i) : 1;
882
+ }
883
+ return await n.run({
884
+ ctx: t,
885
+ logger: this.logger,
886
+ args: i
887
+ }) ?? 0;
888
+ }
889
+ async suggestCommand(t) {
890
+ const e = this.getAvailableCommands(), { bestMatch: i, bestMatchIndex: n, ratings: s } = this.stringSimilarity.findBestMatch(t, e), o = s.filter((u) => u.rating > 0.3).map((u) => u.target);
891
+ if (i.rating > 0 && o.length <= 1 || i.rating > 0.7 && o.length > 1) {
892
+ const u = e[n];
893
+ return await this.askRunSimilarCommand(t, u) ? u : null;
894
+ }
895
+ if (o.length) {
896
+ this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
897
+ `);
898
+ const u = await this.io.askForSelect(a.green("Did you mean to run one of these commands instead?"), o);
899
+ if (u)
900
+ return u;
901
+ }
902
+ throw new V(t);
903
+ }
904
+ async askRunSimilarCommand(t, e) {
905
+ return this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
906
+ `), this.io.askForConfirmation(`${a.green(`Do you want to run ${a.yellow(e)} instead?`)} `);
907
+ }
908
+ async *listCommandsFiles(t) {
909
+ const e = (void 0)(t, { withFileTypes: !0 });
910
+ for (const i of e) {
911
+ const n = F.resolve(t, i.name);
912
+ if (i.isDirectory())
913
+ yield* this.listCommandsFiles(F.resolve(t, i.name));
914
+ else {
915
+ if (!n.endsWith(".ts") && !n.endsWith(".js") && !n.endsWith(".mjs") && !n.endsWith(".cjs"))
916
+ continue;
917
+ yield n;
918
+ }
919
+ }
920
+ }
921
+ }
922
+ class j {
923
+ logger;
924
+ constructor(t) {
925
+ this.logger = t;
926
+ }
927
+ handle(t) {
928
+ if (t instanceof f)
929
+ return t.pretty(this.logger), -1;
930
+ throw t;
931
+ }
932
+ }
933
+ class W extends v {
934
+ constructor(t) {
935
+ super("help", {
936
+ description: a.bold("Show help information about the CLI and its commands")
937
+ }), this.opts = t;
938
+ }
939
+ async handle() {
940
+ const t = this.opts.commandRegistry.getCommands(), e = this.opts.cliName ?? "Bob CLI", i = this.opts.cliVersion ?? "0.0.0", n = (await import("../package-DZqOZEXL.js"))?.default?.version ?? "0.0.0";
941
+ this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(n)})
942
+
943
+ ${a.yellow("Usage")}:
944
+ command [options] [arguments]
945
+
946
+ ${a.yellow("Available commands")}:
947
+ `);
948
+ const s = Math.max(...t.map((m) => m.command.length)) ?? 0, o = {};
949
+ for (const m of t) {
950
+ const h = m.group ?? m.command.split(":")[0];
951
+ o[h] || (o[h] = []), o[h].push(m);
952
+ }
953
+ const u = Object.entries(o).sort(([m], [h]) => m.toLowerCase().localeCompare(h.toLowerCase())).sort(([, m], [, h]) => m.length - h.length);
954
+ for (const [m, h] of u) {
955
+ const l = h.length > 1;
956
+ l && this.io.log(a.yellow(`${m}:`));
957
+ const d = h.sort((c, p) => c.command.toLowerCase().localeCompare(p.command.toLowerCase()));
958
+ for (const c of d) {
959
+ let p = A(s - c.command.length);
960
+ l && (p = p.slice(2)), this.io.log(`${l ? " " : ""}${a.green(c.command)} ${p} ${c.description}`);
961
+ }
962
+ }
963
+ }
964
+ }
965
+ class U {
966
+ ctx;
967
+ logger;
968
+ commandRegistry;
969
+ exceptionHandler;
970
+ helpCommand;
971
+ newCommandRegistry(t) {
972
+ return new D(t);
973
+ }
974
+ newHelpCommand(t) {
975
+ return new W(t);
976
+ }
977
+ newExceptionHandler(t) {
978
+ return new j(t.logger);
979
+ }
980
+ constructor(t = {}) {
981
+ this.ctx = t.ctx, this.logger = t.logger ?? new N(), this.commandRegistry = this.newCommandRegistry({
982
+ logger: this.logger
983
+ }), this.exceptionHandler = this.newExceptionHandler({
984
+ logger: this.logger
985
+ }), this.helpCommand = this.newHelpCommand({
986
+ cliName: t.name,
987
+ cliVersion: t.version,
988
+ commandRegistry: this.commandRegistry
989
+ });
990
+ }
991
+ withCommandResolver(t) {
992
+ return this.commandRegistry.withCommandResolver(t), this;
993
+ }
994
+ withFileImporter(t) {
995
+ return this.commandRegistry.withFileImporter(t), this;
996
+ }
997
+ async withCommands(...t) {
998
+ for (const e of t)
999
+ typeof e == "string" ? await this.commandRegistry.loadCommandsPath(e) : typeof e == "function" ? this.registerCommand(new e()) : this.registerCommand(e);
1000
+ }
1001
+ async runCommand(t, ...e) {
1002
+ return t ? await this.commandRegistry.runCommand(this.ctx ?? {}, t, ...e).catch(this.exceptionHandler.handle.bind(this.exceptionHandler)) : await this.runHelpCommand();
1003
+ }
1004
+ async runHelpCommand() {
1005
+ return await this.runCommand(this.helpCommand);
1006
+ }
1007
+ registerCommand(t) {
1008
+ this.commandRegistry.registerCommand(t);
1009
+ }
1010
+ }
1011
+ export {
1012
+ C as BadCommandOption,
1013
+ B as BadCommandParameter,
1014
+ f as BobError,
1015
+ U as Cli,
1016
+ v as Command,
1017
+ S as CommandIO,
1018
+ V as CommandNotFoundError,
1019
+ k as CommandParser,
1020
+ D as CommandRegistry,
1021
+ $ as CommandSignatureParser,
1022
+ G as CommandWithSignature,
1023
+ j as ExceptionHandler,
1024
+ P as HelpOption,
1025
+ b as InvalidOption,
1026
+ N as Logger,
1027
+ E as MissingRequiredArgumentValue,
1028
+ I as MissingRequiredOptionValue,
1029
+ H as StringSimilarity
1030
+ };