bob-core 2.0.0-beta.8 → 2.0.0

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