bob-core 1.4.0 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/index.js +4 -4
  3. package/dist/cjs/package-BKSqoABj.cjs +1 -0
  4. package/dist/cjs/src/Cli.d.ts +17 -10
  5. package/dist/cjs/src/Command.d.ts +47 -34
  6. package/dist/cjs/src/CommandIO.d.ts +12 -0
  7. package/dist/cjs/src/CommandParser.d.ts +76 -44
  8. package/dist/cjs/src/CommandRegistry.d.ts +7 -6
  9. package/dist/cjs/src/CommandSignatureParser.d.ts +85 -0
  10. package/dist/cjs/src/CommandWithSignature.d.ts +37 -0
  11. package/dist/cjs/src/ExceptionHandler.d.ts +3 -0
  12. package/dist/cjs/src/Logger.d.ts +17 -0
  13. package/dist/cjs/src/commands/HelpCommand.d.ts +2 -4
  14. package/dist/cjs/src/contracts/CommandOption.d.ts +3 -4
  15. package/dist/cjs/src/contracts/LoggerContract.d.ts +14 -0
  16. package/dist/cjs/src/contracts/index.d.ts +1 -0
  17. package/dist/cjs/src/errors/BadCommandOption.d.ts +1 -1
  18. package/dist/cjs/src/errors/BadCommandParameter.d.ts +1 -1
  19. package/dist/cjs/src/errors/BobError.d.ts +2 -1
  20. package/dist/cjs/src/errors/CommandNotFoundError.d.ts +1 -1
  21. package/dist/cjs/src/errors/InvalidOption.d.ts +4 -4
  22. package/dist/cjs/src/errors/MissingRequiredArgumentValue.d.ts +3 -4
  23. package/dist/cjs/src/errors/MissingRequiredOptionValue.d.ts +6 -0
  24. package/dist/cjs/src/errors/MissingSignatureArgument.d.ts +4 -4
  25. package/dist/cjs/src/errors/MissingSignatureOption.d.ts +4 -4
  26. package/dist/cjs/src/errors/index.d.ts +6 -0
  27. package/dist/cjs/src/index.d.ts +7 -1
  28. package/dist/cjs/src/lib/optionHelpers.d.ts +5 -0
  29. package/dist/cjs/src/lib/types.d.ts +29 -0
  30. package/dist/cjs/src/lib/valueConverter.d.ts +10 -0
  31. package/dist/cjs/src/options/HelpOption.d.ts +4 -2
  32. package/dist/cjs/src/testFixtures.d.ts +11 -0
  33. package/dist/esm/index.js +817 -371
  34. package/dist/esm/package-Pf7NCMvE.js +31 -0
  35. package/dist/esm/src/Cli.d.ts +17 -10
  36. package/dist/esm/src/Command.d.ts +47 -34
  37. package/dist/esm/src/CommandIO.d.ts +12 -0
  38. package/dist/esm/src/CommandParser.d.ts +76 -44
  39. package/dist/esm/src/CommandRegistry.d.ts +7 -6
  40. package/dist/esm/src/CommandSignatureParser.d.ts +85 -0
  41. package/dist/esm/src/CommandWithSignature.d.ts +37 -0
  42. package/dist/esm/src/ExceptionHandler.d.ts +3 -0
  43. package/dist/esm/src/Logger.d.ts +17 -0
  44. package/dist/esm/src/commands/HelpCommand.d.ts +2 -4
  45. package/dist/esm/src/contracts/CommandOption.d.ts +3 -4
  46. package/dist/esm/src/contracts/LoggerContract.d.ts +14 -0
  47. package/dist/esm/src/contracts/index.d.ts +1 -0
  48. package/dist/esm/src/errors/BadCommandOption.d.ts +1 -1
  49. package/dist/esm/src/errors/BadCommandParameter.d.ts +1 -1
  50. package/dist/esm/src/errors/BobError.d.ts +2 -1
  51. package/dist/esm/src/errors/CommandNotFoundError.d.ts +1 -1
  52. package/dist/esm/src/errors/InvalidOption.d.ts +4 -4
  53. package/dist/esm/src/errors/MissingRequiredArgumentValue.d.ts +3 -4
  54. package/dist/esm/src/errors/MissingRequiredOptionValue.d.ts +6 -0
  55. package/dist/esm/src/errors/MissingSignatureArgument.d.ts +4 -4
  56. package/dist/esm/src/errors/MissingSignatureOption.d.ts +4 -4
  57. package/dist/esm/src/errors/index.d.ts +6 -0
  58. package/dist/esm/src/index.d.ts +7 -1
  59. package/dist/esm/src/lib/optionHelpers.d.ts +5 -0
  60. package/dist/esm/src/lib/types.d.ts +29 -0
  61. package/dist/esm/src/lib/valueConverter.d.ts +10 -0
  62. package/dist/esm/src/options/HelpOption.d.ts +4 -2
  63. package/dist/esm/src/testFixtures.d.ts +11 -0
  64. package/package.json +5 -1
  65. package/dist/cjs/package-6sByjm31.cjs +0 -1
  66. package/dist/esm/package-eljsfLkU.js +0 -31
package/dist/esm/index.js CHANGED
@@ -1,276 +1,416 @@
1
- import b from "minimist";
2
- import o from "chalk";
3
- import f from "prompts";
4
- import * as R from "node:fs";
5
- import $ from "path";
6
- import * as O from "string-similarity";
7
- class c extends Error {
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
8
  }
9
- class v extends c {
9
+ class J extends y {
10
10
  constructor(t) {
11
- super(`Argument "${t.name}" is required.`), this.paramSignature = 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;
12
13
  }
13
- pretty() {
14
- const t = console.log;
15
- t(o`{white.bgRed ERROR } Argument {bold.yellow ${this.paramSignature.name}} is required.`);
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
16
  }
17
17
  }
18
- class y extends c {
19
- constructor(t, e) {
20
- super(`Missing ${t} in the command signature`), this.option = t, this.optionsSignature = e;
21
- }
22
- pretty() {
23
- const t = console.log;
24
- if (this.optionsSignature.length) {
25
- t(o`{yellow Available options}:`);
26
- for (const e of this.optionsSignature) {
27
- const n = e.type ? o`{white (${e.type})}` : "", s = " ".repeat(20 - e.name.length);
28
- t(o` {green ${e.name}} ${s} ${e.help ?? "\b"} ${n}`);
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})}`);
29
67
  }
30
- t("");
68
+ t.log("");
31
69
  }
32
- t(o`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is missing in the signature.`);
70
+ t.log(a`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is not recognized.`);
33
71
  }
34
72
  }
35
- class w extends c {
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 {
36
82
  constructor(t, e) {
37
- super(`Missing ${t} in the command signature`), this.argument = t, this.argumentSignatures = e;
38
- }
39
- pretty() {
40
- const t = console.log;
41
- if (this.argumentSignatures.length) {
42
- t(o`\n{yellow Available arguments}:`);
43
- for (const e of this.argumentSignatures) {
44
- const n = e.type ? o`{white (${e.type})}` : "", s = " ".repeat(20 - e.name.length);
45
- t(o` {green ${e.name}} ${s} ${e.help ?? "\b"} ${n}`);
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}`);
46
92
  }
47
- t("");
93
+ t.log("");
48
94
  }
49
- t(o`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is missing in the signature.`);
95
+ t.log(a`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is missing in the signature.`);
50
96
  }
51
97
  }
52
- class A extends c {
98
+ class b extends y {
53
99
  constructor(t, e) {
54
- super(`Invalid option ${t} in not recognized`), this.option = t, this.optionsSignature = e;
55
- }
56
- pretty() {
57
- const t = console.log;
58
- if (this.optionsSignature.length > 0) {
59
- t(o`\n{yellow Available options}:`);
60
- for (const e of this.optionsSignature) {
61
- const n = e.type ? o`{white (${e.type})}` : "", s = `--${e.name}${e.alias?.map((i) => `, -${i}`).join("") ?? ""}`, r = " ".repeat(30 - s.length);
62
- t(o` {green ${s}} ${r} ${e.help ?? "\b"} ${n}`);
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}`);
63
109
  }
64
- t("");
110
+ t.log("");
65
111
  }
66
- t(o`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is not recognized.`);
112
+ t.log(a`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is missing in the signature.`);
67
113
  }
68
114
  }
69
- class x {
70
- constructor(t, e, n, s, ...r) {
71
- this.io = t, this.signature = e, this.helperDefinitions = n, this.defaultCommandOptions = s;
72
- const [i, ...m] = e.split(/\{(.*?)\}/g).map((p) => p.trim()).filter(Boolean), { _: a, ...l } = b(r);
73
- this.command = i, this.parseSignature(m), this.parseDefaultOptions(), this.handleArguments(a), this.handleOptions(l);
74
- }
75
- command;
76
- arguments = {};
77
- options = {};
78
- argumentsSignature = {};
79
- optionSignatures = {};
80
- optionAliases = {};
81
- option(t) {
82
- if (!this.optionSignatures[t])
83
- throw new y(t, Object.values(this.optionSignatures));
84
- return this.options[t];
115
+ class C extends y {
116
+ constructor(t) {
117
+ super(`Argument "${t}" is required.`), this.argument = t;
85
118
  }
86
- setOption(t, e) {
87
- if (!this.optionSignatures[t])
88
- throw new y(t, Object.values(this.optionSignatures));
89
- this.options[t] = e;
119
+ pretty(t) {
120
+ t.log(a`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is required.`);
90
121
  }
91
- optionHelp(t) {
92
- if (!this.optionSignatures[t])
93
- throw new y(t, Object.values(this.optionSignatures));
94
- return this.optionSignatures[t].help;
122
+ }
123
+ class T extends y {
124
+ constructor(t) {
125
+ super(`Argument "${t}" is required.`), this.option = t;
95
126
  }
96
- argument(t) {
97
- if (!this.argumentsSignature[t])
98
- throw new w(t, Object.values(this.argumentsSignature));
99
- return this.arguments[t];
127
+ pretty(t) {
128
+ t.log(a`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is required.`);
100
129
  }
101
- setArgument(t, e) {
102
- if (!this.argumentsSignature[t])
103
- throw new w(t, Object.values(this.argumentsSignature));
104
- this.arguments[t] = e;
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;
105
172
  }
106
- argumentHelp(t) {
107
- if (!this.argumentsSignature[t])
108
- throw new w(t, Object.values(this.argumentsSignature));
109
- return this.argumentsSignature[t].help;
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
+ };
110
187
  }
111
- getArgumentSignatures() {
112
- return this.argumentsSignature;
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);
113
199
  }
114
- getOptionSignatures() {
115
- return this.optionSignatures;
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];
116
210
  }
117
- getParamValue(t, e) {
118
- return e.type === "boolean" ? t === "true" || t === "1" ? !0 : t === "false" || t === "0" ? !1 : !!t : e.type === "array" ? t ? Array.isArray(t) ? t : [t] : [] : t ?? e.defaultValue;
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];
119
221
  }
120
- handleArguments(t) {
121
- for (const [e, n] of Object.entries(this.arguments)) {
122
- const s = this.argumentsSignature[e];
123
- if (s.variadic)
124
- this.arguments[e] = t;
125
- else {
126
- const r = t.shift();
127
- this.arguments[e] = this.getParamValue(r, s);
128
- }
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);
129
234
  }
235
+ for (const n in t)
236
+ if (!e.has(n))
237
+ throw new H(n, this.options);
130
238
  }
239
+ /**
240
+ * Processes named options from minimist output
241
+ */
131
242
  handleOptions(t) {
132
- for (const [e, n] of Object.entries(t)) {
133
- const s = this.optionAliases[e], r = this.optionSignatures[e] ?? this.optionSignatures[s];
134
- if (!r)
135
- throw new A(e, Object.values(this.optionSignatures));
136
- this.options[e] = this.getParamValue(n, r);
137
- for (const i of r.alias ?? [])
138
- t[i] && (this.options[r.name] = t[i]);
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
+ );
139
252
  }
253
+ return e;
140
254
  }
141
- parseSignature(t) {
142
- for (const e of t) {
143
- const n = this.parseParamSignature(e);
144
- if (n.isOption) {
145
- this.options[n.name] = n.defaultValue ?? null, this.optionSignatures[n.name] = n;
146
- for (const s of n.alias ?? [])
147
- this.optionAliases[s] = n.name;
148
- } else
149
- this.arguments[n.name] = n.defaultValue ?? null, this.argumentsSignature[n.name] = n;
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());
150
267
  }
268
+ return e;
151
269
  }
152
- parseDefaultOptions() {
153
- if (this.defaultCommandOptions.length) {
154
- for (const t of this.defaultCommandOptions)
155
- if (this.optionSignatures[t.option] = {
156
- name: t.option,
157
- type: t.defaultValue == null ? "string" : typeof t.defaultValue == "boolean" ? "boolean" : Array.isArray(t.defaultValue) ? "array" : "string",
158
- optional: !0,
159
- alias: t.alias,
160
- variadic: !1,
161
- help: t.description,
162
- defaultValue: t.defaultValue ?? null,
163
- isOption: !0
164
- }, this.options[t.option] = t.defaultValue, t.alias)
165
- for (const e of t.alias)
166
- this.optionAliases[e] = t.option;
167
- }
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;
168
275
  }
169
- parseParamSignature(t) {
170
- const e = {
171
- name: t,
172
- optional: !1,
173
- type: "string",
174
- help: void 0,
175
- defaultValue: null,
176
- variadic: !1,
177
- isOption: !1
178
- };
179
- if (e.name.includes(":")) {
180
- const [n, s] = e.name.split(":");
181
- e.name = n.trim(), e.help = s.trim();
182
- }
183
- if (e.name.includes("=")) {
184
- const [n, s] = e.name.split("=");
185
- e.name = n.trim(), e.defaultValue = s.trim(), e.optional = !0, e.defaultValue.length ? e.defaultValue === "true" ? (e.defaultValue = !0, e.type = "boolean") : e.defaultValue === "false" && (e.defaultValue = !1, e.type = "boolean") : e.defaultValue = null;
186
- } else
187
- e.name.startsWith("--") && (e.optional = !0, e.defaultValue = !1, e.type = "boolean");
188
- if (e.name.includes("|")) {
189
- const [n, ...s] = e.name.split("|");
190
- e.name = n.trim(), e.alias = s.map((r) => r.trim());
191
- }
192
- return e.name.startsWith("--") && (e.isOption = !0, e.name = e.name.slice(2)), e.defaultValue === "*" && (e.defaultValue = [], e.type = "array"), e.name.endsWith("?") && (e.optional = !0, e.name = e.name.slice(0, -1)), e.name.endsWith("*") && (e.type = "array", e.variadic = !0, e.defaultValue = [], e.name = e.name.slice(0, -1)), e.help = e.help ?? this.helperDefinitions[e.name] ?? this.helperDefinitions[`--${e.name}`], e;
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);
193
282
  }
194
- async validate() {
195
- for (const [t, e] of Object.entries(this.arguments)) {
196
- const n = this.argumentsSignature[t];
197
- if (!e && !n.optional) {
198
- let s = null;
199
- switch (n.type) {
200
- case "string":
201
- let r = o`{yellow.bold ${n.name}} is required`;
202
- n.help && (r += o`: {gray (${n.help})}`), r += `
203
- `, s = await this.io.askForInput(r, n.defaultValue, {
204
- validate: (i) => i?.trim()?.length ? !0 : `${n.name} cannot be empty`
205
- });
206
- break;
207
- }
208
- if (s)
209
- this.setArgument(t, s);
210
- else
211
- throw new v(n);
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;
212
294
  }
213
- if (!e?.length && n.variadic && !n.optional)
214
- throw new v(n);
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;
215
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);
216
322
  }
217
323
  }
218
- function C(u) {
219
- return new Array(u + 5).join(" ");
324
+ function O(r) {
325
+ return new Array(r + 5).join(" ");
220
326
  }
221
- class V {
327
+ class M {
328
+ type = "boolean";
222
329
  option = "help";
223
330
  alias = ["h"];
224
- defaultValue = !1;
225
- description = o`Display help for the given command. When no command is given display help for the {green list} command`;
331
+ default = !1;
332
+ description = a`Display help for the given command. When no command is given display help for the {green list} command`;
226
333
  async handler() {
227
- const t = console.log, e = Object.values(this.parser.getArgumentSignatures()), n = Object.values(this.parser.getOptionSignatures()).map((a) => ({
228
- ...a,
229
- optionWithAlias: `--${a.name}${a.alias?.map((l) => `, -${l}`).join("") ?? ""}`
230
- })), s = e.filter((a) => !a.optional);
231
- t(o`{yellow Description}:`), t(o` ${this.description}\n`), t(o`{yellow Usage}:`), t(o` ${this.command} ${s.length > 0 ? s.map((a) => `<${a.name}>`).join(" ") : "\b"} [options]`);
232
- const r = Math.max(...n.map((a) => a.optionWithAlias.length)) ?? 0, i = Math.max(...e.map((a) => a.name.length)) ?? 0, m = i > r ? i : r;
233
- if (e.length > 0) {
234
- t(o`\n{yellow Arguments}:`);
235
- for (const a of e) {
236
- const l = C(m - a.name.length);
237
- let p = o` {green ${a.name}} ${l} ${a.help ?? "\b"}`;
238
- if (a.defaultValue !== void 0 && a.optional) {
239
- const h = a.type === "array" ? JSON.stringify(a.defaultValue) : a.defaultValue;
240
- p += o` {yellow [default: ${h}]}`;
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}]}`;
241
352
  }
242
- a.variadic && (p += o` {white (variadic)}`), t(p);
353
+ h.variadic && (p += a` {white (variadic)}`), this.io.log(p);
243
354
  }
244
355
  }
245
- if (n.length > 0) {
246
- t(o`\n{yellow Options}:`);
247
- for (const a of n) {
248
- const l = C(m - a.optionWithAlias.length);
249
- let p = o`{green ${a.optionWithAlias}} ${l} ${a.help ?? "\b"}`;
250
- if (a.type && (p += o` {white (${a.type})}`), a.defaultValue !== void 0 && a.optional) {
251
- const h = a.type === "array" ? JSON.stringify(a.defaultValue) : a.defaultValue;
252
- p += o` {yellow [default: ${h}]}`;
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}]}`;
253
368
  }
254
- t(p);
369
+ this.io.log(d);
255
370
  }
256
371
  }
257
372
  if (this.commandsExamples.length > 0) {
258
- t(o`\n{yellow Examples}:`);
259
- let a = process.argv[0].split("/").pop();
260
- a === "node" && (a += " " + process.argv[1].split("/").pop());
261
- for (const [l, p] of this.commandsExamples.entries())
262
- l > 0 && t(""), t(` ${p.description}
263
- `), t(o` {green ${a} ${p.command}}`);
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}}`);
264
379
  }
265
380
  return -1;
266
381
  }
267
382
  }
268
- class S {
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
+ }
269
409
  /**
270
410
  * Prompt utils
271
411
  */
272
412
  async askForConfirmation(t = "Do you want to continue?", e) {
273
- return (await f({
413
+ return (await w({
274
414
  type: "confirm",
275
415
  name: "value",
276
416
  message: t,
@@ -278,7 +418,7 @@ class S {
278
418
  })).value;
279
419
  }
280
420
  async askForInput(t, e, n) {
281
- return (await f({
421
+ return (await w({
282
422
  type: "text",
283
423
  name: "value",
284
424
  message: t,
@@ -287,7 +427,7 @@ class S {
287
427
  }))?.value ?? null;
288
428
  }
289
429
  async askForToggle(t, e, n) {
290
- return (await f({
430
+ return (await w({
291
431
  type: "toggle",
292
432
  name: "value",
293
433
  message: t,
@@ -298,107 +438,380 @@ class S {
298
438
  async askForSelect(t, e, n) {
299
439
  if (e.length === 0)
300
440
  throw new Error("No options provided");
301
- const s = [];
302
- for (const i of e)
303
- typeof i == "string" ? s.push({ title: i, value: i }) : s.push(i);
304
- return (await f({
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({
305
445
  type: "select",
306
446
  name: "value",
307
447
  message: t,
308
- choices: s,
448
+ choices: i,
309
449
  ...n
310
450
  }))?.value ?? null;
311
451
  }
312
452
  newLoader(t = "", e = ["⠙", "⠘", "⠰", "⠴", "⠤", "⠦", "⠆", "⠃", "⠋", "⠉"], n = 100) {
313
- let s = t, r = null, i = 0;
314
- const m = setInterval(function() {
315
- r && (process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(r.length + 5) + "\r")), r = null), process.stdout.write(new TextEncoder().encode("\r" + e[i++] + " " + s)), i = i % e.length;
316
- }, n), a = () => {
317
- clearInterval(m), process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(s.length + 5) + "\r"));
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"));
318
458
  };
319
459
  return {
320
- [Symbol.dispose]: a,
321
- [Symbol.asyncDispose]: a,
322
- updateText: (l) => {
323
- r = s, s = l;
460
+ [Symbol.dispose]: u,
461
+ [Symbol.asyncDispose]: u,
462
+ updateText: (c) => {
463
+ s = i, i = c;
324
464
  },
325
- stop: a
465
+ stop: u
326
466
  };
327
467
  }
328
468
  }
329
- class E {
330
- ctx;
331
- helperDefinitions = {};
469
+ class R {
470
+ _command;
471
+ description = "";
332
472
  commandsExamples = [];
333
- parser;
473
+ get command() {
474
+ return this._command;
475
+ }
476
+ ctx;
334
477
  io;
335
- get CommandParserClass() {
336
- return x;
478
+ logger;
479
+ _handler;
480
+ parser;
481
+ tmp;
482
+ defaultOptions() {
483
+ return [new M()];
337
484
  }
338
- get CommandIOClass() {
339
- return S;
485
+ newCommandParser(t) {
486
+ return new k({
487
+ io: t.io,
488
+ options: t.options,
489
+ arguments: t.arguments
490
+ });
340
491
  }
341
- defaultOptions() {
342
- return [new V()];
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 };
343
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 = {};
344
747
  get command() {
345
748
  return this.parser ? this.parser.command : this.signature.split(" ")[0];
346
749
  }
347
- async run(t, ...e) {
348
- this.ctx = t;
349
- const n = this.defaultOptions();
350
- this.io = new this.CommandIOClass(), this.parser = new this.CommandParserClass(this.io, this.signature, this.helperDefinitions, n, ...e);
351
- for (const r of n)
352
- if (this.parser.option(r.option)) {
353
- const i = await r.handler.call(this);
354
- if (i && i !== 0)
355
- return i;
356
- }
357
- await this.parser.validate();
358
- const s = this.preHandle ? await this.preHandle() : null;
359
- return s && s !== 0 ? s : await this.handle() ?? 0;
750
+ newCommandParser(t) {
751
+ return new g({
752
+ io: t.io,
753
+ signature: this.signature,
754
+ helperDefinitions: this.helperDefinitions,
755
+ defaultOptions: this.defaultOptions()
756
+ });
360
757
  }
758
+ constructor() {
759
+ super("");
760
+ }
761
+ // Helper methods from LegacyCommand
361
762
  setOption(t, e) {
362
763
  this.parser.setOption(t, e);
363
764
  }
364
765
  setArgument(t, e) {
365
- this.parser.setArgument(t, e);
766
+ this.parser instanceof g && this.parser.setArgument(t, e);
366
767
  }
367
768
  option(t, e = null) {
368
- return this.parser.option(t) ?? e;
769
+ return this.parser instanceof g ? this.parser.option(t) ?? e : e;
369
770
  }
370
771
  optionBoolean(t, e = !1) {
371
- return this.parser.option(t) ?? e;
772
+ return this.parser instanceof g ? this.parser.option(t) ?? e : e;
372
773
  }
373
774
  optionArray(t, e = []) {
374
- const n = this.parser.option(t);
375
- if (!Array.isArray(n))
376
- throw new Error(`Option ${t} is not an array`);
377
- return n.length ? n : 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;
378
783
  }
379
784
  optionNumber(t, e = null) {
380
- const n = this.parser.option(t);
381
- return n ? typeof n == "number" ? n : parseInt(n) : e;
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;
382
790
  }
383
791
  argument(t, e = null) {
384
- return this.parser.argument(t) ?? e;
792
+ return this.parser instanceof g ? this.parser.argument(t) ?? e : e;
385
793
  }
386
794
  argumentArray(t, e = []) {
387
- const n = this.parser.argument(t);
388
- if (!Array.isArray(n))
389
- throw new Error(`Argument ${t} is not an array`);
390
- return n?.length ? n : 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;
391
803
  }
392
804
  argumentBoolean(t, e = !1) {
393
- return this.parser.argument(t) ?? e;
805
+ return this.parser instanceof g ? this.parser.argument(t) ?? e : e;
394
806
  }
395
807
  argumentNumber(t, e = null) {
396
- const n = this.parser.argument(t);
397
- return n ? typeof n == "number" ? n : parseInt(n) : e;
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;
398
813
  }
399
- /**
400
- * Prompt utils
401
- */
814
+ // Prompt utils
402
815
  async askForConfirmation(...t) {
403
816
  return this.io.askForConfirmation(...t);
404
817
  }
@@ -412,26 +825,49 @@ class E {
412
825
  return this.io.newLoader(...t);
413
826
  }
414
827
  }
415
- class j extends c {
416
- constructor(t) {
417
- super(`Command "${t}" not found.`), this.command = t;
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);
418
845
  }
419
- pretty() {
420
- const t = console.log;
421
- t(o`{bgRed ERROR } Command {yellow ${this.command}} not found.`);
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);
422
860
  }
423
861
  }
424
- class F {
862
+ class W {
425
863
  commands = {};
426
864
  io;
427
- get commandSuffix() {
428
- return "Command";
429
- }
865
+ logger;
430
866
  get CommandIOClass() {
431
- return S;
867
+ return q;
432
868
  }
433
- constructor() {
434
- this.io = new this.CommandIOClass();
869
+ constructor(t) {
870
+ this.logger = t ?? new L(), this.io = new this.CommandIOClass(this.logger);
435
871
  }
436
872
  getAvailableCommands() {
437
873
  return Object.keys(this.commands);
@@ -440,15 +876,24 @@ class F {
440
876
  return Object.values(this.commands);
441
877
  }
442
878
  commandResolver = async (t) => {
443
- const e = (await import(t)).default;
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);
444
883
  let n;
445
- return e?.default ? n = new e.default() : n = new e(), 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;
446
891
  };
447
892
  setCommandResolver(t) {
448
893
  this.commandResolver = t;
449
894
  }
450
895
  registerCommand(t, e = !1) {
451
- const n = t.signature.split(" ")[0];
896
+ const n = t.command;
452
897
  if (!n)
453
898
  throw new Error("Command signature is invalid, it must have a command name.");
454
899
  if (!e && this.commands[n])
@@ -461,126 +906,115 @@ class F {
461
906
  const n = await this.commandResolver(e);
462
907
  this.registerCommand(n);
463
908
  } catch (n) {
464
- throw new Error(`Command ${e} failed to load. ${n}`);
909
+ throw new Error(`Command ${e} failed to load. ${n}`, {
910
+ cause: n
911
+ });
465
912
  }
466
913
  }
467
914
  async runCommand(t, e, ...n) {
468
- const s = typeof e == "string" ? this.commands[e] : e, r = typeof e == "string" ? e : s.command;
469
- if (!s) {
470
- const i = await this.suggestCommand(r);
471
- return i ? await this.runCommand(t, i, ...n) : 1;
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;
472
919
  }
473
- return await s.run(t, ...n);
920
+ return await i.run({
921
+ ctx: t,
922
+ logger: this.logger,
923
+ args: n
924
+ }) ?? 0;
474
925
  }
475
926
  async suggestCommand(t) {
476
- const e = this.getAvailableCommands(), { bestMatch: n, bestMatchIndex: s, ratings: r } = O.findBestMatch(t, e), i = r.filter((m) => m.rating > 0.3).map((m) => m.target);
477
- if (n.rating > 0 && i.length <= 1 || n.rating > 0.7 && i.length > 1) {
478
- const m = e[s];
479
- return await this.askRunSimilarCommand(t, m) ? m : null;
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;
480
931
  }
481
- if (i.length) {
482
- console.log(o`{bgRed ERROR } Command {yellow ${t}} not found.\n`);
483
- const m = await this.io.askForSelect(
484
- o`{green Did you mean to run one of these commands instead?}`,
485
- i
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
486
937
  );
487
- if (m)
488
- return m;
938
+ if (l)
939
+ return l;
489
940
  }
490
941
  throw new j(t);
491
942
  }
492
943
  async askRunSimilarCommand(t, e) {
493
- return console.log(o`{bgRed ERROR } Command {yellow ${t}} not found.\n`), this.io.askForConfirmation(o`{green Do you want to run {yellow ${e}} instead?} `);
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?} `);
494
945
  }
495
946
  async *listCommandsFiles(t) {
496
- const e = R.readdirSync(t, { withFileTypes: !0 });
947
+ const e = F.readdirSync(t, { withFileTypes: !0 });
497
948
  for (const n of e) {
498
- const s = $.resolve(t, n.name);
499
- if (n.isDirectory())
500
- yield* this.listCommandsFiles($.resolve(t, n.name));
501
- else {
502
- if (!s.endsWith(`${this.commandSuffix}.ts`) && !s.endsWith(`${this.commandSuffix}.js`))
503
- continue;
504
- yield s;
505
- }
949
+ const i = S.resolve(t, n.name);
950
+ n.isDirectory() ? yield* this.listCommandsFiles(S.resolve(t, n.name)) : yield i;
506
951
  }
507
952
  }
508
953
  }
509
- class k extends E {
954
+ class B extends R {
510
955
  constructor(t) {
511
- super(), this.opts = t;
956
+ super("help", {
957
+ description: a.bold("Show help information about the CLI and its commands")
958
+ }), this.opts = t;
512
959
  }
513
- signature = "help";
514
- description = "Show help";
515
960
  async handle() {
516
- const t = this.opts.commandRegistry.getCommands(), e = this.opts.cliName ?? "Bob CLI", n = this.opts.cliVersion ?? "0.0.0", s = (await import("./package-eljsfLkU.js"))?.default?.version ?? "0.0.0";
517
- console.log(o`${e} {green ${n}} (core: {yellow ${s}})
961
+ const t = this.opts.commandRegistry.getCommands(), e = this.opts.cliName ?? "Bob CLI", n = this.opts.cliVersion ?? "0.0.0", i = (await import("./package-Pf7NCMvE.js"))?.default?.version ?? "0.0.0";
962
+ this.io.log(a`${e} {green ${n}} (core: {yellow ${i}})
518
963
 
519
964
  {yellow Usage}:
520
965
  command [options] [arguments]
521
966
 
522
967
  {yellow Available commands}:
523
968
  `);
524
- const r = Math.max(...t.map((a) => a.command.length)) ?? 0, i = {};
525
- for (const a of t) {
526
- const l = a.command.split(":")[0];
527
- i[l] || (i[l] = []), i[l].push(a);
969
+ const s = Math.max(...t.map((u) => u.command.length)) ?? 0, o = {};
970
+ for (const u of t) {
971
+ const c = u.command.split(":")[0];
972
+ o[c] || (o[c] = []), o[c].push(u);
528
973
  }
529
- const m = Object.entries(i).sort(([a], [l]) => a.toLowerCase().localeCompare(l.toLowerCase())).sort(([, a], [, l]) => a.length - l.length);
530
- for (const [a, l] of m) {
531
- const p = l.length > 1;
532
- p && console.log(o`{yellow ${a}}:`);
533
- const h = l.sort((d, g) => d.command.toLowerCase().localeCompare(g.command.toLowerCase()));
974
+ const l = Object.entries(o).sort(([u], [c]) => u.toLowerCase().localeCompare(c.toLowerCase())).sort(([, u], [, c]) => u.length - c.length);
975
+ for (const [u, c] of l) {
976
+ const m = c.length > 1;
977
+ m && this.io.log(a`{yellow ${u}}:`);
978
+ const h = c.sort((d, p) => d.command.toLowerCase().localeCompare(p.command.toLowerCase()));
534
979
  for (const d of h) {
535
- let g = C(r - d.command.length);
536
- p && (g = g.slice(2)), console.log(o`${p ? " " : ""}{green ${d.command}} ${g} ${d.description}`);
980
+ let p = O(s - d.command.length);
981
+ m && (p = p.slice(2)), this.io.log(a`${m ? " " : ""}{green ${d.command}} ${p} ${d.description}`);
537
982
  }
538
983
  }
539
984
  }
540
985
  }
541
- class W extends c {
986
+ class P {
987
+ logger;
542
988
  constructor(t) {
543
- let e = `Argument "${t.param}" value is invalid.`;
544
- t.reason ? e += ` Reason: ${t.reason}` : e += ` Value: "${t.value}"`, super(e), this.param = t;
545
- }
546
- pretty() {
547
- const t = console.log;
548
- t(o` {white.bgRed ERROR } Argument {bold.yellow ${this.param.param}} value is invalid. `), (this.param.value || this.param.reason) && t(""), this.param.value && t(o` {blue Value}: ${this.param.value}`), this.param.reason && t(o` {yellow Reason}: ${this.param.reason}`);
989
+ this.logger = t;
549
990
  }
550
- }
551
- class M extends c {
552
- constructor(t) {
553
- let e = `Option "${t.option}" value is invalid.`;
554
- t.reason ? e += ` Reason: ${t.reason}` : e += ` Value: "${t.value}"`, super(e), this.param = t;
555
- }
556
- pretty() {
557
- const t = console.log;
558
- t(o` {white.bgRed ERROR } Option {bold.yellow ${this.param.option}} value is invalid. `), (this.param.value || this.param.reason) && t(""), this.param.value && t(o` {blue Value}: ${this.param.value}`), this.param.reason && t(o` {yellow Reason}: ${this.param.reason}`);
559
- }
560
- }
561
- class H {
562
991
  handle(t) {
563
- if (t instanceof c)
564
- return t.pretty(), -1;
992
+ if (t instanceof y)
993
+ return t.pretty(this.logger), -1;
565
994
  throw t;
566
995
  }
567
996
  }
568
- class N {
997
+ class Q {
998
+ ctx;
999
+ logger;
569
1000
  commandRegistry;
570
1001
  exceptionHandler;
571
- ctx;
572
1002
  helpCommand;
573
- get CommandRegistryClass() {
574
- return F;
1003
+ newCommandRegistry(t) {
1004
+ return new W(t.logger);
575
1005
  }
576
- get HelpCommandClass() {
577
- return k;
1006
+ newHelpCommand(t) {
1007
+ return new B(t);
578
1008
  }
579
- get ExceptionHandlerClass() {
580
- return H;
1009
+ newExceptionHandler(t) {
1010
+ return new P(t.logger);
581
1011
  }
582
1012
  constructor(t = {}) {
583
- this.ctx = t.ctx, this.commandRegistry = new this.CommandRegistryClass(), this.exceptionHandler = new this.ExceptionHandlerClass(), this.helpCommand = new this.HelpCommandClass({
1013
+ this.ctx = t.ctx, this.logger = t.logger ?? new L(), this.commandRegistry = this.newCommandRegistry({
1014
+ logger: this.logger
1015
+ }), this.exceptionHandler = this.newExceptionHandler({
1016
+ logger: this.logger
1017
+ }), this.helpCommand = this.newHelpCommand({
584
1018
  cliName: t.name,
585
1019
  cliVersion: t.version,
586
1020
  commandRegistry: this.commandRegistry
@@ -594,7 +1028,7 @@ class N {
594
1028
  typeof e == "string" ? await this.commandRegistry.loadCommandsPath(e) : typeof e == "function" ? this.registerCommand(new e()) : this.registerCommand(e);
595
1029
  }
596
1030
  async runCommand(t, ...e) {
597
- return t ? await this.commandRegistry.runCommand(this.ctx, t, ...e).catch(this.exceptionHandler.handle) : await this.runHelpCommand();
1031
+ return t ? await this.commandRegistry.runCommand(this.ctx, t, ...e).catch(this.exceptionHandler.handle.bind(this.exceptionHandler)) : await this.runHelpCommand();
598
1032
  }
599
1033
  async runHelpCommand() {
600
1034
  return await this.runCommand(this.helpCommand);
@@ -604,11 +1038,23 @@ class N {
604
1038
  }
605
1039
  }
606
1040
  export {
607
- M as BadCommandOption,
608
- W as BadCommandParameter,
609
- c as BobError,
610
- N as Cli,
611
- E as Command,
612
- S as CommandIO,
613
- V as HelpOption
1041
+ $ as BadCommandOption,
1042
+ J as BadCommandParameter,
1043
+ y as BobError,
1044
+ Q as Cli,
1045
+ R as Command,
1046
+ q as CommandIO,
1047
+ j as CommandNotFoundError,
1048
+ k as CommandParser,
1049
+ W as CommandRegistry,
1050
+ g as CommandSignatureParser,
1051
+ K as CommandWithSignature,
1052
+ P as ExceptionHandler,
1053
+ M as HelpOption,
1054
+ H as InvalidOption,
1055
+ L as Logger,
1056
+ C as MissingRequiredArgumentValue,
1057
+ T as MissingRequiredOptionValue,
1058
+ v as MissingSignatureArgument,
1059
+ b as MissingSignatureOption
614
1060
  };