cli-kiss 0.2.6 → 0.2.8
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/README.md +62 -4
- package/dist/index.d.ts +135 -128
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/.vitepress/config.mts +1 -1
- package/docs/.vitepress/theme/Layout.vue +16 -0
- package/docs/.vitepress/theme/index.ts +5 -1
- package/docs/.vitepress/theme/style.css +5 -1
- package/docs/guide/02_commands.md +1 -1
- package/docs/guide/03_options.md +11 -11
- package/docs/guide/05_input_types.md +9 -10
- package/docs/guide/06_run_as_cli.md +1 -1
- package/docs/index.md +2 -2
- package/docs/public/favicon.ico +0 -0
- package/docs/public/logo.png +0 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/lib/Command.ts +50 -30
- package/src/lib/Operation.ts +29 -21
- package/src/lib/Option.ts +198 -133
- package/src/lib/Positional.ts +46 -24
- package/src/lib/Reader.ts +194 -207
- package/src/lib/Run.ts +19 -8
- package/src/lib/Suggest.ts +78 -0
- package/src/lib/Type.ts +46 -48
- package/src/lib/Typo.ts +72 -47
- package/src/lib/Usage.ts +13 -13
- package/tests/unit.Reader.commons.ts +92 -116
- package/tests/unit.Reader.parsings.ts +14 -26
- package/tests/unit.Reader.shortBig.ts +81 -96
- package/tests/unit.command.aliases.ts +100 -0
- package/tests/unit.command.execute.ts +1 -1
- package/tests/unit.command.usage.ts +12 -6
- package/tests/unit.fuzzed.alternatives.ts +43 -0
- package/tests/unit.runner.colors.ts +11 -35
- package/tests/unit.runner.cycle.ts +181 -128
- package/tests/unit.runner.errors.ts +26 -19
- package/docs/public/hero.png +0 -0
- package/tests/unit.Reader.aliases.ts +0 -62
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { it } from "@jest/globals";
|
|
1
|
+
import { expect, it } from "@jest/globals";
|
|
2
2
|
import {
|
|
3
3
|
command,
|
|
4
4
|
commandWithSubcommands,
|
|
@@ -18,110 +18,102 @@ import {
|
|
|
18
18
|
|
|
19
19
|
it("run", async function () {
|
|
20
20
|
const rootUsage = [
|
|
21
|
-
"Usage: my-cli <
|
|
21
|
+
"Usage: my-cli <req1> <subcommand>",
|
|
22
22
|
"",
|
|
23
23
|
"Root Description",
|
|
24
24
|
"",
|
|
25
25
|
"Positionals:",
|
|
26
|
-
" <
|
|
26
|
+
" <req1> Required1 positional description",
|
|
27
27
|
"",
|
|
28
28
|
"Subcommands:",
|
|
29
|
-
"
|
|
29
|
+
" sub Subcommand Description",
|
|
30
30
|
"",
|
|
31
31
|
"Options:",
|
|
32
|
-
" --flag[=no] Option flag description",
|
|
33
|
-
" --repeatable <string> [*] Option repeatable description",
|
|
34
|
-
" --single-value <enum(number)> Option single value description",
|
|
32
|
+
" -ff, --flag[=no] Option flag description",
|
|
33
|
+
" -r, --repeatable <string> [*] Option repeatable description",
|
|
34
|
+
" -s, --single-value <enum(number)> Option single value description",
|
|
35
35
|
"",
|
|
36
36
|
].join("\n");
|
|
37
|
-
const
|
|
38
|
-
"Usage: my-cli <
|
|
37
|
+
const subUsage = [
|
|
38
|
+
"Usage: my-cli <req1> sub <req2> [optional] [variadic]...",
|
|
39
39
|
"",
|
|
40
40
|
"Subcommand Description",
|
|
41
41
|
"",
|
|
42
42
|
"Positionals:",
|
|
43
|
-
" <
|
|
44
|
-
" <
|
|
43
|
+
" <req1> Required1 positional description",
|
|
44
|
+
" <req2> Required2 positional description",
|
|
45
45
|
" [optional] Optional positional description",
|
|
46
46
|
" [variadic]... Variadics positional description",
|
|
47
47
|
"",
|
|
48
48
|
"Options:",
|
|
49
|
-
" --flag[=no] Option flag description",
|
|
50
|
-
" --repeatable <string> [*] Option repeatable description",
|
|
51
|
-
" --single-value <enum(number)> Option single value description",
|
|
52
|
-
" --url <url> [*] Option url description",
|
|
49
|
+
" -ff, --flag[=no] Option flag description",
|
|
50
|
+
" -r, --repeatable <string> [*] Option repeatable description",
|
|
51
|
+
" -s, --single-value <enum(number)> Option single value description",
|
|
52
|
+
" -u, --url <url> [*] Option url description",
|
|
53
53
|
"",
|
|
54
54
|
].join("\n");
|
|
55
55
|
|
|
56
56
|
// Test that everything could work normally
|
|
57
57
|
await testCase(
|
|
58
|
-
["
|
|
59
|
-
["Has executed root command", "Has executed
|
|
58
|
+
["req1", "sub", "req2"],
|
|
59
|
+
["Has executed root command", "Has executed sub"],
|
|
60
60
|
[],
|
|
61
61
|
0,
|
|
62
62
|
);
|
|
63
63
|
|
|
64
64
|
// Check that version flag takes precedence over execution
|
|
65
65
|
await testCase(["--version"], ["my-cli 1.0.0"], [], 0);
|
|
66
|
-
await testCase(["
|
|
67
|
-
await testCase(
|
|
68
|
-
|
|
69
|
-
["my-cli 1.0.0"],
|
|
70
|
-
[],
|
|
71
|
-
0,
|
|
72
|
-
);
|
|
73
|
-
await testCase(
|
|
74
|
-
["required1", "subcommand", "required2", "--version"],
|
|
75
|
-
["my-cli 1.0.0"],
|
|
76
|
-
[],
|
|
77
|
-
0,
|
|
78
|
-
);
|
|
66
|
+
await testCase(["req1", "--version"], ["my-cli 1.0.0"], [], 0);
|
|
67
|
+
await testCase(["req1", "sub", "--version"], ["my-cli 1.0.0"], [], 0);
|
|
68
|
+
await testCase(["req1", "sub", "req2", "--version"], ["my-cli 1.0.0"], [], 0);
|
|
79
69
|
|
|
80
70
|
// Check that help flag takes precedence over execution
|
|
81
71
|
await testCase(["--help"], [rootUsage], [], 0);
|
|
82
|
-
await testCase(["
|
|
83
|
-
await testCase(
|
|
84
|
-
|
|
85
|
-
[subcommandUsage],
|
|
86
|
-
[],
|
|
87
|
-
0,
|
|
88
|
-
);
|
|
89
|
-
await testCase(
|
|
90
|
-
["required1", "subcommand", "required2", "--help"],
|
|
91
|
-
[subcommandUsage],
|
|
92
|
-
[],
|
|
93
|
-
0,
|
|
94
|
-
);
|
|
72
|
+
await testCase(["req1", "--help"], [rootUsage], [], 0);
|
|
73
|
+
await testCase(["req1", "sub", "--help"], [subUsage], [], 0);
|
|
74
|
+
await testCase(["req1", "sub", "req2", "--help"], [subUsage], [], 0);
|
|
95
75
|
|
|
96
76
|
// Help takes precedence over version
|
|
97
77
|
await testCase(["--version", "--help"], [rootUsage], [], 0);
|
|
98
78
|
await testCase(["--help", "--version"], [rootUsage], [], 0);
|
|
99
79
|
|
|
80
|
+
// Help still works after failed parsing (should show usage for the right command)
|
|
81
|
+
await testCase(["--invalid", "--help"], [rootUsage], [], 0);
|
|
82
|
+
await testCase(["invalid", "--help"], [rootUsage], [], 0);
|
|
83
|
+
await testCase(["req1", "sub", "--invalid", "--help"], [subUsage], [], 0);
|
|
84
|
+
await testCase(["req1", "sub", "invalid", "--help"], [subUsage], [], 0);
|
|
85
|
+
|
|
100
86
|
// Weird help/version values inputs
|
|
101
87
|
await testCase(
|
|
102
88
|
["--help=invalid"],
|
|
103
89
|
[],
|
|
104
|
-
[rootUsage, `Error: --help: value: Not a boolean: "invalid"
|
|
90
|
+
[rootUsage, `Error: --help: value: Not a boolean: "invalid".`],
|
|
105
91
|
1,
|
|
106
92
|
);
|
|
107
93
|
await testCase(
|
|
108
94
|
["--version=invalid"],
|
|
109
95
|
[],
|
|
110
|
-
[rootUsage, `Error: --version: value: Not a boolean: "invalid"
|
|
96
|
+
[rootUsage, `Error: --version: value: Not a boolean: "invalid".`],
|
|
111
97
|
1,
|
|
112
98
|
);
|
|
113
99
|
|
|
114
100
|
// Test multiple errors at once (first one should show only)
|
|
115
101
|
await testCase(
|
|
116
|
-
["--invalid1", "--invalid2", "
|
|
102
|
+
["--invalid1", "--invalid2", "req1", "--invalid3"],
|
|
117
103
|
[],
|
|
118
|
-
[
|
|
104
|
+
[
|
|
105
|
+
rootUsage,
|
|
106
|
+
'Error: Unknown option: "--invalid1". Did you mean: --single-value, --help, --version, ... ?',
|
|
107
|
+
],
|
|
119
108
|
1,
|
|
120
109
|
);
|
|
121
110
|
await testCase(
|
|
122
|
-
["
|
|
111
|
+
["req1", "unknown", "-wut", "--flag", "--single-value"],
|
|
123
112
|
[],
|
|
124
|
-
[
|
|
113
|
+
[
|
|
114
|
+
rootUsage,
|
|
115
|
+
'Error: <subcommand>: Unknown name: "unknown". Did you mean: sub ?',
|
|
116
|
+
],
|
|
125
117
|
1,
|
|
126
118
|
);
|
|
127
119
|
|
|
@@ -129,109 +121,130 @@ it("run", async function () {
|
|
|
129
121
|
await testCase(
|
|
130
122
|
[],
|
|
131
123
|
[],
|
|
132
|
-
[
|
|
124
|
+
[
|
|
125
|
+
rootUsage,
|
|
126
|
+
"Error: <req1>: Is required, but was not provided. (Required1 positional description)",
|
|
127
|
+
],
|
|
133
128
|
1,
|
|
134
129
|
);
|
|
135
130
|
await testCase(
|
|
136
|
-
["
|
|
131
|
+
["req1"],
|
|
137
132
|
[],
|
|
138
|
-
[rootUsage, "Error: <subcommand>:
|
|
133
|
+
[rootUsage, "Error: <subcommand>: Missing argument. Did you mean: sub ?"],
|
|
139
134
|
1,
|
|
140
135
|
);
|
|
141
136
|
await testCase(
|
|
142
|
-
["
|
|
137
|
+
["req1", "sub"],
|
|
143
138
|
[],
|
|
144
|
-
[
|
|
139
|
+
[
|
|
140
|
+
subUsage,
|
|
141
|
+
"Error: <req2>: Is required, but was not provided. (Required2 positional description)",
|
|
142
|
+
],
|
|
145
143
|
1,
|
|
146
144
|
);
|
|
147
145
|
|
|
148
|
-
// Test that flags become available when
|
|
146
|
+
// Test that flags become available when sub is known
|
|
149
147
|
await testCase(
|
|
150
148
|
["--url", "https://example.com"],
|
|
151
149
|
[],
|
|
152
|
-
[
|
|
150
|
+
[
|
|
151
|
+
rootUsage,
|
|
152
|
+
'Error: Unknown option: "--url". Did you mean: --help, -r, --version, ... ?',
|
|
153
|
+
],
|
|
153
154
|
1,
|
|
154
155
|
);
|
|
155
156
|
await testCase(
|
|
156
|
-
["
|
|
157
|
+
["req1", "--url", "https://example.com"],
|
|
157
158
|
[],
|
|
158
|
-
[
|
|
159
|
+
[
|
|
160
|
+
rootUsage,
|
|
161
|
+
'Error: Unknown option: "--url". Did you mean: --help, -r, --version, ... ?',
|
|
162
|
+
],
|
|
159
163
|
1,
|
|
160
164
|
);
|
|
161
165
|
await testCase(
|
|
162
|
-
["
|
|
166
|
+
["req1", "sub", "--url", "https://example.com"],
|
|
163
167
|
[],
|
|
164
|
-
[
|
|
168
|
+
[
|
|
169
|
+
subUsage,
|
|
170
|
+
"Error: <req2>: Is required, but was not provided. (Required2 positional description)",
|
|
171
|
+
],
|
|
165
172
|
1,
|
|
166
173
|
);
|
|
167
174
|
await testCase(
|
|
168
|
-
["
|
|
169
|
-
["Has executed root command", "Has executed
|
|
175
|
+
["req1", "sub", "req2", "--url", "https://example.com"],
|
|
176
|
+
["Has executed root command", "Has executed sub"],
|
|
170
177
|
[],
|
|
171
178
|
0,
|
|
172
179
|
);
|
|
173
180
|
|
|
174
181
|
// Test option as flag parsing cases
|
|
175
182
|
await testCase(
|
|
176
|
-
["--flag", "--flag", "
|
|
183
|
+
["--flag", "--flag", "req1", "sub", "req2"],
|
|
177
184
|
[],
|
|
178
|
-
[
|
|
185
|
+
[subUsage, "Error: --flag: Must not be set multiple times."],
|
|
179
186
|
1,
|
|
180
187
|
);
|
|
181
188
|
await testCase(
|
|
182
|
-
["--flag=42", "
|
|
189
|
+
["--flag=42", "req1", "sub", "req2"],
|
|
183
190
|
[],
|
|
184
|
-
[
|
|
191
|
+
[subUsage, 'Error: --flag: value: Not a boolean: "42".'],
|
|
185
192
|
1,
|
|
186
193
|
);
|
|
187
194
|
await testCase(
|
|
188
|
-
["--flag=no", "
|
|
189
|
-
["Has executed root command", "Has executed
|
|
195
|
+
["--flag=no", "req1", "sub", "req2"],
|
|
196
|
+
["Has executed root command", "Has executed sub"],
|
|
190
197
|
[],
|
|
191
198
|
0,
|
|
192
199
|
);
|
|
193
200
|
await testCase(
|
|
194
|
-
["--flag=yes", "
|
|
195
|
-
["Has executed root command", "Has executed
|
|
201
|
+
["--flag=yes", "req1", "sub", "req2"],
|
|
202
|
+
["Has executed root command", "Has executed sub"],
|
|
196
203
|
[],
|
|
197
204
|
0,
|
|
198
205
|
);
|
|
199
206
|
await testCase(
|
|
200
|
-
["--flag", "
|
|
201
|
-
["Has executed root command", "Has executed
|
|
207
|
+
["--flag", "req1", "sub", "req2"],
|
|
208
|
+
["Has executed root command", "Has executed sub"],
|
|
202
209
|
[],
|
|
203
210
|
0,
|
|
204
211
|
);
|
|
205
212
|
|
|
206
213
|
// Test option parsing errors
|
|
207
214
|
await testCase(
|
|
208
|
-
["--invalid", "
|
|
215
|
+
["--invalid", "req1", "sub", "req2"],
|
|
209
216
|
[],
|
|
210
|
-
[
|
|
217
|
+
[
|
|
218
|
+
rootUsage,
|
|
219
|
+
'Error: Unknown option: "--invalid". Did you mean: --single-value, --help, --flag, ... ?',
|
|
220
|
+
],
|
|
211
221
|
1,
|
|
212
222
|
);
|
|
213
223
|
await testCase(
|
|
214
|
-
["
|
|
224
|
+
["req1", "sub", "req2", "--nope"],
|
|
215
225
|
[],
|
|
216
|
-
[
|
|
226
|
+
[
|
|
227
|
+
subUsage,
|
|
228
|
+
'Error: Unknown option: "--nope". Did you mean: --help, --flag, --repeatable, ... ?',
|
|
229
|
+
],
|
|
217
230
|
1,
|
|
218
231
|
);
|
|
219
232
|
await testCase(
|
|
220
|
-
["
|
|
233
|
+
["req1", "sub", "req2", "--url"],
|
|
221
234
|
[],
|
|
222
|
-
[
|
|
235
|
+
[subUsage, "Error: --url: Requires a value, but got end of input."],
|
|
223
236
|
1,
|
|
224
237
|
);
|
|
225
238
|
await testCase(
|
|
226
|
-
["
|
|
239
|
+
["req1", "sub", "req2", "--url", "--", "url"],
|
|
227
240
|
[],
|
|
228
|
-
[
|
|
241
|
+
[subUsage, 'Error: --url: Requires a value but got: "--".'],
|
|
229
242
|
1,
|
|
230
243
|
);
|
|
231
244
|
await testCase(
|
|
232
|
-
["
|
|
245
|
+
["req1", "sub", "req2", "--url", "--url"],
|
|
233
246
|
[],
|
|
234
|
-
[
|
|
247
|
+
[subUsage, 'Error: --url: Requires a value, but got: "--url".'],
|
|
235
248
|
1,
|
|
236
249
|
);
|
|
237
250
|
|
|
@@ -239,105 +252,141 @@ it("run", async function () {
|
|
|
239
252
|
await testCase(
|
|
240
253
|
["invalid"],
|
|
241
254
|
[],
|
|
242
|
-
[rootUsage, "Error: <subcommand>:
|
|
255
|
+
[rootUsage, "Error: <subcommand>: Missing argument. Did you mean: sub ?"],
|
|
243
256
|
1,
|
|
244
257
|
);
|
|
245
258
|
await testCase(
|
|
246
|
-
["invalid", "
|
|
259
|
+
["invalid", "sub"],
|
|
247
260
|
[],
|
|
248
261
|
[
|
|
249
|
-
|
|
250
|
-
'Error: <
|
|
262
|
+
subUsage,
|
|
263
|
+
'Error: <req1>: Unknown value: "invalid". Did you mean: "req1-bis", "req1" ?',
|
|
251
264
|
],
|
|
252
265
|
1,
|
|
253
266
|
);
|
|
254
267
|
await testCase(
|
|
255
|
-
["invalid", "
|
|
268
|
+
["invalid", "sub", "req2"],
|
|
256
269
|
[],
|
|
257
270
|
[
|
|
258
|
-
|
|
259
|
-
'Error: <
|
|
271
|
+
subUsage,
|
|
272
|
+
'Error: <req1>: Unknown value: "invalid". Did you mean: "req1-bis", "req1" ?',
|
|
260
273
|
],
|
|
261
274
|
1,
|
|
262
275
|
);
|
|
263
276
|
await testCase(
|
|
264
|
-
["
|
|
277
|
+
["req1", "sub", "invalid"],
|
|
265
278
|
[],
|
|
266
279
|
[
|
|
267
|
-
|
|
268
|
-
'Error: <
|
|
280
|
+
subUsage,
|
|
281
|
+
'Error: <req2>: Unknown value: "invalid". Did you mean: "req2-bis", "req2" ?',
|
|
269
282
|
],
|
|
270
283
|
1,
|
|
271
284
|
);
|
|
272
285
|
await testCase(
|
|
273
|
-
["invalid", "
|
|
286
|
+
["invalid", "sub", "invalid"],
|
|
274
287
|
[],
|
|
275
288
|
[
|
|
276
|
-
|
|
277
|
-
'Error: <
|
|
289
|
+
subUsage,
|
|
290
|
+
'Error: <req1>: Unknown value: "invalid". Did you mean: "req1-bis", "req1" ?',
|
|
278
291
|
],
|
|
279
292
|
1,
|
|
280
293
|
);
|
|
281
294
|
|
|
282
295
|
// Test root command option invalid values (must not block parsing)
|
|
283
296
|
await testCase(
|
|
284
|
-
["--single-value=dodo", "
|
|
297
|
+
["--single-value=dodo", "req1", "sub", "req2"],
|
|
285
298
|
[],
|
|
286
299
|
[
|
|
287
|
-
|
|
288
|
-
'Error: --single-value: <enum(number)>: from: enum(string):
|
|
300
|
+
subUsage,
|
|
301
|
+
'Error: --single-value: <enum(number)>: from: enum(string): Unknown value: "dodo". Did you mean: "42", "43" ?',
|
|
289
302
|
],
|
|
290
303
|
1,
|
|
291
304
|
);
|
|
292
305
|
await testCase(
|
|
293
|
-
["
|
|
306
|
+
["req1", "sub", "req2", "--single-value=44"],
|
|
294
307
|
[],
|
|
295
308
|
[
|
|
296
|
-
|
|
297
|
-
'Error: --single-value: <enum(number)>: from: enum(string):
|
|
309
|
+
subUsage,
|
|
310
|
+
'Error: --single-value: <enum(number)>: from: enum(string): Unknown value: "44". Did you mean: "42", "43" ?',
|
|
298
311
|
],
|
|
299
312
|
1,
|
|
300
313
|
);
|
|
301
314
|
|
|
302
|
-
// Test
|
|
315
|
+
// Test sub-only option failures
|
|
303
316
|
await testCase(
|
|
304
|
-
["--url", "not-a-url", "
|
|
317
|
+
["--url", "not-a-url", "req1", "sub", "req2"],
|
|
305
318
|
[],
|
|
306
|
-
[
|
|
319
|
+
[
|
|
320
|
+
rootUsage,
|
|
321
|
+
'Error: Unknown option: "--url". Did you mean: --help, -r, --version, ... ?',
|
|
322
|
+
],
|
|
307
323
|
1,
|
|
308
324
|
);
|
|
309
325
|
await testCase(
|
|
310
|
-
["
|
|
326
|
+
["req1", "sub", "req2", "--url", "not-a-url"],
|
|
311
327
|
[],
|
|
312
|
-
[
|
|
328
|
+
[subUsage, 'Error: --url: <url>: Not an URL: "not-a-url".'],
|
|
313
329
|
1,
|
|
314
330
|
);
|
|
315
331
|
|
|
316
332
|
// Test option multiple value parsing cases
|
|
317
333
|
await testCase(
|
|
318
|
-
[
|
|
319
|
-
|
|
320
|
-
"subcommand",
|
|
321
|
-
"required2",
|
|
322
|
-
"--repeatable=42",
|
|
323
|
-
"--repeatable",
|
|
324
|
-
"43",
|
|
325
|
-
],
|
|
326
|
-
["Has executed root command", "Has executed subcommand"],
|
|
334
|
+
["req1", "sub", "req2", "--repeatable=42", "--repeatable", "43"],
|
|
335
|
+
["Has executed root command", "Has executed sub"],
|
|
327
336
|
[],
|
|
328
337
|
0,
|
|
329
338
|
);
|
|
330
339
|
await testCase(
|
|
340
|
+
["req1", "sub", "req2", "--single-value=42", "--single-value", "43"],
|
|
341
|
+
[],
|
|
342
|
+
[subUsage, "Error: --single-value: Must not be set multiple times."],
|
|
343
|
+
1,
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
// Test suggestions
|
|
347
|
+
await testCase(
|
|
348
|
+
["req1", "sub", "req2", "-f"],
|
|
349
|
+
[],
|
|
350
|
+
[subUsage, 'Error: Unknown option: "-f". Did you mean: -ff, -r, -s, ... ?'],
|
|
351
|
+
1,
|
|
352
|
+
);
|
|
353
|
+
await testCase(
|
|
354
|
+
["req1", "sub", "req2", "-flag"],
|
|
355
|
+
[],
|
|
356
|
+
[subUsage, 'Error: Unknown option: "-flag". Did you mean: --flag ?'],
|
|
357
|
+
1,
|
|
358
|
+
);
|
|
359
|
+
await testCase(
|
|
360
|
+
["req1", "sub", "req2", "--uri"],
|
|
361
|
+
[],
|
|
362
|
+
[subUsage, 'Error: Unknown option: "--uri". Did you mean: --url ?'],
|
|
363
|
+
1,
|
|
364
|
+
);
|
|
365
|
+
await testCase(
|
|
366
|
+
["req1", "sub", "req2", "--single-"],
|
|
367
|
+
[],
|
|
331
368
|
[
|
|
332
|
-
|
|
333
|
-
"
|
|
334
|
-
"required2",
|
|
335
|
-
"--single-value=42",
|
|
336
|
-
"--single-value",
|
|
337
|
-
"43",
|
|
369
|
+
subUsage,
|
|
370
|
+
'Error: Unknown option: "--single-". Did you mean: --single-value ?',
|
|
338
371
|
],
|
|
372
|
+
1,
|
|
373
|
+
);
|
|
374
|
+
await testCase(
|
|
375
|
+
["1req", "sub", "req2"],
|
|
339
376
|
[],
|
|
340
|
-
[
|
|
377
|
+
[
|
|
378
|
+
subUsage,
|
|
379
|
+
'Error: <req1>: Unknown value: "1req". Did you mean: "req1", "req1-bis" ?',
|
|
380
|
+
],
|
|
381
|
+
1,
|
|
382
|
+
);
|
|
383
|
+
await testCase(
|
|
384
|
+
["req1", "subcomm"],
|
|
385
|
+
[],
|
|
386
|
+
[
|
|
387
|
+
rootUsage,
|
|
388
|
+
'Error: <subcommand>: Unknown name: "subcomm". Did you mean: sub ?',
|
|
389
|
+
],
|
|
341
390
|
1,
|
|
342
391
|
);
|
|
343
392
|
});
|
|
@@ -364,27 +413,30 @@ async function testCase(
|
|
|
364
413
|
options: {
|
|
365
414
|
optionFlag: optionFlag({
|
|
366
415
|
long: "flag",
|
|
416
|
+
short: "ff",
|
|
367
417
|
description: "Option flag description",
|
|
368
418
|
}),
|
|
369
419
|
optionRepeatable: optionRepeatable({
|
|
370
420
|
long: "repeatable",
|
|
421
|
+
short: "r",
|
|
371
422
|
type: type(),
|
|
372
423
|
description: "Option repeatable description",
|
|
373
424
|
}),
|
|
374
425
|
optionSingleValue: optionSingleValue({
|
|
375
426
|
long: "single-value",
|
|
427
|
+
short: "s",
|
|
376
428
|
type: typeConverted(
|
|
377
429
|
"enum(number)",
|
|
378
430
|
typeChoice("enum(string)", ["42", "43"]),
|
|
379
431
|
(value) => Number(value),
|
|
380
432
|
),
|
|
381
433
|
description: "Option single value description",
|
|
382
|
-
|
|
434
|
+
fallbackValueIfAbsent: () => 42,
|
|
383
435
|
}),
|
|
384
436
|
},
|
|
385
437
|
positionals: [
|
|
386
438
|
positionalRequired({
|
|
387
|
-
type: typeChoice("
|
|
439
|
+
type: typeChoice("req1", ["req1", "req1-bis"]),
|
|
388
440
|
description: "Required1 positional description",
|
|
389
441
|
}),
|
|
390
442
|
],
|
|
@@ -394,20 +446,21 @@ async function testCase(
|
|
|
394
446
|
},
|
|
395
447
|
),
|
|
396
448
|
{
|
|
397
|
-
|
|
449
|
+
sub: command(
|
|
398
450
|
{ description: "Subcommand Description" },
|
|
399
451
|
operation(
|
|
400
452
|
{
|
|
401
453
|
options: {
|
|
402
454
|
optionExtra: optionRepeatable({
|
|
403
455
|
long: "url",
|
|
456
|
+
short: "u",
|
|
404
457
|
description: "Option url description",
|
|
405
|
-
type: typeUrl(
|
|
458
|
+
type: typeUrl(),
|
|
406
459
|
}),
|
|
407
460
|
},
|
|
408
461
|
positionals: [
|
|
409
462
|
positionalRequired({
|
|
410
|
-
type: typeChoice("
|
|
463
|
+
type: typeChoice("req2", ["req2", "req2-bis"]),
|
|
411
464
|
description: "Required2 positional description",
|
|
412
465
|
}),
|
|
413
466
|
positionalOptional({
|
|
@@ -422,7 +475,7 @@ async function testCase(
|
|
|
422
475
|
],
|
|
423
476
|
},
|
|
424
477
|
async function (_, _inputs) {
|
|
425
|
-
console.log(`Has executed
|
|
478
|
+
console.log(`Has executed sub`);
|
|
426
479
|
},
|
|
427
480
|
),
|
|
428
481
|
),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { it } from "@jest/globals";
|
|
1
|
+
import { expect, it } from "@jest/globals";
|
|
2
2
|
import {
|
|
3
3
|
command,
|
|
4
4
|
operation,
|
|
@@ -13,35 +13,43 @@ import {
|
|
|
13
13
|
it("run", async function () {
|
|
14
14
|
await testCase(
|
|
15
15
|
["hello"],
|
|
16
|
-
'{{Error:}@darkRed}+ Unexpected argument: {{"hello"}@darkYellow}
|
|
16
|
+
'{{Error:}@darkRed}+ Unexpected argument: {{"hello"}@darkYellow}+.', // TODO - should we recommend help here ?
|
|
17
17
|
);
|
|
18
18
|
await testCase(
|
|
19
19
|
["--nope"],
|
|
20
|
-
|
|
20
|
+
'{{Error:}@darkRed}+ Unknown option: {{"--nope"}@darkYellow}+. Did you mean: {{--help}@darkCyan}+, {{--flag}@darkCyan}+, {{--repeatable}@darkCyan}+, {{...}-}* ?',
|
|
21
21
|
);
|
|
22
22
|
await testCase(
|
|
23
|
-
["--
|
|
24
|
-
|
|
25
|
-
);
|
|
26
|
-
await testCase(
|
|
27
|
-
["--flag=invalid"],
|
|
28
|
-
'{{Error:}@darkRed}+ {{--flag}@darkCyan}+: {{value}@darkMagenta}+: Not a boolean: {{"invalid"}@darkYellow}+',
|
|
23
|
+
["--repeat"],
|
|
24
|
+
'{{Error:}@darkRed}+ Unknown option: {{"--repeat"}@darkYellow}+. Did you mean: {{--repeatable}@darkCyan}+ ?',
|
|
29
25
|
);
|
|
30
26
|
await testCase(
|
|
31
27
|
["--single-value=a", "--single-value=b"],
|
|
32
|
-
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Must not be set multiple times",
|
|
28
|
+
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Must not be set multiple times.",
|
|
33
29
|
);
|
|
34
30
|
await testCase(
|
|
35
31
|
["--single-value"],
|
|
36
|
-
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Requires a value, but got end of input",
|
|
32
|
+
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Requires a value, but got end of input.",
|
|
33
|
+
);
|
|
34
|
+
await testCase(
|
|
35
|
+
[],
|
|
36
|
+
"{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: {{<location>}@darkBlue}+: Is required, but was not set.",
|
|
37
37
|
);
|
|
38
38
|
await testCase(
|
|
39
39
|
["--single-value=invalid"],
|
|
40
|
-
'{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: {{<location>}@darkBlue}+: Not an URL: {{"invalid"}@darkYellow}
|
|
40
|
+
'{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: {{<location>}@darkBlue}+: Not an URL: {{"invalid"}@darkYellow}+.',
|
|
41
41
|
);
|
|
42
42
|
await testCase(
|
|
43
43
|
["--repeatable=invalid"],
|
|
44
|
-
'{{Error:}@darkRed}+ {{--repeatable}@darkCyan}+: {{<index>}@darkBlue}+: Not a number: {{"invalid"}@darkYellow}
|
|
44
|
+
'{{Error:}@darkRed}+ {{--repeatable}@darkCyan}+: {{<index>}@darkBlue}+: Not a number: {{"invalid"}@darkYellow}+.',
|
|
45
|
+
);
|
|
46
|
+
await testCase(
|
|
47
|
+
["--flag", "-f"],
|
|
48
|
+
"{{Error:}@darkRed}+ {{--flag}@darkCyan}+, {{-f}@darkCyan}+: Must not be set multiple times.",
|
|
49
|
+
);
|
|
50
|
+
await testCase(
|
|
51
|
+
["--flag=invalid"],
|
|
52
|
+
'{{Error:}@darkRed}+ {{--flag}@darkCyan}+: {{value}@darkMagenta}+: Not a boolean: {{"invalid"}@darkYellow}+.',
|
|
45
53
|
);
|
|
46
54
|
});
|
|
47
55
|
|
|
@@ -54,16 +62,15 @@ async function testCase(args: Array<string>, error: string) {
|
|
|
54
62
|
operation(
|
|
55
63
|
{
|
|
56
64
|
options: {
|
|
57
|
-
optionFlag: optionFlag({ long: "flag" }),
|
|
58
|
-
optionSingleValue: optionSingleValue({
|
|
59
|
-
long: "single-value",
|
|
60
|
-
type: typeUrl("location"),
|
|
61
|
-
defaultWhenNotDefined: () => undefined,
|
|
62
|
-
}),
|
|
65
|
+
optionFlag: optionFlag({ long: "flag", short: "f" }),
|
|
63
66
|
optionRepeatable: optionRepeatable({
|
|
64
67
|
long: "repeatable",
|
|
65
68
|
type: typeNumber("index"),
|
|
66
69
|
}),
|
|
70
|
+
optionSingleValue: optionSingleValue({
|
|
71
|
+
long: "single-value",
|
|
72
|
+
type: typeUrl("location"),
|
|
73
|
+
}),
|
|
67
74
|
},
|
|
68
75
|
positionals: [],
|
|
69
76
|
},
|
package/docs/public/hero.png
DELETED
|
Binary file
|