cli-kiss 0.2.7 → 0.2.9

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.
Files changed (42) hide show
  1. package/README.md +8 -3
  2. package/dist/index.d.ts +200 -190
  3. package/dist/index.js +2 -2
  4. package/dist/index.js.map +1 -1
  5. package/docs/.vitepress/config.mts +1 -1
  6. package/docs/.vitepress/theme/Layout.vue +16 -0
  7. package/docs/.vitepress/theme/index.ts +5 -1
  8. package/docs/.vitepress/theme/style.css +5 -1
  9. package/docs/guide/01_getting_started.md +2 -2
  10. package/docs/guide/02_commands.md +3 -3
  11. package/docs/guide/03_options.md +11 -11
  12. package/docs/guide/04_positionals.md +9 -9
  13. package/docs/guide/05_input_types.md +17 -16
  14. package/docs/guide/06_run_as_cli.md +1 -1
  15. package/docs/index.md +2 -2
  16. package/docs/public/favicon.ico +0 -0
  17. package/docs/public/logo.png +0 -0
  18. package/package.json +1 -1
  19. package/src/index.ts +1 -1
  20. package/src/lib/Command.ts +51 -40
  21. package/src/lib/Operation.ts +41 -25
  22. package/src/lib/Option.ts +198 -127
  23. package/src/lib/Positional.ts +51 -25
  24. package/src/lib/Reader.ts +188 -226
  25. package/src/lib/Run.ts +20 -9
  26. package/src/lib/Suggest.ts +78 -0
  27. package/src/lib/Type.ts +178 -154
  28. package/src/lib/Typo.ts +58 -55
  29. package/src/lib/Usage.ts +12 -12
  30. package/tests/unit.Reader.commons.ts +86 -123
  31. package/tests/unit.Reader.parsings.ts +14 -26
  32. package/tests/unit.Reader.shortBig.ts +75 -101
  33. package/tests/unit.command.aliases.ts +88 -0
  34. package/tests/unit.command.execute.ts +6 -6
  35. package/tests/unit.command.usage.ts +19 -13
  36. package/tests/unit.fuzzed.alternatives.ts +35 -26
  37. package/tests/unit.runner.colors.ts +8 -33
  38. package/tests/unit.runner.cycle.ts +141 -156
  39. package/tests/unit.runner.errors.ts +25 -22
  40. package/docs/public/hero.png +0 -0
  41. package/src/lib/Similarity.ts +0 -41
  42. package/tests/unit.Reader.aliases.ts +0 -62
package/dist/index.d.ts CHANGED
@@ -1,47 +1,37 @@
1
1
  /**
2
- * Opaque key returned by {@link ReaderArgs.registerOption}.
2
+ * Represents the parsing specification for a long option
3
3
  */
4
- type ReaderOptionKey = (string | {
5
- __brand: "ReaderOptionKey";
6
- }) & {
7
- __brand: "ReaderOptionKey";
4
+ type ReaderOptionLongSpec = {
5
+ key: string;
6
+ nextGuard: ReaderOptionNextGuard;
8
7
  };
9
8
  /**
10
- * Parsing behaviour for a registered option, passed to {@link ReaderArgs.registerOption}.
9
+ * Represents the parsing specification for a short option
11
10
  */
12
- type ReaderOptionParsing = {
13
- consumeShortGroup: boolean;
14
- consumeNextArg: (inlined: string | null, separated: Array<string>, nextArg: string | undefined) => boolean;
11
+ type ReaderOptionShortSpec = ReaderOptionLongSpec & {
12
+ consumeGroupRestAsValue: boolean;
15
13
  };
16
14
  /**
17
- * Result of parsing an option, including its inlined value and any following separated values.
15
+ * Determines whether the next token is valid for a given option.
16
+ */
17
+ type ReaderOptionNextGuard = (value: ReaderOptionValue, next: string | undefined) => boolean;
18
+ /**
19
+ * Represents the values parsed for an option.
18
20
  */
19
21
  type ReaderOptionValue = {
20
22
  inlined: string | null;
21
- separated: Array<string>;
23
+ separated: ReadonlyArray<string>;
22
24
  };
25
+ /**
26
+ * Returns the parsed values for a registered option.
27
+ */
28
+ type ReaderOptionGetter = () => ReadonlyArray<ReaderOptionValue>;
23
29
  /**
24
30
  * Option registration/query interface. Subset of {@link ReaderArgs}.
25
31
  */
26
32
  type ReaderOptions = {
27
- /**
28
- * Registers an option; all `longs` and `shorts` share the same key.
29
- *
30
- * @param definition.longs - Long-form names (without `--`).
31
- * @param definition.shorts - Short-form names (without `-`).
32
- * @param definition.parsing - Parsing behaviour.
33
- * @returns A {@link ReaderOptionKey} for later retrieval.
34
- * @throws `Error` if a name is already registered or short names overlap.
35
- */
36
- registerOption(definition: {
37
- longs: Array<string>;
38
- shorts: Array<string>;
39
- parsing: ReaderOptionParsing;
40
- }): ReaderOptionKey;
41
- /**
42
- * Returns all values collected for `key`.
43
- */
44
- getOptionValues(key: ReaderOptionKey): Array<ReaderOptionValue>;
33
+ registerOptionLong(longSpec: ReaderOptionLongSpec): ReaderOptionGetter;
34
+ registerOptionShort(shortSpec: ReaderOptionShortSpec): ReaderOptionGetter;
45
35
  };
46
36
  /**
47
37
  * Positional consumption interface. Subset of {@link ReaderArgs}.
@@ -51,7 +41,7 @@ type ReaderPositionals = {
51
41
  * Returns the next positional token, parsing intervening options as side-effects.
52
42
  *
53
43
  * @returns The next positional, or `undefined` when exhausted.
54
- * @throws {@link TypoError} on an unrecognised option.
44
+ * @throws on an unrecognised option.
55
45
  */
56
46
  consumePositional(): string | undefined;
57
47
  };
@@ -67,38 +57,23 @@ type ReaderPositionals = {
67
57
  declare class ReaderArgs {
68
58
  #private;
69
59
  /**
70
- * @param args - Raw CLI tokens (e.g. `process.argv.slice(2)`). Not mutated.
60
+ * @param tokens - Raw CLI tokens (e.g. `process.argv.slice(2)`).
71
61
  */
72
- constructor(args: ReadonlyArray<string>);
62
+ constructor(tokens: ReadonlyArray<string>);
73
63
  /**
74
- * Registers an option; all `longs` and `shorts` share the same key.
75
- * Short names must not be prefixes of one another.
76
- *
77
- * @param definition.longs - Long-form names (without `--`).
78
- * @param definition.shorts - Short-form names (without `-`).
79
- * @param definition.parsing - Parsing behaviour.
80
- * @returns A {@link ReaderOptionKey} for {@link ReaderArgs.getOptionValues}.
81
- * @throws `Error` if any name is already registered or short names overlap.
82
- */
83
- registerOption(definition: {
84
- longs: Array<string>;
85
- shorts: Array<string>;
86
- parsing: ReaderOptionParsing;
87
- }): ReaderOptionKey;
88
- /**
89
- * Returns all values collected for `key`.
90
- *
91
- * @param key - Key from {@link ReaderArgs.registerOption}.
92
- * @returns One entry per occurrence.
93
- * @throws `Error` if `key` was not registered.
64
+ * Registers a long option and returns a getter for its parsed values.
65
+ */
66
+ registerOptionLong(longSpec: ReaderOptionLongSpec): ReaderOptionGetter;
67
+ /**
68
+ * Registers a short option and returns a getter for its parsed values.
94
69
  */
95
- getOptionValues(key: ReaderOptionKey): Array<ReaderOptionValue>;
70
+ registerOptionShort(shortSpec: ReaderOptionShortSpec): ReaderOptionGetter;
96
71
  /**
97
72
  * Returns the next positional token; parses intervening options as a side-effect.
98
73
  * All tokens after `--` are treated as positionals.
99
74
  *
100
75
  * @returns The next positional, or `undefined` when exhausted.
101
- * @throws {@link TypoError} on an unrecognised option.
76
+ * @throws on an unrecognised option.
102
77
  */
103
78
  consumePositional(): string | undefined;
104
79
  }
@@ -107,15 +82,26 @@ declare class ReaderArgs {
107
82
  * Decodes a raw CLI string into a typed value.
108
83
  * A pair of a human-readable `content` name and a `decoder` function.
109
84
  *
110
- * Built-in: {@link type}, {@link typeBoolean}, {@link typeNumber},
111
- * {@link typeInteger}, {@link typeDatetime}, {@link typeUrl}.
112
- * Composite: {@link typeChoice}, {@link typeConverted}, {@link typeTuple}, {@link typeList}.
85
+ * Primitive Types:
86
+ * - {@link typeString}
87
+ * - {@link typeBoolean}
88
+ * - {@link typeNumber},
89
+ * - {@link typeInteger}
90
+ * - {@link typeDatetime}
91
+ * - {@link typeUrl}
92
+ * - {@link typePath}
93
+ * - {@link typeChoice}
94
+ *
95
+ * Composed Types:
96
+ * - {@link typeMapped}
97
+ * - {@link typeTuple}
98
+ * - {@link typeList}
113
99
  *
114
100
  * @typeParam Value - Type produced by the decoder.
115
101
  */
116
102
  type Type<Value> = {
117
103
  /**
118
- * Human-readable name shown in help and errors (e.g. `"name"`, `"number"`).
104
+ * Human-readable name shown in help and errors (e.g. `"name"`, `"context"`).
119
105
  */
120
106
  content: string;
121
107
  /**
@@ -123,10 +109,20 @@ type Type<Value> = {
123
109
  *
124
110
  * @param input - Raw string from the command line.
125
111
  * @returns The decoded value.
126
- * @throws {@link TypoError} on invalid input.
112
+ * @throws on invalid input.
127
113
  */
128
114
  decoder(input: string): Value;
129
115
  };
116
+ /**
117
+ * A named type that accepts any string as input.
118
+ * @param name - Name shown in help and errors (e.g. `"my-value"`).
119
+ * @example
120
+ * ```ts
121
+ * typeString("greeting").decoder("hello") // → "hello"
122
+ * typeString("greeting").decoder("") // → ""
123
+ * ```
124
+ */
125
+ declare function typeString(name?: string): Type<string>;
130
126
  /**
131
127
  * Decodes a string to `boolean` (case-insensitive).
132
128
  * Used by {@link optionFlag} for `--flag=<value>`.
@@ -135,29 +131,16 @@ type Type<Value> = {
135
131
  * ```ts
136
132
  * typeBoolean("flag").decoder("true") // → true
137
133
  * typeBoolean("flag").decoder("yes") // → true
138
- * typeBoolean("flag").decoder("y") // → true
139
- * typeBoolean("flag").decoder("false") // → false
140
- * typeBoolean("flag").decoder("no") // → false
134
+ * typeBoolean("flag").decoder("Y") // → true
135
+ * typeBoolean("flag").decoder("FALSE") // → false
136
+ * typeBoolean("flag").decoder("NO") // → false
141
137
  * typeBoolean("flag").decoder("n") // → false
138
+ * typeBoolean("flag").decoder("maybe") // throws
142
139
  * ```
143
140
  */
144
141
  declare function typeBoolean(name?: string): Type<boolean>;
145
- declare const typeBooleanValuesTrue: Set<string>;
146
- declare const typeBooleanValuesFalse: Set<string>;
147
- /**
148
- * Parses a date/time string via `Date.parse`.
149
- * Accepts any format supported by `Date.parse`, including ISO 8601.
150
- *
151
- * @example
152
- * ```ts
153
- * typeDatetime("my-datetime").decoder("2024-01-15") // → Date object for 2024-01-15
154
- * typeDatetime("my-datetime").decoder("2024-01-15T13:45:30Z") // → Date object for 2024-01-15 13:45:30 UTC
155
- * typeDatetime("my-datetime").decoder("not a date") // throws TypoError
156
- * ```
157
- */
158
- declare function typeDatetime(name?: string): Type<Date>;
159
142
  /**
160
- * Parses a string to `number` via `Number()`; `NaN` throws {@link TypoError}.
143
+ * Parses a string to `number` via `Number()`; `NaN` throws.
161
144
  *
162
145
  * @example
163
146
  * ```ts
@@ -169,7 +152,7 @@ declare function typeDatetime(name?: string): Type<Date>;
169
152
  declare function typeNumber(name?: string): Type<number>;
170
153
  /**
171
154
  * Parses an integer string to `bigint` via `BigInt()`.
172
- * Floats and non-numeric strings throw {@link TypoError}.
155
+ * Floats and non-numeric strings throws.
173
156
  *
174
157
  * @example
175
158
  * ```ts
@@ -179,9 +162,21 @@ declare function typeNumber(name?: string): Type<number>;
179
162
  * ```
180
163
  */
181
164
  declare function typeInteger(name?: string): Type<bigint>;
165
+ /**
166
+ * Parses a date/time string via `Date.parse`.
167
+ * Accepts any format supported by `Date.parse`, including ISO 8601.
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * typeDatetime("start").decoder("2024-01-15") // → Date object for 2024-01-15
172
+ * typeDatetime("start").decoder("2024-01-15T13:45:30Z") // → Date object for 2024-01-15 13:45:30 UTC
173
+ * typeDatetime("start").decoder("not a date") // throws
174
+ * ```
175
+ */
176
+ declare function typeDatetime(name?: string): Type<Date>;
182
177
  /**
183
178
  * Parses an absolute URL string to a `URL` object.
184
- * Relative or malformed URLs throw {@link TypoError}.
179
+ * Relative or malformed URLs throws.
185
180
  *
186
181
  * @example
187
182
  * ```ts
@@ -191,15 +186,36 @@ declare function typeInteger(name?: string): Type<bigint>;
191
186
  */
192
187
  declare function typeUrl(name?: string): Type<URL>;
193
188
  /**
194
- * A named type that accepts any string as input.
195
- * @param name - Name shown in help and errors (e.g. `"my-value"`).
189
+ * Creates a {@link Type} for filesystem paths with optional existence checks.
190
+ *
191
+ * @param checks - Optional checks for path existence and type (file/directory).
192
+ * @returns A {@link Type}`<string>` representing the path.
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * const typeInputFile = typePath("input-file", { checkSyncExistAs: "file" });
197
+ * typeInputFile.decoder("data.txt"); // → "data.txt" if it exists and is a file, otherwise throws
198
+ * typeInputFile.decoder("somedir"); // throws if "somedir" exists and is a directory
199
+ * ```
200
+ */
201
+ declare function typePath(name?: string, checks?: {
202
+ checkSyncExistAs?: "file" | "directory" | "anything";
203
+ }): Type<string>;
204
+ /**
205
+ * Creates a {@link Type}`<string>` that only accepts a fixed set of values.
206
+ *
207
+ * @param name - Name shown in help and errors.
208
+ * @param values - Ordered list of accepted values.
209
+ * @returns A {@link Type}`<string>`.
210
+ *
196
211
  * @example
197
212
  * ```ts
198
- * type("greeting").decoder("hello") // "hello"
199
- * type("greeting").decoder("") // → ""
213
+ * const typeEnv = typeChoice("environment", ["dev", "staging", "prod"]);
214
+ * typeEnv.decoder("prod") // → "prod"
215
+ * typeEnv.decoder("unknown") // throws
200
216
  * ```
201
217
  */
202
- declare function type(name?: string): Type<string>;
218
+ declare function typeChoice<const Value extends string>(name: string, values: Array<Value>, caseSensitive?: boolean): Type<Value>;
203
219
  /**
204
220
  * Chains `before`'s decoder with an `after` transformation.
205
221
  * `before` errors are prefixed with `"from: <content>"` for traceability.
@@ -214,15 +230,17 @@ declare function type(name?: string): Type<string>;
214
230
  *
215
231
  * @example
216
232
  * ```ts
217
- * const typePort = typeConverted("port", typeNumber(), (n) => {
218
- * if (n < 1 || n > 65535) throw new Error("Out of range");
233
+ * const typePort = typeMapped("port", typeNumber(), (n) => {
234
+ * if (n < 1 || n > 65535) {
235
+ * throw new Error("Out of range");
236
+ * }
219
237
  * return n;
220
238
  * });
221
- * // "--port 8080" 8080
222
- * // "--port 99999" → TypoError: --port: <PORT>: Port: Out of range
239
+ * typePort.decoder("8080"); // 8080
240
+ * typePort.decoder("70000"); // throws
223
241
  * ```
224
242
  */
225
- declare function typeConverted<Before, After>(name: string, before: Type<Before>, mapper: (value: Before) => After): Type<After>;
243
+ declare function typeMapped<Before, After>(name: string, before: Type<Before>, mapper: (value: Before) => After): Type<After>;
226
244
  /**
227
245
  * Adds a name to a {@link Type} for clearer error messages and help text.
228
246
  *
@@ -231,33 +249,9 @@ declare function typeConverted<Before, After>(name: string, before: Type<Before>
231
249
  * @returns A {@link Type} with the given name.
232
250
  */
233
251
  declare function typeRenamed<Value>(type: Type<Value>, name: string): Type<Value>;
234
- /**
235
- * Creates a {@link Type} for filesystem paths with optional existence checks.
236
- * @param checks - Optional checks for path existence and type (file/directory).
237
- * @returns A {@link Type}`<string>` representing the path.
238
- */
239
- declare function typePath(name?: string, checks?: {
240
- checkSyncExistAs?: "file" | "directory" | "anything";
241
- }): Type<string>;
242
- /**
243
- * Creates a {@link Type}`<string>` that only accepts a fixed set of values.
244
- * Out-of-set inputs throw {@link TypoError} listing up to 5 valid options.
245
- *
246
- * @param name - Name shown in help and errors.
247
- * @param values - Ordered list of accepted values.
248
- * @returns A {@link Type}`<string>`.
249
- *
250
- * @example
251
- * ```ts
252
- * const typeEnv = typeChoice("environment", ["dev", "staging", "prod"]);
253
- * typeEnv.decoder("prod") // → "prod"
254
- * typeEnv.decoder("unknown") // throws TypoError: Invalid value: "unknown" (expected one of: "dev" | "staging" | "prod")
255
- * ```
256
- */
257
- declare function typeChoice<const Value extends string>(name: string, values: Array<Value>, caseSensitive?: boolean): Type<Value>;
258
252
  /**
259
253
  * Splits a delimited string into a typed tuple.
260
- * Each part is decoded by the corresponding element type; wrong count or decode failure throws {@link TypoError}.
254
+ * Each part is decoded by the corresponding element type; wrong count or decode failure throws.
261
255
  *
262
256
  * @typeParam Elements - Tuple of decoded value types (inferred from `elementTypes`).
263
257
  *
@@ -269,8 +263,9 @@ declare function typeChoice<const Value extends string>(name: string, values: Ar
269
263
  * ```ts
270
264
  * const typePoint = typeTuple([typeNumber("x"), typeNumber("y")]);
271
265
  * typePoint.decoder("3.14,2.71") // → [3.14, 2.71]
272
- * typePoint.decoder("1,2,3") // → [1, 2]
273
- * typePoint.decoder("x,2") // throws TypoError: at 0: Number: Unable to parse: "x"
266
+ * typePoint.decoder("1") // throws
267
+ * typePoint.decoder("1,2,3") // throws
268
+ * typePoint.decoder("x,2") // throws
274
269
  * ```
275
270
  */
276
271
  declare function typeTuple<const Elements extends Array<any>>(elementTypes: {
@@ -278,7 +273,7 @@ declare function typeTuple<const Elements extends Array<any>>(elementTypes: {
278
273
  }, separator?: string): Type<Elements>;
279
274
  /**
280
275
  * Splits a delimited string into a typed array.
281
- * Each part is decoded by `elementType`; failed decodes throw {@link TypoError}.
276
+ * Each part is decoded by `elementType`; failed decodes throws.
282
277
  * Note: splitting an empty string yields one empty element — prefer {@link optionRepeatable} for a zero-default.
283
278
  *
284
279
  * @typeParam Value - Element type produced by `elementType.decoder`.
@@ -289,12 +284,13 @@ declare function typeTuple<const Elements extends Array<any>>(elementTypes: {
289
284
  *
290
285
  * @example
291
286
  * ```ts
292
- * const typeNumbers = typeList(typeNumber);
287
+ * const typeNumbers = typeList(typeNumber("v"));
293
288
  * typeNumbers.decoder("1,2,3") // → [1, 2, 3]
294
- * typeNumbers.decoder("1,x,3") // throws TypoError: at 1: Number: Unable to parse: "x"
295
- *
289
+ * typeNumbers.decoder("1,x,3") // throws
296
290
  * const typePaths = typeList(typePath(), ":");
297
- * typePaths.decoder("/usr/bin:/usr/local/bin") // → ["/usr/bin", "/usr/local/bin"]
291
+ * typePaths.decoder("/bin:/usr") // → ["/bin", "/usr"]
292
+ * typePaths.decoder("/usr/bin") // → ["/usr/bin"]
293
+ * typePaths.decoder("") // → throws
298
294
  * ```
299
295
  */
300
296
  declare function typeList<Value>(elementType: Type<Value>, separator?: string): Type<Array<Value>>;
@@ -381,9 +377,9 @@ declare class TypoString {
381
377
  #private;
382
378
  /**
383
379
  * @param value - Raw text content.
384
- * @param typoStyle - Style to apply when rendering. Defaults to `undefined` (no style).
380
+ * @param style - Style to apply when rendering.
385
381
  */
386
- constructor(value: string, typoStyle?: TypoStyle);
382
+ constructor(value: string, style?: TypoStyle);
387
383
  /**
388
384
  * Returns the text styled by `typoSupport`.
389
385
  *
@@ -394,11 +390,15 @@ declare class TypoString {
394
390
  * Returns the raw text.
395
391
  */
396
392
  getRawString(): string;
393
+ /**
394
+ * Predefined ellipsis segment with subtle styling.
395
+ */
396
+ static elipsis: TypoString;
397
397
  }
398
398
  /**
399
399
  * A segment of styled text, a string, or an array of segments.
400
400
  */
401
- type TypoSegment = TypoText | TypoString | string | Array<TypoSegment>;
401
+ type TypoSegment = TypoText | TypoString | Array<TypoSegment>;
402
402
  /**
403
403
  * Mutable sequence of {@link TypoString} segments.
404
404
  */
@@ -407,13 +407,15 @@ declare class TypoText {
407
407
  /**
408
408
  * @param segments - Initial text segments
409
409
  */
410
- constructor(...segments: TypoSegment[]);
410
+ constructor(...segments: Array<TypoSegment>);
411
411
  /**
412
412
  * Appends new text segment(s).
413
- *
414
- * @param segment - Text segment(s) to append.
415
413
  */
416
- push(segment: TypoSegment): void;
414
+ push(...segments: Array<TypoSegment>): void;
415
+ /**
416
+ * Appends separated segments, optionally truncating with an ellipsis.
417
+ */
418
+ pushJoined(segments: Array<TypoSegment>, separator: TypoSegment, ellipsisLimit: number): void;
417
419
  /**
418
420
  * Renders all segments into a single styled string.
419
421
  *
@@ -429,11 +431,6 @@ declare class TypoText {
429
431
  * Returns the total raw character count.
430
432
  */
431
433
  computeRawLength(): number;
432
- /**
433
- * Joins multiple segments with a separator.
434
- * @returns A new {@link TypoText} containing the joined segments.
435
- */
436
- static join(segments: Array<TypoSegment>, separator: TypoSegment): TypoText;
437
434
  }
438
435
  /**
439
436
  * Column-aligned grid of {@link TypoText} cells.
@@ -680,7 +677,7 @@ type Option<Value> = {
680
677
  /**
681
678
  * Registers the option on `readerOptions` and returns an {@link OptionDecoder}.
682
679
  */
683
- registerAndMakeDecoder(readerOptions: ReaderArgs): OptionDecoder<Value>;
680
+ registerAndMakeDecoder(readerOptions: ReaderOptions): OptionDecoder<Value>;
684
681
  };
685
682
  /**
686
683
  * Produced by {@link Option.registerAndMakeDecoder}.
@@ -691,15 +688,19 @@ type OptionDecoder<Value> = {
691
688
  /**
692
689
  * Returns the decoded option value.
693
690
  *
694
- * @throws {@link TypoError} if decoding failed.
691
+ * @throws if decoding failed.
695
692
  */
696
693
  getAndDecodeValue(): Value;
697
694
  };
698
695
  /**
699
696
  * Creates a boolean flag option (`--verbose`, optionally `--flag=no`).
700
697
  *
701
- * Parsing: absent → default value; `--flag` / `--flag=yes` `true`; `--flag=no` → `false`;
702
- * specified more than once → throws {@link TypoError}.
698
+ * Syntax: `--long`, `--long=no`, `-s`, `-s=no`.
699
+ * Parsing logic:
700
+ * - absent → default value
701
+ * - `--flag` / `--flag=yes` → `true`
702
+ * - `--flag=no` → `false`
703
+ * - specified more than once → throws.
703
704
  *
704
705
  * @param definition.long - Long-form name (without `--`).
705
706
  * @param definition.short - Short-form name (without `-`).
@@ -716,11 +717,6 @@ type OptionDecoder<Value> = {
716
717
  * short: "v",
717
718
  * description: "Enable verbose output",
718
719
  * });
719
- * // Usage:
720
- * // my-cli → false
721
- * // my-cli --verbose → true
722
- * // my-cli --verbose=yes → true
723
- * // my-cli -v=no → false
724
720
  * ```
725
721
  */
726
722
  declare function optionFlag(definition: {
@@ -737,8 +733,13 @@ declare function optionFlag(definition: {
737
733
  /**
738
734
  * Creates an option that accepts exactly one value (e.g. `--output dist/`).
739
735
  *
740
- * Parsing: absent `defaultValue()`; once decoded with `type`; more than once → {@link TypoError}.
741
- * Value syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
736
+ * Syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
737
+ * Parsing logic:
738
+ * - absent → `fallbackValueIfAbsent()`
739
+ * - `--long value` → decoded with `type.decoder("value")`
740
+ * - more than once → throws
741
+ * - if `impliedValueIfNotInlined` is not provided, then: `--long` / `-s` without a value → throws
742
+ * - if `impliedValueIfNotInlined` is provided, then: `--long` / `-s` without an inline value → `impliedValueIfNotInlined()`
742
743
  *
743
744
  * @typeParam Value - Type produced by the decoder.
744
745
  *
@@ -748,8 +749,8 @@ declare function optionFlag(definition: {
748
749
  * @param definition.hint - Short note shown in parentheses.
749
750
  * @param definition.aliases - Additional names.
750
751
  * @param definition.type - Decoder for the raw string value.
751
- * @param definition.defaultIfNotSpecified - Default value when the option is not specified at all.
752
- * @param definition.valueIfNothingInlined - Default value when the option is specified without an inline value (e.g. `--option` or `-o`).
752
+ * @param definition.fallbackValueIfAbsent - Default value when the option is not specified at all.
753
+ * @param definition.impliedValueIfNotInlined - Default value when the option is specified without an inline value (e.g. `--option` or `-o`).
753
754
  * @returns An {@link Option}`<Value>`.
754
755
  *
755
756
  * @example
@@ -759,12 +760,8 @@ declare function optionFlag(definition: {
759
760
  * short: "o",
760
761
  * type: typePath(),
761
762
  * description: "Output directory",
762
- * defaultIfNotSpecified: () => "dist",
763
+ * fallbackValueIfAbsent: () => "dist",
763
764
  * });
764
- * // Usage:
765
- * // my-cli → "dist"
766
- * // my-cli --output folder → "folder"
767
- * // my-cli -o folder → "folder"
768
765
  * ```
769
766
  */
770
767
  declare function optionSingleValue<Value>(definition: {
@@ -777,14 +774,16 @@ declare function optionSingleValue<Value>(definition: {
777
774
  shorts?: Array<string>;
778
775
  };
779
776
  type: Type<Value>;
780
- defaultIfNotSpecified: () => Value;
781
- valueIfNothingInlined?: () => Value;
777
+ fallbackValueIfAbsent?: () => Value;
778
+ impliedValueIfNotInlined?: () => Value;
782
779
  }): Option<Value>;
783
780
  /**
784
781
  * Creates an option that collects every occurrence into an array (e.g. `--file a.ts --file b.ts`).
785
782
  *
786
- * Parsing: absent `[]`; N occurrences array of N decoded values in order.
787
- * Value syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
783
+ * Syntax: `--long value`, `--long=value`, `-s value`, `-s=value`, `-svalue`.
784
+ * Parsing logic:
785
+ * - absent → `[]`
786
+ * - N occurrences → array of N decoded values in order.
788
787
  *
789
788
  * @typeParam Value - Type produced by the decoder for each occurrence.
790
789
  *
@@ -805,7 +804,6 @@ declare function optionSingleValue<Value>(definition: {
805
804
  * label: "PATH",
806
805
  * description: "Input file (may be repeated)",
807
806
  * });
808
- * // Usage: my-cli --file a.ts --file b.ts → ["a.ts", "b.ts"]
809
807
  * ```
810
808
  */
811
809
  declare function optionRepeatable<Value>(definition: {
@@ -846,18 +844,24 @@ type PositionalDecoder<Value> = {
846
844
  /**
847
845
  * Returns the decoded positional value.
848
846
  *
849
- * @throws {@link TypoError} if decoding failed.
847
+ * @throws if decoding failed.
850
848
  */
851
849
  decodeValue(): Value;
852
850
  };
853
851
  /**
854
- * Creates a required positional — missing token throws {@link TypoError}.
852
+ * Creates a required positional — missing token throws.
853
+ *
854
+ * Syntax: `<type>`, e.g. `<NAME>`.
855
+ * Parsing logic:
856
+ * - "token" → decoded with `type.decoder("token")`
857
+ * - token missing → throws
855
858
  *
856
859
  * @typeParam Value - Type produced by the decoder.
857
860
  *
858
861
  * @param definition.description - Help text.
859
862
  * @param definition.hint - Short note shown in parentheses.
860
863
  * @param definition.type - Decoder for the raw token.
864
+ * @param definition.missing - Message shown when the token is missing.
861
865
  * @returns A {@link Positional}`<Value>`.
862
866
  *
863
867
  * @example
@@ -866,8 +870,6 @@ type PositionalDecoder<Value> = {
866
870
  * type: type("name"),
867
871
  * description: "The name to greet",
868
872
  * });
869
- * // Usage:
870
- * // my-cli Alice → "Alice"
871
873
  * ```
872
874
  */
873
875
  declare function positionalRequired<Value>(definition: {
@@ -878,6 +880,11 @@ declare function positionalRequired<Value>(definition: {
878
880
  /**
879
881
  * Creates an optional positional — absent token falls back to `default()`.
880
882
  *
883
+ * Syntax: `[type]`, e.g. `[NAME]`.
884
+ * Parsing logic:
885
+ * - "token" → decoded with `type.decoder("token")`
886
+ * - token missing → `default()`
887
+ *
881
888
  * @typeParam Value - Type produced by the decoder (or the default).
882
889
  *
883
890
  * @param definition.description - Help text.
@@ -894,9 +901,6 @@ declare function positionalRequired<Value>(definition: {
894
901
  * hint: "Defaults to \"world\"",
895
902
  * default: () => "world",
896
903
  * });
897
- * // Usage:
898
- * // my-cli → "world"
899
- * // my-cli Alice → "Alice"
900
904
  * ```
901
905
  */
902
906
  declare function positionalOptional<Value>(definition: {
@@ -909,6 +913,12 @@ declare function positionalOptional<Value>(definition: {
909
913
  * Creates a variadic positional that collects zero or more remaining tokens into an array.
910
914
  * Optionally stops at `endDelimiter` (consumed, not included).
911
915
  *
916
+ * Syntax: `[type]...`, e.g. `[NAME]...`.
917
+ * Parsing logic:
918
+ * - "a b ..." → decoded with `[type.decoder("a")`, `type.decoder("b"), ...]``
919
+ * - token missing → stops collection
920
+ * - endDelimiter encountered → stops collection
921
+ *
912
922
  * @typeParam Value - Type produced by the decoder for each token.
913
923
  *
914
924
  * @param definition.endDelimiter - Sentinel token that stops collection (consumed, not included).
@@ -923,9 +933,6 @@ declare function positionalOptional<Value>(definition: {
923
933
  * type: typePath(),
924
934
  * description: "Files to process",
925
935
  * });
926
- * // Usage:
927
- * // my-cli → []
928
- * // my-cli a.ts b.ts c.ts → ["a.ts", "b.ts", "c.ts"]
929
936
  * ```
930
937
  */
931
938
  declare function positionalVariadics<Value>(definition: {
@@ -944,7 +951,7 @@ declare function positionalVariadics<Value>(definition: {
944
951
  * @typeParam Context - Injected at execution; forwarded to handlers.
945
952
  * @typeParam Result - Value produced on execution; typically `void`.
946
953
  */
947
- type Operation<Context, Result> = {
954
+ type Operation<Context, Result = void> = {
948
955
  /**
949
956
  * Returns usage metadata without consuming any arguments.
950
957
  */
@@ -973,7 +980,7 @@ type OperationDecoder<Context, Result> = {
973
980
  /**
974
981
  * Creates a ready-to-execute {@link OperationInterpreter}.
975
982
  *
976
- * @throws {@link TypoError} if parsing or decoding failed.
983
+ * @throws if parsing or decoding failed.
977
984
  */
978
985
  decodeAndMakeInterpreter(): OperationInterpreter<Context, Result>;
979
986
  };
@@ -1023,18 +1030,22 @@ type OperationInterpreter<Context, Result> = {
1023
1030
  * );
1024
1031
  * ```
1025
1032
  */
1026
- declare function operation<Context, Result, Options extends {
1033
+ declare function operation<Context, Result, const Options extends {
1027
1034
  [option: string]: any;
1028
- }, const Positionals extends Array<any>>(inputs: {
1029
- options: {
1035
+ } = {}, const Positionals extends Array<any> = []>(inputs: {
1036
+ options?: {
1030
1037
  [K in keyof Options]: Option<Options[K]>;
1031
1038
  };
1032
- positionals: {
1039
+ positionals?: {
1033
1040
  [K in keyof Positionals]: Positional<Positionals[K]>;
1034
1041
  };
1035
1042
  }, handler: (context: Context, inputs: {
1036
- options: Options;
1037
- positionals: Positionals;
1043
+ options: {
1044
+ [K in keyof Options]: Options[K];
1045
+ };
1046
+ positionals: {
1047
+ [K in keyof Positionals]: Positionals[K];
1048
+ };
1038
1049
  }) => Promise<Result>): Operation<Context, Result>;
1039
1050
 
1040
1051
  /**
@@ -1043,7 +1054,7 @@ declare function operation<Context, Result, Options extends {
1043
1054
  * @typeParam Context - Injected at execution; forwarded to handlers.
1044
1055
  * @typeParam Result - Produced on execution; typically `void`.
1045
1056
  */
1046
- type Command<Context, Result> = {
1057
+ type Command<Context, Result = void> = {
1047
1058
  /**
1048
1059
  * Returns static metadata.
1049
1060
  */
@@ -1067,7 +1078,7 @@ type CommandDecoder<Context, Result> = {
1067
1078
  /**
1068
1079
  * Creates a ready-to-execute {@link CommandInterpreter}.
1069
1080
  *
1070
- * @throws {@link TypoError} if parsing or decoding failed.
1081
+ * @throws if parsing or decoding failed.
1071
1082
  */
1072
1083
  decodeAndMakeInterpreter(): CommandInterpreter<Context, Result>;
1073
1084
  };
@@ -1142,15 +1153,16 @@ type CommandInformation = {
1142
1153
  * const greet = command(
1143
1154
  * { description: "Greet a user" },
1144
1155
  * operation(
1145
- * { options: {}, positionals: [positionalRequired({ type: type("name") })] },
1156
+ * { positionals: [positionalRequired({ type: type("name") })] },
1146
1157
  * async (_ctx, { positionals: [name] }) => console.log(`Hello, ${name}!`),
1147
1158
  * ),
1148
1159
  * );
1149
1160
  * ```
1150
1161
  */
1151
- declare function command<Context, Result>(information: CommandInformation, operation: Operation<Context, Result>): Command<Context, Result>;
1162
+ declare function command<Context, Result = void>(information: CommandInformation, operation: Operation<Context, Result>): Command<Context, Result>;
1152
1163
  /**
1153
- * Creates a command that runs `operation` first, then dispatches to a named subcommand.
1164
+ * Creates a command that runs `operation` first,
1165
+ * then dispatches result to a named subcommand.
1154
1166
  *
1155
1167
  * @typeParam Context - Context accepted by `operation`.
1156
1168
  * @typeParam Payload - Output of `operation`; becomes the subcommand's context.
@@ -1173,12 +1185,12 @@ declare function command<Context, Result>(information: CommandInformation, opera
1173
1185
  * );
1174
1186
  * ```
1175
1187
  */
1176
- declare function commandWithSubcommands<Context, Payload, Result>(information: CommandInformation, operation: Operation<Context, Payload>, subcommands: {
1188
+ declare function commandWithSubcommands<Context, Payload, Result = void>(information: CommandInformation, operation: Operation<Context, Payload>, subcommands: {
1177
1189
  [subcommand: string]: Command<Payload, Result>;
1178
1190
  }): Command<Context, Result>;
1179
1191
  /**
1180
- * Chains an {@link Operation} and a {@link Command}: `operation` runs first, its
1181
- * output becomes `subcommand`'s context. No token is consumed for routing.
1192
+ * Chains an {@link Operation} and a {@link Command}: `operation` runs first,
1193
+ * its output becomes `subcommand`'s context. No token is consumed for routing.
1182
1194
  *
1183
1195
  * @typeParam Context - Context accepted by `operation`.
1184
1196
  * @typeParam Payload - Output of `operation`; becomes `subcommand`'s context.
@@ -1189,7 +1201,7 @@ declare function commandWithSubcommands<Context, Payload, Result>(information: C
1189
1201
  * @param subcommand - Runs after `operation`.
1190
1202
  * @returns A {@link Command} composing both stages.
1191
1203
  */
1192
- declare function commandChained<Context, Payload, Result>(information: CommandInformation, operation: Operation<Context, Payload>, subcommand: Command<Payload, Result>): Command<Context, Result>;
1204
+ declare function commandChained<Context, Payload, Result = void>(information: CommandInformation, operation: Operation<Context, Payload>, subcommand: Command<Payload, Result>): Command<Context, Result>;
1193
1205
 
1194
1206
  /**
1195
1207
  * Color selection modes availables
@@ -1246,11 +1258,9 @@ declare function runAndExit<Context>(cliName: string, cliArgs: ReadonlyArray<str
1246
1258
  onExit?: ((code: number) => never) | undefined;
1247
1259
  }): Promise<never>;
1248
1260
 
1249
- declare function similaritySort<Value>(reference: string, candidates: {
1250
- [key: string]: Value;
1251
- } | Array<{
1252
- key: string;
1253
- value: Value;
1254
- }>): Array<Value>;
1261
+ declare function suggestTextPushMessage(text: TypoText, query: string, candidates: Array<{
1262
+ reference: string;
1263
+ hint: TypoSegment;
1264
+ }>): void;
1255
1265
 
1256
- export { type Command, type CommandDecoder, type CommandInformation, type CommandInterpreter, type Operation, type OperationDecoder, type OperationInterpreter, type Option, type OptionDecoder, type Positional, type PositionalDecoder, ReaderArgs, type ReaderOptionKey, type ReaderOptionParsing, type ReaderOptionValue, type ReaderOptions, type ReaderPositionals, type RunColorMode, type Type, type TypoColor, TypoError, TypoGrid, type TypoSegment, TypoString, type TypoStyle, TypoSupport, TypoText, type UsageCommand, type UsageOption, type UsagePositional, type UsageSubcommand, command, commandChained, commandWithSubcommands, operation, optionFlag, optionRepeatable, optionSingleValue, positionalOptional, positionalRequired, positionalVariadics, runAndExit, similaritySort, type, typeBoolean, typeBooleanValuesFalse, typeBooleanValuesTrue, typeChoice, typeConverted, typeDatetime, typeInteger, typeList, typeNumber, typePath, typeRenamed, typeTuple, typeUrl, typoStyleConstants, typoStyleFailure, typoStyleLogic, typoStyleQuote, typoStyleRegularStrong, typoStyleRegularWeaker, typoStyleTitle, typoStyleUserInput, usageToStyledLines };
1266
+ export { type Command, type CommandDecoder, type CommandInformation, type CommandInterpreter, type Operation, type OperationDecoder, type OperationInterpreter, type Option, type OptionDecoder, type Positional, type PositionalDecoder, ReaderArgs, type ReaderOptionGetter, type ReaderOptionLongSpec, type ReaderOptionNextGuard, type ReaderOptionShortSpec, type ReaderOptionValue, type ReaderOptions, type ReaderPositionals, type RunColorMode, type Type, type TypoColor, TypoError, TypoGrid, type TypoSegment, TypoString, type TypoStyle, TypoSupport, TypoText, type UsageCommand, type UsageOption, type UsagePositional, type UsageSubcommand, command, commandChained, commandWithSubcommands, operation, optionFlag, optionRepeatable, optionSingleValue, positionalOptional, positionalRequired, positionalVariadics, runAndExit, suggestTextPushMessage, typeBoolean, typeChoice, typeDatetime, typeInteger, typeList, typeMapped, typeNumber, typePath, typeRenamed, typeString, typeTuple, typeUrl, typoStyleConstants, typoStyleFailure, typoStyleLogic, typoStyleQuote, typoStyleRegularStrong, typoStyleRegularWeaker, typoStyleTitle, typoStyleUserInput, usageToStyledLines };