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/Command.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Operation } from "./Operation";
|
|
2
|
-
import { OptionUsage } from "./Option";
|
|
3
|
-
import { PositionalUsage } from "./Positional";
|
|
4
2
|
import { ReaderArgs } from "./Reader";
|
|
5
3
|
import {
|
|
6
4
|
TypoError,
|
|
@@ -9,176 +7,108 @@ import {
|
|
|
9
7
|
typoStyleUserInput,
|
|
10
8
|
TypoText,
|
|
11
9
|
} from "./Typo";
|
|
10
|
+
import { UsageCommand, UsageSegment } from "./Usage";
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
|
-
*
|
|
15
|
-
* execute it within a given context.
|
|
13
|
+
* A CLI command. Created with {@link command}, {@link commandWithSubcommands}, or {@link commandChained}.
|
|
16
14
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* or {@link commandChained}, and pass it to {@link runAndExit} to run your CLI.
|
|
20
|
-
*
|
|
21
|
-
* @typeParam Context - The value passed into the command when it is executed. It flows
|
|
22
|
-
* from {@link runAndExit}'s `context` argument down through the command chain.
|
|
23
|
-
* @typeParam Result - The value produced by executing the command. For root commands
|
|
24
|
-
* passed to {@link runAndExit} this is always `void`.
|
|
15
|
+
* @typeParam Context - Injected at execution; forwarded to handlers.
|
|
16
|
+
* @typeParam Result - Produced on execution; typically `void`.
|
|
25
17
|
*/
|
|
26
18
|
export type Command<Context, Result> = {
|
|
27
19
|
/**
|
|
28
|
-
* Returns
|
|
20
|
+
* Returns static metadata.
|
|
29
21
|
*/
|
|
30
22
|
getInformation(): CommandInformation;
|
|
31
23
|
/**
|
|
32
|
-
*
|
|
33
|
-
* information or create a ready-to-run {@link CommandInstance}.
|
|
34
|
-
*
|
|
35
|
-
* Parsing errors are captured and deferred: `createFactory` never throws; instead
|
|
36
|
-
* the error surfaces when {@link CommandFactory.createInstance} is called on the
|
|
37
|
-
* returned factory.
|
|
24
|
+
* Registers options/positionals on `readerArgs`; returns a {@link CommandDecoder}.
|
|
38
25
|
*/
|
|
39
|
-
|
|
26
|
+
consumeAndMakeDecoder(
|
|
27
|
+
readerArgs: ReaderArgs,
|
|
28
|
+
): CommandDecoder<Context, Result>;
|
|
40
29
|
};
|
|
41
30
|
|
|
42
31
|
/**
|
|
43
|
-
* Produced by {@link Command.
|
|
44
|
-
* been parsed. Provides two capabilities:
|
|
32
|
+
* Produced by {@link Command.consumeAndMakeDecoder}.
|
|
45
33
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @typeParam Context - Input passed to the command {@link Command}.
|
|
50
|
-
* @typeParam Result - Result of the command's logic {@link Command}.
|
|
34
|
+
* @typeParam Context - See {@link Command}.
|
|
35
|
+
* @typeParam Result - See {@link Command}.
|
|
51
36
|
*/
|
|
52
|
-
export type
|
|
37
|
+
export type CommandDecoder<Context, Result> = {
|
|
53
38
|
/**
|
|
54
|
-
*
|
|
55
|
-
* This is called to render the `--help` output and on error when `usageOnError`
|
|
56
|
-
* is enabled.
|
|
39
|
+
* Returns {@link UsageCommand} for the current command path.
|
|
57
40
|
*/
|
|
58
|
-
generateUsage():
|
|
41
|
+
generateUsage(): UsageCommand;
|
|
59
42
|
/**
|
|
60
|
-
* Creates a {@link
|
|
43
|
+
* Creates a ready-to-execute {@link CommandInterpreter}.
|
|
61
44
|
*
|
|
62
|
-
* @throws {@link TypoError} if
|
|
63
|
-
* {@link Command.createFactory} encountered an error (e.g. unknown
|
|
64
|
-
* option, missing required positional, invalid type).
|
|
45
|
+
* @throws {@link TypoError} if parsing or decoding failed.
|
|
65
46
|
*/
|
|
66
|
-
|
|
47
|
+
decodeAndMakeInterpreter(): CommandInterpreter<Context, Result>;
|
|
67
48
|
};
|
|
68
49
|
|
|
69
50
|
/**
|
|
70
|
-
* A fully parsed, ready-to-execute command.
|
|
51
|
+
* A fully parsed, decoded and ready-to-execute command.
|
|
71
52
|
*
|
|
72
|
-
* @typeParam Context -
|
|
73
|
-
* @typeParam Result -
|
|
53
|
+
* @typeParam Context - Context passed to the handler.
|
|
54
|
+
* @typeParam Result - Value produced on success.
|
|
74
55
|
*/
|
|
75
|
-
export type
|
|
56
|
+
export type CommandInterpreter<Context, Result> = {
|
|
76
57
|
/**
|
|
77
|
-
* Executes
|
|
78
|
-
*
|
|
79
|
-
* @param context - Arbitrary value injected by the caller (see {@link runAndExit}).
|
|
80
|
-
* @returns A promise that resolves to the command's result, or rejects if the
|
|
81
|
-
* command handler throws.
|
|
58
|
+
* Executes with the provided context.
|
|
82
59
|
*/
|
|
83
60
|
executeWithContext(context: Context): Promise<Result>;
|
|
84
61
|
};
|
|
85
62
|
|
|
86
63
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* This information is displayed in the usage/help output produced by {@link usageToStyledLines}.
|
|
64
|
+
* Command metadata shown in `--help` output.
|
|
90
65
|
*/
|
|
91
66
|
export type CommandInformation = {
|
|
92
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Shown in the usage header.
|
|
69
|
+
*/
|
|
93
70
|
description: string;
|
|
94
71
|
/**
|
|
95
|
-
*
|
|
96
|
-
* Suitable for short caveats such as `"deprecated"` or `"experimental"`.
|
|
72
|
+
* Shown in parentheses, e.g. `"deprecated"`, `"experimental"`.
|
|
97
73
|
*/
|
|
98
74
|
hint?: string;
|
|
99
75
|
/**
|
|
100
|
-
*
|
|
101
|
-
* Useful for multi-line explanations, examples, or caveats that don't fit in
|
|
102
|
-
* a single sentence.
|
|
76
|
+
* Extra lines printed below the description.
|
|
103
77
|
*/
|
|
104
78
|
details?: Array<string>;
|
|
105
|
-
// TODO - printable examples ?
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* The full usage/help model for a command as it appears after argument parsing.
|
|
110
|
-
*
|
|
111
|
-
* This is produced by {@link CommandFactory.generateUsage} and consumed by
|
|
112
|
-
* {@link usageToStyledLines} to render the `--help` output.
|
|
113
|
-
*/
|
|
114
|
-
export type CommandUsage = {
|
|
115
79
|
/**
|
|
116
|
-
*
|
|
117
|
-
* `Usage: my-cli <POSITIONAL> subcommand <ANOTHER_POSITIONAL>`.
|
|
118
|
-
*
|
|
119
|
-
* Each element is either a positional placeholder or a literal subcommand name.
|
|
80
|
+
* Shown in the `Examples:` section.
|
|
120
81
|
*/
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* A single element in the usage breadcrumb trail shown at the top of the help output.
|
|
144
|
-
*
|
|
145
|
-
* - `{ positional: string }` — A positional placeholder such as `<NAME>` or `[FILE]`.
|
|
146
|
-
* - `{ command: string }` — A literal subcommand token such as `deploy`.
|
|
147
|
-
*/
|
|
148
|
-
export type CommandUsageBreadcrumb =
|
|
149
|
-
| { positional: string }
|
|
150
|
-
| { command: string };
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Summary information about a single subcommand shown in the `Subcommands:` section
|
|
154
|
-
* of the usage output.
|
|
155
|
-
*/
|
|
156
|
-
export type CommandUsageSubcommand = {
|
|
157
|
-
/** The literal token the user types to select this subcommand (e.g. `"deploy"`). */
|
|
158
|
-
name: string;
|
|
159
|
-
/** Short description forwarded from the subcommand's {@link CommandInformation}. */
|
|
160
|
-
description: string | undefined;
|
|
161
|
-
/** Optional hint forwarded from the subcommand's {@link CommandInformation}. */
|
|
162
|
-
hint: string | undefined;
|
|
82
|
+
examples?: Array<{
|
|
83
|
+
/**
|
|
84
|
+
* Explanation shown above the example.
|
|
85
|
+
*/
|
|
86
|
+
explanation: string;
|
|
87
|
+
/**
|
|
88
|
+
* Example command args.
|
|
89
|
+
*/
|
|
90
|
+
commandArgs: Array<
|
|
91
|
+
| string
|
|
92
|
+
| { positional: string }
|
|
93
|
+
| { subcommand: string }
|
|
94
|
+
| {
|
|
95
|
+
option:
|
|
96
|
+
| { long: string; value?: string }
|
|
97
|
+
| { short: string; value?: string };
|
|
98
|
+
}
|
|
99
|
+
>;
|
|
100
|
+
}>;
|
|
163
101
|
};
|
|
164
102
|
|
|
165
103
|
/**
|
|
166
|
-
* Creates a leaf command
|
|
167
|
-
* an {@link Operation}.
|
|
168
|
-
*
|
|
169
|
-
* During parsing, `command` reads all positionals and options consumed by `operation`,
|
|
170
|
-
* then asserts that no extra positionals remain. Any unexpected trailing positional
|
|
171
|
-
* causes a {@link TypoError} deferred to {@link CommandFactory.createInstance}.
|
|
104
|
+
* Creates a leaf command that directly executes an {@link Operation}.
|
|
172
105
|
*
|
|
173
|
-
* @typeParam Context -
|
|
174
|
-
*
|
|
175
|
-
* @typeParam Result - The value returned by the operation handler.
|
|
106
|
+
* @typeParam Context - Context forwarded to the handler.
|
|
107
|
+
* @typeParam Result - Value returned by the handler.
|
|
176
108
|
*
|
|
177
|
-
* @param information -
|
|
178
|
-
* @param operation -
|
|
179
|
-
*
|
|
180
|
-
* @returns A {@link Command} suitable for passing to {@link runAndExit}
|
|
181
|
-
* or composing with {@link commandWithSubcommands} / {@link commandChained}.
|
|
109
|
+
* @param information - Command metadata.
|
|
110
|
+
* @param operation - Options, positionals, and handler.
|
|
111
|
+
* @returns A {@link Command}.
|
|
182
112
|
*
|
|
183
113
|
* @example
|
|
184
114
|
* ```ts
|
|
@@ -199,21 +129,9 @@ export function command<Context, Result>(
|
|
|
199
129
|
getInformation() {
|
|
200
130
|
return information;
|
|
201
131
|
},
|
|
202
|
-
|
|
203
|
-
function generateUsage(): CommandUsage {
|
|
204
|
-
const operationUsage = operation.generateUsage();
|
|
205
|
-
return {
|
|
206
|
-
breadcrumbs: operationUsage.positionals.map((positional) =>
|
|
207
|
-
breadcrumbPositional(positional.label),
|
|
208
|
-
),
|
|
209
|
-
information: information,
|
|
210
|
-
positionals: operationUsage.positionals,
|
|
211
|
-
subcommands: [],
|
|
212
|
-
options: operationUsage.options,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
132
|
+
consumeAndMakeDecoder(readerArgs: ReaderArgs) {
|
|
215
133
|
try {
|
|
216
|
-
const
|
|
134
|
+
const operationDecoder = operation.consumeAndMakeDecoder(readerArgs);
|
|
217
135
|
const endPositional = readerArgs.consumePositional();
|
|
218
136
|
if (endPositional !== undefined) {
|
|
219
137
|
throw new TypoError(
|
|
@@ -224,20 +142,21 @@ export function command<Context, Result>(
|
|
|
224
142
|
);
|
|
225
143
|
}
|
|
226
144
|
return {
|
|
227
|
-
generateUsage,
|
|
228
|
-
|
|
229
|
-
const
|
|
145
|
+
generateUsage: () => generateUsageLeaf(information, operation),
|
|
146
|
+
decodeAndMakeInterpreter() {
|
|
147
|
+
const operationInterpreter =
|
|
148
|
+
operationDecoder.decodeAndMakeInterpreter();
|
|
230
149
|
return {
|
|
231
150
|
async executeWithContext(context: Context) {
|
|
232
|
-
return await
|
|
151
|
+
return await operationInterpreter.executeWithContext(context);
|
|
233
152
|
},
|
|
234
153
|
};
|
|
235
154
|
},
|
|
236
155
|
};
|
|
237
156
|
} catch (error) {
|
|
238
157
|
return {
|
|
239
|
-
generateUsage,
|
|
240
|
-
|
|
158
|
+
generateUsage: () => generateUsageLeaf(information, operation),
|
|
159
|
+
decodeAndMakeInterpreter() {
|
|
241
160
|
throw error;
|
|
242
161
|
},
|
|
243
162
|
};
|
|
@@ -247,34 +166,16 @@ export function command<Context, Result>(
|
|
|
247
166
|
}
|
|
248
167
|
|
|
249
168
|
/**
|
|
250
|
-
* Creates a command that
|
|
251
|
-
* intermediate `Payload`, then dispatches execution to one of several named subcommands
|
|
252
|
-
* based on the next positional argument.
|
|
169
|
+
* Creates a command that runs `operation` first, then dispatches to a named subcommand.
|
|
253
170
|
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
* - If no token is present, a {@link TypoError} is deferred.
|
|
258
|
-
* - If the token does not match any key in `subcommands`, a {@link TypoError} is
|
|
259
|
-
* deferred.
|
|
260
|
-
* 3. The matched subcommand's factory is created with the remaining `readerArgs`.
|
|
171
|
+
* @typeParam Context - Context accepted by `operation`.
|
|
172
|
+
* @typeParam Payload - Output of `operation`; becomes the subcommand's context.
|
|
173
|
+
* @typeParam Result - Value produced by the selected subcommand.
|
|
261
174
|
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
* @
|
|
266
|
-
* @typeParam Payload - The value produced by the root operation and forwarded as the
|
|
267
|
-
* context to the selected subcommand.
|
|
268
|
-
* @typeParam Result - The value produced by the selected subcommand.
|
|
269
|
-
*
|
|
270
|
-
* @param information - Static metadata shown in the top-level usage when no valid
|
|
271
|
-
* subcommand has been selected.
|
|
272
|
-
* @param operation - The operation that is always executed first, before the
|
|
273
|
-
* subcommand. Its output becomes the subcommand's context.
|
|
274
|
-
* @param subcommands - A map of lowercase subcommand names to their
|
|
275
|
-
* {@link Command}s. The keys are the literal tokens the user types.
|
|
276
|
-
* @returns A {@link Command} that dispatches to one of the provided
|
|
277
|
-
* subcommands.
|
|
175
|
+
* @param information - Command metadata.
|
|
176
|
+
* @param operation - Runs first; output becomes the subcommand's context.
|
|
177
|
+
* @param subcommands - Map of subcommand names to their {@link Command}s.
|
|
178
|
+
* @returns A dispatching {@link Command}.
|
|
278
179
|
*
|
|
279
180
|
* @example
|
|
280
181
|
* ```ts
|
|
@@ -297,9 +198,9 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
297
198
|
getInformation() {
|
|
298
199
|
return information;
|
|
299
200
|
},
|
|
300
|
-
|
|
201
|
+
consumeAndMakeDecoder(readerArgs: ReaderArgs) {
|
|
301
202
|
try {
|
|
302
|
-
const
|
|
203
|
+
const operationDecoder = operation.consumeAndMakeDecoder(readerArgs);
|
|
303
204
|
const subcommandName = readerArgs.consumePositional();
|
|
304
205
|
if (subcommandName === undefined) {
|
|
305
206
|
throw new TypoError(
|
|
@@ -320,31 +221,29 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
320
221
|
),
|
|
321
222
|
);
|
|
322
223
|
}
|
|
323
|
-
const
|
|
224
|
+
const subcommandDecoder =
|
|
225
|
+
subcommandInput.consumeAndMakeDecoder(readerArgs);
|
|
324
226
|
return {
|
|
325
227
|
generateUsage() {
|
|
326
|
-
const
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
subcommandUsage.positionals,
|
|
336
|
-
),
|
|
337
|
-
subcommands: subcommandUsage.subcommands,
|
|
338
|
-
options: operationUsage.options.concat(subcommandUsage.options),
|
|
339
|
-
};
|
|
228
|
+
const subcommandUsage = subcommandDecoder.generateUsage();
|
|
229
|
+
const currentUsage = generateUsageLeaf(information, operation);
|
|
230
|
+
currentUsage.segments.push(segmentSubcommand(subcommandName));
|
|
231
|
+
currentUsage.segments.push(...subcommandUsage.segments);
|
|
232
|
+
currentUsage.information = subcommandUsage.information;
|
|
233
|
+
currentUsage.positionals.push(...subcommandUsage.positionals);
|
|
234
|
+
currentUsage.subcommands = subcommandUsage.subcommands;
|
|
235
|
+
currentUsage.options.push(...subcommandUsage.options);
|
|
236
|
+
return currentUsage;
|
|
340
237
|
},
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
238
|
+
decodeAndMakeInterpreter() {
|
|
239
|
+
const operationInterpreter =
|
|
240
|
+
operationDecoder.decodeAndMakeInterpreter();
|
|
241
|
+
const subcommandInterpreter =
|
|
242
|
+
subcommandDecoder.decodeAndMakeInterpreter();
|
|
344
243
|
return {
|
|
345
244
|
async executeWithContext(context: Context) {
|
|
346
|
-
return await
|
|
347
|
-
await
|
|
245
|
+
return await subcommandInterpreter.executeWithContext(
|
|
246
|
+
await operationInterpreter.executeWithContext(context),
|
|
348
247
|
);
|
|
349
248
|
},
|
|
350
249
|
};
|
|
@@ -353,25 +252,15 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
353
252
|
} catch (error) {
|
|
354
253
|
return {
|
|
355
254
|
generateUsage() {
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
subcommands: Object.entries(subcommands).map((subcommand) => {
|
|
364
|
-
const metadata = subcommand[1].getInformation();
|
|
365
|
-
return {
|
|
366
|
-
name: subcommand[0],
|
|
367
|
-
description: metadata.description,
|
|
368
|
-
hint: metadata.hint,
|
|
369
|
-
};
|
|
370
|
-
}),
|
|
371
|
-
options: operationUsage.options,
|
|
372
|
-
};
|
|
255
|
+
const currentUsage = generateUsageLeaf(information, operation);
|
|
256
|
+
currentUsage.segments.push(segmentPositional("<SUBCOMMAND>"));
|
|
257
|
+
for (const [name, subcommand] of Object.entries(subcommands)) {
|
|
258
|
+
const { description, hint } = subcommand.getInformation();
|
|
259
|
+
currentUsage.subcommands.push({ name, description, hint });
|
|
260
|
+
}
|
|
261
|
+
return currentUsage;
|
|
373
262
|
},
|
|
374
|
-
|
|
263
|
+
decodeAndMakeInterpreter() {
|
|
375
264
|
throw error;
|
|
376
265
|
},
|
|
377
266
|
};
|
|
@@ -381,36 +270,17 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
381
270
|
}
|
|
382
271
|
|
|
383
272
|
/**
|
|
384
|
-
*
|
|
385
|
-
*
|
|
273
|
+
* Chains an {@link Operation} and a {@link Command}: `operation` runs first, its
|
|
274
|
+
* output becomes `subcommand`'s context. No token is consumed for routing.
|
|
386
275
|
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* different sub-actions.
|
|
276
|
+
* @typeParam Context - Context accepted by `operation`.
|
|
277
|
+
* @typeParam Payload - Output of `operation`; becomes `subcommand`'s context.
|
|
278
|
+
* @typeParam Result - Value produced by `subcommand`.
|
|
391
279
|
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* 3. At execution time, `operation` runs first; its result is passed as the context to
|
|
397
|
-
* `nextCommand`.
|
|
398
|
-
*
|
|
399
|
-
* **Usage:** breadcrumbs, positionals, and options from both stages are merged into a
|
|
400
|
-
* single flat usage description. The `information` of `nextCommand` takes precedence in
|
|
401
|
-
* the generated usage output.
|
|
402
|
-
*
|
|
403
|
-
* @typeParam Context - The context value accepted by `operation`.
|
|
404
|
-
* @typeParam Payload - The value produced by `operation` and used as the context for
|
|
405
|
-
* `nextCommand`.
|
|
406
|
-
* @typeParam Result - The value produced by `nextCommand`.
|
|
407
|
-
*
|
|
408
|
-
* @param information - Fallback metadata used in the usage output when `nextCommand`'s
|
|
409
|
-
* factory cannot be created (i.e. on parse error in the next stage).
|
|
410
|
-
* @param operation - The first stage operation. Its output becomes `nextCommand`'s
|
|
411
|
-
* context.
|
|
412
|
-
* @param nextCommand - The second stage command, executed after `operation` succeeds.
|
|
413
|
-
* @returns A {@link Command} that transparently composes the two stages.
|
|
280
|
+
* @param information - Command metadata.
|
|
281
|
+
* @param operation - Runs first; output becomes `subcommand`'s context.
|
|
282
|
+
* @param subcommand - Runs after `operation`.
|
|
283
|
+
* @returns A {@link Command} composing both stages.
|
|
414
284
|
*
|
|
415
285
|
* @example
|
|
416
286
|
* ```ts
|
|
@@ -427,39 +297,36 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
427
297
|
export function commandChained<Context, Payload, Result>(
|
|
428
298
|
information: CommandInformation,
|
|
429
299
|
operation: Operation<Context, Payload>,
|
|
430
|
-
|
|
300
|
+
subcommand: Command<Payload, Result>,
|
|
431
301
|
): Command<Context, Result> {
|
|
432
302
|
return {
|
|
433
303
|
getInformation() {
|
|
434
304
|
return information;
|
|
435
305
|
},
|
|
436
|
-
|
|
306
|
+
consumeAndMakeDecoder(readerArgs: ReaderArgs) {
|
|
437
307
|
try {
|
|
438
|
-
const
|
|
439
|
-
const
|
|
308
|
+
const operationDecoder = operation.consumeAndMakeDecoder(readerArgs);
|
|
309
|
+
const subcommandDecoder = subcommand.consumeAndMakeDecoder(readerArgs);
|
|
440
310
|
return {
|
|
441
311
|
generateUsage() {
|
|
442
|
-
const
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
nextCommandUsage.positionals,
|
|
451
|
-
),
|
|
452
|
-
subcommands: nextCommandUsage.subcommands,
|
|
453
|
-
options: operationUsage.options.concat(nextCommandUsage.options),
|
|
454
|
-
};
|
|
312
|
+
const subcommandUsage = subcommandDecoder.generateUsage();
|
|
313
|
+
const currentUsage = generateUsageLeaf(information, operation);
|
|
314
|
+
currentUsage.segments.push(...subcommandUsage.segments);
|
|
315
|
+
currentUsage.information = subcommandUsage.information;
|
|
316
|
+
currentUsage.positionals.push(...subcommandUsage.positionals);
|
|
317
|
+
currentUsage.subcommands = subcommandUsage.subcommands;
|
|
318
|
+
currentUsage.options.push(...subcommandUsage.options);
|
|
319
|
+
return currentUsage;
|
|
455
320
|
},
|
|
456
|
-
|
|
457
|
-
const
|
|
458
|
-
|
|
321
|
+
decodeAndMakeInterpreter() {
|
|
322
|
+
const operationInterpreter =
|
|
323
|
+
operationDecoder.decodeAndMakeInterpreter();
|
|
324
|
+
const subcommandInterpreter =
|
|
325
|
+
subcommandDecoder.decodeAndMakeInterpreter();
|
|
459
326
|
return {
|
|
460
327
|
async executeWithContext(context: Context) {
|
|
461
|
-
return await
|
|
462
|
-
await
|
|
328
|
+
return await subcommandInterpreter.executeWithContext(
|
|
329
|
+
await operationInterpreter.executeWithContext(context),
|
|
463
330
|
);
|
|
464
331
|
},
|
|
465
332
|
};
|
|
@@ -468,18 +335,11 @@ export function commandChained<Context, Payload, Result>(
|
|
|
468
335
|
} catch (error) {
|
|
469
336
|
return {
|
|
470
337
|
generateUsage() {
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
.map((positional) => breadcrumbPositional(positional.label))
|
|
475
|
-
.concat([breadcrumbPositional("[REST]...")]),
|
|
476
|
-
information: information,
|
|
477
|
-
positionals: operationUsage.positionals,
|
|
478
|
-
subcommands: [],
|
|
479
|
-
options: operationUsage.options,
|
|
480
|
-
};
|
|
338
|
+
const currentUsage = generateUsageLeaf(information, operation);
|
|
339
|
+
currentUsage.segments.push(segmentPositional("[REST]..."));
|
|
340
|
+
return currentUsage;
|
|
481
341
|
},
|
|
482
|
-
|
|
342
|
+
decodeAndMakeInterpreter() {
|
|
483
343
|
throw error;
|
|
484
344
|
},
|
|
485
345
|
};
|
|
@@ -488,10 +348,26 @@ export function commandChained<Context, Payload, Result>(
|
|
|
488
348
|
};
|
|
489
349
|
}
|
|
490
350
|
|
|
491
|
-
function
|
|
351
|
+
function segmentPositional(value: string): UsageSegment {
|
|
492
352
|
return { positional: value };
|
|
493
353
|
}
|
|
494
354
|
|
|
495
|
-
function
|
|
496
|
-
return {
|
|
355
|
+
function segmentSubcommand(value: string): UsageSegment {
|
|
356
|
+
return { subcommand: value };
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function generateUsageLeaf(
|
|
360
|
+
information: CommandInformation,
|
|
361
|
+
operation: Operation<any, any>,
|
|
362
|
+
): UsageCommand {
|
|
363
|
+
const { positionals, options } = operation.generateUsage();
|
|
364
|
+
return {
|
|
365
|
+
segments: positionals.map((positional) =>
|
|
366
|
+
segmentPositional(positional.label),
|
|
367
|
+
),
|
|
368
|
+
information,
|
|
369
|
+
positionals,
|
|
370
|
+
subcommands: [],
|
|
371
|
+
options,
|
|
372
|
+
};
|
|
497
373
|
}
|