@boneskull/bargs 3.2.0 → 3.4.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.
- package/README.md +125 -52
- package/dist/bargs.cjs +139 -21
- package/dist/bargs.cjs.map +1 -1
- package/dist/bargs.d.cts +51 -5
- package/dist/bargs.d.cts.map +1 -1
- package/dist/bargs.d.ts +51 -5
- package/dist/bargs.d.ts.map +1 -1
- package/dist/bargs.js +136 -20
- package/dist/bargs.js.map +1 -1
- package/dist/help.cjs +31 -2
- package/dist/help.cjs.map +1 -1
- package/dist/help.d.cts +4 -0
- package/dist/help.d.cts.map +1 -1
- package/dist/help.d.ts +4 -0
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +31 -2
- package/dist/help.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/opt.cjs +38 -0
- package/dist/opt.cjs.map +1 -1
- package/dist/opt.d.cts +63 -0
- package/dist/opt.d.cts.map +1 -1
- package/dist/opt.d.ts +63 -0
- package/dist/opt.d.ts.map +1 -1
- package/dist/opt.js +38 -0
- package/dist/opt.js.map +1 -1
- package/dist/osc.cjs +12 -0
- package/dist/osc.cjs.map +1 -1
- package/dist/osc.d.cts +6 -0
- package/dist/osc.d.cts.map +1 -1
- package/dist/osc.d.ts +6 -0
- package/dist/osc.d.ts.map +1 -1
- package/dist/osc.js +12 -0
- package/dist/osc.js.map +1 -1
- package/dist/parser.cjs +48 -1
- package/dist/parser.cjs.map +1 -1
- package/dist/parser.d.cts +2 -0
- package/dist/parser.d.cts.map +1 -1
- package/dist/parser.d.ts +2 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +48 -1
- package/dist/parser.js.map +1 -1
- package/dist/theme.cjs +8 -0
- package/dist/theme.cjs.map +1 -1
- package/dist/theme.d.cts +6 -0
- package/dist/theme.d.cts.map +1 -1
- package/dist/theme.d.ts +6 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +8 -0
- package/dist/theme.js.map +1 -1
- package/dist/types.d.cts +50 -1
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +50 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.cjs +16 -0
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +4 -0
- package/dist/version.d.cts.map +1 -1
- package/dist/version.d.ts +4 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -27,8 +27,7 @@ A CLI with an optional command and a couple options:
|
|
|
27
27
|
```typescript
|
|
28
28
|
import { bargs, opt, pos } from '@boneskull/bargs';
|
|
29
29
|
|
|
30
|
-
await bargs
|
|
31
|
-
.create('greet', { version: '1.0.0' })
|
|
30
|
+
await bargs('greet', { version: '1.0.0' })
|
|
32
31
|
.globals(
|
|
33
32
|
opt.options({
|
|
34
33
|
name: opt.string({ default: 'world' }),
|
|
@@ -112,11 +111,10 @@ const parser = pos.positionals(pos.variadic('string', { name: 'text' }))(
|
|
|
112
111
|
}),
|
|
113
112
|
);
|
|
114
113
|
|
|
115
|
-
const { values, positionals } = await bargs
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
})
|
|
114
|
+
const { values, positionals } = await bargs('echo', {
|
|
115
|
+
description: 'Echo text to stdout',
|
|
116
|
+
version: '1.0.0',
|
|
117
|
+
})
|
|
120
118
|
.globals(parser)
|
|
121
119
|
.parseAsync();
|
|
122
120
|
|
|
@@ -132,11 +130,10 @@ For a CLI with multiple subcommands:
|
|
|
132
130
|
```typescript
|
|
133
131
|
import { bargs, merge, opt, pos } from '@boneskull/bargs';
|
|
134
132
|
|
|
135
|
-
await bargs
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
})
|
|
133
|
+
await bargs('tasks', {
|
|
134
|
+
description: 'A task manager',
|
|
135
|
+
version: '1.0.0',
|
|
136
|
+
})
|
|
140
137
|
.globals(
|
|
141
138
|
opt.options({
|
|
142
139
|
verbose: opt.boolean({ aliases: ['v'], default: false }),
|
|
@@ -183,36 +180,36 @@ All tasks
|
|
|
183
180
|
|
|
184
181
|
### Nested Commands (Subcommands)
|
|
185
182
|
|
|
186
|
-
Commands can be nested to arbitrary depth
|
|
183
|
+
Commands can be nested to arbitrary depth. Use the **factory pattern** for full type inference of parent globals:
|
|
187
184
|
|
|
188
185
|
```typescript
|
|
189
186
|
import { bargs, opt, pos } from '@boneskull/bargs';
|
|
190
187
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
188
|
+
await bargs('git')
|
|
189
|
+
.globals(opt.options({ verbose: opt.boolean({ aliases: ['v'] }) }))
|
|
190
|
+
// Factory pattern: receives a builder with parent globals already typed
|
|
194
191
|
.command(
|
|
195
|
-
'
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
192
|
+
'remote',
|
|
193
|
+
(remote) =>
|
|
194
|
+
remote
|
|
195
|
+
.command(
|
|
196
|
+
'add',
|
|
197
|
+
pos.positionals(
|
|
198
|
+
pos.string({ name: 'name', required: true }),
|
|
199
|
+
pos.string({ name: 'url', required: true }),
|
|
200
|
+
),
|
|
201
|
+
({ positionals, values }) => {
|
|
202
|
+
const [name, url] = positionals;
|
|
203
|
+
// values.verbose is fully typed! (from parent globals)
|
|
204
|
+
if (values.verbose) console.log(`Adding ${name}: ${url}`);
|
|
205
|
+
},
|
|
206
|
+
'Add a remote',
|
|
207
|
+
)
|
|
208
|
+
.command('remove' /* ... */)
|
|
209
|
+
.defaultCommand('add'),
|
|
210
|
+
'Manage remotes',
|
|
206
211
|
)
|
|
207
|
-
.command('
|
|
208
|
-
.defaultCommand('add');
|
|
209
|
-
|
|
210
|
-
// Nest under parent CLI
|
|
211
|
-
await bargs
|
|
212
|
-
.create('git')
|
|
213
|
-
.globals(opt.options({ verbose: opt.boolean({ aliases: ['v'] }) }))
|
|
214
|
-
.command('remote', remoteCommands, 'Manage remotes') // ← CliBuilder
|
|
215
|
-
.command('commit', commitParser, commitHandler) // ← Regular command
|
|
212
|
+
.command('commit', commitParser, commitHandler) // Regular command
|
|
216
213
|
.parseAsync();
|
|
217
214
|
```
|
|
218
215
|
|
|
@@ -223,11 +220,13 @@ Adding origin: https://github.com/...
|
|
|
223
220
|
$ git remote remove origin
|
|
224
221
|
```
|
|
225
222
|
|
|
226
|
-
|
|
223
|
+
The factory function receives a `CliBuilder` that already has parent globals typed, so all nested command handlers get full type inference for merged `global + command` options.
|
|
224
|
+
|
|
225
|
+
You can also pass a pre-built `CliBuilder` directly (see [.command(name, cliBuilder)](#commandname-clibuilder-description)), but handlers won't have parent globals typed at compile time. See `examples/nested-commands.ts` for a full example.
|
|
227
226
|
|
|
228
227
|
## API
|
|
229
228
|
|
|
230
|
-
### bargs
|
|
229
|
+
### bargs(name, options?)
|
|
231
230
|
|
|
232
231
|
Create a CLI builder.
|
|
233
232
|
|
|
@@ -243,7 +242,7 @@ Create a CLI builder.
|
|
|
243
242
|
Set global options and transforms that apply to all commands.
|
|
244
243
|
|
|
245
244
|
```typescript
|
|
246
|
-
bargs
|
|
245
|
+
bargs('my-cli').globals(opt.options({ verbose: opt.boolean() }));
|
|
247
246
|
// ...
|
|
248
247
|
```
|
|
249
248
|
|
|
@@ -265,12 +264,12 @@ Register a command. The handler receives merged global + command types.
|
|
|
265
264
|
|
|
266
265
|
### .command(name, cliBuilder, description?)
|
|
267
266
|
|
|
268
|
-
Register a nested command group. The `cliBuilder` is another `CliBuilder` whose commands become subcommands. Parent globals are passed down to nested handlers.
|
|
267
|
+
Register a nested command group. The `cliBuilder` is another `CliBuilder` whose commands become subcommands. Parent globals are passed down to nested handlers at runtime, but **handlers won't have parent globals typed** at compile time.
|
|
269
268
|
|
|
270
269
|
```typescript
|
|
271
|
-
const subCommands = bargs
|
|
270
|
+
const subCommands = bargs('sub').command('foo', ...).command('bar', ...);
|
|
272
271
|
|
|
273
|
-
bargs
|
|
272
|
+
bargs('main')
|
|
274
273
|
.command('nested', subCommands, 'Nested commands') // nested group
|
|
275
274
|
.parseAsync();
|
|
276
275
|
|
|
@@ -278,6 +277,26 @@ bargs.create('main')
|
|
|
278
277
|
// $ main nested bar
|
|
279
278
|
```
|
|
280
279
|
|
|
280
|
+
### .command(name, factory, description?)
|
|
281
|
+
|
|
282
|
+
Register a nested command group using a factory function. **This is the recommended form** because the factory receives a builder that already has parent globals typed, giving full type inference in nested handlers.
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
bargs('main')
|
|
286
|
+
.globals(opt.options({ verbose: opt.boolean() }))
|
|
287
|
+
.command(
|
|
288
|
+
'nested',
|
|
289
|
+
(nested) =>
|
|
290
|
+
nested
|
|
291
|
+
.command('foo', fooParser, ({ values }) => {
|
|
292
|
+
// values.verbose is typed correctly!
|
|
293
|
+
})
|
|
294
|
+
.command('bar', barParser, barHandler),
|
|
295
|
+
'Nested commands',
|
|
296
|
+
)
|
|
297
|
+
.parseAsync();
|
|
298
|
+
```
|
|
299
|
+
|
|
281
300
|
### .defaultCommand(name)
|
|
282
301
|
|
|
283
302
|
> Or `.defaultCommand(parser, handler)`
|
|
@@ -304,11 +323,11 @@ Parse arguments and execute handlers.
|
|
|
304
323
|
|
|
305
324
|
```typescript
|
|
306
325
|
// Async (supports async transforms/handlers)
|
|
307
|
-
const result = await bargs
|
|
326
|
+
const result = await bargs('my-cli').globals(...).parseAsync();
|
|
308
327
|
console.log(result.values, result.positionals, result.command);
|
|
309
328
|
|
|
310
329
|
// Sync (no async transforms/handlers)
|
|
311
|
-
const result = bargs
|
|
330
|
+
const result = bargs('my-cli').globals(...).parse();
|
|
312
331
|
```
|
|
313
332
|
|
|
314
333
|
## Option Helpers
|
|
@@ -336,6 +355,32 @@ opt.count(); // -vvv → 3
|
|
|
336
355
|
| `hidden` | `boolean` | Hide from `--help` output |
|
|
337
356
|
| `required` | `boolean` | Mark as required (makes the option non-nullable) |
|
|
338
357
|
|
|
358
|
+
### Boolean Negation (`--no-<flag>`)
|
|
359
|
+
|
|
360
|
+
All boolean options automatically support a negated form `--no-<flag>` to explicitly set the option to `false`:
|
|
361
|
+
|
|
362
|
+
```shell
|
|
363
|
+
$ my-cli --verbose # verbose: true
|
|
364
|
+
$ my-cli --no-verbose # verbose: false
|
|
365
|
+
$ my-cli # verbose: undefined (or default)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
If both `--flag` and `--no-flag` are specified, bargs throws an error:
|
|
369
|
+
|
|
370
|
+
```shell
|
|
371
|
+
$ my-cli --verbose --no-verbose
|
|
372
|
+
Error: Conflicting options: --verbose and --no-verbose cannot both be specified
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
In help output, booleans with `default: true` display as `--no-<flag>` (since that's how users would turn them off):
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
opt.options({
|
|
379
|
+
colors: opt.boolean({ default: true, description: 'Use colors' }),
|
|
380
|
+
});
|
|
381
|
+
// Help output shows: --no-colors Use colors [boolean] default: true
|
|
382
|
+
```
|
|
383
|
+
|
|
339
384
|
### `opt.options(schema)`
|
|
340
385
|
|
|
341
386
|
Create a parser from an options schema:
|
|
@@ -443,8 +488,7 @@ const globals = map(
|
|
|
443
488
|
}),
|
|
444
489
|
);
|
|
445
490
|
|
|
446
|
-
await bargs
|
|
447
|
-
.create('my-cli')
|
|
491
|
+
await bargs('my-cli')
|
|
448
492
|
.globals(globals)
|
|
449
493
|
.command(
|
|
450
494
|
'info',
|
|
@@ -480,18 +524,47 @@ const globals = map(
|
|
|
480
524
|
);
|
|
481
525
|
```
|
|
482
526
|
|
|
527
|
+
### CamelCase Option Keys
|
|
528
|
+
|
|
529
|
+
If you prefer camelCase property names instead of kebab-case, use the `camelCaseValues` transform:
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
import { bargs, map, opt, camelCaseValues } from '@boneskull/bargs';
|
|
533
|
+
|
|
534
|
+
const { values } = await bargs('my-cli')
|
|
535
|
+
.globals(
|
|
536
|
+
map(
|
|
537
|
+
opt.options({
|
|
538
|
+
'output-dir': opt.string({ default: '/tmp' }),
|
|
539
|
+
'dry-run': opt.boolean(),
|
|
540
|
+
}),
|
|
541
|
+
camelCaseValues,
|
|
542
|
+
),
|
|
543
|
+
)
|
|
544
|
+
.parseAsync(['--output-dir', './dist', '--dry-run']);
|
|
545
|
+
|
|
546
|
+
console.log(values.outputDir); // './dist'
|
|
547
|
+
console.log(values.dryRun); // true
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
The `camelCaseValues` transform:
|
|
551
|
+
|
|
552
|
+
- Converts all kebab-case keys to camelCase (`output-dir` → `outputDir`)
|
|
553
|
+
- Preserves keys that are already camelCase or have no hyphens
|
|
554
|
+
- Is fully type-safe—TypeScript knows the transformed key names
|
|
555
|
+
|
|
483
556
|
## Epilog
|
|
484
557
|
|
|
485
558
|
By default, **bargs** displays your package's homepage and repository URLs (from `package.json`) at the end of help output. URLs become clickable hyperlinks in supported terminals.
|
|
486
559
|
|
|
487
560
|
```typescript
|
|
488
561
|
// Custom epilog
|
|
489
|
-
bargs
|
|
562
|
+
bargs('my-cli', {
|
|
490
563
|
epilog: 'For more info, visit https://example.com',
|
|
491
564
|
});
|
|
492
565
|
|
|
493
566
|
// Disable epilog entirely
|
|
494
|
-
bargs
|
|
567
|
+
bargs('my-cli', { epilog: false });
|
|
495
568
|
```
|
|
496
569
|
|
|
497
570
|
## Theming
|
|
@@ -500,10 +573,10 @@ Customize help output colors with built-in themes or your own:
|
|
|
500
573
|
|
|
501
574
|
```typescript
|
|
502
575
|
// Use a built-in theme: 'default', 'mono', 'ocean', 'warm'
|
|
503
|
-
bargs
|
|
576
|
+
bargs('my-cli', { theme: 'ocean' });
|
|
504
577
|
|
|
505
578
|
// Disable colors entirely
|
|
506
|
-
bargs
|
|
579
|
+
bargs('my-cli', { theme: 'mono' });
|
|
507
580
|
```
|
|
508
581
|
|
|
509
582
|
The `ansi` export provides common ANSI escape codes for styled terminal output:
|
|
@@ -511,7 +584,7 @@ The `ansi` export provides common ANSI escape codes for styled terminal output:
|
|
|
511
584
|
```typescript
|
|
512
585
|
import { ansi } from '@boneskull/bargs';
|
|
513
586
|
|
|
514
|
-
bargs
|
|
587
|
+
bargs('my-cli', {
|
|
515
588
|
theme: {
|
|
516
589
|
command: ansi.bold,
|
|
517
590
|
flag: ansi.brightCyan,
|
|
@@ -557,7 +630,7 @@ import {
|
|
|
557
630
|
} from '@boneskull/bargs';
|
|
558
631
|
|
|
559
632
|
try {
|
|
560
|
-
await bargs
|
|
633
|
+
await bargs('my-cli').parseAsync();
|
|
561
634
|
} catch (error) {
|
|
562
635
|
if (error instanceof ValidationError) {
|
|
563
636
|
// Config validation failed (e.g., invalid schema)
|
package/dist/bargs.cjs
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Core bargs API using parser combinator pattern.
|
|
4
4
|
*
|
|
5
|
-
* Provides `bargs
|
|
6
|
-
*
|
|
5
|
+
* Provides `bargs()` for building CLIs with a fluent API, plus combinator
|
|
6
|
+
* functions like `pipe()`, `map()`, and `handle()`.
|
|
7
7
|
*
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.bargs = void 0;
|
|
11
|
+
exports.bargs = exports.camelCaseValues = void 0;
|
|
12
12
|
exports.handle = handle;
|
|
13
13
|
exports.map = map;
|
|
14
14
|
exports.merge = merge;
|
|
@@ -53,27 +53,47 @@ function handle(parserOrFn, maybeFn) {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
function map(parserOrFn, maybeFn) {
|
|
56
|
+
// Helper to compose transforms (chains existing + new)
|
|
57
|
+
/**
|
|
58
|
+
* @function
|
|
59
|
+
*/
|
|
60
|
+
const composeTransform = (parser, fn) => {
|
|
61
|
+
const existing = parser.__transform;
|
|
62
|
+
if (!existing) {
|
|
63
|
+
return fn;
|
|
64
|
+
}
|
|
65
|
+
// Chain: existing transform first, then new transform
|
|
66
|
+
return (r) => {
|
|
67
|
+
const r1 = existing(r);
|
|
68
|
+
if (r1 instanceof Promise) {
|
|
69
|
+
return r1.then(fn);
|
|
70
|
+
}
|
|
71
|
+
return fn(r1);
|
|
72
|
+
};
|
|
73
|
+
};
|
|
56
74
|
// Direct form: map(parser, fn) returns Parser
|
|
57
75
|
// Check for Parser first since CallableParser is also a function
|
|
58
76
|
if (isParser(parserOrFn)) {
|
|
59
77
|
const parser = parserOrFn;
|
|
60
78
|
const fn = maybeFn;
|
|
79
|
+
const composedTransform = composeTransform(parser, fn);
|
|
61
80
|
return {
|
|
62
81
|
...parser,
|
|
63
82
|
__brand: 'Parser',
|
|
64
83
|
__positionals: [],
|
|
65
|
-
__transform:
|
|
84
|
+
__transform: composedTransform,
|
|
66
85
|
__values: {},
|
|
67
86
|
};
|
|
68
87
|
}
|
|
69
88
|
// Curried form: map(fn) returns (parser) => Parser
|
|
70
89
|
const fn = parserOrFn;
|
|
71
90
|
return (parser) => {
|
|
91
|
+
const composedTransform = composeTransform(parser, fn);
|
|
72
92
|
return {
|
|
73
93
|
...parser,
|
|
74
94
|
__brand: 'Parser',
|
|
75
95
|
__positionals: [],
|
|
76
|
-
__transform:
|
|
96
|
+
__transform: composedTransform,
|
|
77
97
|
__values: {},
|
|
78
98
|
};
|
|
79
99
|
};
|
|
@@ -130,6 +150,43 @@ function merge(...parsers) {
|
|
|
130
150
|
return result;
|
|
131
151
|
}
|
|
132
152
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
153
|
+
// CAMEL CASE HELPER
|
|
154
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
155
|
+
/**
|
|
156
|
+
* Convert kebab-case string to camelCase.
|
|
157
|
+
*
|
|
158
|
+
* @function
|
|
159
|
+
*/
|
|
160
|
+
const kebabToCamel = (s) => s.replace(/-([a-zA-Z])/g, (_, c) => c.toUpperCase());
|
|
161
|
+
/**
|
|
162
|
+
* Transform for use with `map()` that converts kebab-case option keys to
|
|
163
|
+
* camelCase.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
*
|
|
167
|
+
* ```typescript
|
|
168
|
+
* import { bargs, opt, map, camelCaseValues } from '@boneskull/bargs';
|
|
169
|
+
*
|
|
170
|
+
* const { values } = await bargs('my-cli')
|
|
171
|
+
* .globals(
|
|
172
|
+
* map(opt.options({ 'output-dir': opt.string() }), camelCaseValues),
|
|
173
|
+
* )
|
|
174
|
+
* .parseAsync();
|
|
175
|
+
*
|
|
176
|
+
* console.log(values.outputDir); // camelCased!
|
|
177
|
+
* ```
|
|
178
|
+
*
|
|
179
|
+
* @function
|
|
180
|
+
*/
|
|
181
|
+
const camelCaseValues = (result) => ({
|
|
182
|
+
...result,
|
|
183
|
+
values: Object.fromEntries(Object.entries(result.values).map(([k, v]) => [
|
|
184
|
+
kebabToCamel(k),
|
|
185
|
+
v,
|
|
186
|
+
])),
|
|
187
|
+
});
|
|
188
|
+
exports.camelCaseValues = camelCaseValues;
|
|
189
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
133
190
|
// CLI BUILDER
|
|
134
191
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
135
192
|
/**
|
|
@@ -138,8 +195,7 @@ function merge(...parsers) {
|
|
|
138
195
|
* @example
|
|
139
196
|
*
|
|
140
197
|
* ```typescript
|
|
141
|
-
* const cli = await bargs
|
|
142
|
-
* .create('my-app', { version: '1.0.0' })
|
|
198
|
+
* const cli = await bargs('my-app', { version: '1.0.0' })
|
|
143
199
|
* .globals(
|
|
144
200
|
* map(opt.options({ verbose: opt.boolean() }), ({ values }) => ({
|
|
145
201
|
* values: { ...values, ts: Date.now() },
|
|
@@ -153,8 +209,10 @@ function merge(...parsers) {
|
|
|
153
209
|
* )
|
|
154
210
|
* .parseAsync();
|
|
155
211
|
* ```
|
|
212
|
+
*
|
|
213
|
+
* @function
|
|
156
214
|
*/
|
|
157
|
-
const
|
|
215
|
+
const bargs = (name, options = {}) => {
|
|
158
216
|
const theme = options.theme ? (0, theme_js_1.getTheme)(options.theme) : theme_js_1.defaultTheme;
|
|
159
217
|
return createCliBuilder({
|
|
160
218
|
commands: new Map(),
|
|
@@ -163,8 +221,11 @@ const create = (name, options = {}) => {
|
|
|
163
221
|
theme,
|
|
164
222
|
});
|
|
165
223
|
};
|
|
224
|
+
exports.bargs = bargs;
|
|
166
225
|
/**
|
|
167
226
|
* Check if something is a Command (has __brand: 'Command').
|
|
227
|
+
*
|
|
228
|
+
* @function
|
|
168
229
|
*/
|
|
169
230
|
const isCommand = (x) => {
|
|
170
231
|
if (x === null || x === undefined) {
|
|
@@ -175,6 +236,8 @@ const isCommand = (x) => {
|
|
|
175
236
|
};
|
|
176
237
|
/**
|
|
177
238
|
* Create a CLI builder.
|
|
239
|
+
*
|
|
240
|
+
* @function
|
|
178
241
|
*/
|
|
179
242
|
const createCliBuilder = (state) => {
|
|
180
243
|
const builder = {
|
|
@@ -183,11 +246,39 @@ const createCliBuilder = (state) => {
|
|
|
183
246
|
const stateWithGlobals = { ...state, parentGlobals };
|
|
184
247
|
return parseCore(stateWithGlobals, args, allowAsync);
|
|
185
248
|
},
|
|
186
|
-
// Overloaded command(): accepts (name,
|
|
187
|
-
|
|
249
|
+
// Overloaded command(): accepts (name, factory, desc?), (name, CliBuilder, desc?),
|
|
250
|
+
// (name, Command, desc?), or (name, Parser, handler, desc?)
|
|
251
|
+
command(name, cmdOrParserOrBuilderOrFactory, handlerOrDesc, maybeDesc) {
|
|
252
|
+
// Form 4: command(name, factory, description?) - factory for nested commands with parent globals
|
|
253
|
+
// Check this FIRST before isCliBuilder/isParser since those check for __brand which a plain function won't have
|
|
254
|
+
if (typeof cmdOrParserOrBuilderOrFactory === 'function' &&
|
|
255
|
+
!isParser(cmdOrParserOrBuilderOrFactory) &&
|
|
256
|
+
!isCommand(cmdOrParserOrBuilderOrFactory) &&
|
|
257
|
+
!isCliBuilder(cmdOrParserOrBuilderOrFactory)) {
|
|
258
|
+
const factory = cmdOrParserOrBuilderOrFactory;
|
|
259
|
+
const description = handlerOrDesc;
|
|
260
|
+
// Create a child builder with parent global TYPES (for type inference)
|
|
261
|
+
// but NOT the globalParser (parent globals are passed via parentGlobals at runtime,
|
|
262
|
+
// not re-parsed from args)
|
|
263
|
+
const childBuilder = createCliBuilder({
|
|
264
|
+
commands: new Map(),
|
|
265
|
+
globalParser: undefined, // Parent globals come via parentGlobals, not re-parsing
|
|
266
|
+
name,
|
|
267
|
+
options: state.options,
|
|
268
|
+
theme: state.theme,
|
|
269
|
+
});
|
|
270
|
+
// Call factory to let user add commands
|
|
271
|
+
const nestedBuilder = factory(childBuilder);
|
|
272
|
+
state.commands.set(name, {
|
|
273
|
+
builder: nestedBuilder,
|
|
274
|
+
description,
|
|
275
|
+
type: 'nested',
|
|
276
|
+
});
|
|
277
|
+
return this;
|
|
278
|
+
}
|
|
188
279
|
// Form 3: command(name, CliBuilder, description?) - nested commands
|
|
189
|
-
if (isCliBuilder(
|
|
190
|
-
const builder =
|
|
280
|
+
if (isCliBuilder(cmdOrParserOrBuilderOrFactory)) {
|
|
281
|
+
const builder = cmdOrParserOrBuilderOrFactory;
|
|
191
282
|
const description = handlerOrDesc;
|
|
192
283
|
state.commands.set(name, {
|
|
193
284
|
builder: builder,
|
|
@@ -198,14 +289,14 @@ const createCliBuilder = (state) => {
|
|
|
198
289
|
}
|
|
199
290
|
let cmd;
|
|
200
291
|
let description;
|
|
201
|
-
if (isCommand(
|
|
292
|
+
if (isCommand(cmdOrParserOrBuilderOrFactory)) {
|
|
202
293
|
// Form 1: command(name, Command, description?)
|
|
203
|
-
cmd =
|
|
294
|
+
cmd = cmdOrParserOrBuilderOrFactory;
|
|
204
295
|
description = handlerOrDesc;
|
|
205
296
|
}
|
|
206
|
-
else if (isParser(
|
|
297
|
+
else if (isParser(cmdOrParserOrBuilderOrFactory)) {
|
|
207
298
|
// Form 2: command(name, Parser, handler, description?)
|
|
208
|
-
const parser =
|
|
299
|
+
const parser = cmdOrParserOrBuilderOrFactory;
|
|
209
300
|
const handler = handlerOrDesc;
|
|
210
301
|
description = maybeDesc;
|
|
211
302
|
// Create Command from Parser + handler
|
|
@@ -223,7 +314,7 @@ const createCliBuilder = (state) => {
|
|
|
223
314
|
cmd = newCmd;
|
|
224
315
|
}
|
|
225
316
|
else {
|
|
226
|
-
throw new Error('command() requires a Command, Parser, or
|
|
317
|
+
throw new Error('command() requires a Command, Parser, CliBuilder, or factory function as second argument');
|
|
227
318
|
}
|
|
228
319
|
state.commands.set(name, { cmd, description, type: 'command' });
|
|
229
320
|
return this;
|
|
@@ -298,6 +389,8 @@ const createCliBuilder = (state) => {
|
|
|
298
389
|
};
|
|
299
390
|
/**
|
|
300
391
|
* Core parse logic shared between parse() and parseAsync().
|
|
392
|
+
*
|
|
393
|
+
* @function
|
|
301
394
|
*/
|
|
302
395
|
const parseCore = (state, args, allowAsync) => {
|
|
303
396
|
const { commands, options, theme } = state;
|
|
@@ -330,6 +423,8 @@ const parseCore = (state, args, allowAsync) => {
|
|
|
330
423
|
};
|
|
331
424
|
/**
|
|
332
425
|
* Generate command-specific help.
|
|
426
|
+
*
|
|
427
|
+
* @function
|
|
333
428
|
*/
|
|
334
429
|
const generateCommandHelpNew = (state, commandName, theme) => {
|
|
335
430
|
const commandEntry = state.commands.get(commandName);
|
|
@@ -356,6 +451,8 @@ const generateCommandHelpNew = (state, commandName, theme) => {
|
|
|
356
451
|
};
|
|
357
452
|
/**
|
|
358
453
|
* Generate help for the new CLI structure.
|
|
454
|
+
*
|
|
455
|
+
* @function
|
|
359
456
|
*/
|
|
360
457
|
const generateHelpNew = (state, theme) => {
|
|
361
458
|
// TODO: Implement proper help generation for new structure
|
|
@@ -375,6 +472,8 @@ const generateHelpNew = (state, theme) => {
|
|
|
375
472
|
/**
|
|
376
473
|
* Check if something is a Parser (has __brand: 'Parser'). Parsers can be either
|
|
377
474
|
* objects or functions (CallableParser).
|
|
475
|
+
*
|
|
476
|
+
* @function
|
|
378
477
|
*/
|
|
379
478
|
const isParser = (x) => {
|
|
380
479
|
if (x === null || x === undefined) {
|
|
@@ -387,6 +486,8 @@ const isParser = (x) => {
|
|
|
387
486
|
/**
|
|
388
487
|
* Check if something is a CliBuilder (has command, globals, parse, parseAsync
|
|
389
488
|
* methods).
|
|
489
|
+
*
|
|
490
|
+
* @function
|
|
390
491
|
*/
|
|
391
492
|
const isCliBuilder = (x) => {
|
|
392
493
|
if (x === null || x === undefined || typeof x !== 'object') {
|
|
@@ -400,6 +501,8 @@ const isCliBuilder = (x) => {
|
|
|
400
501
|
};
|
|
401
502
|
/**
|
|
402
503
|
* Run a simple CLI (no commands).
|
|
504
|
+
*
|
|
505
|
+
* @function
|
|
403
506
|
*/
|
|
404
507
|
const runSimple = (state, args, allowAsync) => {
|
|
405
508
|
const { globalParser } = state;
|
|
@@ -436,6 +539,8 @@ const runSimple = (state, args, allowAsync) => {
|
|
|
436
539
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
437
540
|
/**
|
|
438
541
|
* Delegate parsing to a nested CliBuilder, passing down parent globals.
|
|
542
|
+
*
|
|
543
|
+
* @function
|
|
439
544
|
*/
|
|
440
545
|
const delegateToNestedBuilder = (builder, remainingArgs, parentGlobals, allowAsync) => {
|
|
441
546
|
// Access the internal parse function that accepts parent globals
|
|
@@ -444,6 +549,8 @@ const delegateToNestedBuilder = (builder, remainingArgs, parentGlobals, allowAsy
|
|
|
444
549
|
};
|
|
445
550
|
/**
|
|
446
551
|
* Run a CLI with commands.
|
|
552
|
+
*
|
|
553
|
+
* @function
|
|
447
554
|
*/
|
|
448
555
|
const runWithCommands = (state, args, allowAsync) => {
|
|
449
556
|
const { commands, defaultCommandName, globalParser } = state;
|
|
@@ -532,6 +639,9 @@ const runWithCommands = (state, args, allowAsync) => {
|
|
|
532
639
|
values: { ...parentValues, ...parsed.values },
|
|
533
640
|
};
|
|
534
641
|
// Helper to check for async and throw if not allowed
|
|
642
|
+
/**
|
|
643
|
+
* @function
|
|
644
|
+
*/
|
|
535
645
|
const checkAsync = (value, context) => {
|
|
536
646
|
if (value instanceof Promise && !allowAsync) {
|
|
537
647
|
throw new errors_js_1.BargsError(`Async ${context} detected. Use parseAsync() instead of parse().`);
|
|
@@ -541,6 +651,9 @@ const runWithCommands = (state, args, allowAsync) => {
|
|
|
541
651
|
const globalTransform = globalParser?.__transform;
|
|
542
652
|
const commandTransform = cmd?.__transform;
|
|
543
653
|
// Apply transforms and run handler
|
|
654
|
+
/**
|
|
655
|
+
* @function
|
|
656
|
+
*/
|
|
544
657
|
const applyTransformsAndHandle = () => {
|
|
545
658
|
// Apply global transforms first
|
|
546
659
|
if (globalTransform) {
|
|
@@ -556,6 +669,9 @@ const runWithCommands = (state, args, allowAsync) => {
|
|
|
556
669
|
}
|
|
557
670
|
return continueWithCommandTransform();
|
|
558
671
|
};
|
|
672
|
+
/**
|
|
673
|
+
* @function
|
|
674
|
+
*/
|
|
559
675
|
const continueWithCommandTransform = () => {
|
|
560
676
|
// Apply command transforms
|
|
561
677
|
if (commandTransform) {
|
|
@@ -571,6 +687,9 @@ const runWithCommands = (state, args, allowAsync) => {
|
|
|
571
687
|
}
|
|
572
688
|
return runHandler();
|
|
573
689
|
};
|
|
690
|
+
/**
|
|
691
|
+
* @function
|
|
692
|
+
*/
|
|
574
693
|
const runHandler = () => {
|
|
575
694
|
const handlerResult = cmd.handler(result);
|
|
576
695
|
checkAsync(handlerResult, 'handler');
|
|
@@ -582,9 +701,8 @@ const runWithCommands = (state, args, allowAsync) => {
|
|
|
582
701
|
return applyTransformsAndHandle();
|
|
583
702
|
};
|
|
584
703
|
/**
|
|
585
|
-
*
|
|
704
|
+
* @ignore
|
|
705
|
+
* @deprecated
|
|
586
706
|
*/
|
|
587
|
-
exports.bargs =
|
|
588
|
-
create,
|
|
589
|
-
};
|
|
707
|
+
exports.bargs.create = exports.bargs;
|
|
590
708
|
//# sourceMappingURL=bargs.js.map
|