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/Reader.ts
CHANGED
|
@@ -7,216 +7,200 @@ import {
|
|
|
7
7
|
} from "./Typo";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* {@link ReaderArgs} instance.
|
|
12
|
-
*
|
|
13
|
-
* Keys are returned by {@link ReaderArgs.registerOption} and passed back to
|
|
14
|
-
* {@link ReaderArgs.getOptionValues} to retrieve the parsed values. The internal
|
|
15
|
-
* representation is intentionally opaque — treat it as a handle, not a string.
|
|
10
|
+
* Opaque key returned by {@link ReaderArgs.registerOption}.
|
|
16
11
|
*/
|
|
17
12
|
export type ReaderOptionKey = (string | { __brand: "ReaderOptionKey" }) & {
|
|
18
13
|
__brand: "ReaderOptionKey";
|
|
19
14
|
};
|
|
20
15
|
|
|
21
16
|
/**
|
|
22
|
-
*
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
* Parsing behaviour for a registered option, passed to {@link ReaderArgs.registerOption}.
|
|
18
|
+
*/
|
|
19
|
+
export type ReaderOptionParsing = {
|
|
20
|
+
consumeShortGroup: boolean;
|
|
21
|
+
consumeNextArg: (
|
|
22
|
+
inlined: string | null,
|
|
23
|
+
separated: Array<string>,
|
|
24
|
+
next: string | undefined,
|
|
25
|
+
) => boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Result of parsing an option, including its inlined value and any following separated values.
|
|
30
|
+
*/
|
|
31
|
+
export type ReaderOptionValue = {
|
|
32
|
+
inlined: string | null;
|
|
33
|
+
separated: Array<string>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Option registration/query interface. Subset of {@link ReaderArgs}.
|
|
27
38
|
*/
|
|
28
39
|
export type ReaderOptions = {
|
|
29
40
|
/**
|
|
30
|
-
* Registers
|
|
41
|
+
* Registers an option; all `longs` and `shorts` share the same key.
|
|
31
42
|
*
|
|
32
|
-
* @param definition.longs -
|
|
33
|
-
* @param definition.shorts -
|
|
34
|
-
* @param definition.
|
|
35
|
-
*
|
|
36
|
-
* @
|
|
37
|
-
* @throws `Error` if any of the given names has already been registered, or if a
|
|
38
|
-
* short name overlaps (is a prefix of, or has as a prefix, another registered short).
|
|
43
|
+
* @param definition.longs - Long-form names (without `--`).
|
|
44
|
+
* @param definition.shorts - Short-form names (without `-`).
|
|
45
|
+
* @param definition.parsing - Parsing behaviour.
|
|
46
|
+
* @returns A {@link ReaderOptionKey} for later retrieval.
|
|
47
|
+
* @throws `Error` if a name is already registered or short names overlap.
|
|
39
48
|
*/
|
|
40
49
|
registerOption(definition: {
|
|
41
50
|
longs: Array<string>;
|
|
42
51
|
shorts: Array<string>;
|
|
43
|
-
|
|
52
|
+
parsing: ReaderOptionParsing;
|
|
44
53
|
}): ReaderOptionKey;
|
|
45
54
|
/**
|
|
46
|
-
* Returns all values collected for
|
|
47
|
-
*
|
|
48
|
-
* @param key - The key returned by a prior {@link ReaderOptions.registerOption} call.
|
|
49
|
-
* @returns An array of raw string values, one per occurrence of the option on the
|
|
50
|
-
* command line. Empty if the option was never provided.
|
|
51
|
-
* @throws `Error` if `key` was not previously registered on this instance.
|
|
55
|
+
* Returns all values collected for `key`.
|
|
52
56
|
*/
|
|
53
|
-
getOptionValues(key: ReaderOptionKey): Array<
|
|
57
|
+
getOptionValues(key: ReaderOptionKey): Array<ReaderOptionValue>;
|
|
54
58
|
};
|
|
55
59
|
|
|
56
60
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* {@link ReaderArgs} implements both {@link ReaderOptions} and `ReaderPositionals`.
|
|
61
|
+
* Positional consumption interface. Subset of {@link ReaderArgs}.
|
|
60
62
|
*/
|
|
61
63
|
export type ReaderPositionals = {
|
|
62
64
|
/**
|
|
63
|
-
*
|
|
64
|
-
* any option tokens (which are parsed as side-effects).
|
|
65
|
+
* Returns the next positional token, parsing intervening options as side-effects.
|
|
65
66
|
*
|
|
66
|
-
* @returns The next positional
|
|
67
|
-
*
|
|
68
|
-
* @throws {@link TypoError} if an unrecognised option token is encountered while
|
|
69
|
-
* scanning for the next positional.
|
|
67
|
+
* @returns The next positional, or `undefined` when exhausted.
|
|
68
|
+
* @throws {@link TypoError} on an unrecognised option.
|
|
70
69
|
*/
|
|
71
70
|
consumePositional(): string | undefined;
|
|
72
71
|
};
|
|
73
72
|
|
|
74
73
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* Options must be registered with {@link ReaderArgs.registerOption} **before**
|
|
79
|
-
* {@link ReaderArgs.consumePositional} is called, because the parser needs to know
|
|
80
|
-
* whether each token is an option name, an option value, or a bare positional.
|
|
74
|
+
* Core argument parser: converts raw CLI tokens into named options and positionals.
|
|
75
|
+
* Options must be registered before {@link ReaderArgs.consumePositional} is called.
|
|
81
76
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* - Short options: `-n`, `-n value`, `-n=value`, `-nvalue`, `-abc` (stacked flags)
|
|
85
|
-
* - End-of-options separator: `--` — all subsequent tokens are treated as positionals.
|
|
77
|
+
* Supported syntax: `--name`, `--name value`, `--name=value`,
|
|
78
|
+
* `-n`, `-n value`, `-nvalue`, `-abc` (stacked), `--` (end-of-options).
|
|
86
79
|
*
|
|
87
|
-
*
|
|
88
|
-
* by {@link runAndExit}. It is exposed for advanced use cases such as building
|
|
89
|
-
* custom runners.
|
|
80
|
+
* Created internally by {@link runAndExit}; exposed for advanced / custom runners.
|
|
90
81
|
*/
|
|
91
82
|
export class ReaderArgs {
|
|
92
83
|
#args: ReadonlyArray<string>;
|
|
93
84
|
#parsedIndex: number;
|
|
94
85
|
#parsedDouble: boolean;
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#resultByKey: Map<ReaderOptionKey, Array<string>>;
|
|
86
|
+
#optionContextByLong: Map<string, ReaderOptionContext>;
|
|
87
|
+
#optionContextByShort: Map<string, ReaderOptionContext>;
|
|
88
|
+
#optionContextByKey: Map<ReaderOptionKey, ReaderOptionContext>;
|
|
99
89
|
|
|
100
90
|
/**
|
|
101
|
-
* @param args -
|
|
102
|
-
* The array is not modified; a read cursor is maintained internally.
|
|
91
|
+
* @param args - Raw CLI tokens (e.g. `process.argv.slice(2)`). Not mutated.
|
|
103
92
|
*/
|
|
104
93
|
constructor(args: ReadonlyArray<string>) {
|
|
105
94
|
this.#args = args;
|
|
106
95
|
this.#parsedIndex = 0;
|
|
107
96
|
this.#parsedDouble = false;
|
|
108
|
-
this.#
|
|
109
|
-
this.#
|
|
110
|
-
this.#
|
|
111
|
-
this.#resultByKey = new Map();
|
|
97
|
+
this.#optionContextByLong = new Map();
|
|
98
|
+
this.#optionContextByShort = new Map();
|
|
99
|
+
this.#optionContextByKey = new Map();
|
|
112
100
|
}
|
|
113
101
|
|
|
114
102
|
/**
|
|
115
|
-
* Registers
|
|
116
|
-
*
|
|
117
|
-
* All `longs` and `shorts` are associated with the same returned key. Calling
|
|
118
|
-
* `getOptionValues(key)` after parsing will return values collected under any of the
|
|
119
|
-
* registered names.
|
|
120
|
-
*
|
|
121
|
-
* Short names support stacking (e.g. `-abc` is parsed as `-a -b -c`) and inline
|
|
122
|
-
* values (e.g. `-nvalue`). Short names must not be a prefix of, nor have as a prefix,
|
|
123
|
-
* any other registered short name — the parser uses prefix matching to parse stacked
|
|
124
|
-
* shorts, so overlapping prefixes would be ambiguous.
|
|
103
|
+
* Registers an option; all `longs` and `shorts` share the same key.
|
|
104
|
+
* Short names must not be prefixes of one another.
|
|
125
105
|
*
|
|
126
106
|
* @param definition.longs - Long-form names (without `--`).
|
|
127
107
|
* @param definition.shorts - Short-form names (without `-`).
|
|
128
|
-
* @param definition.
|
|
129
|
-
* @returns
|
|
130
|
-
* @throws `Error` if any name is already registered or
|
|
108
|
+
* @param definition.parsing - Parsing behaviour.
|
|
109
|
+
* @returns A {@link ReaderOptionKey} for {@link ReaderArgs.getOptionValues}.
|
|
110
|
+
* @throws `Error` if any name is already registered or short names overlap.
|
|
131
111
|
*/
|
|
132
112
|
registerOption(definition: {
|
|
133
113
|
longs: Array<string>;
|
|
134
114
|
shorts: Array<string>;
|
|
135
|
-
|
|
115
|
+
parsing: ReaderOptionParsing;
|
|
136
116
|
}) {
|
|
137
117
|
const key = [
|
|
138
118
|
...definition.longs.map((long) => `--${long}`),
|
|
139
119
|
...definition.shorts.map((short) => `-${short}`),
|
|
140
120
|
].join(", ") as ReaderOptionKey;
|
|
141
121
|
for (const long of definition.longs) {
|
|
142
|
-
if (this.#
|
|
122
|
+
if (!this.#isValidOptionName(long)) {
|
|
123
|
+
throw new Error(`Invalid option name: --${long}`);
|
|
124
|
+
}
|
|
125
|
+
if (this.#optionContextByLong.has(long)) {
|
|
143
126
|
throw new Error(`Option already registered: --${long}`);
|
|
144
127
|
}
|
|
145
|
-
this.#keyByLong.set(long, key);
|
|
146
128
|
}
|
|
147
129
|
for (const short of definition.shorts) {
|
|
148
|
-
if (this.#
|
|
130
|
+
if (!this.#isValidOptionName(short)) {
|
|
131
|
+
throw new Error(`Invalid option name: -${short}`);
|
|
132
|
+
}
|
|
133
|
+
if (this.#optionContextByShort.has(short)) {
|
|
149
134
|
throw new Error(`Option already registered: -${short}`);
|
|
150
135
|
}
|
|
151
136
|
for (let i = 0; i < short.length; i++) {
|
|
152
137
|
const shortSlice = short.slice(0, i);
|
|
153
|
-
if (this.#
|
|
138
|
+
if (this.#optionContextByShort.has(shortSlice)) {
|
|
154
139
|
throw new Error(
|
|
155
140
|
`Option -${short} overlap with shorter option: -${shortSlice}`,
|
|
156
141
|
);
|
|
157
142
|
}
|
|
158
143
|
}
|
|
159
|
-
for (const shortOther of this.#
|
|
144
|
+
for (const shortOther of this.#optionContextByShort.keys()) {
|
|
160
145
|
if (shortOther.startsWith(short)) {
|
|
161
146
|
throw new Error(
|
|
162
147
|
`Option -${short} overlap with longer option: -${shortOther}`,
|
|
163
148
|
);
|
|
164
149
|
}
|
|
165
150
|
}
|
|
166
|
-
this.#keyByShort.set(short, key);
|
|
167
151
|
}
|
|
168
|
-
|
|
169
|
-
|
|
152
|
+
const optionContext = {
|
|
153
|
+
parsing: definition.parsing,
|
|
154
|
+
results: new Array<ReaderOptionValue>(),
|
|
155
|
+
};
|
|
156
|
+
for (const long of definition.longs) {
|
|
157
|
+
this.#optionContextByLong.set(long, optionContext);
|
|
158
|
+
}
|
|
159
|
+
for (const short of definition.shorts) {
|
|
160
|
+
this.#optionContextByShort.set(short, optionContext);
|
|
161
|
+
}
|
|
162
|
+
this.#optionContextByKey.set(key, optionContext);
|
|
170
163
|
return key;
|
|
171
164
|
}
|
|
172
165
|
|
|
173
166
|
/**
|
|
174
|
-
* Returns all
|
|
167
|
+
* Returns all values collected for `key`.
|
|
175
168
|
*
|
|
176
|
-
* @param key -
|
|
177
|
-
* @returns
|
|
178
|
-
*
|
|
179
|
-
* literal value strings.
|
|
180
|
-
* @throws `Error` if `key` was not registered on this instance.
|
|
169
|
+
* @param key - Key from {@link ReaderArgs.registerOption}.
|
|
170
|
+
* @returns One entry per occurrence.
|
|
171
|
+
* @throws `Error` if `key` was not registered.
|
|
181
172
|
*/
|
|
182
|
-
getOptionValues(key: ReaderOptionKey): Array<
|
|
183
|
-
const
|
|
184
|
-
if (
|
|
173
|
+
getOptionValues(key: ReaderOptionKey): Array<ReaderOptionValue> {
|
|
174
|
+
const optionContext = this.#optionContextByKey.get(key);
|
|
175
|
+
if (optionContext === undefined) {
|
|
185
176
|
throw new Error(`Unregistered option: ${key}`);
|
|
186
177
|
}
|
|
187
|
-
return
|
|
178
|
+
return optionContext.results;
|
|
188
179
|
}
|
|
189
180
|
|
|
190
181
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* Option tokens encountered during the scan are recorded in the internal results map
|
|
195
|
-
* (equivalent to recording their values against their key). Any unrecognised option token
|
|
196
|
-
* causes a {@link TypoError} to be thrown immediately.
|
|
182
|
+
* Returns the next positional token; parses intervening options as a side-effect.
|
|
183
|
+
* All tokens after `--` are treated as positionals.
|
|
197
184
|
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* @returns The next positional string, or `undefined` when the argument list is
|
|
201
|
-
* exhausted.
|
|
202
|
-
* @throws {@link TypoError} if an unrecognised option (long or short) is encountered.
|
|
185
|
+
* @returns The next positional, or `undefined` when exhausted.
|
|
186
|
+
* @throws {@link TypoError} on an unrecognised option.
|
|
203
187
|
*/
|
|
204
188
|
consumePositional(): string | undefined {
|
|
205
189
|
while (true) {
|
|
206
190
|
const arg = this.#consumeArg();
|
|
207
|
-
if (arg ===
|
|
191
|
+
if (arg === undefined) {
|
|
208
192
|
return undefined;
|
|
209
193
|
}
|
|
210
|
-
if (this.#
|
|
194
|
+
if (!this.#tryConsumeAsOption(arg)) {
|
|
211
195
|
return arg;
|
|
212
196
|
}
|
|
213
197
|
}
|
|
214
198
|
}
|
|
215
199
|
|
|
216
|
-
#consumeArg(): string |
|
|
200
|
+
#consumeArg(): string | undefined {
|
|
217
201
|
const arg = this.#args[this.#parsedIndex];
|
|
218
202
|
if (arg === undefined) {
|
|
219
|
-
return
|
|
203
|
+
return undefined;
|
|
220
204
|
}
|
|
221
205
|
this.#parsedIndex++;
|
|
222
206
|
if (!this.#parsedDouble) {
|
|
@@ -228,9 +212,9 @@ export class ReaderArgs {
|
|
|
228
212
|
return arg;
|
|
229
213
|
}
|
|
230
214
|
|
|
231
|
-
#
|
|
215
|
+
#tryConsumeAsOption(arg: string): boolean {
|
|
232
216
|
if (this.#parsedDouble) {
|
|
233
|
-
return
|
|
217
|
+
return false;
|
|
234
218
|
}
|
|
235
219
|
if (arg.startsWith("--")) {
|
|
236
220
|
const valueIndexStart = arg.indexOf("=");
|
|
@@ -242,80 +226,90 @@ export class ReaderArgs {
|
|
|
242
226
|
arg.slice(valueIndexStart + 1),
|
|
243
227
|
);
|
|
244
228
|
}
|
|
245
|
-
return
|
|
229
|
+
return true;
|
|
246
230
|
}
|
|
247
231
|
if (arg.startsWith("-")) {
|
|
248
232
|
let shortIndexStart = 1;
|
|
249
233
|
let shortIndexEnd = 2;
|
|
250
234
|
while (shortIndexEnd <= arg.length) {
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if (result === false) {
|
|
235
|
+
const short = arg.slice(shortIndexStart, shortIndexEnd);
|
|
236
|
+
const optionContext = this.#optionContextByShort.get(short);
|
|
237
|
+
if (optionContext !== undefined) {
|
|
238
|
+
const rest = arg.slice(shortIndexEnd);
|
|
239
|
+
if (this.#tryConsumeOptionShort(optionContext, short, rest)) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
259
242
|
shortIndexStart = shortIndexEnd;
|
|
260
243
|
}
|
|
261
244
|
shortIndexEnd++;
|
|
262
245
|
}
|
|
263
246
|
throw new TypoError(
|
|
264
247
|
new TypoText(
|
|
265
|
-
new TypoString(
|
|
266
|
-
new TypoString(
|
|
248
|
+
new TypoString(`Unexpected unknown option(s): `),
|
|
249
|
+
new TypoString(`-${arg.slice(shortIndexStart)}`, typoStyleQuote),
|
|
267
250
|
),
|
|
268
251
|
);
|
|
269
252
|
}
|
|
270
|
-
return
|
|
253
|
+
return false;
|
|
271
254
|
}
|
|
272
255
|
|
|
273
|
-
#consumeOptionLong(long: string,
|
|
256
|
+
#consumeOptionLong(long: string, inlined: string | null): void {
|
|
274
257
|
const constant = `--${long}`;
|
|
275
|
-
const
|
|
276
|
-
if (
|
|
277
|
-
|
|
278
|
-
return this.#acknowledgeOption(key, direct);
|
|
279
|
-
}
|
|
280
|
-
const valued = this.#valuedByKey.get(key);
|
|
281
|
-
if (valued) {
|
|
282
|
-
return this.#acknowledgeOption(key, this.#consumeOptionValue(constant));
|
|
283
|
-
}
|
|
284
|
-
return this.#acknowledgeOption(key, "true");
|
|
258
|
+
const optionContext = this.#optionContextByLong.get(long);
|
|
259
|
+
if (optionContext !== undefined) {
|
|
260
|
+
return this.#consumeOptionValues(optionContext, constant, inlined);
|
|
285
261
|
}
|
|
286
262
|
throw new TypoError(
|
|
287
263
|
new TypoText(
|
|
288
|
-
new TypoString(
|
|
289
|
-
new TypoString(
|
|
264
|
+
new TypoString(`Unexpected unknown option: `),
|
|
265
|
+
new TypoString(constant, typoStyleQuote),
|
|
290
266
|
),
|
|
291
267
|
);
|
|
292
268
|
}
|
|
293
269
|
|
|
294
|
-
#tryConsumeOptionShort(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
return true;
|
|
309
|
-
}
|
|
310
|
-
this.#acknowledgeOption(key, "true");
|
|
311
|
-
return rest === "";
|
|
270
|
+
#tryConsumeOptionShort(
|
|
271
|
+
optionContext: ReaderOptionContext,
|
|
272
|
+
short: string,
|
|
273
|
+
rest: string,
|
|
274
|
+
): boolean {
|
|
275
|
+
const constant = `-${short}`;
|
|
276
|
+
if (rest.startsWith("=")) {
|
|
277
|
+
this.#consumeOptionValues(optionContext, constant, rest.slice(1));
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
if (rest.length === 0) {
|
|
281
|
+
this.#consumeOptionValues(optionContext, constant, null);
|
|
282
|
+
return true;
|
|
312
283
|
}
|
|
313
|
-
|
|
284
|
+
if (optionContext.parsing.consumeShortGroup) {
|
|
285
|
+
this.#consumeOptionValues(optionContext, constant, rest);
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
this.#consumeOptionValues(optionContext, constant, null);
|
|
289
|
+
return false;
|
|
314
290
|
}
|
|
315
291
|
|
|
316
|
-
#
|
|
292
|
+
#consumeOptionValues(
|
|
293
|
+
optionContext: ReaderOptionContext,
|
|
294
|
+
constant: string,
|
|
295
|
+
inlined: string | null,
|
|
296
|
+
) {
|
|
297
|
+
const separated = new Array<string>();
|
|
298
|
+
while (
|
|
299
|
+
optionContext.parsing.consumeNextArg(
|
|
300
|
+
inlined,
|
|
301
|
+
separated,
|
|
302
|
+
this.#args[this.#parsedIndex],
|
|
303
|
+
)
|
|
304
|
+
) {
|
|
305
|
+
separated.push(this.#consumeOptionValue(constant));
|
|
306
|
+
}
|
|
307
|
+
optionContext.results.push({ inlined, separated });
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
#consumeOptionValue(constant: string): string {
|
|
317
311
|
const arg = this.#consumeArg();
|
|
318
|
-
if (arg ===
|
|
312
|
+
if (arg === undefined) {
|
|
319
313
|
throw new TypoError(
|
|
320
314
|
new TypoText(
|
|
321
315
|
new TypoString(constant, typoStyleConstants),
|
|
@@ -345,7 +339,12 @@ export class ReaderArgs {
|
|
|
345
339
|
return arg;
|
|
346
340
|
}
|
|
347
341
|
|
|
348
|
-
#
|
|
349
|
-
|
|
342
|
+
#isValidOptionName(name: string): boolean {
|
|
343
|
+
return name.length > 0 && !name.includes("=");
|
|
350
344
|
}
|
|
351
345
|
}
|
|
346
|
+
|
|
347
|
+
type ReaderOptionContext = {
|
|
348
|
+
parsing: ReaderOptionParsing;
|
|
349
|
+
results: Array<ReaderOptionValue>;
|
|
350
|
+
};
|