@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.
- package/LICENSE +55 -0
- package/README.md +483 -0
- package/dist/bargs.cjs +167 -0
- package/dist/bargs.cjs.map +1 -0
- package/dist/bargs.d.cts +31 -0
- package/dist/bargs.d.cts.map +1 -0
- package/dist/bargs.d.ts +31 -0
- package/dist/bargs.d.ts.map +1 -0
- package/dist/bargs.js +163 -0
- package/dist/bargs.js.map +1 -0
- package/dist/errors.cjs +57 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +40 -0
- package/dist/errors.d.cts.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +51 -0
- package/dist/errors.js.map +1 -0
- package/dist/help.cjs +309 -0
- package/dist/help.cjs.map +1 -0
- package/dist/help.d.cts +21 -0
- package/dist/help.d.cts.map +1 -0
- package/dist/help.d.ts +21 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +304 -0
- package/dist/help.js.map +1 -0
- package/dist/index.cjs +63 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +96 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/opt.cjs +205 -0
- package/dist/opt.cjs.map +1 -0
- package/dist/opt.d.cts +145 -0
- package/dist/opt.d.cts.map +1 -0
- package/dist/opt.d.ts +145 -0
- package/dist/opt.d.ts.map +1 -0
- package/dist/opt.js +202 -0
- package/dist/opt.js.map +1 -0
- package/dist/osc.cjs +190 -0
- package/dist/osc.cjs.map +1 -0
- package/dist/osc.d.cts +30 -0
- package/dist/osc.d.cts.map +1 -0
- package/dist/osc.d.ts +30 -0
- package/dist/osc.d.ts.map +1 -0
- package/dist/osc.js +181 -0
- package/dist/osc.js.map +1 -0
- package/dist/parser.cjs +293 -0
- package/dist/parser.cjs.map +1 -0
- package/dist/parser.d.cts +47 -0
- package/dist/parser.d.cts.map +1 -0
- package/dist/parser.d.ts +47 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +285 -0
- package/dist/parser.js.map +1 -0
- package/dist/theme.cjs +203 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.cts +227 -0
- package/dist/theme.d.cts.map +1 -0
- package/dist/theme.d.ts +227 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +198 -0
- package/dist/theme.js.map +1 -0
- package/dist/types.cjs +18 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +244 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.ts +244 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.cjs +452 -0
- package/dist/validate.cjs.map +1 -0
- package/dist/validate.d.cts +28 -0
- package/dist/validate.d.cts.map +1 -0
- package/dist/validate.d.ts +28 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +448 -0
- package/dist/validate.js.map +1 -0
- package/dist/version.cjs +134 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.d.cts +27 -0
- package/dist/version.d.cts.map +1 -0
- package/dist/version.d.ts +27 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +129 -0
- package/dist/version.js.map +1 -0
- 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
|