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/README.md +1 -1
- package/dist/index.d.ts +711 -1046
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/.vitepress/config.mts +1 -0
- package/docs/.vitepress/theme/index.ts +4 -0
- package/docs/.vitepress/theme/style.css +4 -0
- package/docs/guide/01_getting_started.md +4 -4
- package/docs/guide/02_commands.md +72 -41
- package/docs/guide/03_options.md +13 -14
- package/docs/guide/04_positionals.md +6 -8
- package/docs/guide/05_types.md +9 -11
- package/docs/guide/06_run.md +4 -5
- package/docs/index.md +8 -3
- package/docs/public/hero.png +0 -0
- package/package.json +1 -1
- package/src/lib/Command.ts +151 -275
- package/src/lib/Operation.ts +57 -95
- package/src/lib/Option.ts +194 -181
- package/src/lib/Positional.ts +54 -112
- package/src/lib/Reader.ts +155 -156
- package/src/lib/Run.ts +64 -69
- package/src/lib/Type.ts +89 -145
- package/src/lib/Typo.ts +131 -195
- package/src/lib/Usage.ts +203 -69
- package/tests/unit.Reader.aliases.ts +31 -15
- package/tests/unit.Reader.commons.ts +99 -43
- package/tests/unit.Reader.shortBig.ts +75 -31
- package/tests/unit.command.execute.ts +146 -91
- package/tests/unit.command.usage.ts +235 -114
- package/tests/unit.runner.cycle.ts +50 -20
- package/tests/unit.runner.errors.ts +19 -3
package/src/lib/Usage.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
-
*
|
|
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> [
|
|
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
|
|
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 -
|
|
42
|
-
* @param params.
|
|
43
|
-
* @param params.typoSupport -
|
|
44
|
-
* @returns
|
|
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
|
-
*
|
|
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
|
-
|
|
174
|
+
usage: UsageCommand;
|
|
60
175
|
typoSupport: TypoSupport;
|
|
61
176
|
}) {
|
|
62
|
-
const { cliName,
|
|
177
|
+
const { cliName, usage, typoSupport } = params;
|
|
63
178
|
|
|
64
179
|
const lines = new Array<string>();
|
|
65
180
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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.
|
|
89
|
-
if (
|
|
90
|
-
introText.
|
|
91
|
-
introText.
|
|
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.
|
|
206
|
+
detailText.push(textSubtleInfo(detail));
|
|
98
207
|
lines.push(detailText.computeStyledString(typoSupport));
|
|
99
208
|
}
|
|
100
209
|
|
|
101
|
-
if (
|
|
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
|
|
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 (
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
152
|
-
|
|
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
|
-
|
|
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
|
-
"--
|
|
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
|
-
|
|
21
|
+
parsing: optionValueFixedUniqueParsing,
|
|
22
22
|
});
|
|
23
23
|
const kFlag1 = readerArgs.registerOption({
|
|
24
|
-
longs: ["flag1", "
|
|
24
|
+
longs: ["flag1", "flag1-alias"],
|
|
25
25
|
shorts: [],
|
|
26
|
-
|
|
26
|
+
parsing: optionFlagParsing,
|
|
27
27
|
});
|
|
28
28
|
const kFlag2 = readerArgs.registerOption({
|
|
29
29
|
longs: ["flag2"],
|
|
30
30
|
shorts: ["fa2"],
|
|
31
|
-
|
|
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
|
-
|
|
52
|
+
parsing: optionFlagParsing,
|
|
41
53
|
});
|
|
42
54
|
const kFlagPositive = stream.registerOption({
|
|
43
55
|
longs: ["flag-positive"],
|
|
44
56
|
shorts: [],
|
|
45
|
-
|
|
57
|
+
parsing: optionFlagParsing,
|
|
46
58
|
});
|
|
47
59
|
const kFlagNegative = stream.registerOption({
|
|
48
60
|
longs: ["flag-negative"],
|
|
49
61
|
shorts: [],
|
|
50
|
-
|
|
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
|
-
|
|
75
|
+
parsing: optionValueFixedUniqueParsing,
|
|
64
76
|
});
|
|
65
77
|
const kOptionJoin = stream.registerOption({
|
|
66
78
|
longs: ["option-join"],
|
|
67
79
|
shorts: [],
|
|
68
|
-
|
|
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
|
-
|
|
86
|
+
parsing: optionFlagParsing,
|
|
80
87
|
});
|
|
81
88
|
const kB = stream.registerOption({
|
|
82
89
|
longs: [],
|
|
83
90
|
shorts: ["b"],
|
|
84
|
-
|
|
91
|
+
parsing: optionValueFixedUniqueParsing,
|
|
85
92
|
});
|
|
86
93
|
|
|
87
94
|
const kC = stream.registerOption({
|
|
88
95
|
longs: [],
|
|
89
96
|
shorts: ["c"],
|
|
90
|
-
|
|
97
|
+
parsing: optionFlagParsing,
|
|
91
98
|
});
|
|
92
99
|
const kD = stream.registerOption({
|
|
93
100
|
longs: [],
|
|
94
101
|
shorts: ["d"],
|
|
95
|
-
|
|
102
|
+
parsing: optionValueFixedUniqueParsing,
|
|
96
103
|
});
|
|
97
104
|
|
|
98
105
|
const kE = stream.registerOption({
|
|
99
106
|
longs: [],
|
|
100
107
|
shorts: ["e"],
|
|
101
|
-
|
|
108
|
+
parsing: optionFlagParsing,
|
|
102
109
|
});
|
|
103
110
|
const kF = stream.registerOption({
|
|
104
111
|
longs: [],
|
|
105
112
|
shorts: ["f"],
|
|
106
|
-
|
|
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
|
-
|
|
121
|
+
parsing: optionFlagParsing,
|
|
115
122
|
});
|
|
116
123
|
const kH = stream.registerOption({
|
|
117
124
|
longs: [],
|
|
118
125
|
shorts: ["h"],
|
|
119
|
-
|
|
126
|
+
parsing: optionFlagParsing,
|
|
120
127
|
});
|
|
121
128
|
|
|
122
129
|
const kI = stream.registerOption({
|
|
123
130
|
longs: [],
|
|
124
131
|
shorts: ["i"],
|
|
125
|
-
|
|
132
|
+
parsing: optionFlagParsing,
|
|
126
133
|
});
|
|
127
134
|
const kJ = stream.registerOption({
|
|
128
135
|
longs: [],
|
|
129
136
|
shorts: ["j"],
|
|
130
|
-
|
|
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([
|
|
148
|
-
|
|
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([
|
|
151
|
-
|
|
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([
|
|
154
|
-
|
|
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([
|
|
157
|
-
|
|
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([
|
|
160
|
-
|
|
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([
|
|
163
|
-
|
|
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
|
+
};
|