cli-kiss 0.2.2 → 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.
package/src/lib/Usage.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CommandUsage } from "./Command";
1
+ import { CommandInformation } from "./Command";
2
2
  import {
3
3
  TypoGrid,
4
4
  TypoString,
@@ -13,12 +13,125 @@ import {
13
13
  } from "./Typo";
14
14
 
15
15
  /**
16
- * Converts a {@link CommandUsage} model into an array of styled lines ready to be
16
+ * Usage model. Produced by {@link CommandDecoder.generateUsage}, consumed by {@link usageToStyledLines}.
17
+ */
18
+ export type UsageCommand = {
19
+ /**
20
+ * Segments of the usage line
21
+ * (e.g. `my-cli <POSITIONAL> subcommand <ANOTHER_POSITIONAL>`).
22
+ */
23
+ segments: Array<UsageSegment>;
24
+ /**
25
+ * Command metadata.
26
+ */
27
+ information: CommandInformation;
28
+ /**
29
+ * Positionals in declaration order.
30
+ */
31
+ positionals: Array<UsagePositional>;
32
+ /**
33
+ * Subcommands, populated when none was selected.
34
+ */
35
+ subcommands: Array<UsageSubcommand>;
36
+ /**
37
+ * Options in registration order.
38
+ */
39
+ options: Array<UsageOption>;
40
+ };
41
+
42
+ /**
43
+ * One segment of the usage line.
44
+ */
45
+ export type UsageSegment = { positional: string } | { subcommand: string };
46
+
47
+ /**
48
+ * Usage metadata. Produced by {@link Operation.generateUsage}, consumed when building {@link UsageCommand}.
49
+ */
50
+ export type UsageOperation = {
51
+ /**
52
+ * Registered options.
53
+ */
54
+ options: Array<UsageOption>;
55
+ /**
56
+ * Declared positionals, in order.
57
+ */
58
+ positionals: Array<UsagePositional>;
59
+ };
60
+
61
+ /**
62
+ * Positional metadata for the `Positionals:` section of help.
63
+ */
64
+ export type UsagePositional = {
65
+ /**
66
+ * Help text.
67
+ */
68
+ description: string | undefined;
69
+ /**
70
+ * Short note shown in parentheses.
71
+ */
72
+ hint: string | undefined;
73
+ /**
74
+ * Placeholder label shown in the usage line and the `Positionals:` section.
75
+ * Required: `<NAME>`, optional: `[NAME]`, variadic: `[NAME]...`.
76
+ */
77
+ label: Uppercase<string>;
78
+ };
79
+
80
+ /**
81
+ * Entry in the `Subcommands:` section.
82
+ */
83
+ export type UsageSubcommand = {
84
+ /**
85
+ * Token the user types (e.g. `"deploy"`).
86
+ */
87
+ name: string;
88
+ /**
89
+ * From {@link CommandInformation.description}.
90
+ */
91
+ description: string | undefined;
92
+ /**
93
+ * From {@link CommandInformation.hint}.
94
+ */
95
+ hint: string | undefined;
96
+ };
97
+
98
+ /**
99
+ * Option metadata for the `Options:` section of help.
100
+ */
101
+ export type UsageOption = {
102
+ /**
103
+ * Short-form name without `-` (e.g. `"v"`).
104
+ */
105
+ short: string | undefined;
106
+ /**
107
+ * Long-form name without `--` (e.g. `"verbose"`).
108
+ */
109
+ long: Lowercase<string>;
110
+ /**
111
+ * Extra annotation appended to the option label in help (e.g. `[=no]`, ` [*]`).
112
+ */
113
+ annotation: string | undefined;
114
+ /**
115
+ * Help text.
116
+ */
117
+ description: string | undefined;
118
+ /**
119
+ * Short note shown in parentheses.
120
+ */
121
+ hint: string | undefined;
122
+ /**
123
+ * Value placeholder in help (e.g. `"<FILE>"`). `undefined` for flags.
124
+ */
125
+ label: Uppercase<string> | undefined;
126
+ };
127
+
128
+ /**
129
+ * Converts a {@link UsageCommand} model into an array of styled lines ready to be
17
130
  * joined with `"\n"` and printed to the terminal.
18
131
  *
19
132
  * The output format is:
20
133
  * ```
21
- * Usage: <cliName> [breadcrumbs...]
134
+ * Usage: <cliName> [segments...]
22
135
  *
23
136
  * <description> (<hint>)
24
137
  * <detail lines...>
@@ -30,25 +143,27 @@ import {
30
143
  * <name> <description> (<hint>)
31
144
  *
32
145
  * Options:
33
- * -s, --long <LABEL> <description> (<hint>)
146
+ * -s, --long <LABEL><annotation> <description> (<hint>)
147
+ *
148
+ * Examples:
149
+ * <description>
150
+ * <command line>
34
151
  *
35
152
  * ```
36
153
  * Sections that have no entries are omitted. The trailing empty line is always included.
37
154
  *
38
- * Column alignment within each section is handled by {@link TypoGrid}: the widest entry
39
- * in each column sets the width for the entire section.
155
+ * Column alignment per section via {@link TypoGrid}.
40
156
  *
41
- * @param params.cliName - The CLI program name shown at the start of the usage line.
42
- * @param params.commandUsage - The usage model produced by {@link CommandFactory.generateUsage}.
43
- * @param params.typoSupport - Controls color/styling of the output.
44
- * @returns An ordered array of strings, one per output line (including a trailing
45
- * empty string for the blank line at the end).
157
+ * @param params.cliName - Program name for the usage line.
158
+ * @param params.usage - From {@link CommandDecoder.generateUsage}.
159
+ * @param params.typoSupport - Rendering mode.
160
+ * @returns Styled lines; includes a trailing empty string.
46
161
  *
47
162
  * @example
48
163
  * ```ts
49
164
  * const lines = usageToStyledLines({
50
165
  * cliName: "my-cli",
51
- * commandUsage: commandFactory.generateUsage(),
166
+ * usage: commandDecoder.generateUsage(),
52
167
  * typoSupport: TypoSupport.tty(),
53
168
  * });
54
169
  * process.stdout.write(lines.join("\n"));
@@ -56,85 +171,75 @@ import {
56
171
  */
57
172
  export function usageToStyledLines(params: {
58
173
  cliName: Lowercase<string>;
59
- commandUsage: CommandUsage;
174
+ usage: UsageCommand;
60
175
  typoSupport: TypoSupport;
61
176
  }) {
62
- const { cliName, commandUsage, typoSupport } = params;
177
+ const { cliName, usage, typoSupport } = params;
63
178
 
64
179
  const lines = new Array<string>();
65
180
 
66
- const breadcrumbs = [
67
- textUsageHero("Usage:").computeStyledString(typoSupport),
68
- textConstants(cliName).computeStyledString(typoSupport),
69
- ].concat(
70
- commandUsage.breadcrumbs.map((breadcrumb) => {
71
- if ("positional" in breadcrumb) {
72
- return textUserInput(breadcrumb.positional).computeStyledString(
73
- typoSupport,
74
- );
75
- }
76
- if ("command" in breadcrumb) {
77
- return textConstants(breadcrumb.command).computeStyledString(
78
- typoSupport,
79
- );
80
- }
81
- throw new Error(`Unknown breadcrumb: ${JSON.stringify(breadcrumb)}`);
82
- }),
83
- );
84
- lines.push(breadcrumbs.join(" "));
181
+ const segmentsText = new TypoText();
182
+ segmentsText.push(textUsageHero("Usage:"));
183
+ segmentsText.push(textDelimiter(" "));
184
+ segmentsText.push(textConstants(cliName));
185
+ for (const segment of usage.segments) {
186
+ segmentsText.push(textDelimiter(" "));
187
+ if ("positional" in segment) {
188
+ segmentsText.push(textUserInput(segment.positional));
189
+ }
190
+ if ("subcommand" in segment) {
191
+ segmentsText.push(textConstants(segment.subcommand));
192
+ }
193
+ }
194
+ lines.push(segmentsText.computeStyledString(typoSupport));
85
195
 
86
196
  lines.push("");
87
197
  const introText = new TypoText();
88
- introText.pushString(textUsageText(commandUsage.information.description));
89
- if (commandUsage.information.hint) {
90
- introText.pushString(textDelimiter(" "));
91
- introText.pushString(textSubtleInfo(`(${commandUsage.information.hint})`));
198
+ introText.push(textUsageText(usage.information.description));
199
+ if (usage.information.hint) {
200
+ introText.push(textDelimiter(" "));
201
+ introText.push(textSubtleInfo(`(${usage.information.hint})`));
92
202
  }
93
203
  lines.push(introText.computeStyledString(typoSupport));
94
-
95
- for (const detail of commandUsage.information.details ?? []) {
204
+ for (const detail of usage.information.details ?? []) {
96
205
  const detailText = new TypoText();
97
- detailText.pushString(textSubtleInfo(detail));
206
+ detailText.push(textSubtleInfo(detail));
98
207
  lines.push(detailText.computeStyledString(typoSupport));
99
208
  }
100
209
 
101
- if (commandUsage.positionals.length > 0) {
210
+ if (usage.positionals.length > 0) {
102
211
  lines.push("");
103
212
  lines.push(textBlockTitle("Positionals:").computeStyledString(typoSupport));
104
213
  const typoGrid = new TypoGrid();
105
- for (const positionalUsage of commandUsage.positionals) {
214
+ for (const positionalUsage of usage.positionals) {
106
215
  const typoGridRow = new Array<TypoText>();
107
216
  typoGridRow.push(new TypoText(textDelimiter(" ")));
108
217
  typoGridRow.push(new TypoText(textUserInput(positionalUsage.label)));
109
218
  typoGridRow.push(...createInformationals(positionalUsage));
110
219
  typoGrid.pushRow(typoGridRow);
111
220
  }
112
- lines.push(
113
- ...typoGrid.computeStyledGrid(typoSupport).map((row) => row.join("")),
114
- );
221
+ lines.push(...typoGrid.computeStyledLines(typoSupport));
115
222
  }
116
223
 
117
- if (commandUsage.subcommands.length > 0) {
224
+ if (usage.subcommands.length > 0) {
118
225
  lines.push("");
119
226
  lines.push(textBlockTitle("Subcommands:").computeStyledString(typoSupport));
120
227
  const typoGrid = new TypoGrid();
121
- for (const subcommandUsage of commandUsage.subcommands) {
228
+ for (const subcommandUsage of usage.subcommands) {
122
229
  const typoGridRow = new Array<TypoText>();
123
230
  typoGridRow.push(new TypoText(textDelimiter(" ")));
124
231
  typoGridRow.push(new TypoText(textConstants(subcommandUsage.name)));
125
232
  typoGridRow.push(...createInformationals(subcommandUsage));
126
233
  typoGrid.pushRow(typoGridRow);
127
234
  }
128
- lines.push(
129
- ...typoGrid.computeStyledGrid(typoSupport).map((row) => row.join("")),
130
- );
235
+ lines.push(...typoGrid.computeStyledLines(typoSupport));
131
236
  }
132
237
 
133
- if (commandUsage.options.length > 0) {
238
+ if (usage.options.length > 0) {
134
239
  lines.push("");
135
240
  lines.push(textBlockTitle("Options:").computeStyledString(typoSupport));
136
241
  const typoGrid = new TypoGrid();
137
- for (const optionUsage of commandUsage.options) {
242
+ for (const optionUsage of usage.options) {
138
243
  const typoGridRow = new Array<TypoText>();
139
244
  typoGridRow.push(new TypoText(textDelimiter(" ")));
140
245
  if (optionUsage.short) {
@@ -147,28 +252,57 @@ export function usageToStyledLines(params: {
147
252
  } else {
148
253
  typoGridRow.push(new TypoText());
149
254
  }
255
+ const longOptionText = new TypoText(
256
+ textConstants(`--${optionUsage.long}`),
257
+ );
150
258
  if (optionUsage.label) {
151
- typoGridRow.push(
152
- new TypoText(
153
- textConstants(`--${optionUsage.long}`),
154
- textDelimiter(" "),
155
- textUserInput(optionUsage.label),
156
- ),
157
- );
158
- } else {
159
- typoGridRow.push(
160
- new TypoText(
161
- textConstants(`--${optionUsage.long}`),
162
- textSubtleInfo("[=no]"),
163
- ),
164
- );
259
+ longOptionText.push(textDelimiter(" "));
260
+ longOptionText.push(textUserInput(optionUsage.label));
165
261
  }
262
+ if (optionUsage.annotation) {
263
+ longOptionText.push(textSubtleInfo(optionUsage.annotation));
264
+ }
265
+ typoGridRow.push(longOptionText);
166
266
  typoGridRow.push(...createInformationals(optionUsage));
167
267
  typoGrid.pushRow(typoGridRow);
168
268
  }
169
- lines.push(
170
- ...typoGrid.computeStyledGrid(typoSupport).map((row) => row.join("")),
171
- );
269
+ lines.push(...typoGrid.computeStyledLines(typoSupport));
270
+ }
271
+
272
+ if (usage.information.examples) {
273
+ lines.push("");
274
+ lines.push(textBlockTitle("Examples:").computeStyledString(typoSupport));
275
+ for (const example of usage.information.examples) {
276
+ const exampleExplanationText = new TypoText();
277
+ exampleExplanationText.push(textDelimiter(" "));
278
+ exampleExplanationText.push(textSubtleInfo(`# ${example.explanation}`));
279
+ lines.push(exampleExplanationText.computeStyledString(typoSupport));
280
+ const commandLineText = new TypoText();
281
+ commandLineText.push(textDelimiter(" "));
282
+ commandLineText.push(textConstants(cliName));
283
+ for (const commandArg of example.commandArgs) {
284
+ commandLineText.push(textDelimiter(" "));
285
+ if (typeof commandArg === "string") {
286
+ commandLineText.push(commandArg);
287
+ } else if ("positional" in commandArg) {
288
+ commandLineText.push(textUserInput(commandArg.positional));
289
+ } else if ("subcommand" in commandArg) {
290
+ commandLineText.push(textConstants(commandArg.subcommand));
291
+ } else if ("option" in commandArg) {
292
+ const option = commandArg.option;
293
+ if ("short" in option) {
294
+ commandLineText.push(textConstants(`-${option.short}`));
295
+ } else {
296
+ commandLineText.push(textConstants(`--${option.long}`));
297
+ }
298
+ if (option.value !== undefined) {
299
+ commandLineText.push(textSubtleInfo("="));
300
+ commandLineText.push(textUserInput(option.value));
301
+ }
302
+ }
303
+ }
304
+ lines.push(commandLineText.computeStyledString(typoSupport));
305
+ }
172
306
  }
173
307
 
174
308
  lines.push("");
@@ -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 readerArgs = new ReaderArgs([
6
6
  "--option=1.1",
7
7
  "--option-alias1=1.2",
@@ -10,7 +10,7 @@ it("run", async () => {
10
10
  "-pts=1.4",
11
11
  "-o",
12
12
  "1.5",
13
- "--flag-alias",
13
+ "--flag1-alias",
14
14
  "-fa2=woops",
15
15
  "-fa2o=1.6",
16
16
  ]);
@@ -18,29 +18,45 @@ it("run", async () => {
18
18
  const kOption = readerArgs.registerOption({
19
19
  longs: ["option", "option-alias1", "option-alias2"],
20
20
  shorts: ["pts", "o"],
21
- valued: true,
21
+ parsing: optionValueFixedUniqueParsing,
22
22
  });
23
23
  const kFlag1 = readerArgs.registerOption({
24
- longs: ["flag1", "flag-alias"],
24
+ longs: ["flag1", "flag1-alias"],
25
25
  shorts: [],
26
- valued: false,
26
+ parsing: optionFlagParsing,
27
27
  });
28
28
  const kFlag2 = readerArgs.registerOption({
29
29
  longs: ["flag2"],
30
30
  shorts: ["fa2"],
31
- valued: false,
31
+ parsing: optionFlagParsing,
32
32
  });
33
33
 
34
34
  expect(readerArgs.consumePositional()).toStrictEqual(undefined);
35
35
 
36
36
  expect(readerArgs.getOptionValues(kOption)).toStrictEqual([
37
- "1.1",
38
- "1.2",
39
- "1.3",
40
- "1.4",
41
- "1.5",
42
- "1.6",
37
+ { inlined: "1.1", separated: [] },
38
+ { inlined: "1.2", separated: [] },
39
+ { inlined: null, separated: ["1.3"] },
40
+ { inlined: "1.4", separated: [] },
41
+ { inlined: null, separated: ["1.5"] },
42
+ { inlined: "1.6", separated: [] },
43
+ ]);
44
+ expect(readerArgs.getOptionValues(kFlag1)).toStrictEqual([
45
+ { inlined: null, separated: [] },
46
+ ]);
47
+ expect(readerArgs.getOptionValues(kFlag2)).toStrictEqual([
48
+ { inlined: "woops", separated: [] },
49
+ { inlined: null, separated: [] },
43
50
  ]);
44
- expect(readerArgs.getOptionValues(kFlag1)).toStrictEqual(["true"]);
45
- expect(readerArgs.getOptionValues(kFlag2)).toStrictEqual(["woops", "true"]);
46
51
  });
52
+
53
+ const optionFlagParsing: ReaderOptionParsing = {
54
+ consumeShortGroup: false,
55
+ consumeNextArg: () => false,
56
+ };
57
+
58
+ const optionValueFixedUniqueParsing: ReaderOptionParsing = {
59
+ consumeShortGroup: true,
60
+ consumeNextArg: (inlined, separated) =>
61
+ inlined === null && separated.length === 0,
62
+ };
@@ -1,9 +1,10 @@
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
+ "--no-flag-no",
7
8
  "--flag-normal",
8
9
  "--flag-positive=true",
9
10
  "--flag-negative=false",
@@ -12,7 +13,8 @@ it("run", async () => {
12
13
  "1.1",
13
14
  "--option-split",
14
15
  "1.2",
15
- "--option-join=2",
16
+ "--option-join=2.1",
17
+ "--option-join=2.2",
16
18
  "-ab",
17
19
  "3.1",
18
20
  "-cd=4.1",
@@ -34,76 +36,81 @@ it("run", async () => {
34
36
 
35
37
  expect(stream.consumePositional()).toStrictEqual("positional-0");
36
38
 
39
+ const kFlagUnset = stream.registerOption({
40
+ longs: ["flag-unset"],
41
+ shorts: [],
42
+ parsing: optionFlagParsing,
43
+ });
44
+ const kFlagNo = stream.registerOption({
45
+ longs: ["no-flag-no"],
46
+ shorts: [],
47
+ parsing: optionFlagParsing,
48
+ });
37
49
  const kFlagNormal = stream.registerOption({
38
50
  longs: ["flag-normal"],
39
51
  shorts: [],
40
- valued: false,
52
+ parsing: optionFlagParsing,
41
53
  });
42
54
  const kFlagPositive = stream.registerOption({
43
55
  longs: ["flag-positive"],
44
56
  shorts: [],
45
- valued: false,
57
+ parsing: optionFlagParsing,
46
58
  });
47
59
  const kFlagNegative = stream.registerOption({
48
60
  longs: ["flag-negative"],
49
61
  shorts: [],
50
- valued: false,
51
- });
52
- const kFlagUnset = stream.registerOption({
53
- longs: ["flag-unset"],
54
- shorts: [],
55
- valued: false,
62
+ parsing: optionFlagParsing,
56
63
  });
57
64
 
58
65
  expect(stream.consumePositional()).toStrictEqual("positional-1");
59
66
 
67
+ const kOptionUnset = stream.registerOption({
68
+ longs: ["option-unset"],
69
+ shorts: [],
70
+ parsing: optionValueFixedUniqueParsing,
71
+ });
60
72
  const kOptionSplit = stream.registerOption({
61
73
  longs: ["option-split"],
62
74
  shorts: [],
63
- valued: true,
75
+ parsing: optionValueFixedUniqueParsing,
64
76
  });
65
77
  const kOptionJoin = stream.registerOption({
66
78
  longs: ["option-join"],
67
79
  shorts: [],
68
- valued: true,
69
- });
70
- const kOptionUnset = stream.registerOption({
71
- longs: ["option-unset"],
72
- shorts: [],
73
- valued: true,
80
+ parsing: optionValueFixedUniqueParsing,
74
81
  });
75
82
 
76
83
  const kA = stream.registerOption({
77
84
  longs: [],
78
85
  shorts: ["a"],
79
- valued: false,
86
+ parsing: optionFlagParsing,
80
87
  });
81
88
  const kB = stream.registerOption({
82
89
  longs: [],
83
90
  shorts: ["b"],
84
- valued: true,
91
+ parsing: optionValueFixedUniqueParsing,
85
92
  });
86
93
 
87
94
  const kC = stream.registerOption({
88
95
  longs: [],
89
96
  shorts: ["c"],
90
- valued: false,
97
+ parsing: optionFlagParsing,
91
98
  });
92
99
  const kD = stream.registerOption({
93
100
  longs: [],
94
101
  shorts: ["d"],
95
- valued: true,
102
+ parsing: optionValueFixedUniqueParsing,
96
103
  });
97
104
 
98
105
  const kE = stream.registerOption({
99
106
  longs: [],
100
107
  shorts: ["e"],
101
- valued: false,
108
+ parsing: optionFlagParsing,
102
109
  });
103
110
  const kF = stream.registerOption({
104
111
  longs: [],
105
112
  shorts: ["f"],
106
- valued: true,
113
+ parsing: optionValueFixedUniqueParsing,
107
114
  });
108
115
 
109
116
  expect(stream.consumePositional()).toStrictEqual("positional-2");
@@ -111,23 +118,23 @@ it("run", async () => {
111
118
  const kG = stream.registerOption({
112
119
  longs: [],
113
120
  shorts: ["g"],
114
- valued: false,
121
+ parsing: optionFlagParsing,
115
122
  });
116
123
  const kH = stream.registerOption({
117
124
  longs: [],
118
125
  shorts: ["h"],
119
- valued: false,
126
+ parsing: optionFlagParsing,
120
127
  });
121
128
 
122
129
  const kI = stream.registerOption({
123
130
  longs: [],
124
131
  shorts: ["i"],
125
- valued: false,
132
+ parsing: optionFlagParsing,
126
133
  });
127
134
  const kJ = stream.registerOption({
128
135
  longs: [],
129
136
  shorts: ["j"],
130
- valued: false,
137
+ parsing: optionFlagParsing,
131
138
  });
132
139
 
133
140
  expect(stream.consumePositional()).toStrictEqual("positional-3");
@@ -138,27 +145,76 @@ it("run", async () => {
138
145
  expect(stream.consumePositional()).toStrictEqual("positional-4");
139
146
  expect(stream.consumePositional()).toStrictEqual(undefined);
140
147
 
141
- expect(stream.getOptionValues(kFlagNormal)).toStrictEqual(["true"]);
142
- expect(stream.getOptionValues(kFlagPositive)).toStrictEqual(["true"]);
143
- expect(stream.getOptionValues(kFlagNegative)).toStrictEqual(["false"]);
144
148
  expect(stream.getOptionValues(kFlagUnset)).toStrictEqual([]);
149
+ expect(stream.getOptionValues(kFlagNo)).toStrictEqual([
150
+ { inlined: null, separated: [] },
151
+ ]);
152
+ expect(stream.getOptionValues(kFlagNormal)).toStrictEqual([
153
+ { inlined: null, separated: [] },
154
+ ]);
155
+ expect(stream.getOptionValues(kFlagPositive)).toStrictEqual([
156
+ { inlined: "true", separated: [] },
157
+ ]);
158
+ expect(stream.getOptionValues(kFlagNegative)).toStrictEqual([
159
+ { inlined: "false", separated: [] },
160
+ ]);
145
161
 
146
162
  expect(stream.getOptionValues(kOptionUnset)).toStrictEqual([]);
147
- expect(stream.getOptionValues(kOptionSplit)).toStrictEqual(["1.1", "1.2"]);
148
- expect(stream.getOptionValues(kOptionJoin)).toStrictEqual(["2"]);
163
+ expect(stream.getOptionValues(kOptionSplit)).toStrictEqual([
164
+ { inlined: null, separated: ["1.1"] },
165
+ { inlined: null, separated: ["1.2"] },
166
+ ]);
167
+ expect(stream.getOptionValues(kOptionJoin)).toStrictEqual([
168
+ { inlined: "2.1", separated: [] },
169
+ { inlined: "2.2", separated: [] },
170
+ ]);
149
171
 
150
- expect(stream.getOptionValues(kA)).toStrictEqual(["true"]);
151
- expect(stream.getOptionValues(kB)).toStrictEqual(["3.1", "3.2"]);
172
+ expect(stream.getOptionValues(kA)).toStrictEqual([
173
+ { inlined: null, separated: [] },
174
+ ]);
175
+ expect(stream.getOptionValues(kB)).toStrictEqual([
176
+ { inlined: null, separated: ["3.1"] },
177
+ { inlined: null, separated: ["3.2"] },
178
+ ]);
152
179
 
153
- expect(stream.getOptionValues(kC)).toStrictEqual(["true"]);
154
- expect(stream.getOptionValues(kD)).toStrictEqual(["4.1", "4.2"]);
180
+ expect(stream.getOptionValues(kC)).toStrictEqual([
181
+ { inlined: null, separated: [] },
182
+ ]);
183
+ expect(stream.getOptionValues(kD)).toStrictEqual([
184
+ { inlined: "4.1", separated: [] },
185
+ { inlined: "4.2", separated: [] },
186
+ ]);
155
187
 
156
- expect(stream.getOptionValues(kE)).toStrictEqual(["true"]);
157
- expect(stream.getOptionValues(kF)).toStrictEqual(["5.1", "5.2"]);
188
+ expect(stream.getOptionValues(kE)).toStrictEqual([
189
+ { inlined: null, separated: [] },
190
+ ]);
191
+ expect(stream.getOptionValues(kF)).toStrictEqual([
192
+ { inlined: "5.1", separated: [] },
193
+ { inlined: "5.2", separated: [] },
194
+ ]);
158
195
 
159
- expect(stream.getOptionValues(kG)).toStrictEqual(["true"]);
160
- expect(stream.getOptionValues(kH)).toStrictEqual(["FALSE"]);
196
+ expect(stream.getOptionValues(kG)).toStrictEqual([
197
+ { inlined: null, separated: [] },
198
+ ]);
199
+ expect(stream.getOptionValues(kH)).toStrictEqual([
200
+ { inlined: "FALSE", separated: [] },
201
+ ]);
161
202
 
162
- expect(stream.getOptionValues(kI)).toStrictEqual(["true"]);
163
- expect(stream.getOptionValues(kJ)).toStrictEqual(["TRUE"]);
203
+ expect(stream.getOptionValues(kI)).toStrictEqual([
204
+ { inlined: null, separated: [] },
205
+ ]);
206
+ expect(stream.getOptionValues(kJ)).toStrictEqual([
207
+ { inlined: "TRUE", separated: [] },
208
+ ]);
164
209
  });
210
+
211
+ const optionFlagParsing: ReaderOptionParsing = {
212
+ consumeShortGroup: false,
213
+ consumeNextArg: () => false,
214
+ };
215
+
216
+ const optionValueFixedUniqueParsing: ReaderOptionParsing = {
217
+ consumeShortGroup: true,
218
+ consumeNextArg: (inlined, separated) =>
219
+ inlined === null && separated.length === 0,
220
+ };