cli-kiss 0.2.1 → 0.2.3
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 -2
- package/dist/index.d.ts +527 -830
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/.vitepress/config.mts +3 -0
- package/docs/guide/01_getting_started.md +9 -9
- package/docs/guide/02_commands.md +6 -11
- package/docs/guide/03_options.md +4 -6
- package/docs/guide/04_positionals.md +6 -8
- package/docs/guide/05_types.md +8 -10
- package/docs/guide/06_run.md +6 -7
- package/docs/index.md +4 -4
- package/package.json +1 -1
- package/src/lib/Command.ts +189 -256
- package/src/lib/Operation.ts +68 -82
- package/src/lib/Option.ts +115 -132
- package/src/lib/Positional.ts +95 -100
- package/src/lib/Reader.ts +53 -78
- package/src/lib/Run.ts +40 -58
- package/src/lib/Type.ts +81 -141
- package/src/lib/Typo.ts +121 -164
- package/src/lib/Usage.ts +56 -18
- package/tests/unit.command.execute.ts +83 -71
- package/tests/unit.command.usage.ts +230 -109
- package/tests/unit.runner.cycle.ts +56 -7
package/src/lib/Operation.ts
CHANGED
|
@@ -1,114 +1,89 @@
|
|
|
1
|
-
import { Option, OptionUsage } from "./Option";
|
|
2
|
-
import { Positional, PositionalUsage } from "./Positional";
|
|
1
|
+
import { Option, OptionDecoder, OptionUsage } from "./Option";
|
|
2
|
+
import { Positional, PositionalDecoder, PositionalUsage } from "./Positional";
|
|
3
3
|
import { ReaderArgs } from "./Reader";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* async execution handler that together form the core logic of a CLI command.
|
|
6
|
+
* Options, positionals, and an async handler that together form the logic of a CLI command.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
* {@link
|
|
11
|
-
* a full {@link CommandDescriptor}.
|
|
8
|
+
* Created with {@link operation} and passed to {@link command},
|
|
9
|
+
* {@link commandWithSubcommands}, or {@link commandChained}.
|
|
12
10
|
*
|
|
13
|
-
* @typeParam
|
|
14
|
-
*
|
|
15
|
-
* @typeParam Output - The value the handler produces. For leaf operations this is
|
|
16
|
-
* typically `void`; for intermediate stages it is the payload forwarded to the next
|
|
17
|
-
* command in a chain.
|
|
11
|
+
* @typeParam Context - Injected at execution time; forwarded to handlers. Use to inject dependencies.
|
|
12
|
+
* @typeParam Result - Value produced on execution; typically `void` for leaf commands.
|
|
18
13
|
*/
|
|
19
|
-
export type
|
|
14
|
+
export type Operation<Context, Result> = {
|
|
20
15
|
/**
|
|
21
|
-
* Returns usage metadata
|
|
22
|
-
* Called by the parent command factory when building the help/usage output.
|
|
16
|
+
* Returns usage metadata without consuming any arguments.
|
|
23
17
|
*/
|
|
24
18
|
generateUsage(): OperationUsage;
|
|
25
19
|
/**
|
|
26
|
-
*
|
|
27
|
-
* {@link OperationFactory} that can create a ready-to-execute
|
|
28
|
-
* {@link OperationInstance}.
|
|
29
|
-
*
|
|
30
|
-
* Any parse error (unknown option, type mismatch, etc.) is captured and re-thrown
|
|
31
|
-
* when {@link OperationFactory.createInstance} is called.
|
|
32
|
-
*
|
|
33
|
-
* @param readerArgs - The shared argument reader. Options are registered on it and
|
|
34
|
-
* positionals are consumed in declaration order.
|
|
20
|
+
* Consumes args from `readerArgs` and returns an {@link OperationDecoder}.
|
|
35
21
|
*/
|
|
36
|
-
|
|
22
|
+
consumeAndMakeDecoder(
|
|
23
|
+
readerArgs: ReaderArgs,
|
|
24
|
+
): OperationDecoder<Context, Result>;
|
|
37
25
|
};
|
|
38
26
|
|
|
39
27
|
/**
|
|
40
|
-
* Produced by {@link
|
|
41
|
-
* Instantiating it finalises value extraction and produces an {@link OperationInstance}.
|
|
28
|
+
* Produced by {@link Operation.consumeAndMakeDecoder}.
|
|
42
29
|
*
|
|
43
|
-
* @typeParam
|
|
44
|
-
* @typeParam
|
|
30
|
+
* @typeParam Context - See {@link Operation}.
|
|
31
|
+
* @typeParam Result - See {@link Operation}.
|
|
45
32
|
*/
|
|
46
|
-
export type
|
|
33
|
+
export type OperationDecoder<Context, Result> = {
|
|
47
34
|
/**
|
|
48
|
-
*
|
|
49
|
-
* {@link OperationInstance} ready for execution.
|
|
35
|
+
* Creates a ready-to-execute {@link OperationInterpreter}.
|
|
50
36
|
*
|
|
51
|
-
* @throws {@link TypoError} if
|
|
52
|
-
* {@link OperationDescriptor.createFactory}.
|
|
37
|
+
* @throws {@link TypoError} if parsing or decoding failed.
|
|
53
38
|
*/
|
|
54
|
-
|
|
39
|
+
decodeAndMakeInterpreter(): OperationInterpreter<Context, Result>;
|
|
55
40
|
};
|
|
56
41
|
|
|
57
42
|
/**
|
|
58
|
-
* A fully parsed, ready-to-execute operation.
|
|
43
|
+
* A fully parsed, decoded and ready-to-execute operation.
|
|
59
44
|
*
|
|
60
|
-
* @typeParam
|
|
61
|
-
* @typeParam
|
|
45
|
+
* @typeParam Context - Caller-supplied context.
|
|
46
|
+
* @typeParam Result - Value produced on success.
|
|
62
47
|
*/
|
|
63
|
-
export type
|
|
48
|
+
export type OperationInterpreter<Context, Result> = {
|
|
64
49
|
/**
|
|
65
|
-
*
|
|
66
|
-
* option/positional values.
|
|
67
|
-
*
|
|
68
|
-
* @param input - Context from the parent command (or the root context supplied to
|
|
69
|
-
* {@link runAndExit}).
|
|
70
|
-
* @returns A promise resolving to the handler's return value.
|
|
50
|
+
* Executes with the provided context.
|
|
71
51
|
*/
|
|
72
|
-
executeWithContext(
|
|
52
|
+
executeWithContext(context: Context): Promise<Result>;
|
|
73
53
|
};
|
|
74
54
|
|
|
75
55
|
/**
|
|
76
|
-
*
|
|
77
|
-
* Consumed
|
|
56
|
+
* Usage metadata produced by {@link Operation.generateUsage}.
|
|
57
|
+
* Consumed when building {@link CommandUsage}.
|
|
78
58
|
*/
|
|
79
59
|
export type OperationUsage = {
|
|
80
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Usage descriptors for all registered options.
|
|
62
|
+
*/
|
|
81
63
|
options: Array<OptionUsage>;
|
|
82
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Usage descriptors for all declared positionals, in order.
|
|
66
|
+
*/
|
|
83
67
|
positionals: Array<PositionalUsage>;
|
|
84
68
|
};
|
|
85
69
|
|
|
86
70
|
/**
|
|
87
|
-
* Creates an {@link
|
|
88
|
-
* async handler function.
|
|
71
|
+
* Creates an {@link Operation} from options, positionals, and an async handler.
|
|
89
72
|
*
|
|
90
|
-
* The `handler` receives
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* - `inputs.options` — an object whose keys match those declared in `inputs.options` and whose values are
|
|
94
|
-
* the parsed option values.
|
|
95
|
-
* - `inputs.positionals` — a tuple whose elements match `inputs.positionals` and whose
|
|
96
|
-
* values are the parsed positional values, in declaration order.
|
|
73
|
+
* The `handler` receives the parent `context` and an `inputs` object with
|
|
74
|
+
* `options` (keyed by the same names declared in `inputs.options`) and
|
|
75
|
+
* `positionals` (a tuple in declaration order).
|
|
97
76
|
*
|
|
98
|
-
* @typeParam Context -
|
|
99
|
-
* @typeParam Result -
|
|
100
|
-
* @typeParam Options -
|
|
101
|
-
* @typeParam Positionals - Tuple
|
|
77
|
+
* @typeParam Context - Context type accepted by the handler.
|
|
78
|
+
* @typeParam Result - Return type of the handler.
|
|
79
|
+
* @typeParam Options - Map of option keys to parsed value types.
|
|
80
|
+
* @typeParam Positionals - Tuple of parsed positional value types, in order.
|
|
102
81
|
*
|
|
103
|
-
* @param inputs -
|
|
104
|
-
* @param inputs.options -
|
|
105
|
-
*
|
|
106
|
-
* @param
|
|
107
|
-
*
|
|
108
|
-
* same order.
|
|
109
|
-
* @param handler - The async function that implements the command logic. Receives the
|
|
110
|
-
* execution context and all parsed inputs.
|
|
111
|
-
* @returns An {@link OperationDescriptor} ready to be composed into a command.
|
|
82
|
+
* @param inputs - Options and positionals this operation accepts.
|
|
83
|
+
* @param inputs.options - Map of keys to {@link Option} descriptors.
|
|
84
|
+
* @param inputs.positionals - Ordered array of {@link Positional} descriptors.
|
|
85
|
+
* @param handler - Async function implementing the command logic.
|
|
86
|
+
* @returns An {@link Operation} ready to be composed into a command.
|
|
112
87
|
*
|
|
113
88
|
* @example
|
|
114
89
|
* ```ts
|
|
@@ -140,9 +115,12 @@ export function operation<
|
|
|
140
115
|
},
|
|
141
116
|
handler: (
|
|
142
117
|
context: Context,
|
|
143
|
-
inputs: {
|
|
118
|
+
inputs: {
|
|
119
|
+
options: Options;
|
|
120
|
+
positionals: Positionals;
|
|
121
|
+
},
|
|
144
122
|
) => Promise<Result>,
|
|
145
|
-
):
|
|
123
|
+
): Operation<Context, Result> {
|
|
146
124
|
return {
|
|
147
125
|
generateUsage() {
|
|
148
126
|
const optionsUsage = new Array<OptionUsage>();
|
|
@@ -158,21 +136,29 @@ export function operation<
|
|
|
158
136
|
}
|
|
159
137
|
return { options: optionsUsage, positionals: positionalsUsage };
|
|
160
138
|
},
|
|
161
|
-
|
|
162
|
-
const
|
|
139
|
+
consumeAndMakeDecoder(readerArgs: ReaderArgs) {
|
|
140
|
+
const optionsDecoders: Record<string, OptionDecoder<any>> = {};
|
|
163
141
|
for (const optionKey in inputs.options) {
|
|
164
142
|
const optionInput = inputs.options[optionKey]!;
|
|
165
|
-
|
|
143
|
+
optionsDecoders[optionKey] =
|
|
144
|
+
optionInput.registerAndMakeDecoder(readerArgs);
|
|
166
145
|
}
|
|
167
|
-
const
|
|
146
|
+
const positionalsDecoders: Array<PositionalDecoder<any>> = [];
|
|
168
147
|
for (const positionalInput of inputs.positionals) {
|
|
169
|
-
|
|
148
|
+
positionalsDecoders.push(
|
|
149
|
+
positionalInput.consumeAndMakeDecoder(readerArgs),
|
|
150
|
+
);
|
|
170
151
|
}
|
|
171
152
|
return {
|
|
172
|
-
|
|
153
|
+
decodeAndMakeInterpreter() {
|
|
173
154
|
const optionsValues: any = {};
|
|
174
|
-
for (const optionKey in
|
|
175
|
-
optionsValues[optionKey] =
|
|
155
|
+
for (const optionKey in optionsDecoders) {
|
|
156
|
+
optionsValues[optionKey] =
|
|
157
|
+
optionsDecoders[optionKey]!.getAndDecodeValue();
|
|
158
|
+
}
|
|
159
|
+
const positionalsValues: any = [];
|
|
160
|
+
for (const positionalDecoder of positionalsDecoders) {
|
|
161
|
+
positionalsValues.push(positionalDecoder.decodeValue());
|
|
176
162
|
}
|
|
177
163
|
return {
|
|
178
164
|
executeWithContext(context: Context) {
|
package/src/lib/Option.ts
CHANGED
|
@@ -10,95 +10,78 @@ import {
|
|
|
10
10
|
} from "./Typo";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
* and usage-generation logic.
|
|
13
|
+
* A CLI option (flag or valued) with its parsing and usage-generation logic.
|
|
15
14
|
*
|
|
16
|
-
*
|
|
17
|
-
* {@link optionRepeatable} and
|
|
15
|
+
* Created with {@link optionFlag}, {@link optionSingleValue}, or
|
|
16
|
+
* {@link optionRepeatable} and passed via the `options` map of {@link operation}.
|
|
18
17
|
*
|
|
19
|
-
* @typeParam Value -
|
|
20
|
-
* - `boolean` for flags created with {@link optionFlag}.
|
|
21
|
-
* - `T` for single-value options created with {@link optionSingleValue}.
|
|
22
|
-
* - `Array<T>` for repeatable options created with {@link optionRepeatable}.
|
|
18
|
+
* @typeParam Value - Decoded value type.
|
|
23
19
|
*/
|
|
24
20
|
export type Option<Value> = {
|
|
25
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Returns metadata used to render the `Options:` section of help.
|
|
23
|
+
*/
|
|
26
24
|
generateUsage(): OptionUsage;
|
|
27
25
|
/**
|
|
28
|
-
* Registers the option on `readerOptions`
|
|
29
|
-
|
|
26
|
+
* Registers the option on `readerOptions` and returns an {@link OptionDecoder}.
|
|
27
|
+
*/
|
|
28
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions): OptionDecoder<Value>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Produced by {@link Option.registerAndMakeDecoder}.
|
|
33
|
+
*
|
|
34
|
+
* @typeParam Value - Decoded value type.
|
|
35
|
+
*/
|
|
36
|
+
export type OptionDecoder<Value> = {
|
|
37
|
+
/**
|
|
38
|
+
* Returns the decoded option value.
|
|
30
39
|
*
|
|
31
|
-
* @
|
|
32
|
-
* command-line tokens.
|
|
40
|
+
* @throws {@link TypoError} if decoding failed.
|
|
33
41
|
*/
|
|
34
|
-
|
|
42
|
+
getAndDecodeValue(): Value;
|
|
35
43
|
};
|
|
36
44
|
|
|
37
45
|
/**
|
|
38
|
-
* Human-readable metadata for a single
|
|
46
|
+
* Human-readable metadata for a single option, used to render the `Options:` section
|
|
39
47
|
* of the help output produced by {@link usageToStyledLines}.
|
|
40
48
|
*/
|
|
41
49
|
export type OptionUsage = {
|
|
42
|
-
/** Short description of what the option does. */
|
|
43
|
-
description: string | undefined;
|
|
44
50
|
/**
|
|
45
|
-
*
|
|
46
|
-
* Suitable for short caveats such as `"required"` or `"defaults to 42"`.
|
|
51
|
+
* Long-form name without `--` (e.g. `"verbose"`).
|
|
47
52
|
*/
|
|
48
|
-
|
|
53
|
+
long: Lowercase<string>;
|
|
49
54
|
/**
|
|
50
|
-
*
|
|
51
|
-
* The user passes this as `--verbose` on the command line.
|
|
55
|
+
* Short-form name without `-` (e.g. `"v"`).
|
|
52
56
|
*/
|
|
53
|
-
|
|
57
|
+
short: string | undefined;
|
|
54
58
|
/**
|
|
55
|
-
*
|
|
56
|
-
* The user passes this as `-v` on the command line.
|
|
59
|
+
* Help text in usage.
|
|
57
60
|
*/
|
|
58
|
-
|
|
61
|
+
description: string | undefined;
|
|
59
62
|
/**
|
|
60
|
-
*
|
|
61
|
-
* (e.g. `"<FILE>"`). `undefined` for flags that take no value.
|
|
63
|
+
* Short note shown in parentheses.
|
|
62
64
|
*/
|
|
63
|
-
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Retrieves the parsed value for a registered option after argument parsing is complete.
|
|
68
|
-
*
|
|
69
|
-
* Returned by {@link Option.createGetter} and called by {@link OperationFactory.createInstance}.
|
|
70
|
-
*
|
|
71
|
-
* @typeParam Value - The TypeScript type of the parsed value.
|
|
72
|
-
*/
|
|
73
|
-
export type OptionGetter<Value> = {
|
|
65
|
+
hint: string | undefined;
|
|
74
66
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* @throws {@link TypoError} if the option appeared more times than allowed, the value
|
|
78
|
-
* failed type decoding, or a required default could not be computed.
|
|
67
|
+
* Value placeholder in help (e.g. `"<FILE>"`). `undefined` for flags.
|
|
79
68
|
*/
|
|
80
|
-
|
|
69
|
+
label: Uppercase<string> | undefined;
|
|
81
70
|
};
|
|
82
71
|
|
|
83
72
|
/**
|
|
84
|
-
* Creates a boolean flag option
|
|
85
|
-
* `--verbose`) to signal `true`, or can explicitly set with `--flag=true` / `--flag=no`.
|
|
73
|
+
* Creates a boolean flag option (`--verbose`, optionally `--flag=no`).
|
|
86
74
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* - `--flag` / `--flag=true` / `--flag=yes` → `true`.
|
|
90
|
-
* - `--flag=false` / `--flag=no` → `false`.
|
|
91
|
-
* - Specified more than once → {@link TypoError} ("Must not be set multiple times").
|
|
75
|
+
* Parsing: absent → `false`; `--flag` / `--flag=yes` → `true`; `--flag=no` → `false`;
|
|
76
|
+
* specified more than once → {@link TypoError}.
|
|
92
77
|
*
|
|
93
|
-
* @param definition -
|
|
94
|
-
* @param definition.long -
|
|
95
|
-
* @param definition.short -
|
|
96
|
-
* @param definition.description -
|
|
97
|
-
* @param definition.hint -
|
|
98
|
-
* @param definition.aliases - Additional
|
|
99
|
-
*
|
|
100
|
-
* @param definition.default - Factory for the default value when the flag is absent.
|
|
101
|
-
* Defaults to `() => false` when omitted.
|
|
78
|
+
* @param definition - Flag configuration.
|
|
79
|
+
* @param definition.long - Long-form name (without `--`).
|
|
80
|
+
* @param definition.short - Short-form name (without `-`).
|
|
81
|
+
* @param definition.description - Help text.
|
|
82
|
+
* @param definition.hint - Short note shown in parentheses.
|
|
83
|
+
* @param definition.aliases - Additional names.
|
|
84
|
+
* @param definition.default - Default when absent. Defaults to `() => false`.
|
|
102
85
|
* @returns An {@link Option}`<boolean>`.
|
|
103
86
|
*
|
|
104
87
|
* @example
|
|
@@ -129,13 +112,13 @@ export function optionFlag(definition: {
|
|
|
129
112
|
label: undefined,
|
|
130
113
|
};
|
|
131
114
|
},
|
|
132
|
-
|
|
115
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions) {
|
|
133
116
|
const key = registerOption(readerOptions, {
|
|
134
117
|
...definition,
|
|
135
118
|
valued: false,
|
|
136
119
|
});
|
|
137
120
|
return {
|
|
138
|
-
|
|
121
|
+
getAndDecodeValue() {
|
|
139
122
|
const optionValues = readerOptions.getOptionValues(key);
|
|
140
123
|
if (optionValues.length > 1) {
|
|
141
124
|
throw new TypoError(
|
|
@@ -159,7 +142,13 @@ export function optionFlag(definition: {
|
|
|
159
142
|
);
|
|
160
143
|
}
|
|
161
144
|
}
|
|
162
|
-
return decodeValue(
|
|
145
|
+
return decodeValue({
|
|
146
|
+
long: definition.long,
|
|
147
|
+
short: definition.short,
|
|
148
|
+
label,
|
|
149
|
+
type: typeBoolean,
|
|
150
|
+
input: optionValue,
|
|
151
|
+
});
|
|
163
152
|
},
|
|
164
153
|
};
|
|
165
154
|
},
|
|
@@ -167,32 +156,22 @@ export function optionFlag(definition: {
|
|
|
167
156
|
}
|
|
168
157
|
|
|
169
158
|
/**
|
|
170
|
-
* Creates an option that accepts exactly one value (e.g. `--output dist/`
|
|
171
|
-
* `--output=dist/`).
|
|
159
|
+
* Creates an option that accepts exactly one value (e.g. `--output dist/`).
|
|
172
160
|
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* {@link TypoError} is produced.
|
|
176
|
-
* - Specified once → the value is decoded with `definition.type`.
|
|
177
|
-
* - Specified more than once → {@link TypoError} ("Requires a single value, but got
|
|
178
|
-
* multiple").
|
|
161
|
+
* Parsing: absent → `default()`; once → decoded with `type`; more than once → {@link TypoError}.
|
|
162
|
+
* Value syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
|
|
179
163
|
*
|
|
180
|
-
*
|
|
181
|
-
* `-s=value`, or `-svalue`.
|
|
164
|
+
* @typeParam Value - Type produced by the decoder.
|
|
182
165
|
*
|
|
183
|
-
* @
|
|
184
|
-
*
|
|
185
|
-
* @param definition -
|
|
186
|
-
* @param definition.
|
|
187
|
-
* @param definition.
|
|
188
|
-
* @param definition.
|
|
189
|
-
* @param definition.
|
|
190
|
-
* @param definition.
|
|
191
|
-
* @param definition.
|
|
192
|
-
* Defaults to the uppercased `type.content`.
|
|
193
|
-
* @param definition.type - The {@link Type} used to decode the raw string value.
|
|
194
|
-
* @param definition.default - Factory for the default value when the option is absent.
|
|
195
|
-
* Throw an error from this factory to make the option effectively required.
|
|
166
|
+
* @param definition - Option configuration.
|
|
167
|
+
* @param definition.long - Long-form name (without `--`).
|
|
168
|
+
* @param definition.short - Short-form name (without `-`).
|
|
169
|
+
* @param definition.description - Help text.
|
|
170
|
+
* @param definition.hint - Short note shown in parentheses.
|
|
171
|
+
* @param definition.aliases - Additional names.
|
|
172
|
+
* @param definition.label - Value placeholder in help. Defaults to uppercased `type.content`.
|
|
173
|
+
* @param definition.type - Decoder for the raw string value.
|
|
174
|
+
* @param definition.default - Default when absent. Throw to make the option required.
|
|
196
175
|
* @returns An {@link Option}`<Value>`.
|
|
197
176
|
*
|
|
198
177
|
* @example
|
|
@@ -228,13 +207,13 @@ export function optionSingleValue<Value>(definition: {
|
|
|
228
207
|
label: label as Uppercase<string>,
|
|
229
208
|
};
|
|
230
209
|
},
|
|
231
|
-
|
|
210
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions) {
|
|
232
211
|
const key = registerOption(readerOptions, {
|
|
233
212
|
...definition,
|
|
234
213
|
valued: true,
|
|
235
214
|
});
|
|
236
215
|
return {
|
|
237
|
-
|
|
216
|
+
getAndDecodeValue() {
|
|
238
217
|
const optionValues = readerOptions.getOptionValues(key);
|
|
239
218
|
if (optionValues.length > 1) {
|
|
240
219
|
throw new TypoError(
|
|
@@ -258,12 +237,13 @@ export function optionSingleValue<Value>(definition: {
|
|
|
258
237
|
);
|
|
259
238
|
}
|
|
260
239
|
}
|
|
261
|
-
return decodeValue(
|
|
262
|
-
definition.long,
|
|
240
|
+
return decodeValue({
|
|
241
|
+
long: definition.long,
|
|
242
|
+
short: definition.short,
|
|
263
243
|
label,
|
|
264
|
-
definition.type,
|
|
265
|
-
optionValue,
|
|
266
|
-
);
|
|
244
|
+
type: definition.type,
|
|
245
|
+
input: optionValue,
|
|
246
|
+
});
|
|
267
247
|
},
|
|
268
248
|
};
|
|
269
249
|
},
|
|
@@ -271,30 +251,21 @@ export function optionSingleValue<Value>(definition: {
|
|
|
271
251
|
}
|
|
272
252
|
|
|
273
253
|
/**
|
|
274
|
-
* Creates an option that
|
|
275
|
-
* values into an array (e.g. `--file a.ts --file b.ts`).
|
|
254
|
+
* Creates an option that collects every occurrence into an array (e.g. `--file a.ts --file b.ts`).
|
|
276
255
|
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* - Specified N times → array of N decoded values, in the order they appear on the
|
|
280
|
-
* command line.
|
|
281
|
-
* - Each occurrence is decoded independently with `definition.type`.
|
|
256
|
+
* Parsing: absent → `[]`; N occurrences → array of N decoded values in order.
|
|
257
|
+
* Value syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
|
|
282
258
|
*
|
|
283
|
-
*
|
|
284
|
-
* `-s=value`, or `-svalue`.
|
|
259
|
+
* @typeParam Value - Type produced by the decoder for each occurrence.
|
|
285
260
|
*
|
|
286
|
-
* @
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
* @param definition -
|
|
290
|
-
* @param definition.
|
|
291
|
-
* @param definition.
|
|
292
|
-
* @param definition.
|
|
293
|
-
* @param definition.
|
|
294
|
-
* @param definition.aliases - Additional long/short names the parser also recognises.
|
|
295
|
-
* @param definition.label - Custom label shown in the help output (e.g. `"FILE"`).
|
|
296
|
-
* Defaults to the uppercased `type.content`.
|
|
297
|
-
* @param definition.type - The {@link Type} used to decode each raw string value.
|
|
261
|
+
* @param definition - Option configuration.
|
|
262
|
+
* @param definition.long - Long-form name (without `--`).
|
|
263
|
+
* @param definition.short - Short-form name (without `-`).
|
|
264
|
+
* @param definition.description - Help text.
|
|
265
|
+
* @param definition.hint - Short note shown in parentheses.
|
|
266
|
+
* @param definition.aliases - Additional names.
|
|
267
|
+
* @param definition.label - Value placeholder in help. Defaults to uppercased `type.content`.
|
|
268
|
+
* @param definition.type - Decoder applied to each raw string value.
|
|
298
269
|
* @returns An {@link Option}`<Array<Value>>`.
|
|
299
270
|
*
|
|
300
271
|
* @example
|
|
@@ -330,16 +301,22 @@ export function optionRepeatable<Value>(definition: {
|
|
|
330
301
|
label: label as Uppercase<string>,
|
|
331
302
|
};
|
|
332
303
|
},
|
|
333
|
-
|
|
304
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions) {
|
|
334
305
|
const key = registerOption(readerOptions, {
|
|
335
306
|
...definition,
|
|
336
307
|
valued: true,
|
|
337
308
|
});
|
|
338
309
|
return {
|
|
339
|
-
|
|
310
|
+
getAndDecodeValue() {
|
|
340
311
|
const optionValues = readerOptions.getOptionValues(key);
|
|
341
312
|
return optionValues.map((optionValue) =>
|
|
342
|
-
decodeValue(
|
|
313
|
+
decodeValue({
|
|
314
|
+
long: definition.long,
|
|
315
|
+
short: definition.short,
|
|
316
|
+
label,
|
|
317
|
+
type: definition.type,
|
|
318
|
+
input: optionValue,
|
|
319
|
+
}),
|
|
343
320
|
);
|
|
344
321
|
},
|
|
345
322
|
};
|
|
@@ -347,22 +324,28 @@ export function optionRepeatable<Value>(definition: {
|
|
|
347
324
|
};
|
|
348
325
|
}
|
|
349
326
|
|
|
350
|
-
function decodeValue<Value>(
|
|
351
|
-
long: string
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
327
|
+
function decodeValue<Value>(params: {
|
|
328
|
+
long: string;
|
|
329
|
+
short: string | undefined;
|
|
330
|
+
label: string;
|
|
331
|
+
type: Type<Value>;
|
|
332
|
+
input: string;
|
|
333
|
+
}): Value {
|
|
356
334
|
return TypoError.tryWithContext(
|
|
357
|
-
() => type.decoder(
|
|
358
|
-
() =>
|
|
359
|
-
new TypoText(
|
|
360
|
-
|
|
361
|
-
new TypoString(
|
|
362
|
-
new TypoString(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
)
|
|
335
|
+
() => params.type.decoder(params.input),
|
|
336
|
+
() => {
|
|
337
|
+
const text = new TypoText();
|
|
338
|
+
if (params.short) {
|
|
339
|
+
text.pushString(new TypoString(`-${params.short}`, typoStyleConstants));
|
|
340
|
+
text.pushString(new TypoString(`, `));
|
|
341
|
+
}
|
|
342
|
+
text.pushString(new TypoString(`--${params.long}`, typoStyleConstants));
|
|
343
|
+
text.pushString(new TypoString(`: `));
|
|
344
|
+
text.pushString(new TypoString(params.label, typoStyleUserInput));
|
|
345
|
+
text.pushString(new TypoString(`: `));
|
|
346
|
+
text.pushString(new TypoString(params.type.content, typoStyleLogic));
|
|
347
|
+
return text;
|
|
348
|
+
},
|
|
366
349
|
);
|
|
367
350
|
}
|
|
368
351
|
|