cli-kiss 0.2.3 → 0.2.4

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.
@@ -1,7 +1,7 @@
1
1
  import { expect, it } from "@jest/globals";
2
- import { ReaderArgs } from "../src";
2
+ import { ReaderArgs, ReaderOptionParsing } from "../src";
3
3
 
4
- it("run", async () => {
4
+ it("run", async function () {
5
5
  const stream = new ReaderArgs([
6
6
  "positional-0",
7
7
  "-aasof-normal",
@@ -12,47 +12,48 @@ it("run", async () => {
12
12
  "1.1",
13
13
  "-eesov-split",
14
14
  "1.2",
15
- "-ffsov-join=2",
15
+ "-ffsov-join=2.1",
16
+ "-ggsov-join=2.2",
16
17
  "positional-2",
17
18
  ]);
18
19
 
19
20
  expect(stream.consumePositional()).toStrictEqual("positional-0");
20
21
 
22
+ const kSofUnset = stream.registerOption({
23
+ longs: [],
24
+ shorts: ["sof-unset"],
25
+ parsing: optionFlagParsing,
26
+ });
21
27
  const kSofNormal = stream.registerOption({
22
28
  shorts: ["sof-normal"],
23
29
  longs: [],
24
- valued: false,
30
+ parsing: optionFlagParsing,
25
31
  });
26
32
  const kSofPositive = stream.registerOption({
27
33
  longs: [],
28
34
  shorts: ["sof-positive"],
29
- valued: false,
35
+ parsing: optionFlagParsing,
30
36
  });
31
37
  const kSofNegative = stream.registerOption({
32
38
  longs: [],
33
39
  shorts: ["sof-negative"],
34
- valued: false,
35
- });
36
- const kSofUnset = stream.registerOption({
37
- longs: [],
38
- shorts: ["sof-unset"],
39
- valued: false,
40
+ parsing: optionFlagParsing,
40
41
  });
41
42
 
42
43
  const kAa = stream.registerOption({
43
44
  longs: [],
44
45
  shorts: ["aa"],
45
- valued: false,
46
+ parsing: optionFlagParsing,
46
47
  });
47
48
  const kBb = stream.registerOption({
48
49
  longs: [],
49
50
  shorts: ["bb"],
50
- valued: false,
51
+ parsing: optionFlagParsing,
51
52
  });
52
53
  const kCc = stream.registerOption({
53
54
  longs: [],
54
55
  shorts: ["cc"],
55
- valued: false,
56
+ parsing: optionFlagParsing,
56
57
  });
57
58
 
58
59
  expect(stream.consumePositional()).toStrictEqual("positional-1");
@@ -60,51 +61,94 @@ it("run", async () => {
60
61
  const kSovSplit = stream.registerOption({
61
62
  longs: [],
62
63
  shorts: ["sov-split"],
63
- valued: true,
64
+ parsing: optionValueFixedUniqueParsing,
64
65
  });
65
66
  const kSovJoin = stream.registerOption({
66
67
  longs: [],
67
68
  shorts: ["sov-join"],
68
- valued: true,
69
+ parsing: optionValueFixedUniqueParsing,
69
70
  });
70
71
  const kSovUnset = stream.registerOption({
71
72
  longs: [],
72
73
  shorts: ["sov-unset"],
73
- valued: true,
74
+ parsing: optionValueFixedUniqueParsing,
74
75
  });
75
76
 
76
77
  const kDd = stream.registerOption({
77
78
  longs: [],
78
79
  shorts: ["dd"],
79
- valued: false,
80
+ parsing: optionFlagParsing,
80
81
  });
81
82
  const kEe = stream.registerOption({
82
83
  longs: [],
83
84
  shorts: ["ee"],
84
- valued: false,
85
+ parsing: optionFlagParsing,
85
86
  });
86
87
  const kFf = stream.registerOption({
87
88
  longs: [],
88
89
  shorts: ["ff"],
89
- valued: false,
90
+ parsing: optionFlagParsing,
91
+ });
92
+ const kGg = stream.registerOption({
93
+ longs: [],
94
+ shorts: ["gg"],
95
+ parsing: optionFlagParsing,
90
96
  });
91
97
 
92
98
  expect(stream.consumePositional()).toStrictEqual("positional-2");
93
99
 
94
- expect(stream.getOptionValues(kSofNormal)).toStrictEqual(["true"]);
95
- expect(stream.getOptionValues(kSofPositive)).toStrictEqual(["true"]);
96
- expect(stream.getOptionValues(kSofNegative)).toStrictEqual(["false"]);
97
100
  expect(stream.getOptionValues(kSofUnset)).toStrictEqual([]);
101
+ expect(stream.getOptionValues(kSofNormal)).toStrictEqual([
102
+ { inlined: null, separated: [] },
103
+ ]);
104
+ expect(stream.getOptionValues(kSofPositive)).toStrictEqual([
105
+ { inlined: "true", separated: [] },
106
+ ]);
107
+ expect(stream.getOptionValues(kSofNegative)).toStrictEqual([
108
+ { inlined: "false", separated: [] },
109
+ ]);
98
110
 
99
- expect(stream.getOptionValues(kAa)).toStrictEqual(["true"]);
100
- expect(stream.getOptionValues(kBb)).toStrictEqual(["true"]);
101
- expect(stream.getOptionValues(kCc)).toStrictEqual(["true"]);
111
+ expect(stream.getOptionValues(kAa)).toStrictEqual([
112
+ { inlined: null, separated: [] },
113
+ ]);
114
+ expect(stream.getOptionValues(kBb)).toStrictEqual([
115
+ { inlined: null, separated: [] },
116
+ ]);
117
+ expect(stream.getOptionValues(kCc)).toStrictEqual([
118
+ { inlined: null, separated: [] },
119
+ ]);
102
120
 
103
121
  expect(stream.getOptionValues(kSovUnset)).toStrictEqual([]);
104
- expect(stream.getOptionValues(kSovSplit)).toStrictEqual(["1.1", "1.2"]);
105
- expect(stream.getOptionValues(kSovJoin)).toStrictEqual(["2"]);
122
+ expect(stream.getOptionValues(kSovSplit)).toStrictEqual([
123
+ { inlined: null, separated: ["1.1"] },
124
+ { inlined: null, separated: ["1.2"] },
125
+ ]);
126
+ expect(stream.getOptionValues(kSovJoin)).toStrictEqual([
127
+ { inlined: "2.1", separated: [] },
128
+ { inlined: "2.2", separated: [] },
129
+ ]);
106
130
 
107
- expect(stream.getOptionValues(kDd)).toStrictEqual(["true"]);
108
- expect(stream.getOptionValues(kEe)).toStrictEqual(["true"]);
109
- expect(stream.getOptionValues(kFf)).toStrictEqual(["true"]);
131
+ expect(stream.getOptionValues(kDd)).toStrictEqual([
132
+ { inlined: null, separated: [] },
133
+ ]);
134
+ expect(stream.getOptionValues(kEe)).toStrictEqual([
135
+ { inlined: null, separated: [] },
136
+ ]);
137
+ expect(stream.getOptionValues(kFf)).toStrictEqual([
138
+ { inlined: null, separated: [] },
139
+ ]);
140
+ expect(stream.getOptionValues(kGg)).toStrictEqual([
141
+ { inlined: null, separated: [] },
142
+ ]);
110
143
  });
144
+
145
+ const optionFlagParsing: ReaderOptionParsing = {
146
+ consumeShortGroup: false,
147
+ consumeNextArg: () => false,
148
+ };
149
+
150
+ const optionValueFixedUniqueParsing: ReaderOptionParsing = {
151
+ consumeShortGroup: true,
152
+ consumeNextArg: (inlined, separated) =>
153
+ inlined === null && separated.length === 0,
154
+ };
@@ -21,10 +21,21 @@ const rootCommand = commandChained(
21
21
  { description: "?" },
22
22
  operation(
23
23
  {
24
- options: { flag: optionFlag({ short: "b", long: "boolean-flag" }) },
24
+ options: {
25
+ flagPositive: optionFlag({
26
+ short: "fp",
27
+ long: "flag-positive",
28
+ default: true,
29
+ }),
30
+ flagNegative: optionFlag({
31
+ short: "fn",
32
+ long: "flag-negative",
33
+ default: false,
34
+ }),
35
+ },
25
36
  positionals: [positionalRequired({ label: "POS-1", type: typeNumber })],
26
37
  },
27
- async (context, inputs) => {
38
+ async function (context, inputs) {
28
39
  return { at: "root", context, inputs };
29
40
  },
30
41
  ),
@@ -45,7 +56,7 @@ const rootCommand = commandChained(
45
56
  },
46
57
  positionals: [positionalRequired({ type: typeNumber })],
47
58
  },
48
- async (context, inputs) => {
59
+ async function (context, inputs) {
49
60
  return { at: "mid", context, inputs };
50
61
  },
51
62
  ),
@@ -57,7 +68,7 @@ const rootCommand = commandChained(
57
68
  options: {},
58
69
  positionals: [positionalRequired({ type: typeString })],
59
70
  },
60
- async (context, inputs) => {
71
+ async function (context, inputs) {
61
72
  return { at: "sub1", context, inputs };
62
73
  },
63
74
  ),
@@ -73,7 +84,7 @@ const rootCommand = commandChained(
73
84
  positionalVariadics({ type: typeString }),
74
85
  ],
75
86
  },
76
- async (context, inputs) => {
87
+ async function (context, inputs) {
77
88
  return { at: "sub2", context, inputs };
78
89
  },
79
90
  ),
@@ -82,13 +93,14 @@ const rootCommand = commandChained(
82
93
  ),
83
94
  );
84
95
 
85
- it("run", async () => {
86
- const res1 = await executeInterpreted(
87
- ["50", "51", "sub1", "final"],
88
- "Run Context Input",
89
- rootCommand,
90
- );
91
- expect(res1).toStrictEqual({
96
+ it("run", async function () {
97
+ expect(
98
+ await executeInterpreted(
99
+ ["-fn=true", "-fp", "50", "51", "sub1", "final"],
100
+ "Run Context Input",
101
+ rootCommand,
102
+ ),
103
+ ).toStrictEqual({
92
104
  at: "sub1",
93
105
  context: {
94
106
  at: "mid",
@@ -96,7 +108,7 @@ it("run", async () => {
96
108
  at: "root",
97
109
  context: "Run Context Input",
98
110
  inputs: {
99
- options: { flag: false },
111
+ options: { flagPositive: true, flagNegative: true },
100
112
  positionals: [50],
101
113
  },
102
114
  },
@@ -111,25 +123,56 @@ it("run", async () => {
111
123
  },
112
124
  });
113
125
 
114
- const res2 = await executeInterpreted(
115
- [
116
- "40",
117
- "41",
118
- "sub2",
119
- "--string-option=hello",
120
- "--number-option",
121
- "123.1,123.2",
122
- "--number-option",
123
- "123.3",
124
- "88.88",
125
- "a,b",
126
- "final",
127
- "--boolean-flag",
128
- ],
129
- "Run Context Input",
130
- rootCommand,
131
- );
132
- expect(res2).toStrictEqual({
126
+ expect(
127
+ await executeInterpreted(
128
+ ["50", "51", "sub2", "9999.99"],
129
+ "Run Context Input",
130
+ rootCommand,
131
+ ),
132
+ ).toStrictEqual({
133
+ at: "sub2",
134
+ context: {
135
+ at: "mid",
136
+ context: {
137
+ at: "root",
138
+ context: "Run Context Input",
139
+ inputs: {
140
+ options: { flagPositive: true, flagNegative: false },
141
+ positionals: [50],
142
+ },
143
+ },
144
+ inputs: {
145
+ options: { string: undefined, number: [] },
146
+ positionals: [51],
147
+ },
148
+ },
149
+ inputs: {
150
+ options: {},
151
+ positionals: [9999.99, "42", []],
152
+ },
153
+ });
154
+
155
+ expect(
156
+ await executeInterpreted(
157
+ [
158
+ "40",
159
+ "41",
160
+ "sub2",
161
+ "--string-option=hello",
162
+ "--number-option",
163
+ "123.1,123.2",
164
+ "--number-option",
165
+ "123.3",
166
+ "88.88",
167
+ "a,b",
168
+ "final",
169
+ "--no-flag-positive",
170
+ "--no-flag-negative",
171
+ ],
172
+ "Run Context Input",
173
+ rootCommand,
174
+ ),
175
+ ).toStrictEqual({
133
176
  at: "sub2",
134
177
  context: {
135
178
  at: "mid",
@@ -137,7 +180,7 @@ it("run", async () => {
137
180
  at: "root",
138
181
  context: "Run Context Input",
139
182
  inputs: {
140
- options: { flag: true },
183
+ options: { flagPositive: false, flagNegative: false },
141
184
  positionals: [40],
142
185
  },
143
186
  },
@@ -48,7 +48,7 @@ const rootCommand = commandChained<any, any, any>(
48
48
  }),
49
49
  ],
50
50
  },
51
- async (context, inputs) => {
51
+ async function (context, inputs) {
52
52
  return { at: "root", context, inputs };
53
53
  },
54
54
  ),
@@ -92,7 +92,7 @@ const rootCommand = commandChained<any, any, any>(
92
92
  }),
93
93
  ],
94
94
  },
95
- async (context, inputs) => {
95
+ async function (context, inputs) {
96
96
  return { at: "root", context, inputs };
97
97
  },
98
98
  ),
@@ -128,7 +128,7 @@ const rootCommand = commandChained<any, any, any>(
128
128
  }),
129
129
  ],
130
130
  },
131
- async (context, inputs) => {
131
+ async function (context, inputs) {
132
132
  return { at: "sub1", context, inputs };
133
133
  },
134
134
  ),
@@ -185,7 +185,7 @@ const rootCommand = commandChained<any, any, any>(
185
185
  }),
186
186
  ],
187
187
  },
188
- async (context, inputs) => {
188
+ async function (context, inputs) {
189
189
  return { at: "sub2", context, inputs };
190
190
  },
191
191
  ),
@@ -194,7 +194,7 @@ const rootCommand = commandChained<any, any, any>(
194
194
  ),
195
195
  );
196
196
 
197
- it("run", async () => {
197
+ it("run", async function () {
198
198
  const usage1 = await getUsage([], rootCommand);
199
199
  const usage2 = await getUsage(["50"], rootCommand);
200
200
  const usage3 = await getUsage(["50", "51"], rootCommand);
@@ -209,16 +209,6 @@ it("run", async () => {
209
209
  rootCommand,
210
210
  );
211
211
 
212
- console.log(usage1.join("\n"));
213
- console.log(usage2.join("\n"));
214
- console.log(usage3.join("\n"));
215
- console.log(usage4.join("\n"));
216
- console.log(usage5.join("\n"));
217
- console.log(usage6.join("\n"));
218
- console.log(usage7.join("\n"));
219
- /*
220
- */
221
-
222
212
  const usageRoot = [
223
213
  "{{Usage:}@darkMagenta}+ {{my-cli}@darkCyan}+ {{<POS-1>}@darkBlue}+ {{[REST]...}@darkBlue}+",
224
214
  "",
@@ -233,8 +223,8 @@ it("run", async () => {
233
223
  " {{-b}@darkCyan}+, {{--boolean-flag}@darkCyan}+{{[=no]}-}* boolean-flag description",
234
224
  "",
235
225
  "{{Examples:}@darkGreen}+",
236
- " {{# Example usage of the root command}-}*",
237
- " {{my-cli}@darkCyan}+ {{42}@darkBlue}+ {{-b}@darkCyan}+",
226
+ " {{# Example usage of the root command}-}*",
227
+ " {{my-cli}@darkCyan}+ {{42}@darkBlue}+ {{-b}@darkCyan}+",
238
228
  "",
239
229
  ];
240
230
  const usageMid = [
@@ -253,13 +243,13 @@ it("run", async () => {
253
243
  " {{sub2}@darkCyan}+ Subcommand 2 description {{(Subcommand 2 hint)}-}*",
254
244
  "",
255
245
  "{{Options:}@darkGreen}+",
256
- " {{-b}@darkCyan}+, {{--boolean-flag}@darkCyan}+{{[=no]}-}* boolean-flag description",
257
- " {{-s}@darkCyan}+, {{--string-option}@darkCyan}+ {{<COOL-STUFF>}@darkBlue}+ string-option description",
258
- " {{--complex-option}@darkCyan}+ {{<NUMBER,STRING[,STRING]...>}@darkBlue}+ complex-option description",
246
+ " {{-b}@darkCyan}+, {{--boolean-flag}@darkCyan}+{{[=no]}-}* boolean-flag description",
247
+ " {{-s}@darkCyan}+, {{--string-option}@darkCyan}+ {{<COOL-STUFF>}@darkBlue}+ string-option description",
248
+ " {{--complex-option}@darkCyan}+ {{<NUMBER,STRING[,STRING]...>}@darkBlue}+{{ [*]}-}* complex-option description",
259
249
  "",
260
250
  "{{Examples:}@darkGreen}+",
261
- " {{# Example usage of the mid command}-}*",
262
- " {{my-cli}@darkCyan}+ {{42}@darkBlue}+ {{-b}@darkCyan}+ {{43}@darkBlue}+",
251
+ " {{# Example usage of the mid command}-}*",
252
+ " {{my-cli}@darkCyan}+ {{42}@darkBlue}+ {{-b}@darkCyan}+ {{43}@darkBlue}+",
263
253
  "",
264
254
  ];
265
255
  const usageSub1 = [
@@ -275,13 +265,13 @@ it("run", async () => {
275
265
  " {{<POS-STRING>}@darkBlue}+ Required positional string",
276
266
  "",
277
267
  "{{Options:}@darkGreen}+",
278
- " {{-b}@darkCyan}+, {{--boolean-flag}@darkCyan}+{{[=no]}-}* boolean-flag description",
279
- " {{-s}@darkCyan}+, {{--string-option}@darkCyan}+ {{<COOL-STUFF>}@darkBlue}+ string-option description",
280
- " {{--complex-option}@darkCyan}+ {{<NUMBER,STRING[,STRING]...>}@darkBlue}+ complex-option description",
268
+ " {{-b}@darkCyan}+, {{--boolean-flag}@darkCyan}+{{[=no]}-}* boolean-flag description",
269
+ " {{-s}@darkCyan}+, {{--string-option}@darkCyan}+ {{<COOL-STUFF>}@darkBlue}+ string-option description",
270
+ " {{--complex-option}@darkCyan}+ {{<NUMBER,STRING[,STRING]...>}@darkBlue}+{{ [*]}-}* complex-option description",
281
271
  "",
282
272
  "{{Examples:}@darkGreen}+",
283
- " {{# Example usage of subcommand 1}-}*",
284
- " {{my-cli}@darkCyan}+ {{-b}@darkCyan}+ {{42}@darkBlue}+ {{43}@darkBlue}+ {{sub1}@darkCyan}+ {{valid}@darkBlue}+",
273
+ " {{# Example usage of subcommand 1}-}*",
274
+ " {{my-cli}@darkCyan}+ {{-b}@darkCyan}+ {{42}@darkBlue}+ {{43}@darkBlue}+ {{sub1}@darkCyan}+ {{valid}@darkBlue}+",
285
275
  "",
286
276
  ];
287
277
  const usageSub2 = [
@@ -299,17 +289,27 @@ it("run", async () => {
299
289
  " {{[VARIADIC]...}@darkBlue}+ Variadic positionals strings",
300
290
  "",
301
291
  "{{Options:}@darkGreen}+",
302
- " {{-b}@darkCyan}+, {{--boolean-flag}@darkCyan}+{{[=no]}-}* boolean-flag description",
303
- " {{-s}@darkCyan}+, {{--string-option}@darkCyan}+ {{<COOL-STUFF>}@darkBlue}+ string-option description",
304
- " {{--complex-option}@darkCyan}+ {{<NUMBER,STRING[,STRING]...>}@darkBlue}+ complex-option description",
305
- " {{--dudu}@darkCyan}+ {{<STRING>}@darkBlue}+ Dudu option description {{(Dudu option hint)}-}*",
292
+ " {{-b}@darkCyan}+, {{--boolean-flag}@darkCyan}+{{[=no]}-}* boolean-flag description",
293
+ " {{-s}@darkCyan}+, {{--string-option}@darkCyan}+ {{<COOL-STUFF>}@darkBlue}+ string-option description",
294
+ " {{--complex-option}@darkCyan}+ {{<NUMBER,STRING[,STRING]...>}@darkBlue}+{{ [*]}-}* complex-option description",
295
+ " {{--dudu}@darkCyan}+ {{<STRING>}@darkBlue}+ Dudu option description {{(Dudu option hint)}-}*",
306
296
  "",
307
297
  "{{Examples:}@darkGreen}+",
308
- " {{# Example usage of subcommand 2}-}*",
309
- " {{my-cli}@darkCyan}+ {{40}@darkBlue}+ {{41}@darkBlue}+ {{sub2}@darkCyan}+ {{--dudu}@darkCyan}+{{=}-}*{{hello}@darkBlue}+ {{50}@darkBlue}+",
298
+ " {{# Example usage of subcommand 2}-}*",
299
+ " {{my-cli}@darkCyan}+ {{40}@darkBlue}+ {{41}@darkBlue}+ {{sub2}@darkCyan}+ {{--dudu}@darkCyan}+{{=}-}*{{hello}@darkBlue}+ {{50}@darkBlue}+",
310
300
  "",
311
301
  ];
312
302
 
303
+ /*
304
+ console.log(usage1.join("\n"));
305
+ console.log(usage2.join("\n"));
306
+ console.log(usage3.join("\n"));
307
+ console.log(usage4.join("\n"));
308
+ console.log(usage5.join("\n"));
309
+ console.log(usage6.join("\n"));
310
+ console.log(usage7.join("\n"));
311
+ */
312
+
313
313
  expect(usage1).toStrictEqual(usageRoot);
314
314
  expect(usage2).toStrictEqual(usageMid);
315
315
  expect(usage3).toStrictEqual(usageMid);
@@ -338,7 +338,7 @@ async function getUsage<Context, Result>(
338
338
  */
339
339
  return usageToStyledLines({
340
340
  cliName: "my-cli",
341
- commandUsage: commandDecoder.generateUsage(),
342
- typoSupport: TypoSupport.tty(),
341
+ usage: commandDecoder.generateUsage(),
342
+ typoSupport: TypoSupport.mock(),
343
343
  });
344
344
  }
@@ -16,7 +16,7 @@ import {
16
16
  typeUrl,
17
17
  } from "../src";
18
18
 
19
- it("run", async () => {
19
+ it("run", async function () {
20
20
  const rootUsage = [
21
21
  "Usage: my-cli <REQUIRED1> <SUBCOMMAND>",
22
22
  "",
@@ -30,7 +30,7 @@ it("run", async () => {
30
30
  "",
31
31
  "Options:",
32
32
  " --flag[=no] Option flag description",
33
- " --repeatable <STRING> Option repeatable description",
33
+ " --repeatable <STRING> [*] Option repeatable description",
34
34
  " --single-value <NUMBER-ENUM> Option single value description",
35
35
  "",
36
36
  ].join("\n");
@@ -47,9 +47,9 @@ it("run", async () => {
47
47
  "",
48
48
  "Options:",
49
49
  " --flag[=no] Option flag description",
50
- " --repeatable <STRING> Option repeatable description",
50
+ " --repeatable <STRING> [*] Option repeatable description",
51
51
  " --single-value <NUMBER-ENUM> Option single value description",
52
- " --url <URL> Option url description",
52
+ " --url <URL> [*] Option url description",
53
53
  "",
54
54
  ].join("\n");
55
55
 
@@ -101,7 +101,7 @@ it("run", async () => {
101
101
  await testCase(
102
102
  ["--invalid1", "--invalid2", "required1", "--invalid3"],
103
103
  [],
104
- [rootUsage, "Error: --invalid1: Unexpected unknown option"],
104
+ [rootUsage, "Error: Unexpected unknown option: --invalid1"],
105
105
  1,
106
106
  );
107
107
  await testCase(
@@ -135,13 +135,13 @@ it("run", async () => {
135
135
  await testCase(
136
136
  ["--url", "https://example.com"],
137
137
  [],
138
- [rootUsage, "Error: --url: Unexpected unknown option"],
138
+ [rootUsage, "Error: Unexpected unknown option: --url"],
139
139
  1,
140
140
  );
141
141
  await testCase(
142
142
  ["required1", "--url", "https://example.com"],
143
143
  [],
144
- [rootUsage, "Error: --url: Unexpected unknown option"],
144
+ [rootUsage, "Error: Unexpected unknown option: --url"],
145
145
  1,
146
146
  );
147
147
  await testCase(
@@ -187,13 +187,13 @@ it("run", async () => {
187
187
  await testCase(
188
188
  ["--invalid", "required1", "subcommand", "required2"],
189
189
  [],
190
- [rootUsage, "Error: --invalid: Unexpected unknown option"],
190
+ [rootUsage, "Error: Unexpected unknown option: --invalid"],
191
191
  1,
192
192
  );
193
193
  await testCase(
194
194
  ["required1", "subcommand", "required2", "--nope"],
195
195
  [],
196
- [subcommandUsage, "Error: --nope: Unexpected unknown option"],
196
+ [subcommandUsage, "Error: Unexpected unknown option: --nope"],
197
197
  1,
198
198
  );
199
199
  await testCase(
@@ -283,7 +283,7 @@ it("run", async () => {
283
283
  await testCase(
284
284
  ["--url", "not-a-url", "required1", "subcommand", "required2"],
285
285
  [],
286
- [rootUsage, "Error: --url: Unexpected unknown option"],
286
+ [rootUsage, "Error: Unexpected unknown option: --url"],
287
287
  1,
288
288
  );
289
289
  await testCase(
@@ -372,7 +372,7 @@ async function testCase(
372
372
  }),
373
373
  ],
374
374
  },
375
- async () => {
375
+ async function () {
376
376
  console.log("Has executed root command");
377
377
  },
378
378
  ),
@@ -407,7 +407,7 @@ async function testCase(
407
407
  }),
408
408
  ],
409
409
  },
410
- async () => {
410
+ async function () {
411
411
  console.log("Has executed subcommand");
412
412
  },
413
413
  ),
@@ -435,7 +435,7 @@ function makeMocked<P, R>(returns: Array<R>) {
435
435
  const history = new Array<P>();
436
436
  return {
437
437
  history,
438
- call: (p: P) => {
438
+ call(p: P) {
439
439
  history.push(p);
440
440
  if (history.length > returns.length) {
441
441
  throw new Error(
@@ -10,15 +10,31 @@ import {
10
10
  typeUrl,
11
11
  } from "../src";
12
12
 
13
- it("run", async () => {
13
+ it("run", async function () {
14
14
  await testCase(
15
15
  ["hello"],
16
16
  '{{Error:}@darkRed}+ Unexpected argument: {{"hello"}@darkYellow}+',
17
17
  );
18
+ await testCase(
19
+ ["--nope"],
20
+ "{{Error:}@darkRed}+ Unexpected unknown option: {{--nope}@darkYellow}+",
21
+ );
18
22
  await testCase(
19
23
  ["--flag", "--flag"],
20
24
  "{{Error:}@darkRed}+ {{--flag}@darkCyan}+: Must not be set multiple times",
21
25
  );
26
+ await testCase(
27
+ ["--flag", "--no-flag"],
28
+ "{{Error:}@darkRed}+ {{--flag}@darkCyan}+: Must not be set in combination with: {{--no-flag}@darkCyan}+",
29
+ );
30
+ await testCase(
31
+ ["--no-flag", "--no-flag"],
32
+ "{{Error:}@darkRed}+ {{--no-flag}@darkCyan}+: Must not be set multiple times",
33
+ );
34
+ await testCase(
35
+ ["--single-value=a", "--single-value=b"],
36
+ "{{Error:}@darkRed}+ {{--single-value}@darkCyan}+: Requires a single value, but got multiple",
37
+ );
22
38
  await testCase(
23
39
  ["--flag=invalid"],
24
40
  '{{Error:}@darkRed}+ {{--flag}@darkCyan}+: {{<BOOLEAN>}@darkBlue}+: {{Boolean}@darkMagenta}+: Invalid value: {{"invalid"}@darkYellow}+',
@@ -59,7 +75,7 @@ async function testCase(args: Array<string>, error: string) {
59
75
  },
60
76
  positionals: [],
61
77
  },
62
- async () => {},
78
+ async function () {},
63
79
  ),
64
80
  );
65
81
  console.log = onLogStdOut.call;
@@ -79,7 +95,7 @@ function makeMocked<P, R>(returns: Array<R>) {
79
95
  const history = new Array<P>();
80
96
  return {
81
97
  history,
82
- call: (p: P) => {
98
+ call(p: P) {
83
99
  history.push(p);
84
100
  if (history.length > returns.length) {
85
101
  throw new Error(