cli-kiss 0.2.4 → 0.2.6

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/src/lib/Option.ts CHANGED
@@ -44,15 +44,15 @@ export type OptionDecoder<Value> = {
44
44
  /**
45
45
  * Creates a boolean flag option (`--verbose`, optionally `--flag=no`).
46
46
  *
47
- * Parsing: absent → `false`; `--flag` / `--flag=yes` → `true`; `--flag=no` → `false`;
48
- * specified more than once → {@link TypoError}.
47
+ * Parsing: absent → default value; `--flag` / `--flag=yes` → `true`; `--flag=no` → `false`;
48
+ * specified more than once → throws {@link TypoError}.
49
49
  *
50
50
  * @param definition.long - Long-form name (without `--`).
51
51
  * @param definition.short - Short-form name (without `-`).
52
52
  * @param definition.description - Help text.
53
53
  * @param definition.hint - Short note shown in parentheses.
54
54
  * @param definition.aliases - Additional names.
55
- * @param definition.default - Default when absent. Defaults to `false`.
55
+ * @param definition.default - Default value when absent.
56
56
  * @returns An {@link Option}`<boolean>`.
57
57
  *
58
58
  * @example
@@ -62,102 +62,50 @@ export type OptionDecoder<Value> = {
62
62
  * short: "v",
63
63
  * description: "Enable verbose output",
64
64
  * });
65
+ * // Usage:
66
+ * // my-cli → false
67
+ * // my-cli --verbose → true
68
+ * // my-cli --verbose=yes → true
69
+ * // my-cli -v=no → false
65
70
  * ```
66
71
  */
67
72
  export function optionFlag(definition: {
68
- long: Lowercase<string>;
73
+ long: string;
69
74
  short?: string;
70
75
  description?: string;
71
76
  hint?: string;
72
- aliases?: { longs?: Array<Lowercase<string>>; shorts?: Array<string> };
77
+ aliases?: { longs?: Array<string>; shorts?: Array<string> };
73
78
  default?: boolean;
74
79
  }): Option<boolean> {
75
- const label = `<${typeBoolean.content.toUpperCase()}>`;
80
+ const type = typeBoolean("value");
81
+ const { long, short, description, hint, aliases } = definition;
76
82
  return {
77
83
  generateUsage() {
78
- return {
79
- short: definition.short,
80
- long: definition.long,
81
- label: undefined,
82
- annotation: "[=no]",
83
- description: definition.description,
84
- hint: definition.hint,
85
- };
84
+ return { short, long, annotation: "[=no]", description, hint };
86
85
  },
87
86
  registerAndMakeDecoder(readerOptions: ReaderOptions) {
88
- const longNegative = `no-${definition.long}` as Lowercase<string>;
89
- const aliasesLongsNegatives = definition.aliases?.longs?.map(
90
- (aliasLong) => `no-${aliasLong}` as Lowercase<string>,
91
- );
92
- const keyNegative = registerOption(readerOptions, {
93
- long: longNegative,
94
- short: undefined,
95
- aliasesShorts: undefined,
96
- aliasesLongs: aliasesLongsNegatives,
97
- parsing: { consumeShortGroup: false, consumeNextArg: () => false },
98
- });
99
- const keyPositive = registerOption(readerOptions, {
100
- long: definition.long,
101
- short: definition.short,
102
- aliasesLongs: definition.aliases?.longs,
103
- aliasesShorts: definition.aliases?.shorts,
87
+ const key = registerOption(readerOptions, {
88
+ long,
89
+ short,
90
+ aliasesLongs: aliases?.longs,
91
+ aliasesShorts: aliases?.shorts,
104
92
  parsing: { consumeShortGroup: false, consumeNextArg: () => false },
105
93
  });
106
94
  return {
107
95
  getAndDecodeValue() {
108
- const negativeResults = readerOptions.getOptionValues(keyNegative);
109
- const positiveResults = readerOptions.getOptionValues(keyPositive);
110
- if (positiveResults.length > 1) {
111
- throw new TypoError(
112
- new TypoText(
113
- new TypoString(`--${definition.long}`, typoStyleConstants),
114
- new TypoString(`: Must not be set multiple times`),
115
- ),
116
- );
117
- }
118
- if (negativeResults.length > 1) {
119
- throw new TypoError(
120
- new TypoText(
121
- new TypoString(`--${longNegative}`, typoStyleConstants),
122
- new TypoString(`: Must not be set multiple times`),
123
- ),
124
- );
125
- }
126
- if (negativeResults.length > 0 && positiveResults.length > 0) {
127
- throw new TypoError(
128
- new TypoText(
129
- new TypoString(`--${definition.long}`, typoStyleConstants),
130
- new TypoString(`: Must not be set in combination with: `),
131
- new TypoString(`--${longNegative}`, typoStyleConstants),
132
- ),
133
- );
134
- }
135
- if (negativeResults.length > 0) {
136
- const negativeResult = negativeResults[0]!;
137
- if (negativeResult.inlined) {
138
- throw new TypoError(
139
- new TypoText(
140
- new TypoString(`--${longNegative}`, typoStyleConstants),
141
- new TypoString(`: Must not have a value`),
142
- ),
143
- );
144
- }
145
- return false;
96
+ const optionResults = readerOptions.getOptionValues(key);
97
+ if (optionResults.length > 1) {
98
+ throwSetMultipleTimesError(long);
146
99
  }
147
- if (positiveResults.length > 0) {
148
- const positiveResult = positiveResults[0]!;
149
- return decodeValue({
150
- long: definition.long,
151
- short: definition.short,
152
- label,
153
- type: typeBoolean,
154
- input:
155
- positiveResult.inlined === null
156
- ? "true"
157
- : positiveResult.inlined,
158
- });
100
+ if (optionResults.length === 0) {
101
+ return definition.default === undefined
102
+ ? false
103
+ : definition.default;
159
104
  }
160
- return definition.default ?? false;
105
+ const positiveResult = optionResults[0]!;
106
+ const value =
107
+ positiveResult.inlined === null ? "true" : positiveResult.inlined;
108
+ return decodeValue({ long, short, type, input: value });
161
109
  },
162
110
  };
163
111
  },
@@ -167,7 +115,7 @@ export function optionFlag(definition: {
167
115
  /**
168
116
  * Creates an option that accepts exactly one value (e.g. `--output dist/`).
169
117
  *
170
- * Parsing: absent → `default()`; once → decoded with `type`; more than once → {@link TypoError}.
118
+ * Parsing: absent → `defaultValue()`; once → decoded with `type`; more than once → {@link TypoError}.
171
119
  * Value syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
172
120
  *
173
121
  * @typeParam Value - Type produced by the decoder.
@@ -177,9 +125,9 @@ export function optionFlag(definition: {
177
125
  * @param definition.description - Help text.
178
126
  * @param definition.hint - Short note shown in parentheses.
179
127
  * @param definition.aliases - Additional names.
180
- * @param definition.label - Value placeholder in help. Defaults to uppercased `type.content`.
181
128
  * @param definition.type - Decoder for the raw string value.
182
- * @param definition.default - Default when absent. Throw to make the option required.
129
+ * @param definition.valueWhenNotDefined - Default value when the option is not specified at all.
130
+ * @param definition.valueWhenNotInlined - Default value when the option is specified without an inline value (e.g. `--option` or `-o`).
183
131
  * @returns An {@link Option}`<Value>`.
184
132
  *
185
133
  * @example
@@ -187,79 +135,75 @@ export function optionFlag(definition: {
187
135
  * const outputOption = optionSingleValue({
188
136
  * long: "output",
189
137
  * short: "o",
190
- * type: typeString,
191
- * label: "PATH",
138
+ * type: typePath(),
192
139
  * description: "Output directory",
193
- * default: () => "dist/",
140
+ * valueWhenNotDefined: () => "dist",
194
141
  * });
142
+ * // Usage:
143
+ * // my-cli → "dist"
144
+ * // my-cli --output folder → "folder"
145
+ * // my-cli -o folder → "folder"
195
146
  * ```
196
147
  */
197
148
  export function optionSingleValue<Value>(definition: {
198
- long: Lowercase<string>;
149
+ long: string;
199
150
  short?: string;
200
151
  description?: string;
201
152
  hint?: string;
202
- aliases?: { longs?: Array<Lowercase<string>>; shorts?: Array<string> };
203
- label?: Uppercase<string>;
153
+ aliases?: { longs?: Array<string>; shorts?: Array<string> };
204
154
  type: Type<Value>;
205
- default: () => Value;
155
+ defaultWhenNotDefined: () => Value;
156
+ defaultWhenNotInlined?: () => Value;
206
157
  }): Option<Value> {
207
- const label = `<${definition.label ?? definition.type.content.toUpperCase()}>`;
158
+ const { long, short, description, hint, aliases, type } = definition;
159
+ const label = `<${type.content}>`;
208
160
  return {
209
161
  generateUsage() {
210
- return {
211
- short: definition.short,
212
- long: definition.long,
213
- label: label as Uppercase<string>,
214
- annotation: undefined,
215
- description: definition.description,
216
- hint: definition.hint,
217
- };
162
+ return { short, long, label, description, hint };
218
163
  },
219
164
  registerAndMakeDecoder(readerOptions: ReaderOptions) {
220
165
  const key = registerOption(readerOptions, {
221
- long: definition.long,
222
- short: definition.short,
223
- aliasesLongs: definition.aliases?.longs,
224
- aliasesShorts: definition.aliases?.shorts,
166
+ long,
167
+ short,
168
+ aliasesLongs: aliases?.longs,
169
+ aliasesShorts: aliases?.shorts,
225
170
  parsing: {
226
171
  consumeShortGroup: true,
227
- consumeNextArg: (inlined, separated) =>
228
- inlined === null && separated.length === 0,
172
+ consumeNextArg(inlined, separated) {
173
+ if (definition.defaultWhenNotInlined !== undefined) {
174
+ return false;
175
+ }
176
+ return inlined === null && separated.length === 0;
177
+ },
229
178
  },
230
179
  });
231
180
  return {
232
181
  getAndDecodeValue() {
233
182
  const optionResults = readerOptions.getOptionValues(key);
234
183
  if (optionResults.length > 1) {
235
- throw new TypoError(
236
- new TypoText(
237
- new TypoString(`--${definition.long}`, typoStyleConstants),
238
- new TypoString(`: Requires a single value, but got multiple`),
239
- ),
240
- );
184
+ throwSetMultipleTimesError(long);
241
185
  }
242
186
  const optionResult = optionResults[0];
243
187
  if (optionResult === undefined) {
244
188
  try {
245
- return definition.default();
189
+ return definition.defaultWhenNotDefined();
246
190
  } catch (error) {
247
- throw new TypoError(
248
- new TypoText(
249
- new TypoString(`--${definition.long}`, typoStyleConstants),
250
- new TypoString(`: Failed to get default value`),
251
- ),
252
- error,
253
- );
191
+ throwFailedToGetDefaultValueError(long, error, "not set");
254
192
  }
255
193
  }
256
- return decodeValue({
257
- long: definition.long,
258
- short: definition.short,
259
- label,
260
- type: definition.type,
261
- input: optionResult.inlined ?? optionResult.separated[0]!,
262
- });
194
+ if (optionResult.inlined) {
195
+ const inlined = optionResult.inlined;
196
+ return decodeValue({ long, short, label, type, input: inlined });
197
+ }
198
+ if (definition.defaultWhenNotInlined !== undefined) {
199
+ try {
200
+ return definition.defaultWhenNotInlined();
201
+ } catch (error) {
202
+ throwFailedToGetDefaultValueError(long, error, "not inlined");
203
+ }
204
+ }
205
+ const separated = optionResult.separated[0]!;
206
+ return decodeValue({ long, short, label, type, input: separated });
263
207
  },
264
208
  };
265
209
  },
@@ -279,7 +223,6 @@ export function optionSingleValue<Value>(definition: {
279
223
  * @param definition.description - Help text.
280
224
  * @param definition.hint - Short note shown in parentheses.
281
225
  * @param definition.aliases - Additional names.
282
- * @param definition.label - Value placeholder in help. Defaults to uppercased `type.content`.
283
226
  * @param definition.type - Decoder applied to each raw string value.
284
227
  * @returns An {@link Option}`<Array<Value>>`.
285
228
  *
@@ -296,33 +239,25 @@ export function optionSingleValue<Value>(definition: {
296
239
  * ```
297
240
  */
298
241
  export function optionRepeatable<Value>(definition: {
299
- long: Lowercase<string>;
242
+ long: string;
300
243
  short?: string;
301
244
  description?: string;
302
245
  hint?: string;
303
- aliases?: { longs?: Array<Lowercase<string>>; shorts?: Array<string> };
304
- label?: Uppercase<string>;
246
+ aliases?: { longs?: Array<string>; shorts?: Array<string> };
305
247
  type: Type<Value>;
306
248
  }): Option<Array<Value>> {
307
- const label = `<${definition.label ?? definition.type.content.toUpperCase()}>`;
249
+ const { long, short, description, hint, aliases, type } = definition;
250
+ const label = `<${type.content}>`;
308
251
  return {
309
252
  generateUsage() {
310
- // TODO - showcase that it can be repeated ?
311
- return {
312
- short: definition.short,
313
- long: definition.long,
314
- label: label as Uppercase<string>,
315
- annotation: " [*]",
316
- description: definition.description,
317
- hint: definition.hint,
318
- };
253
+ return { short, long, label, annotation: " [*]", description, hint };
319
254
  },
320
255
  registerAndMakeDecoder(readerOptions: ReaderOptions) {
321
256
  const key = registerOption(readerOptions, {
322
- long: definition.long,
323
- short: definition.short,
324
- aliasesLongs: definition.aliases?.longs,
325
- aliasesShorts: definition.aliases?.shorts,
257
+ long,
258
+ short,
259
+ aliasesLongs: aliases?.longs,
260
+ aliasesShorts: aliases?.shorts,
326
261
  parsing: {
327
262
  consumeShortGroup: true,
328
263
  consumeNextArg: (inlined, separated) =>
@@ -332,15 +267,10 @@ export function optionRepeatable<Value>(definition: {
332
267
  return {
333
268
  getAndDecodeValue() {
334
269
  const optionResults = readerOptions.getOptionValues(key);
335
- return optionResults.map((optionResult) =>
336
- decodeValue({
337
- long: definition.long,
338
- short: definition.short,
339
- label,
340
- type: definition.type,
341
- input: optionResult.inlined ?? optionResult.separated[0]!,
342
- }),
343
- );
270
+ return optionResults.map((optionResult) => {
271
+ const input = optionResult.inlined ?? optionResult.separated[0]!;
272
+ return decodeValue({ long, short, label, type, input });
273
+ });
344
274
  },
345
275
  };
346
276
  },
@@ -349,8 +279,8 @@ export function optionRepeatable<Value>(definition: {
349
279
 
350
280
  function decodeValue<Value>(params: {
351
281
  long: string;
352
- short: string | undefined;
353
- label: string;
282
+ short?: string | undefined;
283
+ label?: string | undefined;
354
284
  type: Type<Value>;
355
285
  input: string;
356
286
  }): Value {
@@ -363,10 +293,13 @@ function decodeValue<Value>(params: {
363
293
  text.push(new TypoString(`, `));
364
294
  }
365
295
  text.push(new TypoString(`--${params.long}`, typoStyleConstants));
366
- text.push(new TypoString(`: `));
367
- text.push(new TypoString(params.label, typoStyleUserInput));
368
- text.push(new TypoString(`: `));
369
- text.push(new TypoString(params.type.content, typoStyleLogic));
296
+ if (params.label) {
297
+ text.push(new TypoString(`: `));
298
+ text.push(new TypoString(params.label, typoStyleUserInput));
299
+ } else {
300
+ text.push(new TypoString(`: `));
301
+ text.push(new TypoString(params.type.content, typoStyleLogic));
302
+ }
370
303
  return text;
371
304
  },
372
305
  );
@@ -375,9 +308,9 @@ function decodeValue<Value>(params: {
375
308
  function registerOption(
376
309
  readerOptions: ReaderOptions,
377
310
  definition: {
378
- long: Lowercase<string>;
311
+ long: string;
379
312
  short: undefined | string;
380
- aliasesLongs: undefined | Array<Lowercase<string>>;
313
+ aliasesLongs: undefined | Array<string>;
381
314
  aliasesShorts: undefined | Array<string>;
382
315
  parsing: ReaderOptionParsing;
383
316
  },
@@ -393,3 +326,26 @@ function registerOption(
393
326
  }
394
327
  return readerOptions.registerOption({ longs, shorts, parsing });
395
328
  }
329
+
330
+ function throwSetMultipleTimesError(long: string): never {
331
+ throw new TypoError(
332
+ new TypoText(
333
+ new TypoString(`--${long}`, typoStyleConstants),
334
+ new TypoString(`: Must not be set multiple times`),
335
+ ),
336
+ );
337
+ }
338
+
339
+ function throwFailedToGetDefaultValueError(
340
+ long: string,
341
+ error: unknown,
342
+ context: string,
343
+ ): never {
344
+ throw new TypoError(
345
+ new TypoText(
346
+ new TypoString(`--${long}`, typoStyleConstants),
347
+ new TypoString(`: Failed to get default value (${context})`),
348
+ ),
349
+ error,
350
+ );
351
+ }
@@ -1,12 +1,6 @@
1
1
  import { ReaderPositionals } from "./Reader";
2
2
  import { Type } from "./Type";
3
- import {
4
- TypoError,
5
- TypoString,
6
- typoStyleLogic,
7
- typoStyleUserInput,
8
- TypoText,
9
- } from "./Typo";
3
+ import { TypoError, TypoString, typoStyleUserInput, TypoText } from "./Typo";
10
4
  import { UsagePositional } from "./Usage";
11
5
 
12
6
  /**
@@ -45,40 +39,34 @@ export type PositionalDecoder<Value> = {
45
39
 
46
40
  /**
47
41
  * Creates a required positional — missing token throws {@link TypoError}.
48
- * Label defaults to uppercased `type.content` in angle brackets (e.g. `<STRING>`).
49
42
  *
50
43
  * @typeParam Value - Type produced by the decoder.
51
44
  *
52
45
  * @param definition.description - Help text.
53
46
  * @param definition.hint - Short note shown in parentheses.
54
- * @param definition.label - Label without brackets; defaults to uppercased `type.content`.
55
47
  * @param definition.type - Decoder for the raw token.
56
48
  * @returns A {@link Positional}`<Value>`.
57
49
  *
58
50
  * @example
59
51
  * ```ts
60
52
  * const namePositional = positionalRequired({
61
- * type: typeString,
62
- * label: "NAME",
53
+ * type: type("name"),
63
54
  * description: "The name to greet",
64
55
  * });
65
- * // Parses: my-cli Alice → "Alice"
56
+ * // Usage:
57
+ * // my-cli Alice → "Alice"
66
58
  * ```
67
59
  */
68
60
  export function positionalRequired<Value>(definition: {
69
61
  description?: string;
70
62
  hint?: string;
71
- label?: Uppercase<string>;
72
63
  type: Type<Value>;
73
64
  }): Positional<Value> {
74
- const label = `<${definition.label ?? definition.type.content.toUpperCase()}>`;
65
+ const { description, hint, type } = definition;
66
+ const label = `<${type.content}>`;
75
67
  return {
76
68
  generateUsage() {
77
- return {
78
- description: definition.description,
79
- hint: definition.hint,
80
- label: label as Uppercase<string>,
81
- };
69
+ return { description, hint, label };
82
70
  },
83
71
  consumeAndMakeDecoder(readerPositionals: ReaderPositionals) {
84
72
  const positional = readerPositionals.consumePositional();
@@ -101,13 +89,11 @@ export function positionalRequired<Value>(definition: {
101
89
 
102
90
  /**
103
91
  * Creates an optional positional — absent token falls back to `default()`.
104
- * Label defaults to uppercased `type.content` in square brackets (e.g. `[STRING]`).
105
92
  *
106
93
  * @typeParam Value - Type produced by the decoder (or the default).
107
94
  *
108
95
  * @param definition.description - Help text.
109
96
  * @param definition.hint - Short note shown in parentheses.
110
- * @param definition.label - Label without brackets; defaults to uppercased `type.content`.
111
97
  * @param definition.type - Decoder for the raw token.
112
98
  * @param definition.default - Value when absent. Throw to make it required.
113
99
  * @returns A {@link Positional}`<Value>`.
@@ -115,30 +101,26 @@ export function positionalRequired<Value>(definition: {
115
101
  * @example
116
102
  * ```ts
117
103
  * const greeteePositional = positionalOptional({
118
- * type: typeString,
119
- * label: "NAME",
104
+ * type: type("name"),
120
105
  * description: "Name to greet (default: world)",
121
106
  * default: () => "world",
122
107
  * });
123
- * // my-cli → "world"
124
- * // my-cli Alice → "Alice"
108
+ * // Usage:
109
+ * // my-cli → "world"
110
+ * // my-cli Alice → "Alice"
125
111
  * ```
126
112
  */
127
113
  export function positionalOptional<Value>(definition: {
128
114
  description?: string;
129
115
  hint?: string;
130
- label?: Uppercase<string>;
131
116
  type: Type<Value>;
132
117
  default: () => Value;
133
118
  }): Positional<Value> {
134
- const label = `[${definition.label ?? definition.type.content.toUpperCase()}]`;
119
+ const { description, hint, type } = definition;
120
+ const label = `[${type.content}]`;
135
121
  return {
136
122
  generateUsage() {
137
- return {
138
- description: definition.description,
139
- hint: definition.hint,
140
- label: label as Uppercase<string>,
141
- };
123
+ return { description, hint, label };
142
124
  },
143
125
  consumeAndMakeDecoder(readerPositionals: ReaderPositionals) {
144
126
  const positional = readerPositionals.consumePositional();
@@ -148,13 +130,7 @@ export function positionalOptional<Value>(definition: {
148
130
  try {
149
131
  return definition.default();
150
132
  } catch (error) {
151
- throw new TypoError(
152
- new TypoText(
153
- new TypoString(label, typoStyleUserInput),
154
- new TypoString(`: Failed to get default value`),
155
- ),
156
- error,
157
- );
133
+ throwsWhenFailedToGetDefault(label);
158
134
  }
159
135
  }
160
136
  return decodeValue(label, definition.type, positional);
@@ -166,46 +142,41 @@ export function positionalOptional<Value>(definition: {
166
142
 
167
143
  /**
168
144
  * Creates a variadic positional that collects zero or more remaining tokens into an array.
169
- * Stops at `endDelimiter` (consumed, not included). Label: `[TYPE]...` notation.
145
+ * Optionally stops at `endDelimiter` (consumed, not included).
170
146
  *
171
147
  * @typeParam Value - Type produced by the decoder for each token.
172
148
  *
173
149
  * @param definition.endDelimiter - Sentinel token that stops collection (consumed, not included).
174
150
  * @param definition.description - Help text.
175
151
  * @param definition.hint - Short note shown in parentheses.
176
- * @param definition.label - Label without brackets; defaults to uppercased `type.content`.
177
152
  * @param definition.type - Decoder applied to each token.
178
153
  * @returns A {@link Positional}`<Array<Value>>`.
179
154
  *
180
155
  * @example
181
156
  * ```ts
182
157
  * const filesPositional = positionalVariadics({
183
- * type: typeString,
184
- * label: "FILE",
158
+ * type: typePath(),
185
159
  * description: "Files to process",
186
160
  * });
187
- * // my-cli a.ts b.ts c.ts → ["a.ts", "b.ts", "c.ts"]
188
- * // my-cli → []
161
+ * // Usage:
162
+ * // my-cli → []
163
+ * // my-cli a.ts b.ts c.ts → ["a.ts", "b.ts", "c.ts"]
189
164
  * ```
190
165
  */
191
166
  export function positionalVariadics<Value>(definition: {
192
167
  endDelimiter?: string;
193
168
  description?: string;
194
169
  hint?: string;
195
- label?: Uppercase<string>;
196
170
  type: Type<Value>;
197
171
  }): Positional<Array<Value>> {
198
- const label = `[${definition.label ?? definition.type.content.toUpperCase()}]`;
172
+ const { description, hint, type } = definition;
173
+ const labelSingle = `[${type.content}]`;
174
+ const labelMultiple =
175
+ `${labelSingle}...` +
176
+ (definition.endDelimiter ? ` ["${definition.endDelimiter}"]` : "");
199
177
  return {
200
178
  generateUsage() {
201
- return {
202
- description: definition.description,
203
- hint: definition.hint,
204
- label: (`${label}...` +
205
- (definition.endDelimiter
206
- ? ` ["${definition.endDelimiter}"]`
207
- : "")) as Uppercase<string>,
208
- };
179
+ return { description, hint, label: labelMultiple };
209
180
  },
210
181
  consumeAndMakeDecoder(readerPositionals: ReaderPositionals) {
211
182
  const positionals = new Array<string>();
@@ -222,7 +193,7 @@ export function positionalVariadics<Value>(definition: {
222
193
  return {
223
194
  decodeValue() {
224
195
  return positionals.map((positional) =>
225
- decodeValue(label, definition.type, positional),
196
+ decodeValue(labelSingle, definition.type, positional),
226
197
  );
227
198
  },
228
199
  };
@@ -237,11 +208,15 @@ function decodeValue<Value>(
237
208
  ): Value {
238
209
  return TypoError.tryWithContext(
239
210
  () => type.decoder(input),
240
- () =>
241
- new TypoText(
242
- new TypoString(label, typoStyleUserInput),
243
- new TypoString(`: `),
244
- new TypoString(type.content, typoStyleLogic),
245
- ),
211
+ () => new TypoText(new TypoString(label, typoStyleUserInput)),
212
+ );
213
+ }
214
+
215
+ function throwsWhenFailedToGetDefault(label: string): never {
216
+ throw new TypoError(
217
+ new TypoText(
218
+ new TypoString(label, typoStyleUserInput),
219
+ new TypoString(`: Failed to get default value`),
220
+ ),
246
221
  );
247
222
  }
package/src/lib/Reader.ts CHANGED
@@ -17,11 +17,11 @@ export type ReaderOptionKey = (string | { __brand: "ReaderOptionKey" }) & {
17
17
  * Parsing behaviour for a registered option, passed to {@link ReaderArgs.registerOption}.
18
18
  */
19
19
  export type ReaderOptionParsing = {
20
- consumeShortGroup: boolean;
20
+ consumeShortGroup: boolean; // TODO - this doesnt matter when no short option
21
21
  consumeNextArg: (
22
22
  inlined: string | null,
23
23
  separated: Array<string>,
24
- next: string | undefined,
24
+ nextArg: string | undefined,
25
25
  ) => boolean;
26
26
  };
27
27
 
@@ -340,7 +340,7 @@ export class ReaderArgs {
340
340
  }
341
341
 
342
342
  #isValidOptionName(name: string): boolean {
343
- return name.length > 0 && !name.includes("=");
343
+ return name.length > 0 && !name.includes("=") && !name.includes("\0");
344
344
  }
345
345
  }
346
346