cli-forge 0.10.1 → 0.12.0

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 (103) hide show
  1. package/.eslintrc.json +35 -0
  2. package/LICENSE.md +5 -0
  3. package/README.md +181 -5
  4. package/cli.js +9 -0
  5. package/dist/bin/cli.d.ts +23 -0
  6. package/{bin → dist/bin}/cli.js +2 -2
  7. package/dist/bin/cli.js.map +1 -0
  8. package/dist/bin/commands/generate-documentation.d.ts +14 -0
  9. package/{bin → dist/bin}/commands/generate-documentation.js +58 -11
  10. package/dist/bin/commands/generate-documentation.js.map +1 -0
  11. package/{bin → dist/bin}/commands/init.d.ts +11 -11
  12. package/{bin → dist/bin}/commands/init.js +11 -6
  13. package/dist/bin/commands/init.js.map +1 -0
  14. package/dist/bin/utils/fs.js.map +1 -0
  15. package/{src → dist}/index.d.ts +2 -1
  16. package/dist/index.js.map +1 -0
  17. package/dist/lib/cli-option-groups.js.map +1 -0
  18. package/dist/lib/composable-builder.d.ts +24 -0
  19. package/dist/lib/composable-builder.js +17 -0
  20. package/dist/lib/composable-builder.js.map +1 -0
  21. package/dist/lib/configuration-providers.js.map +1 -0
  22. package/{src → dist}/lib/documentation.d.ts +3 -3
  23. package/dist/lib/documentation.js.map +1 -0
  24. package/dist/lib/format-help.js.map +1 -0
  25. package/{src → dist}/lib/interactive-shell.d.ts +1 -1
  26. package/{src → dist}/lib/interactive-shell.js +6 -3
  27. package/dist/lib/interactive-shell.js.map +1 -0
  28. package/{src → dist}/lib/internal-cli.d.ts +38 -21
  29. package/{src → dist}/lib/internal-cli.js +48 -3
  30. package/dist/lib/internal-cli.js.map +1 -0
  31. package/dist/lib/public-api.d.ts +332 -0
  32. package/dist/lib/public-api.js.map +1 -0
  33. package/dist/lib/test-harness.js.map +1 -0
  34. package/dist/lib/utils.js.map +1 -0
  35. package/dist/middleware/zod.d.ts +4 -0
  36. package/dist/middleware/zod.js +18 -0
  37. package/dist/middleware/zod.js.map +1 -0
  38. package/dist/middleware.d.ts +1 -0
  39. package/dist/middleware.js +5 -0
  40. package/dist/middleware.js.map +1 -0
  41. package/package.json +29 -10
  42. package/project.json +7 -0
  43. package/src/bin/cli.ts +17 -0
  44. package/src/bin/commands/generate-documentation.ts +403 -0
  45. package/src/bin/commands/init.ts +320 -0
  46. package/src/bin/utils/fs.ts +11 -0
  47. package/src/index.ts +12 -0
  48. package/src/lib/cli-option-groups.ts +69 -0
  49. package/src/lib/composable-builder.ts +57 -0
  50. package/src/lib/configuration-providers.ts +36 -0
  51. package/src/lib/documentation.spec.ts +156 -0
  52. package/src/lib/documentation.ts +107 -0
  53. package/src/lib/format-help.ts +149 -0
  54. package/src/lib/interactive-shell.ts +115 -0
  55. package/src/lib/internal-cli.spec.ts +345 -0
  56. package/src/lib/internal-cli.ts +689 -0
  57. package/src/lib/public-api.ts +943 -0
  58. package/src/lib/test-harness.spec.ts +29 -0
  59. package/src/lib/test-harness.ts +69 -0
  60. package/src/lib/utils.spec.ts +25 -0
  61. package/src/lib/utils.ts +144 -0
  62. package/src/middleware/zod.ts +21 -0
  63. package/src/middleware.ts +1 -0
  64. package/tsconfig.json +23 -0
  65. package/tsconfig.lib.json +20 -0
  66. package/tsconfig.lib.json.tsbuildinfo +1 -0
  67. package/tsconfig.spec.json +26 -0
  68. package/vitest.config.mts +18 -0
  69. package/bin/cli.d.ts +0 -6
  70. package/bin/cli.js.map +0 -1
  71. package/bin/commands/generate-documentation.d.ts +0 -14
  72. package/bin/commands/generate-documentation.js.map +0 -1
  73. package/bin/commands/init.js.map +0 -1
  74. package/bin/utils/fs.js.map +0 -1
  75. package/src/index.js.map +0 -1
  76. package/src/lib/cli-option-groups.js.map +0 -1
  77. package/src/lib/composable-builder.d.ts +0 -3
  78. package/src/lib/composable-builder.js +0 -7
  79. package/src/lib/composable-builder.js.map +0 -1
  80. package/src/lib/configuration-providers.js.map +0 -1
  81. package/src/lib/documentation.js.map +0 -1
  82. package/src/lib/format-help.js.map +0 -1
  83. package/src/lib/interactive-shell.js.map +0 -1
  84. package/src/lib/internal-cli.js.map +0 -1
  85. package/src/lib/public-api.d.ts +0 -215
  86. package/src/lib/public-api.js.map +0 -1
  87. package/src/lib/test-harness.js.map +0 -1
  88. package/src/lib/utils.js.map +0 -1
  89. /package/{bin → dist/bin}/utils/fs.d.ts +0 -0
  90. /package/{bin → dist/bin}/utils/fs.js +0 -0
  91. /package/{src → dist}/index.js +0 -0
  92. /package/{src → dist}/lib/cli-option-groups.d.ts +0 -0
  93. /package/{src → dist}/lib/cli-option-groups.js +0 -0
  94. /package/{src → dist}/lib/configuration-providers.d.ts +0 -0
  95. /package/{src → dist}/lib/configuration-providers.js +0 -0
  96. /package/{src → dist}/lib/documentation.js +0 -0
  97. /package/{src → dist}/lib/format-help.d.ts +0 -0
  98. /package/{src → dist}/lib/format-help.js +0 -0
  99. /package/{src → dist}/lib/public-api.js +0 -0
  100. /package/{src → dist}/lib/test-harness.d.ts +0 -0
  101. /package/{src → dist}/lib/test-harness.js +0 -0
  102. /package/{src → dist}/lib/utils.d.ts +0 -0
  103. /package/{src → dist}/lib/utils.js +0 -0
@@ -0,0 +1,943 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import {
3
+ type ConfigurationFiles,
4
+ OptionConfig,
5
+ OptionConfigToType,
6
+ ParsedArgs,
7
+ EnvOptionConfig,
8
+ ObjectOptionConfig,
9
+ StringOptionConfig,
10
+ NumberOptionConfig,
11
+ BooleanOptionConfig,
12
+ ArrayOptionConfig,
13
+ ResolveProperties,
14
+ WithOptional,
15
+ MakeUndefinedPropertiesOptional,
16
+ WithAdditionalProperties,
17
+ } from '@cli-forge/parser';
18
+
19
+ import { InternalCLI } from './internal-cli';
20
+
21
+ /**
22
+ * Extracts the command name from a Command type.
23
+ * Works with both CLI instances and command config objects.
24
+ */
25
+ export type ExtractCommandName<T> = T extends CLI<any, any, any>
26
+ ? T extends InternalCLI<any, any, any>
27
+ ? string
28
+ : string
29
+ : T extends { name: infer N }
30
+ ? N extends string
31
+ ? N
32
+ : string
33
+ : string;
34
+
35
+ /**
36
+ * Extracts the args type from a Command.
37
+ * Works with both CLI instances and command config objects.
38
+ */
39
+ export type ExtractCommandArgs<T> = T extends CLI<infer A, any, any>
40
+ ? A
41
+ : T extends CLICommandOptions<any, infer A, any, any>
42
+ ? A
43
+ : ParsedArgs;
44
+
45
+ /**
46
+ * Extracts the handler return type from a Command.
47
+ */
48
+ export type ExtractCommandHandlerReturn<T> = T extends CLI<any, infer R, any>
49
+ ? R
50
+ : T extends CLICommandOptions<any, any, infer R, any>
51
+ ? R
52
+ : void;
53
+
54
+ /**
55
+ * Converts a Command to its child CLI entry for TChildren tracking.
56
+ * TParentCLI is the parent CLI type that will be set as the child's TParent.
57
+ */
58
+ export type CommandToChildEntry<T, TParentCLI = undefined> = {
59
+ [K in ExtractCommandName<T>]: CLI<
60
+ ExtractCommandArgs<T>,
61
+ ExtractCommandHandlerReturn<T>,
62
+ {},
63
+ TParentCLI
64
+ >;
65
+ };
66
+
67
+ /**
68
+ * The interface for a CLI application or subcommands.
69
+ *
70
+ * {@link cli} is provided as a small helper function to create a new CLI instance.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * import { cli } from 'cli-forge';
75
+ *
76
+ * cli('basic-cli').command('hello', {
77
+ * builder: (args) =>
78
+ * args.option('name', {
79
+ * type: 'string',
80
+ * }),
81
+ * handler: (args) => {
82
+ * console.log(`Hello, ${args.name}!`);
83
+ * }).forge();
84
+ * ```
85
+ */
86
+ export interface CLI<
87
+ TArgs extends ParsedArgs = ParsedArgs,
88
+ THandlerReturn = void,
89
+ // eslint-disable-next-line @typescript-eslint/ban-types
90
+ TChildren = {},
91
+ TParent = undefined
92
+ > {
93
+ command<TCommandArgs extends TArgs>(
94
+ cmd: Command<TArgs, TCommandArgs>
95
+ ): CLI<
96
+ TArgs,
97
+ THandlerReturn,
98
+ TChildren &
99
+ (typeof cmd extends Command<TArgs, infer TCommandArgs, infer TCmdName>
100
+ ? {
101
+ [key in TCmdName]: CLI<
102
+ TCommandArgs,
103
+ void,
104
+ {},
105
+ CLI<TArgs, THandlerReturn, TChildren, TParent>
106
+ >;
107
+ }
108
+ : {}),
109
+ TParent
110
+ >;
111
+
112
+ /**
113
+ * Registers a new command with the CLI.
114
+ * @param key What should the new command be called?
115
+ * @param options Settings for the new command. See {@link CLICommandOptions}.
116
+ * @returns Updated CLI instance with the new command registered.
117
+ */
118
+ command<
119
+ TCommandArgs extends TArgs,
120
+ TChildHandlerReturn,
121
+ TKey extends string,
122
+ // eslint-disable-next-line @typescript-eslint/ban-types
123
+ TChildChildren = {}
124
+ >(
125
+ key: TKey,
126
+ options: CLICommandOptions<
127
+ TArgs,
128
+ TCommandArgs,
129
+ TChildHandlerReturn,
130
+ any,
131
+ CLI<TArgs, THandlerReturn, TChildren, TParent>,
132
+ TChildChildren
133
+ >
134
+ ): CLI<
135
+ TArgs,
136
+ THandlerReturn,
137
+ TChildren & {
138
+ [key in TKey]: CLI<
139
+ TCommandArgs,
140
+ TChildHandlerReturn,
141
+ TChildChildren,
142
+ CLI<TArgs, THandlerReturn, TChildren, TParent>
143
+ >;
144
+ },
145
+ TParent
146
+ >;
147
+
148
+ /**
149
+ * Registers multiple subcommands with the CLI.
150
+ * @param commands Several commands to register. Can be the result of a call to {@link cli} or a configuration object.
151
+ * @returns Updated CLI instance with the commands registered and their types tracked in TChildren.
152
+ */
153
+ // Typed overloads for 1-10 commands to preserve individual command types
154
+ // Each child command gets this CLI as its TParent
155
+ commands<C1 extends Command>(
156
+ c1: C1
157
+ ): CLI<
158
+ TArgs,
159
+ THandlerReturn,
160
+ TChildren &
161
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
162
+ TParent
163
+ >;
164
+ commands<C1 extends Command, C2 extends Command>(
165
+ c1: C1,
166
+ c2: C2
167
+ ): CLI<
168
+ TArgs,
169
+ THandlerReturn,
170
+ TChildren &
171
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
172
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
173
+ TParent
174
+ >;
175
+ commands<C1 extends Command, C2 extends Command, C3 extends Command>(
176
+ c1: C1,
177
+ c2: C2,
178
+ c3: C3
179
+ ): CLI<
180
+ TArgs,
181
+ THandlerReturn,
182
+ TChildren &
183
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
184
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
185
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
186
+ TParent
187
+ >;
188
+ commands<
189
+ C1 extends Command,
190
+ C2 extends Command,
191
+ C3 extends Command,
192
+ C4 extends Command
193
+ >(
194
+ c1: C1,
195
+ c2: C2,
196
+ c3: C3,
197
+ c4: C4
198
+ ): CLI<
199
+ TArgs,
200
+ THandlerReturn,
201
+ TChildren &
202
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
203
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
204
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
205
+ CommandToChildEntry<C4, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
206
+ TParent
207
+ >;
208
+ commands<
209
+ C1 extends Command,
210
+ C2 extends Command,
211
+ C3 extends Command,
212
+ C4 extends Command,
213
+ C5 extends Command
214
+ >(
215
+ c1: C1,
216
+ c2: C2,
217
+ c3: C3,
218
+ c4: C4,
219
+ c5: C5
220
+ ): CLI<
221
+ TArgs,
222
+ THandlerReturn,
223
+ TChildren &
224
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
225
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
226
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
227
+ CommandToChildEntry<C4, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
228
+ CommandToChildEntry<C5, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
229
+ TParent
230
+ >;
231
+ commands<
232
+ C1 extends Command,
233
+ C2 extends Command,
234
+ C3 extends Command,
235
+ C4 extends Command,
236
+ C5 extends Command,
237
+ C6 extends Command
238
+ >(
239
+ c1: C1,
240
+ c2: C2,
241
+ c3: C3,
242
+ c4: C4,
243
+ c5: C5,
244
+ c6: C6
245
+ ): CLI<
246
+ TArgs,
247
+ THandlerReturn,
248
+ TChildren &
249
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
250
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
251
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
252
+ CommandToChildEntry<C4, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
253
+ CommandToChildEntry<C5, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
254
+ CommandToChildEntry<C6, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
255
+ TParent
256
+ >;
257
+ commands<
258
+ C1 extends Command,
259
+ C2 extends Command,
260
+ C3 extends Command,
261
+ C4 extends Command,
262
+ C5 extends Command,
263
+ C6 extends Command,
264
+ C7 extends Command
265
+ >(
266
+ c1: C1,
267
+ c2: C2,
268
+ c3: C3,
269
+ c4: C4,
270
+ c5: C5,
271
+ c6: C6,
272
+ c7: C7
273
+ ): CLI<
274
+ TArgs,
275
+ THandlerReturn,
276
+ TChildren &
277
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
278
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
279
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
280
+ CommandToChildEntry<C4, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
281
+ CommandToChildEntry<C5, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
282
+ CommandToChildEntry<C6, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
283
+ CommandToChildEntry<C7, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
284
+ TParent
285
+ >;
286
+ commands<
287
+ C1 extends Command,
288
+ C2 extends Command,
289
+ C3 extends Command,
290
+ C4 extends Command,
291
+ C5 extends Command,
292
+ C6 extends Command,
293
+ C7 extends Command,
294
+ C8 extends Command
295
+ >(
296
+ c1: C1,
297
+ c2: C2,
298
+ c3: C3,
299
+ c4: C4,
300
+ c5: C5,
301
+ c6: C6,
302
+ c7: C7,
303
+ c8: C8
304
+ ): CLI<
305
+ TArgs,
306
+ THandlerReturn,
307
+ TChildren &
308
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
309
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
310
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
311
+ CommandToChildEntry<C4, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
312
+ CommandToChildEntry<C5, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
313
+ CommandToChildEntry<C6, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
314
+ CommandToChildEntry<C7, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
315
+ CommandToChildEntry<C8, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
316
+ TParent
317
+ >;
318
+ commands<
319
+ C1 extends Command,
320
+ C2 extends Command,
321
+ C3 extends Command,
322
+ C4 extends Command,
323
+ C5 extends Command,
324
+ C6 extends Command,
325
+ C7 extends Command,
326
+ C8 extends Command,
327
+ C9 extends Command
328
+ >(
329
+ c1: C1,
330
+ c2: C2,
331
+ c3: C3,
332
+ c4: C4,
333
+ c5: C5,
334
+ c6: C6,
335
+ c7: C7,
336
+ c8: C8,
337
+ c9: C9
338
+ ): CLI<
339
+ TArgs,
340
+ THandlerReturn,
341
+ TChildren &
342
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
343
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
344
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
345
+ CommandToChildEntry<C4, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
346
+ CommandToChildEntry<C5, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
347
+ CommandToChildEntry<C6, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
348
+ CommandToChildEntry<C7, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
349
+ CommandToChildEntry<C8, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
350
+ CommandToChildEntry<C9, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
351
+ TParent
352
+ >;
353
+ commands<
354
+ C1 extends Command,
355
+ C2 extends Command,
356
+ C3 extends Command,
357
+ C4 extends Command,
358
+ C5 extends Command,
359
+ C6 extends Command,
360
+ C7 extends Command,
361
+ C8 extends Command,
362
+ C9 extends Command,
363
+ C10 extends Command
364
+ >(
365
+ c1: C1,
366
+ c2: C2,
367
+ c3: C3,
368
+ c4: C4,
369
+ c5: C5,
370
+ c6: C6,
371
+ c7: C7,
372
+ c8: C8,
373
+ c9: C9,
374
+ c10: C10
375
+ ): CLI<
376
+ TArgs,
377
+ THandlerReturn,
378
+ TChildren &
379
+ CommandToChildEntry<C1, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
380
+ CommandToChildEntry<C2, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
381
+ CommandToChildEntry<C3, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
382
+ CommandToChildEntry<C4, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
383
+ CommandToChildEntry<C5, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
384
+ CommandToChildEntry<C6, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
385
+ CommandToChildEntry<C7, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
386
+ CommandToChildEntry<C8, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
387
+ CommandToChildEntry<C9, CLI<TArgs, THandlerReturn, TChildren, TParent>> &
388
+ CommandToChildEntry<C10, CLI<TArgs, THandlerReturn, TChildren, TParent>>,
389
+ TParent
390
+ >;
391
+ // Fallback for arrays or more than 10 commands (loses individual type tracking)
392
+ commands(commands: Command[]): CLI<TArgs, THandlerReturn, TChildren, TParent>;
393
+ commands(
394
+ ...commands: Command[]
395
+ ): CLI<TArgs, THandlerReturn, TChildren, TParent>;
396
+
397
+ /**
398
+ * Register's a configuration provider for the CLI. See {@link ConfigurationProviders} for built-in providers.
399
+ *
400
+ * @param provider Provider to register.
401
+ */
402
+ config(
403
+ provider: ConfigurationFiles.ConfigurationProvider<TArgs>
404
+ ): CLI<TArgs, THandlerReturn, TChildren, TParent>;
405
+
406
+ /**
407
+ * Enables the ability to run CLI commands that contain subcommands as an interactive shell.
408
+ * This presents as a small shell that only knows the current command and its subcommands.
409
+ * Any flags already consumed by the command will be passed to every subcommand invocation.
410
+ */
411
+ enableInteractiveShell(): CLI<TArgs, THandlerReturn, TChildren, TParent>;
412
+
413
+ /**
414
+ * Registers a custom global error handler for the CLI. This handler will be called when an error is thrown
415
+ * during the execution of the CLI and not otherwise handled. Error handlers should re-throw the error if they
416
+ * cannot handle it, s.t. the next error handler can attempt to handle it.
417
+ *
418
+ * @param handler Typically called with an Error object, but you should be prepared to handle any type of error.
419
+ * @param actions Actions that can be taken by the error handler. Prefer using these over process.exit for better support of interactive shells.
420
+ */
421
+ errorHandler(
422
+ handler: ErrorHandler
423
+ ): CLI<TArgs, THandlerReturn, TChildren, TParent>;
424
+
425
+ /**
426
+ * Registers a new option for the CLI command. This option will be accessible
427
+ * within the command handler, as well as any subcommands.
428
+ *
429
+ * @param name The name of the option.
430
+ * @param config Configuration for the option. See {@link UnknownOptionConfig}.
431
+ * @returns Updated CLI instance with the new option registered.
432
+ */
433
+ // Object option overload - must come first for proper contextual typing
434
+ // Uses direct ObjectOptionConfig type (not `extends`) to ensure TypeScript
435
+ // infers TProps from `properties` BEFORE evaluating the coerce callback type
436
+ option<
437
+ TOption extends string,
438
+ TCoerce,
439
+ const TProps extends Record<string, { type: string }>,
440
+ TAdditionalProps extends false | 'string' | 'number' | 'boolean' = false
441
+ >(
442
+ name: TOption,
443
+ config: ObjectOptionConfig<TCoerce, TProps, TAdditionalProps>
444
+ ): CLI<
445
+ TArgs &
446
+ MakeUndefinedPropertiesOptional<{
447
+ [key in TOption]: WithOptional<
448
+ unknown extends TCoerce
449
+ ? WithAdditionalProperties<
450
+ ResolveProperties<TProps>,
451
+ TAdditionalProps
452
+ >
453
+ : TCoerce,
454
+ ObjectOptionConfig<TCoerce, TProps, TAdditionalProps>
455
+ >;
456
+ }>,
457
+ THandlerReturn,
458
+ TChildren,
459
+ TParent
460
+ >;
461
+ // String option overload
462
+ option<
463
+ TOption extends string,
464
+ const TConfig extends StringOptionConfig<any, any>
465
+ >(
466
+ name: TOption,
467
+ config: TConfig
468
+ ): CLI<
469
+ TArgs &
470
+ MakeUndefinedPropertiesOptional<{
471
+ [key in TOption]: OptionConfigToType<TConfig>;
472
+ }>,
473
+ THandlerReturn,
474
+ TChildren,
475
+ TParent
476
+ >;
477
+ // Number option overload
478
+ option<
479
+ TOption extends string,
480
+ const TConfig extends NumberOptionConfig<any, any>
481
+ >(
482
+ name: TOption,
483
+ config: TConfig
484
+ ): CLI<
485
+ TArgs &
486
+ MakeUndefinedPropertiesOptional<{
487
+ [key in TOption]: OptionConfigToType<TConfig>;
488
+ }>,
489
+ THandlerReturn,
490
+ TChildren,
491
+ TParent
492
+ >;
493
+ // Boolean option overload
494
+ option<
495
+ TOption extends string,
496
+ const TConfig extends BooleanOptionConfig<any, any>
497
+ >(
498
+ name: TOption,
499
+ config: TConfig
500
+ ): CLI<
501
+ TArgs &
502
+ MakeUndefinedPropertiesOptional<{
503
+ [key in TOption]: OptionConfigToType<TConfig>;
504
+ }>,
505
+ THandlerReturn,
506
+ TChildren,
507
+ TParent
508
+ >;
509
+ // Array option overload
510
+ option<
511
+ TOption extends string,
512
+ const TConfig extends ArrayOptionConfig<any, any>
513
+ >(
514
+ name: TOption,
515
+ config: TConfig
516
+ ): CLI<
517
+ TArgs &
518
+ MakeUndefinedPropertiesOptional<{
519
+ [key in TOption]: OptionConfigToType<TConfig>;
520
+ }>,
521
+ THandlerReturn,
522
+ TChildren,
523
+ TParent
524
+ >;
525
+ // Generic fallback overload
526
+ option<
527
+ TOption extends string,
528
+ const TOptionConfig extends OptionConfig<any, any, any, any>
529
+ >(
530
+ name: TOption,
531
+ config: TOptionConfig
532
+ ): CLI<
533
+ TArgs &
534
+ MakeUndefinedPropertiesOptional<{
535
+ [key in TOption]: OptionConfigToType<TOptionConfig>;
536
+ }>,
537
+ THandlerReturn,
538
+ TChildren,
539
+ TParent
540
+ >;
541
+
542
+ /**
543
+ * Registers a new positional argument for the CLI command. This argument will be accessible
544
+ * within the command handler, as well as any subcommands.
545
+ * @param name The name of the positional argument.
546
+ * @param config Configuration for the positional argument. See {@link UnknownOptionConfig}.
547
+ * @returns Updated CLI instance with the new positional argument registered.
548
+ */
549
+ // Object option overload - must come first for proper contextual typing
550
+ // Uses direct ObjectOptionConfig type (not `extends`) to ensure TypeScript
551
+ // infers TProps from `properties` BEFORE evaluating the coerce callback type
552
+ positional<
553
+ TOption extends string,
554
+ TCoerce,
555
+ const TProps extends Record<string, { type: string }>,
556
+ TAdditionalProps extends false | 'string' | 'number' | 'boolean' = false
557
+ >(
558
+ name: TOption,
559
+ config: ObjectOptionConfig<TCoerce, TProps, TAdditionalProps>
560
+ ): CLI<
561
+ TArgs &
562
+ MakeUndefinedPropertiesOptional<{
563
+ [key in TOption]: WithOptional<
564
+ unknown extends TCoerce
565
+ ? WithAdditionalProperties<
566
+ ResolveProperties<TProps>,
567
+ TAdditionalProps
568
+ >
569
+ : TCoerce,
570
+ ObjectOptionConfig<TCoerce, TProps, TAdditionalProps>
571
+ >;
572
+ }>,
573
+ THandlerReturn,
574
+ TChildren,
575
+ TParent
576
+ >;
577
+ // String option overload
578
+ positional<
579
+ TOption extends string,
580
+ const TConfig extends StringOptionConfig<any, any>
581
+ >(
582
+ name: TOption,
583
+ config: TConfig
584
+ ): CLI<
585
+ TArgs &
586
+ MakeUndefinedPropertiesOptional<{
587
+ [key in TOption]: OptionConfigToType<TConfig>;
588
+ }>,
589
+ THandlerReturn,
590
+ TChildren,
591
+ TParent
592
+ >;
593
+ // Number option overload
594
+ positional<
595
+ TOption extends string,
596
+ const TConfig extends NumberOptionConfig<any, any>
597
+ >(
598
+ name: TOption,
599
+ config: TConfig
600
+ ): CLI<
601
+ TArgs &
602
+ MakeUndefinedPropertiesOptional<{
603
+ [key in TOption]: OptionConfigToType<TConfig>;
604
+ }>,
605
+ THandlerReturn,
606
+ TChildren,
607
+ TParent
608
+ >;
609
+ // Boolean option overload
610
+ positional<
611
+ TOption extends string,
612
+ const TConfig extends BooleanOptionConfig<any, any>
613
+ >(
614
+ name: TOption,
615
+ config: TConfig
616
+ ): CLI<
617
+ TArgs &
618
+ MakeUndefinedPropertiesOptional<{
619
+ [key in TOption]: OptionConfigToType<TConfig>;
620
+ }>,
621
+ THandlerReturn,
622
+ TChildren,
623
+ TParent
624
+ >;
625
+ // Array option overload
626
+ positional<
627
+ TOption extends string,
628
+ const TConfig extends ArrayOptionConfig<any, any>
629
+ >(
630
+ name: TOption,
631
+ config: TConfig
632
+ ): CLI<
633
+ TArgs &
634
+ MakeUndefinedPropertiesOptional<{
635
+ [key in TOption]: OptionConfigToType<TConfig>;
636
+ }>,
637
+ THandlerReturn,
638
+ TChildren,
639
+ TParent
640
+ >;
641
+ // Generic fallback overload
642
+ positional<
643
+ TOption extends string,
644
+ const TOptionConfig extends OptionConfig<any, any, any, any>
645
+ >(
646
+ name: TOption,
647
+ config: TOptionConfig
648
+ ): CLI<
649
+ TArgs &
650
+ MakeUndefinedPropertiesOptional<{
651
+ [key in TOption]: OptionConfigToType<TOptionConfig>;
652
+ }>,
653
+ THandlerReturn,
654
+ TChildren,
655
+ TParent
656
+ >;
657
+
658
+ /**
659
+ * Adds support for reading CLI options from environment variables.
660
+ * @param prefix The prefix to use when looking up environment variables. Defaults to the command name.
661
+ */
662
+ env(prefix?: string): CLI<TArgs, THandlerReturn, TChildren, TParent>;
663
+
664
+ env(options: EnvOptionConfig): CLI<TArgs, THandlerReturn, TChildren, TParent>;
665
+
666
+ /**
667
+ * Sets a group of options as mutually exclusive. If more than one option is provided, there will be a validation error.
668
+ * @param options The options that should be mutually exclusive.
669
+ */
670
+ conflicts(
671
+ ...options: [string, string, ...string[]]
672
+ ): CLI<TArgs, THandlerReturn, TChildren, TParent>;
673
+
674
+ /**
675
+ * Sets a group of options as mutually inclusive. If one option is provided, all other options must also be provided.
676
+ * @param option The option that implies the other options.
677
+ * @param impliedOptions The options which become required when the option is provided.
678
+ */
679
+ implies(
680
+ option: string,
681
+ ...impliedOptions: string[]
682
+ ): CLI<TArgs, THandlerReturn, TChildren, TParent>;
683
+
684
+ /**
685
+ * Requires a command to be provided when executing the CLI. Useful if your parent command
686
+ * cannot be executed on its own.
687
+ * @returns Updated CLI instance.
688
+ */
689
+ demandCommand(): CLI<TArgs, THandlerReturn, TChildren, TParent>;
690
+
691
+ /**
692
+ * Sets the usage text for the CLI. This text will be displayed in place of the default usage text
693
+ * @param usageText Text displayed in place of the default usage text for `--help` and in generated docs.
694
+ */
695
+ usage(usageText: string): CLI<TArgs, THandlerReturn, TChildren, TParent>;
696
+
697
+ /**
698
+ * Sets the description for the CLI. This text will be displayed in the help text and generated docs.
699
+ * @param examples Examples to display in the help text and generated docs.
700
+ */
701
+ examples(
702
+ ...examples: string[]
703
+ ): CLI<TArgs, THandlerReturn, TChildren, TParent>;
704
+
705
+ /**
706
+ * Allows overriding the version displayed when passing `--version`. Defaults to crawling
707
+ * the file system to get the package.json of the currently executing command.
708
+ * @param override
709
+ */
710
+ version(override?: string): CLI<TArgs, THandlerReturn, TChildren, TParent>;
711
+
712
+ /**
713
+ * Prints help text to stdout.
714
+ */
715
+ printHelp(): void;
716
+
717
+ group({
718
+ label,
719
+ keys,
720
+ sortOrder,
721
+ }: {
722
+ label: string;
723
+ keys: (keyof TArgs)[];
724
+ sortOrder: number;
725
+ }): CLI<TArgs, THandlerReturn, TChildren, TParent>;
726
+ group(
727
+ label: string,
728
+ keys: (keyof TArgs)[]
729
+ ): CLI<TArgs, THandlerReturn, TChildren, TParent>;
730
+
731
+ middleware<TArgs2>(
732
+ callback: MiddlewareFunction<TArgs, TArgs2>
733
+ ): CLI<
734
+ TArgs2 extends void ? TArgs : TArgs & TArgs2,
735
+ THandlerReturn,
736
+ TChildren,
737
+ TParent
738
+ >;
739
+
740
+ /**
741
+ * Parses argv and executes the CLI
742
+ * @param args argv. Defaults to process.argv.slice(2)
743
+ * @returns Promise that resolves when the handler completes.
744
+ */
745
+ forge(args?: string[]): Promise<TArgs>;
746
+
747
+ /**
748
+ * Returns the typed children commands registered with this CLI.
749
+ * The return type is determined by the commands registered via `command()` or `commands()`.
750
+ *
751
+ * @example
752
+ * ```ts
753
+ * const app = cli('app')
754
+ * .command('init', { ... })
755
+ * .command('build', { ... });
756
+ *
757
+ * const children = app.getChildren();
758
+ * // children.init and children.build are typed CLI instances
759
+ * const initHandler = children.init.getHandler();
760
+ * ```
761
+ */
762
+ getChildren(): TChildren;
763
+
764
+ /**
765
+ * Returns the parent CLI instance, if this command was registered as a subcommand.
766
+ * Returns undefined for root-level CLI instances.
767
+ *
768
+ * @example
769
+ * ```ts
770
+ * const build = cli('build', {
771
+ * handler: (args, ctx) => {
772
+ * const parent = ctx.command.getParent();
773
+ * const siblings = parent?.getChildren();
774
+ * // Access sibling commands
775
+ * }
776
+ * });
777
+ * ```
778
+ */
779
+ getParent(): TParent;
780
+
781
+ getBuilder<T extends ParsedArgs = ParsedArgs>(
782
+ initialCli?: CLI<T, any, any>
783
+ ):
784
+ | ((parser: CLI<T, any, any>) => CLI<TArgs, THandlerReturn, TChildren>)
785
+ | undefined;
786
+ getHandler():
787
+ | ((args: Omit<TArgs, keyof ParsedArgs>) => THandlerReturn)
788
+ | undefined;
789
+ }
790
+
791
+ export interface CLIHandlerContext<TChildren = {}, TParent = any> {
792
+ command: CLI<any, any, TChildren, TParent>;
793
+ }
794
+
795
+ /**
796
+ * Extracts the TChildren type parameter from a CLI type.
797
+ */
798
+ export type ExtractCLIChildren<T> = T extends CLI<any, any, infer C, any>
799
+ ? C
800
+ : {};
801
+
802
+ /**
803
+ * Represents the configuration needed to create a CLI command.
804
+ */
805
+ export interface CLICommandOptions<
806
+ /**
807
+ * The type of the arguments that are already registered before `builder` is invoked.
808
+ */
809
+ TInitial extends ParsedArgs,
810
+ /**
811
+ * The type of the arguments that are registered after `builder` is invoked, and the type that is passed to the handler.
812
+ */
813
+ TArgs extends TInitial = TInitial,
814
+ THandlerReturn = void,
815
+ /**
816
+ * The children commands that exist before the builder runs.
817
+ */
818
+ // eslint-disable-next-line @typescript-eslint/ban-types
819
+ TInitialChildren = {},
820
+ TParent = any,
821
+ /**
822
+ * The children commands after the builder runs (includes TInitialChildren plus any added by builder).
823
+ */
824
+ // eslint-disable-next-line @typescript-eslint/ban-types
825
+ TChildren = {}
826
+ > {
827
+ /**
828
+ * If set the command will be registered under the provided name and any aliases.
829
+ *
830
+ * This can be useful if a command should be executed under more than one name, e.g. `npx my-cli` and `npx my-cli hello`.
831
+ */
832
+ alias?: string[];
833
+
834
+ /**
835
+ * The command description. This will be displayed in the help text and generated docs.
836
+ */
837
+ description?: string;
838
+
839
+ /**
840
+ * The command builder. This function is called before the command is executed, and is used to register options and positional parameters.
841
+ * @param parser The parser instance to register options and positionals with.
842
+ */
843
+ // Note: Builder uses 'any' for THandlerReturn to avoid inference conflicts with the handler.
844
+ // The handler's return type is inferred independently from the handler function itself.
845
+ builder?: (
846
+ parser: CLI<TInitial, any, TInitialChildren, TParent>
847
+ ) => CLI<TArgs, any, TChildren, any>;
848
+
849
+ /**
850
+ * The command handler. This function is called when the command is executed.
851
+ * @param args The parsed arguments.
852
+ * @param context Context for the handler. Contains the command instance.
853
+ */
854
+ handler?: (
855
+ args: NoInfer<TArgs>,
856
+ context: CLIHandlerContext<NoInfer<TChildren>, TParent>
857
+ ) => THandlerReturn;
858
+
859
+ /**
860
+ * The usage text for the command. This text will be displayed in place of the default usage text in the help text and generated docs.
861
+ */
862
+ usage?: string;
863
+
864
+ /**
865
+ * Examples to display in the help text and generated docs.
866
+ */
867
+ examples?: string[];
868
+
869
+ /**
870
+ * Hides the command from the help text and generated docs. Useful primarily for experimental or internal commands.
871
+ */
872
+ hidden?: boolean;
873
+
874
+ /**
875
+ * The epilogue text for the command. This text will be displayed at the end of the help text and generated docs.
876
+ */
877
+ epilogue?: string;
878
+ }
879
+
880
+ export type Command<
881
+ TInitial extends ParsedArgs = any,
882
+ TArgs extends TInitial = TInitial,
883
+ TCommandName extends string = string
884
+ > =
885
+ | ({
886
+ name: TCommandName;
887
+ } & CLICommandOptions<TInitial, TArgs>)
888
+ | CLI<TArgs>;
889
+
890
+ /**
891
+ * Error Handler for CLI applications. Error handlers should re-throw the error if they cannot handle it.
892
+ *
893
+ * @param e The error that was thrown.
894
+ * @param actions Actions that can be taken by the error handler. Prefer using these over process.exit for better support of interactive shells.
895
+ */
896
+ export type ErrorHandler = (
897
+ e: unknown,
898
+ actions: {
899
+ /**
900
+ * Exits the process immediately.
901
+ * @param code
902
+ */
903
+ exit: (code?: number) => void;
904
+ }
905
+ ) => void;
906
+
907
+ export type UnknownCLI = CLI<ParsedArgs, any, any, any>;
908
+
909
+ export type MiddlewareFunction<TArgs extends ParsedArgs, TArgs2> = (
910
+ args: TArgs
911
+ ) => TArgs2 | Promise<TArgs2>;
912
+
913
+ /**
914
+ * Constructs a CLI instance. See {@link CLI} for more information.
915
+ * @param name Name for the top level CLI
916
+ * @param rootCommandConfiguration Configuration used when running the bare CLI. e.g. npx my-cli, rather than npx my-cli [cmd]
917
+ * @returns A {@link CLI} instance.
918
+ */
919
+ export function cli<
920
+ TArgs extends ParsedArgs,
921
+ THandlerReturn = void,
922
+ // eslint-disable-next-line @typescript-eslint/ban-types
923
+ TChildren = {},
924
+ TName extends string = string
925
+ >(
926
+ name: TName,
927
+ rootCommandConfiguration?: CLICommandOptions<
928
+ ParsedArgs,
929
+ TArgs,
930
+ THandlerReturn,
931
+ {},
932
+ any,
933
+ TChildren
934
+ >
935
+ ) {
936
+ return new InternalCLI(name, rootCommandConfiguration as any) as any as CLI<
937
+ TArgs,
938
+ THandlerReturn,
939
+ TChildren
940
+ >;
941
+ }
942
+
943
+ export default cli;