cli-kiss 0.2.2 → 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/dist/index.d.ts +509 -820
- 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 +4 -4
- package/docs/guide/02_commands.md +5 -10
- 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 +3 -4
- package/docs/index.md +3 -3
- package/package.json +1 -1
- package/src/lib/Command.ts +178 -245
- package/src/lib/Operation.ts +60 -80
- package/src/lib/Option.ts +112 -123
- package/src/lib/Positional.ts +59 -92
- package/src/lib/Reader.ts +53 -78
- package/src/lib/Run.ts +39 -57
- 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 +81 -69
- package/tests/unit.command.usage.ts +228 -107
- package/tests/unit.runner.cycle.ts +37 -7
package/src/lib/Operation.ts
CHANGED
|
@@ -1,112 +1,88 @@
|
|
|
1
|
-
import { Option,
|
|
2
|
-
import { 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 Command}.
|
|
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 Operation<
|
|
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 Operation.
|
|
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 Operation.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 Operation} from
|
|
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
|
-
* the parsed option values.
|
|
94
|
-
* - `inputs.positionals` — a tuple whose elements match `inputs.positionals` and whose
|
|
95
|
-
* 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).
|
|
96
76
|
*
|
|
97
|
-
* @typeParam Context -
|
|
98
|
-
* @typeParam Result -
|
|
99
|
-
* @typeParam Options -
|
|
100
|
-
* @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.
|
|
101
81
|
*
|
|
102
|
-
* @param inputs -
|
|
103
|
-
* @param inputs.options -
|
|
104
|
-
*
|
|
105
|
-
* @param
|
|
106
|
-
* Their parsed values appear in `handler`'s `inputs.positionals` argument, in the
|
|
107
|
-
* same order.
|
|
108
|
-
* @param handler - The async function that implements the command logic. Receives the
|
|
109
|
-
* execution context and all parsed inputs.
|
|
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.
|
|
110
86
|
* @returns An {@link Operation} ready to be composed into a command.
|
|
111
87
|
*
|
|
112
88
|
* @example
|
|
@@ -160,25 +136,29 @@ export function operation<
|
|
|
160
136
|
}
|
|
161
137
|
return { options: optionsUsage, positionals: positionalsUsage };
|
|
162
138
|
},
|
|
163
|
-
|
|
164
|
-
const
|
|
139
|
+
consumeAndMakeDecoder(readerArgs: ReaderArgs) {
|
|
140
|
+
const optionsDecoders: Record<string, OptionDecoder<any>> = {};
|
|
165
141
|
for (const optionKey in inputs.options) {
|
|
166
142
|
const optionInput = inputs.options[optionKey]!;
|
|
167
|
-
|
|
143
|
+
optionsDecoders[optionKey] =
|
|
144
|
+
optionInput.registerAndMakeDecoder(readerArgs);
|
|
168
145
|
}
|
|
169
|
-
const
|
|
146
|
+
const positionalsDecoders: Array<PositionalDecoder<any>> = [];
|
|
170
147
|
for (const positionalInput of inputs.positionals) {
|
|
171
|
-
|
|
148
|
+
positionalsDecoders.push(
|
|
149
|
+
positionalInput.consumeAndMakeDecoder(readerArgs),
|
|
150
|
+
);
|
|
172
151
|
}
|
|
173
152
|
return {
|
|
174
|
-
|
|
153
|
+
decodeAndMakeInterpreter() {
|
|
175
154
|
const optionsValues: any = {};
|
|
176
|
-
for (const optionKey in
|
|
177
|
-
optionsValues[optionKey] =
|
|
155
|
+
for (const optionKey in optionsDecoders) {
|
|
156
|
+
optionsValues[optionKey] =
|
|
157
|
+
optionsDecoders[optionKey]!.getAndDecodeValue();
|
|
178
158
|
}
|
|
179
159
|
const positionalsValues: any = [];
|
|
180
|
-
for (const
|
|
181
|
-
positionalsValues.push(
|
|
160
|
+
for (const positionalDecoder of positionalsDecoders) {
|
|
161
|
+
positionalsValues.push(positionalDecoder.decodeValue());
|
|
182
162
|
}
|
|
183
163
|
return {
|
|
184
164
|
executeWithContext(context: Context) {
|
package/src/lib/Option.ts
CHANGED
|
@@ -10,89 +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
|
-
* returns an {@link OptionParser} that can later retrieve the parsed value(s).
|
|
30
|
-
*
|
|
31
|
-
* @param readerOptions - The shared {@link ReaderArgs} that will parse the raw
|
|
32
|
-
* command-line tokens.
|
|
26
|
+
* Registers the option on `readerOptions` and returns an {@link OptionDecoder}.
|
|
33
27
|
*/
|
|
34
|
-
|
|
28
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions): OptionDecoder<Value>;
|
|
35
29
|
};
|
|
36
30
|
|
|
37
31
|
/**
|
|
38
|
-
*
|
|
32
|
+
* Produced by {@link Option.registerAndMakeDecoder}.
|
|
39
33
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* @typeParam Value - The TypeScript type of the parsed value.
|
|
34
|
+
* @typeParam Value - Decoded value type.
|
|
43
35
|
*/
|
|
44
|
-
export type
|
|
45
|
-
|
|
36
|
+
export type OptionDecoder<Value> = {
|
|
37
|
+
/**
|
|
38
|
+
* Returns the decoded option value.
|
|
39
|
+
*
|
|
40
|
+
* @throws {@link TypoError} if decoding failed.
|
|
41
|
+
*/
|
|
42
|
+
getAndDecodeValue(): Value;
|
|
46
43
|
};
|
|
47
44
|
|
|
48
45
|
/**
|
|
49
|
-
* Human-readable metadata for a single
|
|
46
|
+
* Human-readable metadata for a single option, used to render the `Options:` section
|
|
50
47
|
* of the help output produced by {@link usageToStyledLines}.
|
|
51
48
|
*/
|
|
52
49
|
export type OptionUsage = {
|
|
53
|
-
/** Short description of what the option does. */
|
|
54
|
-
description: string | undefined;
|
|
55
50
|
/**
|
|
56
|
-
*
|
|
57
|
-
* Suitable for short caveats such as `"required"` or `"defaults to 42"`.
|
|
51
|
+
* Long-form name without `--` (e.g. `"verbose"`).
|
|
58
52
|
*/
|
|
59
|
-
|
|
53
|
+
long: Lowercase<string>;
|
|
60
54
|
/**
|
|
61
|
-
*
|
|
62
|
-
* The user passes this as `--verbose` on the command line.
|
|
55
|
+
* Short-form name without `-` (e.g. `"v"`).
|
|
63
56
|
*/
|
|
64
|
-
|
|
57
|
+
short: string | undefined;
|
|
65
58
|
/**
|
|
66
|
-
*
|
|
67
|
-
* The user passes this as `-v` on the command line.
|
|
59
|
+
* Help text in usage.
|
|
68
60
|
*/
|
|
69
|
-
|
|
61
|
+
description: string | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Short note shown in parentheses.
|
|
64
|
+
*/
|
|
65
|
+
hint: string | undefined;
|
|
70
66
|
/**
|
|
71
|
-
*
|
|
72
|
-
* (e.g. `"<FILE>"`). `undefined` for flags that take no value.
|
|
67
|
+
* Value placeholder in help (e.g. `"<FILE>"`). `undefined` for flags.
|
|
73
68
|
*/
|
|
74
69
|
label: Uppercase<string> | undefined;
|
|
75
70
|
};
|
|
76
71
|
|
|
77
72
|
/**
|
|
78
|
-
* Creates a boolean flag option
|
|
79
|
-
* `--verbose`) to signal `true`, or can explicitly set with `--flag=true` / `--flag=no`.
|
|
73
|
+
* Creates a boolean flag option (`--verbose`, optionally `--flag=no`).
|
|
80
74
|
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* - `--flag` / `--flag=true` / `--flag=yes` → `true`.
|
|
84
|
-
* - `--flag=false` / `--flag=no` → `false`.
|
|
85
|
-
* - 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}.
|
|
86
77
|
*
|
|
87
|
-
* @param definition -
|
|
88
|
-
* @param definition.long -
|
|
89
|
-
* @param definition.short -
|
|
90
|
-
* @param definition.description -
|
|
91
|
-
* @param definition.hint -
|
|
92
|
-
* @param definition.aliases - Additional
|
|
93
|
-
*
|
|
94
|
-
* @param definition.default - Factory for the default value when the flag is absent.
|
|
95
|
-
* 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`.
|
|
96
85
|
* @returns An {@link Option}`<boolean>`.
|
|
97
86
|
*
|
|
98
87
|
* @example
|
|
@@ -123,13 +112,13 @@ export function optionFlag(definition: {
|
|
|
123
112
|
label: undefined,
|
|
124
113
|
};
|
|
125
114
|
},
|
|
126
|
-
|
|
115
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions) {
|
|
127
116
|
const key = registerOption(readerOptions, {
|
|
128
117
|
...definition,
|
|
129
118
|
valued: false,
|
|
130
119
|
});
|
|
131
120
|
return {
|
|
132
|
-
|
|
121
|
+
getAndDecodeValue() {
|
|
133
122
|
const optionValues = readerOptions.getOptionValues(key);
|
|
134
123
|
if (optionValues.length > 1) {
|
|
135
124
|
throw new TypoError(
|
|
@@ -153,7 +142,13 @@ export function optionFlag(definition: {
|
|
|
153
142
|
);
|
|
154
143
|
}
|
|
155
144
|
}
|
|
156
|
-
return decodeValue(
|
|
145
|
+
return decodeValue({
|
|
146
|
+
long: definition.long,
|
|
147
|
+
short: definition.short,
|
|
148
|
+
label,
|
|
149
|
+
type: typeBoolean,
|
|
150
|
+
input: optionValue,
|
|
151
|
+
});
|
|
157
152
|
},
|
|
158
153
|
};
|
|
159
154
|
},
|
|
@@ -161,32 +156,22 @@ export function optionFlag(definition: {
|
|
|
161
156
|
}
|
|
162
157
|
|
|
163
158
|
/**
|
|
164
|
-
* Creates an option that accepts exactly one value (e.g. `--output dist/`
|
|
165
|
-
* `--output=dist/`).
|
|
166
|
-
*
|
|
167
|
-
* **Parsing rules:**
|
|
168
|
-
* - Absent → `definition.default()` is called. If the default factory throws, a
|
|
169
|
-
* {@link TypoError} is produced.
|
|
170
|
-
* - Specified once → the value is decoded with `definition.type`.
|
|
171
|
-
* - Specified more than once → {@link TypoError} ("Requires a single value, but got
|
|
172
|
-
* multiple").
|
|
159
|
+
* Creates an option that accepts exactly one value (e.g. `--output dist/`).
|
|
173
160
|
*
|
|
174
|
-
*
|
|
175
|
-
* `-s=value`,
|
|
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`.
|
|
176
163
|
*
|
|
177
|
-
* @typeParam Value -
|
|
164
|
+
* @typeParam Value - Type produced by the decoder.
|
|
178
165
|
*
|
|
179
|
-
* @param definition -
|
|
180
|
-
* @param definition.long -
|
|
181
|
-
* @param definition.short -
|
|
182
|
-
* @param definition.description -
|
|
183
|
-
* @param definition.hint -
|
|
184
|
-
* @param definition.aliases - Additional
|
|
185
|
-
* @param definition.label -
|
|
186
|
-
*
|
|
187
|
-
* @param definition.
|
|
188
|
-
* @param definition.default - Factory for the default value when the option is absent.
|
|
189
|
-
* 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.
|
|
190
175
|
* @returns An {@link Option}`<Value>`.
|
|
191
176
|
*
|
|
192
177
|
* @example
|
|
@@ -222,13 +207,13 @@ export function optionSingleValue<Value>(definition: {
|
|
|
222
207
|
label: label as Uppercase<string>,
|
|
223
208
|
};
|
|
224
209
|
},
|
|
225
|
-
|
|
210
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions) {
|
|
226
211
|
const key = registerOption(readerOptions, {
|
|
227
212
|
...definition,
|
|
228
213
|
valued: true,
|
|
229
214
|
});
|
|
230
215
|
return {
|
|
231
|
-
|
|
216
|
+
getAndDecodeValue() {
|
|
232
217
|
const optionValues = readerOptions.getOptionValues(key);
|
|
233
218
|
if (optionValues.length > 1) {
|
|
234
219
|
throw new TypoError(
|
|
@@ -252,12 +237,13 @@ export function optionSingleValue<Value>(definition: {
|
|
|
252
237
|
);
|
|
253
238
|
}
|
|
254
239
|
}
|
|
255
|
-
return decodeValue(
|
|
256
|
-
definition.long,
|
|
240
|
+
return decodeValue({
|
|
241
|
+
long: definition.long,
|
|
242
|
+
short: definition.short,
|
|
257
243
|
label,
|
|
258
|
-
definition.type,
|
|
259
|
-
optionValue,
|
|
260
|
-
);
|
|
244
|
+
type: definition.type,
|
|
245
|
+
input: optionValue,
|
|
246
|
+
});
|
|
261
247
|
},
|
|
262
248
|
};
|
|
263
249
|
},
|
|
@@ -265,30 +251,21 @@ export function optionSingleValue<Value>(definition: {
|
|
|
265
251
|
}
|
|
266
252
|
|
|
267
253
|
/**
|
|
268
|
-
* Creates an option that
|
|
269
|
-
* values into an array (e.g. `--file a.ts --file b.ts`).
|
|
270
|
-
*
|
|
271
|
-
* **Parsing rules:**
|
|
272
|
-
* - Absent → empty array `[]`.
|
|
273
|
-
* - Specified N times → array of N decoded values, in the order they appear on the
|
|
274
|
-
* command line.
|
|
275
|
-
* - Each occurrence is decoded independently with `definition.type`.
|
|
254
|
+
* Creates an option that collects every occurrence into an array (e.g. `--file a.ts --file b.ts`).
|
|
276
255
|
*
|
|
277
|
-
*
|
|
278
|
-
* `-s=value`,
|
|
256
|
+
* Parsing: absent → `[]`; N occurrences → array of N decoded values in order.
|
|
257
|
+
* Value syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
|
|
279
258
|
*
|
|
280
|
-
* @typeParam Value -
|
|
281
|
-
* occurrence.
|
|
259
|
+
* @typeParam Value - Type produced by the decoder for each occurrence.
|
|
282
260
|
*
|
|
283
|
-
* @param definition -
|
|
284
|
-
* @param definition.long -
|
|
285
|
-
* @param definition.short -
|
|
286
|
-
* @param definition.description -
|
|
287
|
-
* @param definition.hint -
|
|
288
|
-
* @param definition.aliases - Additional
|
|
289
|
-
* @param definition.label -
|
|
290
|
-
*
|
|
291
|
-
* @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.
|
|
292
269
|
* @returns An {@link Option}`<Array<Value>>`.
|
|
293
270
|
*
|
|
294
271
|
* @example
|
|
@@ -324,16 +301,22 @@ export function optionRepeatable<Value>(definition: {
|
|
|
324
301
|
label: label as Uppercase<string>,
|
|
325
302
|
};
|
|
326
303
|
},
|
|
327
|
-
|
|
304
|
+
registerAndMakeDecoder(readerOptions: ReaderOptions) {
|
|
328
305
|
const key = registerOption(readerOptions, {
|
|
329
306
|
...definition,
|
|
330
307
|
valued: true,
|
|
331
308
|
});
|
|
332
309
|
return {
|
|
333
|
-
|
|
310
|
+
getAndDecodeValue() {
|
|
334
311
|
const optionValues = readerOptions.getOptionValues(key);
|
|
335
312
|
return optionValues.map((optionValue) =>
|
|
336
|
-
decodeValue(
|
|
313
|
+
decodeValue({
|
|
314
|
+
long: definition.long,
|
|
315
|
+
short: definition.short,
|
|
316
|
+
label,
|
|
317
|
+
type: definition.type,
|
|
318
|
+
input: optionValue,
|
|
319
|
+
}),
|
|
337
320
|
);
|
|
338
321
|
},
|
|
339
322
|
};
|
|
@@ -341,22 +324,28 @@ export function optionRepeatable<Value>(definition: {
|
|
|
341
324
|
};
|
|
342
325
|
}
|
|
343
326
|
|
|
344
|
-
function decodeValue<Value>(
|
|
345
|
-
long: string
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
327
|
+
function decodeValue<Value>(params: {
|
|
328
|
+
long: string;
|
|
329
|
+
short: string | undefined;
|
|
330
|
+
label: string;
|
|
331
|
+
type: Type<Value>;
|
|
332
|
+
input: string;
|
|
333
|
+
}): Value {
|
|
350
334
|
return TypoError.tryWithContext(
|
|
351
|
-
() => type.decoder(
|
|
352
|
-
() =>
|
|
353
|
-
new TypoText(
|
|
354
|
-
|
|
355
|
-
new TypoString(
|
|
356
|
-
new TypoString(
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
)
|
|
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
|
+
},
|
|
360
349
|
);
|
|
361
350
|
}
|
|
362
351
|
|