@boneskull/bargs 0.1.1

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 (91) hide show
  1. package/LICENSE +55 -0
  2. package/README.md +483 -0
  3. package/dist/bargs.cjs +167 -0
  4. package/dist/bargs.cjs.map +1 -0
  5. package/dist/bargs.d.cts +31 -0
  6. package/dist/bargs.d.cts.map +1 -0
  7. package/dist/bargs.d.ts +31 -0
  8. package/dist/bargs.d.ts.map +1 -0
  9. package/dist/bargs.js +163 -0
  10. package/dist/bargs.js.map +1 -0
  11. package/dist/errors.cjs +57 -0
  12. package/dist/errors.cjs.map +1 -0
  13. package/dist/errors.d.cts +40 -0
  14. package/dist/errors.d.cts.map +1 -0
  15. package/dist/errors.d.ts +40 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +51 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/help.cjs +309 -0
  20. package/dist/help.cjs.map +1 -0
  21. package/dist/help.d.cts +21 -0
  22. package/dist/help.d.cts.map +1 -0
  23. package/dist/help.d.ts +21 -0
  24. package/dist/help.d.ts.map +1 -0
  25. package/dist/help.js +304 -0
  26. package/dist/help.js.map +1 -0
  27. package/dist/index.cjs +63 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +96 -0
  30. package/dist/index.d.cts.map +1 -0
  31. package/dist/index.d.ts +96 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +47 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/opt.cjs +205 -0
  36. package/dist/opt.cjs.map +1 -0
  37. package/dist/opt.d.cts +145 -0
  38. package/dist/opt.d.cts.map +1 -0
  39. package/dist/opt.d.ts +145 -0
  40. package/dist/opt.d.ts.map +1 -0
  41. package/dist/opt.js +202 -0
  42. package/dist/opt.js.map +1 -0
  43. package/dist/osc.cjs +190 -0
  44. package/dist/osc.cjs.map +1 -0
  45. package/dist/osc.d.cts +30 -0
  46. package/dist/osc.d.cts.map +1 -0
  47. package/dist/osc.d.ts +30 -0
  48. package/dist/osc.d.ts.map +1 -0
  49. package/dist/osc.js +181 -0
  50. package/dist/osc.js.map +1 -0
  51. package/dist/parser.cjs +293 -0
  52. package/dist/parser.cjs.map +1 -0
  53. package/dist/parser.d.cts +47 -0
  54. package/dist/parser.d.cts.map +1 -0
  55. package/dist/parser.d.ts +47 -0
  56. package/dist/parser.d.ts.map +1 -0
  57. package/dist/parser.js +285 -0
  58. package/dist/parser.js.map +1 -0
  59. package/dist/theme.cjs +203 -0
  60. package/dist/theme.cjs.map +1 -0
  61. package/dist/theme.d.cts +227 -0
  62. package/dist/theme.d.cts.map +1 -0
  63. package/dist/theme.d.ts +227 -0
  64. package/dist/theme.d.ts.map +1 -0
  65. package/dist/theme.js +198 -0
  66. package/dist/theme.js.map +1 -0
  67. package/dist/types.cjs +18 -0
  68. package/dist/types.cjs.map +1 -0
  69. package/dist/types.d.cts +244 -0
  70. package/dist/types.d.cts.map +1 -0
  71. package/dist/types.d.ts +244 -0
  72. package/dist/types.d.ts.map +1 -0
  73. package/dist/types.js +17 -0
  74. package/dist/types.js.map +1 -0
  75. package/dist/validate.cjs +452 -0
  76. package/dist/validate.cjs.map +1 -0
  77. package/dist/validate.d.cts +28 -0
  78. package/dist/validate.d.cts.map +1 -0
  79. package/dist/validate.d.ts +28 -0
  80. package/dist/validate.d.ts.map +1 -0
  81. package/dist/validate.js +448 -0
  82. package/dist/validate.js.map +1 -0
  83. package/dist/version.cjs +134 -0
  84. package/dist/version.cjs.map +1 -0
  85. package/dist/version.d.cts +27 -0
  86. package/dist/version.d.cts.map +1 -0
  87. package/dist/version.d.ts +27 -0
  88. package/dist/version.d.ts.map +1 -0
  89. package/dist/version.js +129 -0
  90. package/dist/version.js.map +1 -0
  91. package/package.json +149 -0
package/LICENSE ADDED
@@ -0,0 +1,55 @@
1
+ # Blue Oak Model License
2
+
3
+ Version 1.0.0
4
+
5
+ ## Purpose
6
+
7
+ This license gives everyone as much permission to work with
8
+ this software as possible, while protecting contributors
9
+ from liability.
10
+
11
+ ## Acceptance
12
+
13
+ In order to receive this license, you must agree to its
14
+ rules. The rules of this license are both obligations
15
+ under that agreement and conditions to your license.
16
+ You must not do anything with this software that triggers
17
+ a rule that you cannot or will not follow.
18
+
19
+ ## Copyright
20
+
21
+ Each contributor licenses you to do everything with this
22
+ software that would otherwise infringe that contributor's
23
+ copyright in it.
24
+
25
+ ## Notices
26
+
27
+ You must ensure that everyone who gets a copy of
28
+ any part of this software from you, with or without
29
+ changes, also gets the text of this license or a link to
30
+ <https://blueoakcouncil.org/license/1.0.0>.
31
+
32
+ ## Excuse
33
+
34
+ If anyone notifies you in writing that you have not
35
+ complied with [Notices](#notices), you can keep your
36
+ license by taking all practical steps to comply within 30
37
+ days after the notice. If you do not do so, your license
38
+ ends immediately.
39
+
40
+ ## Patent
41
+
42
+ Each contributor licenses you to do everything with this
43
+ software that would otherwise infringe any patent claims
44
+ they can license or become able to license.
45
+
46
+ ## Reliability
47
+
48
+ No contributor can revoke this license.
49
+
50
+ ## No Liability
51
+
52
+ **_As far as the law allows, this software comes as is,
53
+ without any warranty or condition, and no contributor
54
+ will be liable to anyone for any damages related to this
55
+ software or this license, under any kind of legal claim._**
package/README.md ADDED
@@ -0,0 +1,483 @@
1
+ <p align="center">
2
+ <a href="/"><img src="./assets/logo.png" width="512px" align="center" alt="bargs: a barg parser"/></a>
3
+ <h1 align="center"><span class="bargs">⁓ bargs ⁓<span></h1>
4
+ <p align="center">
5
+ <em>“Ex argumentis, veritas”</em>
6
+ <br/>
7
+ <small>by <a href="https://github.com/boneskull" title="@boneskull on GitHub">@boneskull</a></small>
8
+ </p>
9
+ </p>
10
+
11
+ ## Install
12
+
13
+ ```shell
14
+ npm install @boneskull/bargs
15
+ ```
16
+
17
+ ## Why bargs?
18
+
19
+ Most argument parsers make you choose: either a simple API with weak types, or a complex and overengineered DSL. **bargs** uses _function helpers_ that instead provide a well-typed and composable API.
20
+
21
+ ### Type-Safe by Construction
22
+
23
+ Each helper returns a fully-typed option definition:
24
+
25
+ ```typescript
26
+ const verbose = bargs.boolean({ aliases: ['v'] });
27
+ // Type: BooleanOption & { aliases: ['v'] }
28
+
29
+ const level = bargs.enum(['low', 'medium', 'high'], { default: 'medium' });
30
+ // Type: EnumOption<'low' | 'medium' | 'high'> & { default: 'medium' }
31
+ ```
32
+
33
+ When you pass these to `bargs()`, the result is always well-typed; options with defaults or `required: true` are non-nullable.
34
+
35
+ ### Composable
36
+
37
+ Since helpers are just functions returning objects, composition is trivial:
38
+
39
+ ```typescript
40
+ // Shared options across commands
41
+ const verboseOpt = { verbose: bargs.boolean({ aliases: ['v'] }) };
42
+ const outputOpt = {
43
+ output: bargs.string({ aliases: ['o'], default: 'stdout' }),
44
+ };
45
+
46
+ // Merge with spread
47
+ const result = bargs({
48
+ name: 'tool',
49
+ options: {
50
+ ...verboseOpt,
51
+ ...outputOpt,
52
+ format: bargs.enum(['json', 'text']),
53
+ },
54
+ });
55
+ ```
56
+
57
+ Or use `bargs.options()` and `bargs.positionals()`:
58
+
59
+ ```typescript
60
+ // Throws if aliases collide
61
+ const sharedOpts = bargs.options(verboseOpt, outputOpt);
62
+
63
+ // Combine positionals with type inference
64
+ const sharedPos = bargs.positionals(
65
+ bargs.stringPos({ name: 'input', required: true }),
66
+ bargs.stringPos({ name: 'output' }),
67
+ );
68
+ ```
69
+
70
+ ### Zero (0) Dependencies
71
+
72
+ Only Node.js v22+.
73
+
74
+ ## Quick Start
75
+
76
+ ```typescript
77
+ import { bargs } from '@boneskull/bargs';
78
+
79
+ const result = bargs({
80
+ name: 'greet',
81
+ options: {
82
+ name: bargs.string({ default: 'world' }),
83
+ loud: bargs.boolean({ aliases: ['l'] }),
84
+ },
85
+ });
86
+
87
+ const greeting = `Hello, ${result.values.name}!`;
88
+ console.log(result.values.loud ? greeting.toUpperCase() : greeting);
89
+ ```
90
+
91
+ ```shell
92
+ $ greet --name Alice --loud
93
+ HELLO, ALICE!
94
+ ```
95
+
96
+ ## Sync vs Async
97
+
98
+ **`bargs()`** runs synchronously. If a handler returns a `Promise`, it will break and you will be sorry.
99
+
100
+ ```typescript
101
+ // Sync - no await needed
102
+ const result = bargs({
103
+ name: 'my-cli',
104
+ options: { verbose: bargs.boolean() },
105
+ handler: ({ values }) => {
106
+ console.log('Verbose:', values.verbose);
107
+ },
108
+ });
109
+ ```
110
+
111
+ Instead, use **`bargsAsync()`**:
112
+
113
+ ```typescript
114
+ import { bargsAsync } from '@boneskull/bargs';
115
+
116
+ // Async - handlers can return Promises
117
+ const result = await bargsAsync({
118
+ name: 'my-cli',
119
+ options: { url: bargs.string({ required: true }) },
120
+ handler: async ({ values }) => {
121
+ const response = await fetch(values.url);
122
+ console.log(await response.text());
123
+ },
124
+ });
125
+ ```
126
+
127
+ ## Commands
128
+
129
+ Define subcommands with `bargs.command()`:
130
+
131
+ ```typescript
132
+ bargs({
133
+ name: 'db',
134
+ commands: {
135
+ migrate: bargs.command({
136
+ description: 'Run database migrations',
137
+ options: { dry: bargs.boolean({ aliases: ['n'] }) },
138
+ handler: ({ values }) => {
139
+ console.log(values.dry ? 'Dry run...' : 'Migrating...');
140
+ },
141
+ }),
142
+ seed: bargs.command({
143
+ description: 'Seed the database',
144
+ positionals: [bargs.stringPos({ required: true })],
145
+ handler: ({ positionals }) => {
146
+ const [file] = positionals;
147
+ console.log(`Seeding from ${file}...`);
148
+ },
149
+ }),
150
+ },
151
+ });
152
+ ```
153
+
154
+ ```shell
155
+ $ db migrate --dry
156
+ Dry run...
157
+
158
+ $ db seed data.sql
159
+ Seeding from data.sql...
160
+ ```
161
+
162
+ ### Default Handler
163
+
164
+ For command-based CLIs, use `defaultHandler` to handle the case when no command is provided:
165
+
166
+ ```typescript
167
+ bargs({
168
+ name: 'git',
169
+ commands: {
170
+ /* ... */
171
+ },
172
+ // Run 'status' when no command given
173
+ defaultHandler: 'status',
174
+ });
175
+
176
+ // Or provide a custom handler
177
+ bargs({
178
+ name: 'git',
179
+ commands: {
180
+ /* ... */
181
+ },
182
+ defaultHandler: ({ values }) => {
183
+ console.log('Run "git --help" for usage');
184
+ },
185
+ });
186
+ ```
187
+
188
+ ## Configuration
189
+
190
+ ### Config Properties
191
+
192
+ | Property | Type | Description |
193
+ | ------------- | --------------------- | ------------------------------------------------- |
194
+ | `name` | `string` | CLI name (required) |
195
+ | `description` | `string` | Description shown in help |
196
+ | `version` | `string` | Enables `--version` flag |
197
+ | `options` | `OptionsSchema` | Named options (`--flag`) |
198
+ | `positionals` | `PositionalsSchema` | Positional arguments |
199
+ | `commands` | `Record<string, ...>` | Subcommands |
200
+ | `handler` | `Handler` | Handler function(s) for simple CLIs |
201
+ | `epilog` | `string \| false` | Footer text in help (see [Epilog](#epilog)) |
202
+ | `args` | `string[]` | Custom args (defaults to `process.argv.slice(2)`) |
203
+
204
+ ```typescript
205
+ bargs({
206
+ name: 'my-cli',
207
+ description: 'Does amazing things',
208
+ version: '1.2.3', // enables --version
209
+ args: ['--verbose', 'file.txt'], // useful for testing
210
+ options: {
211
+ /* ... */
212
+ },
213
+ });
214
+ ```
215
+
216
+ ### Runtime Options
217
+
218
+ The second argument to `bargs()` or `bargsAsync()` accepts runtime options:
219
+
220
+ | Property | Type | Description |
221
+ | -------- | ------------ | ---------------------------------------------- |
222
+ | `theme` | `ThemeInput` | `--help` Color theme (see [Theming](#theming)) |
223
+
224
+ ```typescript
225
+ bargs(config, { theme: 'ocean' });
226
+ ```
227
+
228
+ ## Option Helpers
229
+
230
+ ```typescript
231
+ bargs.string({ default: 'value' }); // --name value
232
+ bargs.number({ default: 42 }); // --count 42
233
+ bargs.boolean({ aliases: ['v'] }); // --verbose, -v
234
+ bargs.enum(['a', 'b', 'c']); // --level a
235
+ bargs.array('string'); // --file x --file y
236
+ bargs.count(); // -vvv → 3
237
+ ```
238
+
239
+ ### Option Properties
240
+
241
+ All option helpers accept these properties:
242
+
243
+ | Property | Type | Description |
244
+ | ------------- | ---------- | ------------------------------------------------ |
245
+ | `aliases` | `string[]` | Short flags (e.g., `['v']` for `-v`) |
246
+ | `default` | varies | Default value (makes the option non-nullable) |
247
+ | `description` | `string` | Help text description |
248
+ | `group` | `string` | Groups options under a custom section header |
249
+ | `hidden` | `boolean` | Hide from `--help` output |
250
+ | `required` | `boolean` | Mark as required (makes the option non-nullable) |
251
+
252
+ ```typescript
253
+ bargs.string({
254
+ aliases: ['o'],
255
+ default: 'output.txt',
256
+ description: 'Output file path',
257
+ group: 'Output Options',
258
+ });
259
+
260
+ // Hidden options won't appear in help
261
+ bargs.boolean({ hidden: true });
262
+ ```
263
+
264
+ ## Positional Helpers
265
+
266
+ ```typescript
267
+ bargs.stringPos({ required: true }); // <file>
268
+ bargs.numberPos({ default: 8080 }); // [port]
269
+ bargs.enumPos(['dev', 'prod']); // [env]
270
+ bargs.variadic('string'); // [files...]
271
+ ```
272
+
273
+ ### Positional Properties
274
+
275
+ | Property | Type | Description |
276
+ | ------------- | --------- | ------------------------------------------------------ |
277
+ | `default` | varies | Default value |
278
+ | `description` | `string` | Help text description |
279
+ | `name` | `string` | Display name in help (defaults to `arg0`, `arg1`, ...) |
280
+ | `required` | `boolean` | Mark as required (shown as `<name>` vs `[name]`) |
281
+
282
+ ```typescript
283
+ bargs.stringPos({
284
+ name: 'file',
285
+ description: 'Input file to process',
286
+ required: true,
287
+ });
288
+ ```
289
+
290
+ Positionals are defined as an array and accessed by index:
291
+
292
+ ```typescript
293
+ const result = bargs({
294
+ name: 'cp',
295
+ positionals: [
296
+ bargs.stringPos({ required: true }), // source
297
+ bargs.stringPos({ required: true }), // destination
298
+ ],
299
+ });
300
+
301
+ const [source, dest] = result.positionals;
302
+ console.log(`Copying ${source} to ${dest}`);
303
+ ```
304
+
305
+ Use `variadic` for rest arguments (must be last):
306
+
307
+ ```typescript
308
+ const result = bargs({
309
+ name: 'cat',
310
+ positionals: [bargs.variadic('string')],
311
+ });
312
+
313
+ const [files] = result.positionals; // string[]
314
+ files.forEach((file) => console.log(readFileSync(file, 'utf8')));
315
+ ```
316
+
317
+ ## Epilog
318
+
319
+ 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.
320
+
321
+ ```typescript
322
+ // Custom epilog
323
+ bargs({
324
+ name: 'my-cli',
325
+ epilog: 'For more info, visit https://example.com',
326
+ });
327
+
328
+ // Disable epilog entirely
329
+ bargs({
330
+ name: 'my-cli',
331
+ epilog: false,
332
+ });
333
+ ```
334
+
335
+ ## Theming
336
+
337
+ Customize help output colors with built-in themes or your own:
338
+
339
+ ```typescript
340
+ // Use a built-in theme: 'default', 'mono', 'ocean', 'warm'
341
+ bargs(
342
+ {
343
+ name: 'my-cli',
344
+ options: { verbose: bargs.boolean() },
345
+ },
346
+ { theme: 'ocean' },
347
+ );
348
+
349
+ // Disable colors entirely
350
+ bargs(config, { theme: 'mono' });
351
+ ```
352
+
353
+ The `ansi` export provides common ANSI escape codes for styled terminal output: text styles (`bold`, `dim`, `italic`, `underline`, etc.), foreground colors, background colors, and their `bright*` variants. Use this to create your own themes (instead of hardcoding ANSI escape codes).
354
+
355
+ ```typescript
356
+ import { ansi } from '@boneskull/bargs';
357
+
358
+ bargs(someConfig, {
359
+ theme: {
360
+ command: ansi.bold,
361
+ defaultText: ansi.dim,
362
+ defaultValue: ansi.white,
363
+ description: ansi.white,
364
+ epilog: ansi.dim,
365
+ example: ansi.white + ansi.dim,
366
+ flag: ansi.brightCyan,
367
+ positional: ansi.magenta,
368
+ scriptName: ansi.bold,
369
+ sectionHeader: ansi.brightMagenta,
370
+ type: ansi.magenta,
371
+ url: ansi.cyan,
372
+ usage: ansi.cyan,
373
+ },
374
+ });
375
+ ```
376
+
377
+ Available theme color slots:
378
+
379
+ | Slot | What it styles |
380
+ | --------------- | ----------------------------------------------- |
381
+ | `command` | Command names (e.g., `init`, `build`) |
382
+ | `defaultText` | The `default:` label |
383
+ | `defaultValue` | Default value (e.g., `false`, `"hello"`) |
384
+ | `description` | Description text for options and commands |
385
+ | `epilog` | Footer text (homepage, repository) |
386
+ | `example` | Example code/commands |
387
+ | `flag` | Flag names (e.g., `--verbose`, `-v`) |
388
+ | `positional` | Positional argument names (e.g., `<file>`) |
389
+ | `scriptName` | CLI name shown in header |
390
+ | `sectionHeader` | Section headers (e.g., `USAGE`, `OPTIONS`) |
391
+ | `type` | Type annotations (e.g., `[string]`, `[number]`) |
392
+ | `url` | URLs (for clickable hyperlinks) |
393
+ | `usage` | The usage line text |
394
+
395
+ > [!TIP]
396
+ > You don't need to specify all color slots. Missing colors fall back to the default theme.
397
+
398
+ ## Advanced Usage
399
+
400
+ ### Error Handling
401
+
402
+ **bargs** exports some `Error` subclasses:
403
+
404
+ ```typescript
405
+ import {
406
+ bargs,
407
+ BargsError,
408
+ HelpError,
409
+ ValidationError,
410
+ } from '@boneskull/bargs';
411
+
412
+ try {
413
+ bargs(config);
414
+ } catch (error) {
415
+ if (error instanceof ValidationError) {
416
+ // Config validation failed (e.g., invalid schema)
417
+ console.error(`Config error at "${error.path}": ${error.message}`);
418
+ } else if (error instanceof HelpError) {
419
+ // User needs guidance (e.g., unknown option)
420
+ console.error(error.message);
421
+ } else if (error instanceof BargsError) {
422
+ // General bargs error
423
+ console.error(error.message);
424
+ }
425
+ }
426
+ ```
427
+
428
+ ### Programmatic Help
429
+
430
+ Generate help text without calling `bargs()`:
431
+
432
+ ```typescript
433
+ import { generateHelp, generateCommandHelp } from '@boneskull/bargs';
434
+
435
+ const helpText = generateHelp(config);
436
+ const commandHelp = generateCommandHelp(config, 'migrate');
437
+ ```
438
+
439
+ ### Hyperlink Utilities
440
+
441
+ Create clickable terminal hyperlinks ([OSC 8](https://github.com/Alhadis/OSC8-Adoption)):
442
+
443
+ ```typescript
444
+ import { link, linkifyUrls, supportsHyperlinks } from '@boneskull/bargs';
445
+
446
+ // Check if terminal supports hyperlinks
447
+ if (supportsHyperlinks()) {
448
+ // Create a hyperlink
449
+ console.log(link('Click me', 'https://example.com'));
450
+
451
+ // Auto-linkify URLs in text
452
+ console.log(linkifyUrls('Visit https://example.com for more info'));
453
+ }
454
+ ```
455
+
456
+ > [!TIP]
457
+ > **bargs** already automatically links URLs in `--help` output if the terminal supports hyperlinks.
458
+
459
+ ### Additional Theme Utilities
460
+
461
+ ```typescript
462
+ import {
463
+ ansi, // ANSI escape codes
464
+ createStyler, // Create a styler from a theme
465
+ defaultTheme, // The default theme object
466
+ stripAnsi, // Remove ANSI codes from string
467
+ themes, // All built-in themes
468
+ } from '@boneskull/bargs';
469
+
470
+ // Create a custom styler
471
+ const styler = createStyler({ colors: { flag: ansi.green } });
472
+ console.log(styler.flag('--verbose'));
473
+
474
+ // Strip ANSI codes for plain text output
475
+ const plain = stripAnsi('\x1b[32m--verbose\x1b[0m'); // '--verbose'
476
+
477
+ // Override some colors in a built-in theme
478
+ const customTheme = { ...themes.ocean, colors: { flag: ansi.green } };
479
+ ```
480
+
481
+ ## License
482
+
483
+ Copyright © 2025 [Christopher "boneskull" Hiller](https://github.com/boneskull). Licensed under the [Blue Oak Model License 1.0.0](./LICENSE).
package/dist/bargs.cjs ADDED
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ /**
3
+ * Core bargs parsing functions for both sync and async CLI execution.
4
+ *
5
+ * Provides `bargs()` (synchronous) and `bargsAsync()` (asynchronous) entry
6
+ * points that handle configuration validation, built-in `--help` and
7
+ * `--version` flags, argument parsing, and handler invocation. Supports both
8
+ * simple CLIs with options/positionals and command-based CLIs with
9
+ * subcommands.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.bargs = bargs;
15
+ exports.bargsAsync = bargsAsync;
16
+ const errors_js_1 = require("./errors.cjs");
17
+ const help_js_1 = require("./help.cjs");
18
+ const parser_js_1 = require("./parser.cjs");
19
+ const theme_js_1 = require("./theme.cjs");
20
+ const validate_js_1 = require("./validate.cjs");
21
+ /**
22
+ * Check if config has commands.
23
+ */
24
+ const hasCommands = (config) => config.commands !== undefined && Object.keys(config.commands).length > 0;
25
+ /**
26
+ * Check if user defined their own help option (by name or alias).
27
+ */
28
+ const hasUserDefinedHelp = (options) => {
29
+ if (!options) {
30
+ return false;
31
+ }
32
+ if ('help' in options) {
33
+ return true;
34
+ }
35
+ // Check if any option has 'h' as an alias
36
+ return Object.values(options).some((opt) => opt.aliases?.includes('h'));
37
+ };
38
+ /**
39
+ * Check if user defined their own version option (by name or alias).
40
+ */
41
+ const hasUserDefinedVersion = (options) => {
42
+ if (!options) {
43
+ return false;
44
+ }
45
+ if ('version' in options) {
46
+ return true;
47
+ }
48
+ // Check if any option has 'V' as an alias
49
+ return Object.values(options).some((opt) => opt.aliases?.includes('V'));
50
+ };
51
+ /**
52
+ * Handle help and version flags. Returns true if we should exit.
53
+ */
54
+ const handleBuiltinFlags = (config, args, theme = theme_js_1.defaultTheme) => {
55
+ // Handle --help (unless user defined their own help option)
56
+ const userDefinedHelp = hasUserDefinedHelp(config.options);
57
+ if (!userDefinedHelp && (args.includes('--help') || args.includes('-h'))) {
58
+ if (hasCommands(config)) {
59
+ // Check for command-specific help: cmd --help
60
+ const helpIndex = args.findIndex((a) => a === '--help' || a === '-h');
61
+ const commandIndex = args.findIndex((a) => !a.startsWith('-'));
62
+ if (commandIndex >= 0 && commandIndex < helpIndex) {
63
+ const commandName = args[commandIndex];
64
+ console.log((0, help_js_1.generateCommandHelp)(config, commandName, theme));
65
+ }
66
+ else {
67
+ console.log((0, help_js_1.generateHelp)(config, theme));
68
+ }
69
+ }
70
+ else {
71
+ console.log((0, help_js_1.generateHelp)(config, theme));
72
+ }
73
+ process.exit(0);
74
+ }
75
+ // Handle --version (unless user defined their own version option)
76
+ const userDefinedVersion = hasUserDefinedVersion(config.options);
77
+ if (!userDefinedVersion && args.includes('--version') && config.version) {
78
+ console.log(config.version);
79
+ process.exit(0);
80
+ }
81
+ return false;
82
+ };
83
+ /**
84
+ * Handle HelpError by printing message and help text.
85
+ */
86
+ const handleHelpError = (error, config, theme = theme_js_1.defaultTheme) => {
87
+ if (error instanceof errors_js_1.HelpError) {
88
+ console.error(error.message);
89
+ if (hasCommands(config)) {
90
+ console.log((0, help_js_1.generateHelp)(config, theme));
91
+ }
92
+ else {
93
+ console.log((0, help_js_1.generateHelp)(config, theme));
94
+ }
95
+ process.exit(1);
96
+ }
97
+ throw error;
98
+ };
99
+ /**
100
+ * Main bargs entry point (sync implementation). Throws BargsError if any
101
+ * handler returns a thenable.
102
+ */
103
+ function bargs(config, options) {
104
+ // Validate config upfront (throws ValidationError if invalid)
105
+ (0, validate_js_1.validateConfig)(config);
106
+ const args = config.args ?? process.argv.slice(2);
107
+ const theme = options?.theme
108
+ ? (0, theme_js_1.getTheme)(options.theme)
109
+ : (0, theme_js_1.getTheme)('default');
110
+ try {
111
+ handleBuiltinFlags(config, args, theme);
112
+ // Parse
113
+ if (hasCommands(config)) {
114
+ return (0, parser_js_1.parseCommandsSync)({ ...config, args });
115
+ }
116
+ else {
117
+ const result = (0, parser_js_1.parseSimple)({
118
+ args,
119
+ options: config.options,
120
+ positionals: config.positionals,
121
+ });
122
+ // Call handler(s) if provided (sync)
123
+ if (config.handler) {
124
+ (0, parser_js_1.runSyncHandlers)(config.handler, result);
125
+ }
126
+ return result;
127
+ }
128
+ }
129
+ catch (error) {
130
+ return handleHelpError(error, config, theme);
131
+ }
132
+ }
133
+ /**
134
+ * Main bargs entry point (async implementation). Awaits all handlers,
135
+ * supporting async handlers.
136
+ */
137
+ async function bargsAsync(config, options) {
138
+ // Validate config upfront (throws ValidationError if invalid)
139
+ (0, validate_js_1.validateConfig)(config);
140
+ const args = config.args ?? process.argv.slice(2);
141
+ const theme = options?.theme
142
+ ? (0, theme_js_1.getTheme)(options.theme)
143
+ : (0, theme_js_1.getTheme)('default');
144
+ try {
145
+ handleBuiltinFlags(config, args, theme);
146
+ // Parse
147
+ if (hasCommands(config)) {
148
+ return await (0, parser_js_1.parseCommandsAsync)({ ...config, args });
149
+ }
150
+ else {
151
+ const result = (0, parser_js_1.parseSimple)({
152
+ args,
153
+ options: config.options,
154
+ positionals: config.positionals,
155
+ });
156
+ // Call handler(s) if provided (async)
157
+ if (config.handler) {
158
+ await (0, parser_js_1.runHandlers)(config.handler, result);
159
+ }
160
+ return result;
161
+ }
162
+ }
163
+ catch (error) {
164
+ return handleHelpError(error, config, theme);
165
+ }
166
+ }
167
+ //# sourceMappingURL=bargs.js.map