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

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