convoker 0.2.0 → 0.3.2
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.
- package/dist/color.d.ts +153 -200
- package/dist/color.js +142 -48
- package/dist/command.d.ts +218 -535
- package/dist/command.js +516 -404
- package/dist/error.d.ts +107 -844
- package/dist/error.js +100 -10
- package/dist/index.d.ts +6 -1204
- package/dist/index.js +6 -13
- package/dist/input.d.ts +182 -252
- package/dist/input.js +185 -10
- package/dist/log.d.ts +61 -0
- package/dist/log.js +216 -0
- package/dist/{prompt.d.ts → prompt/index.d.ts} +193 -258
- package/dist/prompt/index.js +273 -0
- package/dist/prompt/raw.js +105 -9
- package/dist/standard-schema.d.ts +62 -0
- package/dist/standard-schema.js +16 -0
- package/dist/utils.d.ts +30 -0
- package/dist/utils.js +56 -0
- package/package.json +4 -5
- package/dist/chunks/__vite-browser-external-DQYBmsno.js +0 -80
- package/dist/chunks/color-CiruG_zQ.js +0 -153
- package/dist/chunks/error-CBR2veuf.js +0 -95
- package/dist/chunks/index-D7JQKzRX.js +0 -198
- package/dist/chunks/input-BfYvlWdG.js +0 -138
- package/dist/chunks/standard-schema-CFxVDMhv.js +0 -12
- package/dist/chunks/utils-DdmSEjLc.js +0 -22
- package/dist/prompt.js +0 -17
- package/dist/raw.d.ts +0 -38
package/dist/command.js
CHANGED
|
@@ -1,419 +1,531 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { gray, cyan, bold } from "./color";
|
|
2
|
+
import { setTheme as setPromptTheme } from "./prompt";
|
|
3
|
+
import { setTheme as setLogTheme } from "./log";
|
|
4
|
+
import { ConvokerError, HelpAskedError, MissingRequiredArgumentError, MissingRequiredOptionError, TooManyArgumentsError, UnknownOptionError, } from "./error";
|
|
5
|
+
import { convert, Option, Positional, } from "./input";
|
|
6
|
+
/**
|
|
7
|
+
* A command.
|
|
8
|
+
*/
|
|
9
|
+
export class Command {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new command.
|
|
12
|
+
* @param names The names (aliases).
|
|
13
|
+
* @param desc The description.
|
|
14
|
+
* @param version The version.
|
|
15
|
+
*/
|
|
16
|
+
constructor(names, desc, version) {
|
|
17
|
+
/**
|
|
18
|
+
* The children of this command.
|
|
19
|
+
*/
|
|
20
|
+
this.$children = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* If this command allows unknown options.
|
|
23
|
+
*/
|
|
24
|
+
this.$allowUnknownOptions = false;
|
|
25
|
+
/**
|
|
26
|
+
* If you should be able to surpass the amount of positional arguments defined in the input.
|
|
27
|
+
*/
|
|
28
|
+
this.$allowSurpassArgLimit = false;
|
|
29
|
+
/**
|
|
30
|
+
* The input this command takes.
|
|
31
|
+
*/
|
|
32
|
+
this.$input = {};
|
|
33
|
+
/**
|
|
34
|
+
* The action function of this command.
|
|
35
|
+
*/
|
|
36
|
+
this.$fn = undefined;
|
|
37
|
+
/**
|
|
38
|
+
* The middlewares associated with this command.
|
|
39
|
+
*/
|
|
40
|
+
this.$middlewares = [];
|
|
41
|
+
/**
|
|
42
|
+
* The error handler of this command.
|
|
43
|
+
*/
|
|
44
|
+
this.$errorFn = undefined;
|
|
45
|
+
this.$names = Array.isArray(names) ? names : [names];
|
|
46
|
+
this.$description = desc;
|
|
47
|
+
this.$version = version;
|
|
14
48
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
console.error(String(n));
|
|
49
|
+
/**
|
|
50
|
+
* Adds a set of aliases to this command.
|
|
51
|
+
* @param aliases The aliases to add.
|
|
52
|
+
* @returns this
|
|
53
|
+
*/
|
|
54
|
+
alias(...aliases) {
|
|
55
|
+
this.$names.concat(aliases);
|
|
56
|
+
this.$parent?.add(this);
|
|
57
|
+
return this;
|
|
25
58
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
start(n) {
|
|
35
|
-
n.close();
|
|
59
|
+
/**
|
|
60
|
+
* Adds a description to this command.
|
|
61
|
+
* @param desc The description.
|
|
62
|
+
* @returns this
|
|
63
|
+
*/
|
|
64
|
+
description(desc) {
|
|
65
|
+
this.$description = desc;
|
|
66
|
+
return this;
|
|
36
67
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
case "xml":
|
|
64
|
-
return `<log>
|
|
65
|
-
<timestamp>${t}</timestamp>
|
|
66
|
-
<level>${n}</level>
|
|
67
|
-
<message>${r}</message>
|
|
68
|
-
</log>
|
|
69
|
-
`;
|
|
70
|
-
case "yaml":
|
|
71
|
-
return `- timestamp: ${t}
|
|
72
|
-
level: ${n}
|
|
73
|
-
message: "${r.replace(/"/g, '\\"')}"
|
|
74
|
-
`;
|
|
75
|
-
case "csv":
|
|
76
|
-
return `"${t}","${n}","${r.replace(/"/g, '""')}"
|
|
77
|
-
`;
|
|
78
|
-
case "text":
|
|
79
|
-
default:
|
|
80
|
-
return `[${t}] [${n.toUpperCase()}] ${r}
|
|
81
|
-
`;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function E(n, e) {
|
|
85
|
-
switch (n) {
|
|
86
|
-
case "trace":
|
|
87
|
-
return m.secondary ? m.secondary(e) : e;
|
|
88
|
-
case "info":
|
|
89
|
-
return m.info ? m.info(e) : e;
|
|
90
|
-
case "warn":
|
|
91
|
-
return m.warning ? m.warning(e) : e;
|
|
92
|
-
case "error":
|
|
93
|
-
return m.error ? m.error(e) : e;
|
|
94
|
-
case "fatal":
|
|
95
|
-
return m.error ? m.error(m.styles?.bold?.(e) ?? e) : e;
|
|
96
|
-
default:
|
|
97
|
-
return e;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async function k(n, e) {
|
|
101
|
-
const t = n.getWriter();
|
|
102
|
-
try {
|
|
103
|
-
await t.write(e);
|
|
104
|
-
} finally {
|
|
105
|
-
t.releaseLock();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async function x(...n) {
|
|
109
|
-
const e = S("trace", ...n), t = E("trace", e);
|
|
110
|
-
await k(g.stdout, t);
|
|
111
|
-
}
|
|
112
|
-
async function tt(...n) {
|
|
113
|
-
const e = S("info", ...n), t = E("info", e);
|
|
114
|
-
await k(g.stdout, t);
|
|
115
|
-
}
|
|
116
|
-
async function et(...n) {
|
|
117
|
-
const e = S("warn", ...n), t = E("warn", e);
|
|
118
|
-
await k(g.stdout, t);
|
|
119
|
-
}
|
|
120
|
-
async function nt(...n) {
|
|
121
|
-
const e = S("error", ...n), t = E("error", e);
|
|
122
|
-
await k(g.stderr, t);
|
|
123
|
-
}
|
|
124
|
-
async function rt(...n) {
|
|
125
|
-
const e = S("fatal", ...n), t = E("fatal", e);
|
|
126
|
-
await k(g.stderr, t), A ? Deno.exit(-1) : (W || j) && process.exit(-1);
|
|
127
|
-
}
|
|
128
|
-
const ct = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
129
|
-
__proto__: null,
|
|
130
|
-
error: nt,
|
|
131
|
-
fatal: rt,
|
|
132
|
-
info: tt,
|
|
133
|
-
setConfig: L,
|
|
134
|
-
setTheme: I,
|
|
135
|
-
setup: Z,
|
|
136
|
-
trace: x,
|
|
137
|
-
warn: et
|
|
138
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
139
|
-
class F {
|
|
140
|
-
/**
|
|
141
|
-
* Creates a new command.
|
|
142
|
-
* @param names The names (aliases).
|
|
143
|
-
* @param desc The description.
|
|
144
|
-
* @param version The version.
|
|
145
|
-
*/
|
|
146
|
-
constructor(e, t, r) {
|
|
147
|
-
this.$children = /* @__PURE__ */ new Map(), this.$allowUnknownOptions = !1, this.$allowSurpassArgLimit = !1, this.$input = {}, this.$fn = void 0, this.$errorFn = void 0, this.$names = Array.isArray(e) ? e : [e], this.$description = t, this.$version = r;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Adds a set of aliases to this command.
|
|
151
|
-
* @param aliases The aliases to add.
|
|
152
|
-
* @returns this
|
|
153
|
-
*/
|
|
154
|
-
alias(...e) {
|
|
155
|
-
return this.$names.concat(e), this.$parent?.add(this), this;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Adds a description to this command.
|
|
159
|
-
* @param desc The description.
|
|
160
|
-
* @returns this
|
|
161
|
-
*/
|
|
162
|
-
description(e) {
|
|
163
|
-
return this.$description = e, this;
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Adds a version to this command.
|
|
167
|
-
* @param version The version.
|
|
168
|
-
* @returns this
|
|
169
|
-
*/
|
|
170
|
-
version(e) {
|
|
171
|
-
return this.$version = e, this;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Sets the input for this command.
|
|
175
|
-
* @param version The input.
|
|
176
|
-
* @returns this
|
|
177
|
-
*/
|
|
178
|
-
input(e) {
|
|
179
|
-
return this.$input = e, this;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Sets the action function for this command.
|
|
183
|
-
* @param fn The action.
|
|
184
|
-
* @returns this
|
|
185
|
-
*/
|
|
186
|
-
action(e) {
|
|
187
|
-
return this.$fn = e, this;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Sets the error function for this command.
|
|
191
|
-
* @param fn The error handler.
|
|
192
|
-
* @returns this
|
|
193
|
-
*/
|
|
194
|
-
error(e) {
|
|
195
|
-
return this.$errorFn = e, this;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Adds an existing command to this.
|
|
199
|
-
* @param command The command.
|
|
200
|
-
* @returns this
|
|
201
|
-
*/
|
|
202
|
-
add(e) {
|
|
203
|
-
e.$parent = this;
|
|
204
|
-
const t = { command: e, alias: e.$names[0] };
|
|
205
|
-
for (let r = 0; r < e.$names.length; r++)
|
|
206
|
-
r === 0 && this.$children.set(e.$names[r], { command: e }), this.$children.set(e.$names[r], t);
|
|
207
|
-
return this;
|
|
208
|
-
}
|
|
209
|
-
subCommand(e, t, r) {
|
|
210
|
-
if (typeof t == "function") {
|
|
211
|
-
const a = new F(e);
|
|
212
|
-
return t(a), this.add(a), this;
|
|
68
|
+
/**
|
|
69
|
+
* Adds a version to this command.
|
|
70
|
+
* @param version The version.
|
|
71
|
+
* @returns this
|
|
72
|
+
*/
|
|
73
|
+
version(version) {
|
|
74
|
+
this.$version = version;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Sets the input for this command.
|
|
79
|
+
* @param version The input.
|
|
80
|
+
* @returns this
|
|
81
|
+
*/
|
|
82
|
+
input(input) {
|
|
83
|
+
this.$input = input;
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Adds a chain of middlewares.
|
|
88
|
+
* @param fns The middlewares to use.
|
|
89
|
+
* @returns this
|
|
90
|
+
*/
|
|
91
|
+
use(...fns) {
|
|
92
|
+
this.$middlewares.push(...fns);
|
|
93
|
+
return this;
|
|
213
94
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return this.$allowUnknownOptions = !0, this;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Parses a set of command-line arguments.
|
|
226
|
-
* @param argv The arguments to parse.
|
|
227
|
-
* @returns A parse result.
|
|
228
|
-
*/
|
|
229
|
-
async parse(e) {
|
|
230
|
-
let t = this, r = !1;
|
|
231
|
-
const i = {}, a = [], d = {}, s = [], c = t.buildInputMap();
|
|
232
|
-
function u(f, o) {
|
|
233
|
-
const l = c.get(f);
|
|
234
|
-
return l ? l.value : (!t.$allowUnknownOptions && !o && s.push(new K(t, f)), null);
|
|
95
|
+
/**
|
|
96
|
+
* Sets the action function for this command.
|
|
97
|
+
* @param fn The action.
|
|
98
|
+
* @returns this
|
|
99
|
+
*/
|
|
100
|
+
action(fn) {
|
|
101
|
+
this.$fn = fn;
|
|
102
|
+
return this;
|
|
235
103
|
}
|
|
236
|
-
|
|
237
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Sets the error function for this command.
|
|
106
|
+
* @param fn The error handler.
|
|
107
|
+
* @returns this
|
|
108
|
+
*/
|
|
109
|
+
error(fn) {
|
|
110
|
+
this.$errorFn = fn;
|
|
111
|
+
return this;
|
|
238
112
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
) : h(l, $, w));
|
|
252
|
-
} else if (o.startsWith("-")) {
|
|
253
|
-
const [l, w] = o.slice(1).split("="), y = l.split("");
|
|
254
|
-
let $ = w;
|
|
255
|
-
for (const D of y) {
|
|
256
|
-
let T = !1;
|
|
257
|
-
D === "h" ? (C = !0, T = !0) : D === "V" && (p = !0, T = !0);
|
|
258
|
-
const U = u(D, T);
|
|
259
|
-
U && (U.$kind !== "boolean" && $ === void 0 && ($ = e[++f]), h(D, U, $), $ = void 0);
|
|
113
|
+
/**
|
|
114
|
+
* Adds an existing command to this.
|
|
115
|
+
* @param command The command.
|
|
116
|
+
* @returns this
|
|
117
|
+
*/
|
|
118
|
+
add(command) {
|
|
119
|
+
command.$parent = this;
|
|
120
|
+
const alias = { command, alias: command.$names[0] };
|
|
121
|
+
for (let i = 0; i < command.$names.length; i++) {
|
|
122
|
+
if (i === 0)
|
|
123
|
+
this.$children.set(command.$names[i], { command });
|
|
124
|
+
this.$children.set(command.$names[i], alias);
|
|
260
125
|
}
|
|
261
|
-
|
|
262
|
-
t.$children.has(o) && !r ? (t = t.$children.get(o).command, t.$theme && (q(t.$theme), I(t.$theme))) : (r = !0, a.push(o));
|
|
126
|
+
return this;
|
|
263
127
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
} else
|
|
275
|
-
for (const w of o.$names)
|
|
276
|
-
if (d[w] !== void 0) {
|
|
277
|
-
l = o.$list ? d[w] : d[w].split(o.$separator ?? ",");
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
280
|
-
l !== void 0 ? i[f] = await G(o.$kind, l) : o.$default !== void 0 ? i[f] = o.$default : o.$required && (o instanceof _ ? s.push(new z(t, f, o)) : s.push(new N(t, f, o)));
|
|
128
|
+
subCommand(names, descOrBuilder, version) {
|
|
129
|
+
if (typeof descOrBuilder === "function") {
|
|
130
|
+
const command = new Command(names);
|
|
131
|
+
descOrBuilder(command);
|
|
132
|
+
this.add(command);
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
const command = new Command(names, descOrBuilder, version);
|
|
136
|
+
this.add(command);
|
|
137
|
+
return command;
|
|
281
138
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
buildInputMap(e) {
|
|
291
|
-
const t = /* @__PURE__ */ new Map();
|
|
292
|
-
let r = 0;
|
|
293
|
-
for (const i in this.$input) {
|
|
294
|
-
const a = this.$input[i];
|
|
295
|
-
if (a instanceof B)
|
|
296
|
-
t.set(r++, { value: a, key: i });
|
|
297
|
-
else
|
|
298
|
-
for (const d of a.$names)
|
|
299
|
-
t.set(d, { value: a, key: i });
|
|
139
|
+
/**
|
|
140
|
+
* Allows unknown options.
|
|
141
|
+
* @returns this
|
|
142
|
+
*/
|
|
143
|
+
allowUnknownOptions() {
|
|
144
|
+
this.$allowUnknownOptions = true;
|
|
145
|
+
return this;
|
|
300
146
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Parses a set of command-line arguments.
|
|
149
|
+
* @param argv The arguments to parse.
|
|
150
|
+
* @returns A parse result.
|
|
151
|
+
*/
|
|
152
|
+
async parse(argv) {
|
|
153
|
+
// eslint-disable-next-line -- alias to this is necessary to go through the tree
|
|
154
|
+
let command = this;
|
|
155
|
+
let found = false;
|
|
156
|
+
const input = {};
|
|
157
|
+
const args = [];
|
|
158
|
+
const opts = {};
|
|
159
|
+
const errors = [];
|
|
160
|
+
const map = command.buildInputMap();
|
|
161
|
+
function getOption(key, isSpecial) {
|
|
162
|
+
const entry = map.get(key);
|
|
163
|
+
if (!entry) {
|
|
164
|
+
if (!command.$allowUnknownOptions && !isSpecial)
|
|
165
|
+
errors.push(new UnknownOptionError(command, key));
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
return entry.value;
|
|
169
|
+
}
|
|
170
|
+
function setOption(key, option, value) {
|
|
171
|
+
if (option.$kind === "boolean") {
|
|
172
|
+
opts[key] = "true";
|
|
173
|
+
}
|
|
174
|
+
else if (value !== undefined) {
|
|
175
|
+
opts[key] = value;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
let isVersion = false;
|
|
179
|
+
let isHelp = false;
|
|
180
|
+
for (let i = 0; i < argv.length; i++) {
|
|
181
|
+
const arg = argv[i];
|
|
182
|
+
if (arg.startsWith("--")) {
|
|
183
|
+
// --long[=value] or --long [value]
|
|
184
|
+
const [key, value] = arg.slice(2).split("=");
|
|
185
|
+
let isSpecial = false;
|
|
186
|
+
if (key === "help") {
|
|
187
|
+
isHelp = true;
|
|
188
|
+
isSpecial = true;
|
|
189
|
+
}
|
|
190
|
+
else if (key === "version") {
|
|
191
|
+
isVersion = true;
|
|
192
|
+
isSpecial = true;
|
|
193
|
+
}
|
|
194
|
+
const option = getOption(key, isSpecial);
|
|
195
|
+
if (option) {
|
|
196
|
+
if (value === undefined)
|
|
197
|
+
setOption(key, option, option.$kind === "boolean" ? undefined : argv[++i]);
|
|
198
|
+
else
|
|
199
|
+
setOption(key, option, value);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else if (arg.startsWith("-")) {
|
|
203
|
+
// -abc or -k[=value] or -k [value]
|
|
204
|
+
const [shortKeys, value] = arg.slice(1).split("=");
|
|
205
|
+
const chars = shortKeys.split("");
|
|
206
|
+
let usedValue = value;
|
|
207
|
+
for (const char of chars) {
|
|
208
|
+
let isSpecial = false;
|
|
209
|
+
if (char === "h") {
|
|
210
|
+
isHelp = true;
|
|
211
|
+
isSpecial = true;
|
|
212
|
+
}
|
|
213
|
+
else if (char === "V") {
|
|
214
|
+
isVersion = true;
|
|
215
|
+
isSpecial = true;
|
|
216
|
+
}
|
|
217
|
+
const option = getOption(char, isSpecial);
|
|
218
|
+
if (!option)
|
|
219
|
+
continue;
|
|
220
|
+
if (option.$kind !== "boolean" && usedValue === undefined) {
|
|
221
|
+
usedValue = argv[++i];
|
|
222
|
+
}
|
|
223
|
+
setOption(char, option, usedValue);
|
|
224
|
+
usedValue = undefined; // only first consumes
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
// positional
|
|
229
|
+
if (command.$children.has(arg) && !found) {
|
|
230
|
+
command = command.$children.get(arg).command;
|
|
231
|
+
if (command.$theme) {
|
|
232
|
+
setPromptTheme(command.$theme);
|
|
233
|
+
setLogTheme(command.$theme);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
found = true;
|
|
238
|
+
args.push(arg);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// Apply user values, defaults, or enforce required
|
|
243
|
+
let index = 0;
|
|
244
|
+
for (const key in command.$input) {
|
|
245
|
+
const entry = command.$input[key];
|
|
246
|
+
let rawValue;
|
|
247
|
+
if (entry instanceof Positional) {
|
|
248
|
+
if (entry.$list) {
|
|
249
|
+
rawValue = args.slice(index);
|
|
250
|
+
index = args.length;
|
|
251
|
+
if (!command.$allowSurpassArgLimit &&
|
|
252
|
+
rawValue.length === 0 &&
|
|
253
|
+
entry.$required) {
|
|
254
|
+
errors.push(new MissingRequiredArgumentError(command, key, entry));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
rawValue = args[index++];
|
|
259
|
+
if (rawValue === undefined && entry.$required) {
|
|
260
|
+
errors.push(new MissingRequiredArgumentError(command, key, entry));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
for (const name of entry.$names) {
|
|
266
|
+
if (opts[name] !== undefined) {
|
|
267
|
+
rawValue = entry.$list
|
|
268
|
+
? opts[name].split(entry.$separator ?? ",")
|
|
269
|
+
: opts[name];
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (rawValue !== undefined) {
|
|
275
|
+
input[key] = await convert(entry.$kind, rawValue);
|
|
276
|
+
}
|
|
277
|
+
else if (entry.$default !== undefined) {
|
|
278
|
+
input[key] = entry.$default;
|
|
279
|
+
}
|
|
280
|
+
else if (entry.$required) {
|
|
281
|
+
if (entry instanceof Option) {
|
|
282
|
+
errors.push(new MissingRequiredOptionError(command, key, entry));
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
errors.push(new MissingRequiredArgumentError(command, key, entry));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Check for too many arguments
|
|
290
|
+
const remainingArgs = args.slice(index);
|
|
291
|
+
if (!command.$allowSurpassArgLimit && remainingArgs.length > 0) {
|
|
292
|
+
errors.push(new TooManyArgumentsError(command));
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
input: input,
|
|
296
|
+
command,
|
|
297
|
+
errors,
|
|
298
|
+
isVersion,
|
|
299
|
+
isHelp,
|
|
300
|
+
};
|
|
345
301
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
302
|
+
buildInputMap(ignoreParentMap) {
|
|
303
|
+
const map = new Map();
|
|
304
|
+
let i = 0;
|
|
305
|
+
for (const key in this.$input) {
|
|
306
|
+
const value = this.$input[key];
|
|
307
|
+
if (value instanceof Positional) {
|
|
308
|
+
map.set(i++, { value, key });
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
for (const name of value.$names) {
|
|
312
|
+
map.set(name, { value, key });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (!ignoreParentMap) {
|
|
317
|
+
for (const [key, entry] of this.$parent?.buildInputMap() ?? []) {
|
|
318
|
+
map.set(key, entry);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
for (const [, { command }] of this.$children) {
|
|
322
|
+
for (const [key, entry] of command.buildInputMap(true)) {
|
|
323
|
+
map.set(key, entry);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return map;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Allows surpassing the amount of arguments specified.
|
|
330
|
+
* @returns this
|
|
331
|
+
*/
|
|
332
|
+
allowSurpassArgLimit() {
|
|
333
|
+
this.$allowSurpassArgLimit = true;
|
|
334
|
+
return this;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Gets the full command path (name including parents).
|
|
338
|
+
* @returns The full command path.
|
|
339
|
+
*/
|
|
340
|
+
fullCommandPath() {
|
|
341
|
+
const names = [];
|
|
342
|
+
// eslint-disable-next-line -- necessary for traversing up the tree
|
|
343
|
+
let cmd = this;
|
|
344
|
+
while (cmd) {
|
|
345
|
+
names.unshift(cmd.$names[0]);
|
|
346
|
+
cmd = cmd.$parent;
|
|
347
|
+
}
|
|
348
|
+
return names.join(" ");
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* The default error screen.
|
|
352
|
+
* @param errors The errors.
|
|
353
|
+
*/
|
|
354
|
+
defaultErrorScreen(errors) {
|
|
355
|
+
let printHelpScreen = false;
|
|
356
|
+
const nonCliErrors = [];
|
|
357
|
+
for (const error of errors) {
|
|
358
|
+
if (error instanceof ConvokerError) {
|
|
359
|
+
if (!(error instanceof HelpAskedError))
|
|
360
|
+
error.print();
|
|
361
|
+
printHelpScreen = true;
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
nonCliErrors.push(error);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (nonCliErrors.length)
|
|
368
|
+
throw nonCliErrors[0];
|
|
369
|
+
if (!printHelpScreen)
|
|
370
|
+
return;
|
|
371
|
+
const pad = (s, len) => s.padEnd(len, " ");
|
|
372
|
+
console.log(`${bold("usage:")} ${cyan(this.fullCommandPath())} ${gray("[options] [arguments]")}`);
|
|
373
|
+
if (this.$description) {
|
|
374
|
+
console.log(`${this.$description}`);
|
|
375
|
+
}
|
|
376
|
+
if (this.$version) {
|
|
377
|
+
console.log(`${bold("version")} ${this.$version}`);
|
|
378
|
+
}
|
|
379
|
+
// OPTIONS
|
|
380
|
+
const opts = Object.entries(this.$input)
|
|
381
|
+
.filter(([, entry]) => entry instanceof Option)
|
|
382
|
+
.map(([key, entry]) => ({ key, entry: entry }));
|
|
383
|
+
if (opts.length > 0) {
|
|
384
|
+
console.log(bold("options:"));
|
|
385
|
+
const longest = Math.max(...opts.map(({ entry }) => entry.$names.join(", ").length));
|
|
386
|
+
for (const { entry } of opts) {
|
|
387
|
+
const names = entry.$names
|
|
388
|
+
.map((n) => (n.length === 1 ? `-${n}` : `--${n}`))
|
|
389
|
+
.join(", ");
|
|
390
|
+
const line = ` ${cyan(pad(names, longest + 4))}${gray(entry.$description ?? "")}`;
|
|
391
|
+
console.log(line);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// POSITIONALS
|
|
395
|
+
const positionals = Object.entries(this.$input)
|
|
396
|
+
.filter(([, entry]) => entry instanceof Positional)
|
|
397
|
+
.map(([key, entry]) => ({
|
|
398
|
+
key,
|
|
399
|
+
entry: entry,
|
|
400
|
+
}));
|
|
401
|
+
if (positionals.length > 0) {
|
|
402
|
+
console.log(bold("arguments:"));
|
|
403
|
+
const longest = Math.max(...positionals.map(({ key }) => key.length));
|
|
404
|
+
for (const { key, entry } of positionals) {
|
|
405
|
+
const name = entry.$required ? `<${key}>` : `[${key}]`;
|
|
406
|
+
const line = ` ${cyan(pad(name, longest + 4))}${gray(entry.$description ?? "")}`;
|
|
407
|
+
console.log(line);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// SUBCOMMANDS
|
|
411
|
+
if (this.$children.size > 0) {
|
|
412
|
+
console.log(bold("sub commands:"));
|
|
413
|
+
const deduped = Array.from(new Map([...this.$children.values()].map((a) => [
|
|
414
|
+
a.command.$names[0],
|
|
415
|
+
a.command,
|
|
416
|
+
])).values());
|
|
417
|
+
const longest = Math.max(...deduped.map((c) => c.$names[0].length));
|
|
418
|
+
for (const cmd of deduped) {
|
|
419
|
+
const line = ` ${cyan(pad(cmd.$names[0], longest + 4))}${gray(cmd.$description) ?? ""}`;
|
|
420
|
+
console.log(line);
|
|
421
|
+
}
|
|
422
|
+
console.log();
|
|
423
|
+
console.log(`run '${cyan(`${this.fullCommandPath()} <command> --help`)}' for more info on a command.`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Handles a set of errors.
|
|
428
|
+
* @param errors The errors to handle.
|
|
429
|
+
* @param input The parsed input, if possible.
|
|
430
|
+
* @returns this
|
|
431
|
+
*/
|
|
432
|
+
async handleErrors(errors, input) {
|
|
433
|
+
// eslint-disable-next-line -- necessary for traversing up the tree
|
|
434
|
+
let command = this;
|
|
435
|
+
while (!command.$errorFn && command.$parent) {
|
|
436
|
+
command = command.$parent;
|
|
437
|
+
}
|
|
438
|
+
if (command.$errorFn) {
|
|
439
|
+
await command.$errorFn(command, errors, input ?? {});
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
this.defaultErrorScreen(errors);
|
|
443
|
+
}
|
|
444
|
+
return this;
|
|
357
445
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
446
|
+
/**
|
|
447
|
+
* Runs a command.
|
|
448
|
+
* @param argv The arguments to run the command with. Defaults to your runtime's `argv` equivalent.
|
|
449
|
+
* @returns this
|
|
450
|
+
*/
|
|
451
|
+
async run(argv) {
|
|
452
|
+
if (!argv) {
|
|
453
|
+
argv =
|
|
454
|
+
typeof Bun !== "undefined"
|
|
455
|
+
? Bun.argv.slice(2)
|
|
456
|
+
: typeof Deno !== "undefined"
|
|
457
|
+
? Deno.args
|
|
458
|
+
: process.argv.slice(2);
|
|
459
|
+
}
|
|
460
|
+
const result = await this.parse(argv);
|
|
461
|
+
if (result.isHelp) {
|
|
462
|
+
result.command.handleErrors([new HelpAskedError(result.command)]);
|
|
463
|
+
return this;
|
|
464
|
+
}
|
|
465
|
+
else if (result.isVersion) {
|
|
466
|
+
console.log(`${result.command.fullCommandPath()} version ${result.command.$version}`);
|
|
467
|
+
return this;
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
if (result.errors.length > 0) {
|
|
471
|
+
await result.command.handleErrors(result.errors, result.input);
|
|
472
|
+
}
|
|
473
|
+
else if (!result.command.$fn) {
|
|
474
|
+
await result.command.handleErrors([new HelpAskedError(result.command), ...result.errors], result.input);
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
const middlewares = collectMiddlewares(result.command);
|
|
478
|
+
if (middlewares.length > 0) {
|
|
479
|
+
const runner = compose(middlewares);
|
|
480
|
+
// finalNext calls the command action with the same input
|
|
481
|
+
await runner(result.input, async () => {
|
|
482
|
+
await result.command.$fn?.(result.input);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
await result.command.$fn(result.input);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
catch (e) {
|
|
491
|
+
if (!(e instanceof Error)) {
|
|
492
|
+
console.warn("[convoker] an error that is not instance of `Error` was thrown. this may cause undefined behavior.");
|
|
493
|
+
}
|
|
494
|
+
await result.command.handleErrors([e]);
|
|
495
|
+
}
|
|
496
|
+
return this;
|
|
375
497
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
for (; !r.$errorFn && r.$parent; )
|
|
386
|
-
r = r.$parent;
|
|
387
|
-
return r.$errorFn ? await r.$errorFn(r, e, t ?? {}) : this.defaultErrorScreen(e), this;
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Runs a command.
|
|
391
|
-
* @param argv The arguments to run the command with. Defaults to your runtime's `argv` equivalent.
|
|
392
|
-
* @returns this
|
|
393
|
-
*/
|
|
394
|
-
async run(e) {
|
|
395
|
-
e || (e = typeof Bun < "u" ? Bun.argv.slice(2) : typeof Deno < "u" ? Deno.args : process.argv.slice(2));
|
|
396
|
-
const t = await this.parse(e);
|
|
397
|
-
if (t.isHelp)
|
|
398
|
-
return t.command.handleErrors([new P(t.command)]), this;
|
|
399
|
-
if (t.isVersion)
|
|
400
|
-
return console.log(
|
|
401
|
-
`${t.command.fullCommandPath()} version ${t.command.$version}`
|
|
402
|
-
), this;
|
|
403
|
-
try {
|
|
404
|
-
t.errors.length > 0 ? await t.command.handleErrors(t.errors, t.input) : t.command.$fn ? await t.command.$fn(t.input) : await t.command.handleErrors(
|
|
405
|
-
[new P(t.command), ...t.errors],
|
|
406
|
-
t.input
|
|
407
|
-
);
|
|
408
|
-
} catch (r) {
|
|
409
|
-
r instanceof Error || console.warn(
|
|
410
|
-
"[convoker] an error that is not instance of `Error` was thrown. this may cause undefined behavior."
|
|
411
|
-
), await t.command.handleErrors([r]);
|
|
498
|
+
}
|
|
499
|
+
function collectMiddlewares(cmd) {
|
|
500
|
+
const middlewares = [];
|
|
501
|
+
let current = cmd;
|
|
502
|
+
while (current) {
|
|
503
|
+
if (current.$middlewares.length) {
|
|
504
|
+
middlewares.unshift(...current.$middlewares);
|
|
505
|
+
}
|
|
506
|
+
current = current.$parent;
|
|
412
507
|
}
|
|
413
|
-
return
|
|
414
|
-
|
|
508
|
+
return middlewares;
|
|
509
|
+
}
|
|
510
|
+
function compose(mws) {
|
|
511
|
+
return (input, finalNext) => {
|
|
512
|
+
let index = -1;
|
|
513
|
+
const dispatch = (i) => {
|
|
514
|
+
if (i <= index)
|
|
515
|
+
return Promise.reject(new Error("next() called multiple times"));
|
|
516
|
+
index = i;
|
|
517
|
+
const fn = mws[i];
|
|
518
|
+
if (!fn) {
|
|
519
|
+
// when middlewares exhausted call finalNext if provided
|
|
520
|
+
return finalNext ? finalNext() : Promise.resolve();
|
|
521
|
+
}
|
|
522
|
+
try {
|
|
523
|
+
return Promise.resolve(fn(input, () => dispatch(i + 1)));
|
|
524
|
+
}
|
|
525
|
+
catch (err) {
|
|
526
|
+
return Promise.reject(err);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
return dispatch(0);
|
|
530
|
+
};
|
|
415
531
|
}
|
|
416
|
-
export {
|
|
417
|
-
F as Command,
|
|
418
|
-
ct as l
|
|
419
|
-
};
|