icore 1.0.4 → 1.0.6
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/dist/argv.d.ts.map +1 -1
- package/dist/argv.js +72 -4
- package/dist/argv.js.map +1 -1
- package/dist/commands.d.ts +3 -3
- package/dist/commands.d.ts.map +1 -1
- package/dist/options.d.ts +4 -3
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +6 -3
- package/dist/options.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +530 -47
- package/docs/api.md +0 -466
- package/docs/design.md +0 -80
- package/docs/examples.md +0 -100
- package/docs/git-flow.md +0 -188
- package/docs/policy/abstraction-policy.md +0 -198
- package/docs/policy/change-policy.md +0 -86
- package/docs/policy/comment-policy.md +0 -253
- package/docs/policy/decision-rule-policy.md +0 -41
- package/docs/policy/dependencies-policy.md +0 -49
- package/docs/policy/documentation-policy.md +0 -27
- package/docs/policy/index.md +0 -49
- package/docs/policy/naming-policy.md +0 -18
- package/docs/policy/non-functional-requirements.md +0 -31
- package/docs/policy/scripts-and-build-policy.md +0 -60
- package/docs/policy/testing-policy.md +0 -335
package/readme.md
CHANGED
|
@@ -5,33 +5,335 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/icore)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
Small dependency-free command line interface mechanics for Node.js applications.
|
|
8
|
+
Small dependency-free command line interface mechanics for [Node.js®](https://nodejs.org) applications.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
registries, validates primitive options, and passes typed input to handlers. It
|
|
12
|
-
stops at CLI mechanics: your application still owns business rules, SDK calls,
|
|
13
|
-
process lifecycle, and output formatting.
|
|
10
|
+
### Installation
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
To use `icore` in your project, run:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm install icore
|
|
16
|
+
```
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
### Table of Contents
|
|
18
19
|
|
|
19
|
-
[API
|
|
20
|
+
* [API](#api)
|
|
21
|
+
* [`parseArgv(args, schema?)`](#parseargvargs-schema)
|
|
22
|
+
* [`parseOptions(schema, values)`](#parseoptionsschema-values)
|
|
23
|
+
* [`parseOptionsDetailed(schema, values)`](#parseoptionsdetailedschema-values)
|
|
24
|
+
* [`defineCommand(command)`](#definecommandcommand)
|
|
25
|
+
* [`defineCommandRegistry(commands)`](#definecommandregistrycommands)
|
|
26
|
+
* [`isCommandName(registry, value)`](#iscommandnameregistry-value)
|
|
27
|
+
* [`resolveCommand(registry, positionals)`](#resolvecommandregistry-positionals)
|
|
28
|
+
* [`resolveCommandFromArgs(registry, args)`](#resolvecommandfromargsregistry-args)
|
|
29
|
+
* [`runCommandFromRegistry(registry, args, context)`](#runcommandfromregistryregistry-args-context)
|
|
30
|
+
* [`mergeOptionsSchema(...schemas)`](#mergeoptionsschemaschemas)
|
|
31
|
+
* [`runCommand(command, args, context)`](#runcommandcommand-args-context)
|
|
32
|
+
* [Example](#example)
|
|
33
|
+
* [Option Schemas](#option-schemas)
|
|
34
|
+
* [Type Inference](#type-inference)
|
|
35
|
+
* [Facade of arguments](#facade-of-arguments)
|
|
36
|
+
* [Error Messages](#error-messages)
|
|
20
37
|
|
|
21
|
-
|
|
38
|
+
### API
|
|
22
39
|
|
|
23
|
-
|
|
40
|
+
#### `parseArgv(args, schema?)`
|
|
24
41
|
|
|
25
|
-
|
|
26
|
-
|
|
42
|
+
Parses raw CLI arguments into positionals and raw option values.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { parseArgv } from 'icore';
|
|
46
|
+
|
|
47
|
+
const argv = parseArgv([
|
|
48
|
+
'hello',
|
|
49
|
+
'--name',
|
|
50
|
+
'User',
|
|
51
|
+
'--upper'
|
|
52
|
+
]);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Result:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
{
|
|
59
|
+
positionals: ['hello'],
|
|
60
|
+
options: {
|
|
61
|
+
name: 'User',
|
|
62
|
+
upper: true
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
When an option schema is provided, boolean options are parsed as flag-only
|
|
68
|
+
options without consuming the following positional argument:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const argv = parseArgv([
|
|
72
|
+
'hello',
|
|
73
|
+
'--upper',
|
|
74
|
+
'User'
|
|
75
|
+
], {
|
|
76
|
+
upper: {
|
|
77
|
+
type: 'boolean'
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Result:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
{
|
|
86
|
+
positionals: ['hello', 'User'],
|
|
87
|
+
options: {
|
|
88
|
+
upper: true
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### `parseOptions(schema, values)`
|
|
94
|
+
|
|
95
|
+
Validates raw option values using an option schema and returns typed options.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { parseOptions } from 'icore';
|
|
99
|
+
|
|
100
|
+
const options = parseOptions({
|
|
101
|
+
name: {
|
|
102
|
+
type: 'string',
|
|
103
|
+
default: 'world'
|
|
104
|
+
},
|
|
105
|
+
upper: {
|
|
106
|
+
type: 'boolean'
|
|
107
|
+
}
|
|
108
|
+
} as const, {
|
|
109
|
+
name: 'User',
|
|
110
|
+
upper: true
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Result:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
{
|
|
118
|
+
name: 'User',
|
|
119
|
+
upper: true
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `parseOptionsDetailed(schema, values)`
|
|
124
|
+
|
|
125
|
+
Validates raw option values and returns parsed options together with
|
|
126
|
+
user-provided metadata.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { parseOptionsDetailed } from 'icore';
|
|
130
|
+
|
|
131
|
+
const result = parseOptionsDetailed({
|
|
132
|
+
name: {
|
|
133
|
+
type: 'string',
|
|
134
|
+
default: 'world'
|
|
135
|
+
},
|
|
136
|
+
upper: {
|
|
137
|
+
type: 'boolean'
|
|
138
|
+
}
|
|
139
|
+
} as const, {
|
|
140
|
+
upper: true
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Result:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
{
|
|
148
|
+
options: {
|
|
149
|
+
name: 'world',
|
|
150
|
+
upper: true
|
|
151
|
+
},
|
|
152
|
+
provided: {
|
|
153
|
+
name: false,
|
|
154
|
+
upper: true
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`provided` is useful when a default value and an omitted option have different
|
|
160
|
+
application-level meaning.
|
|
161
|
+
|
|
162
|
+
#### `defineCommand(command)`
|
|
163
|
+
|
|
164
|
+
Defines a command while preserving its option schema types.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { defineCommand } from 'icore';
|
|
168
|
+
|
|
169
|
+
const command = defineCommand({
|
|
170
|
+
path: ['hello'],
|
|
171
|
+
options: {
|
|
172
|
+
name: {
|
|
173
|
+
type: 'string',
|
|
174
|
+
default: 'world'
|
|
175
|
+
},
|
|
176
|
+
upper: {
|
|
177
|
+
type: 'boolean'
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
async handle({ options }) {
|
|
181
|
+
const message = `Hello, ${options.name}!`;
|
|
182
|
+
|
|
183
|
+
return options.upper ? message.toUpperCase() : message;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### `defineCommandRegistry(commands)`
|
|
189
|
+
|
|
190
|
+
Defines a command registry while preserving literal command path types.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { defineCommandRegistry } from 'icore';
|
|
194
|
+
|
|
195
|
+
const registry = defineCommandRegistry([
|
|
196
|
+
helloCommand,
|
|
197
|
+
helloFormalCommand
|
|
198
|
+
] as const);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The registry exposes ordered commands and derived command names:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
registry.commandNames;
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Result:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
[
|
|
211
|
+
'hello',
|
|
212
|
+
'hello formal'
|
|
213
|
+
]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Duplicate command paths are rejected.
|
|
217
|
+
|
|
218
|
+
#### `isCommandName(registry, value)`
|
|
219
|
+
|
|
220
|
+
Checks whether an unknown value is a command name registered in the registry.
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
if (isCommandName(registry, value)) {
|
|
224
|
+
// value is narrowed to the registry command name union.
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### `resolveCommand(registry, positionals)`
|
|
229
|
+
|
|
230
|
+
Resolves a command from already parsed positional arguments.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { resolveCommand } from 'icore';
|
|
234
|
+
|
|
235
|
+
const resolved = resolveCommand(registry, [
|
|
236
|
+
'hello',
|
|
237
|
+
'formal',
|
|
238
|
+
'User'
|
|
239
|
+
]);
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Result:
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
{
|
|
246
|
+
name: 'hello formal',
|
|
247
|
+
path: ['hello', 'formal'],
|
|
248
|
+
command: helloFormalCommand,
|
|
249
|
+
positionals: ['User']
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
When several command paths match, the most specific command wins. For example,
|
|
254
|
+
`hello formal` is preferred over `hello`.
|
|
255
|
+
|
|
256
|
+
#### `resolveCommandFromArgs(registry, args)`
|
|
257
|
+
|
|
258
|
+
Resolves a command from raw CLI arguments. Each candidate command is parsed with
|
|
259
|
+
its own option schema, so boolean flags do not accidentally consume command path
|
|
260
|
+
segments.
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
const resolved = resolveCommandFromArgs(registry, [
|
|
264
|
+
'hello',
|
|
265
|
+
'--name',
|
|
266
|
+
'User',
|
|
267
|
+
'--upper'
|
|
268
|
+
]);
|
|
27
269
|
```
|
|
28
270
|
|
|
29
|
-
|
|
271
|
+
#### `runCommandFromRegistry(registry, args, context)`
|
|
272
|
+
|
|
273
|
+
Resolves a command from a registry and runs its handler.
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
const output = await runCommandFromRegistry(
|
|
277
|
+
registry,
|
|
278
|
+
['hello', '--name', 'User', '--upper'],
|
|
279
|
+
context
|
|
280
|
+
);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
This is **registry-level mechanics only**. Application-specific setup, side
|
|
284
|
+
effects, and output formatting still belong outside `icore`.
|
|
285
|
+
|
|
286
|
+
#### `mergeOptionsSchema(...schemas)`
|
|
287
|
+
|
|
288
|
+
Merges multiple option schemas while preserving literal option definition types.
|
|
289
|
+
Later schemas override earlier schemas with the same option name.
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
import { mergeOptionsSchema } from 'icore';
|
|
293
|
+
|
|
294
|
+
const nameOptions = {
|
|
295
|
+
name: {
|
|
296
|
+
type: 'string',
|
|
297
|
+
default: 'world'
|
|
298
|
+
}
|
|
299
|
+
} as const;
|
|
300
|
+
|
|
301
|
+
const greetingOptions = {
|
|
302
|
+
upper: {
|
|
303
|
+
type: 'boolean'
|
|
304
|
+
}
|
|
305
|
+
} as const;
|
|
306
|
+
|
|
307
|
+
const options = mergeOptionsSchema(nameOptions, greetingOptions);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### `runCommand(command, args, context)`
|
|
311
|
+
|
|
312
|
+
Parses arguments, validates options, checks command positionals, and runs the
|
|
313
|
+
handler.
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
const output = await runCommand(
|
|
317
|
+
command,
|
|
318
|
+
['hello', '--name', 'User', '--upper'],
|
|
319
|
+
context
|
|
320
|
+
);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**By default**, extra positionals are rejected. A command can opt in to extra
|
|
324
|
+
positionals with `allowExtraPositionals: true`.
|
|
325
|
+
|
|
326
|
+
### How It Works
|
|
327
|
+
|
|
328
|
+

|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
### Example
|
|
30
332
|
|
|
31
333
|
```ts
|
|
32
334
|
import { defineCommand, runCommand } from 'icore';
|
|
33
335
|
|
|
34
|
-
const
|
|
336
|
+
const exampleCommand = defineCommand({
|
|
35
337
|
path: ['hello'],
|
|
36
338
|
options: {
|
|
37
339
|
name: {
|
|
@@ -50,53 +352,234 @@ const helloCommand = defineCommand({
|
|
|
50
352
|
});
|
|
51
353
|
|
|
52
354
|
const output = await runCommand(
|
|
53
|
-
|
|
54
|
-
['hello', '--name', '
|
|
355
|
+
exampleCommand,
|
|
356
|
+
['hello', '--name', 'User', '--upper'],
|
|
55
357
|
{}
|
|
56
358
|
);
|
|
57
359
|
|
|
58
360
|
console.log(output);
|
|
59
361
|
```
|
|
60
362
|
|
|
61
|
-
|
|
363
|
+
Terminal output:
|
|
62
364
|
|
|
63
|
-
|
|
365
|
+
```console
|
|
366
|
+
$ node cli.js hello --name User --upper
|
|
367
|
+
HELLO, USER!
|
|
368
|
+
```
|
|
64
369
|
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
- required options;
|
|
68
|
-
- string choices;
|
|
69
|
-
- number parsing with integer, minimum, and maximum constraints;
|
|
70
|
-
- option presence metadata;
|
|
71
|
-
- typed command handler input.
|
|
370
|
+
The command handler receives parsed options, user-provided option metadata,
|
|
371
|
+
remaining positionals, and caller provided context.
|
|
72
372
|
|
|
73
|
-
|
|
74
|
-
directly when you only need low-level argument parsing.
|
|
373
|
+
### Option Schemas
|
|
75
374
|
|
|
76
|
-
|
|
375
|
+
Options are described as plain objects.
|
|
77
376
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
| `--name=value` | yes | string and number options |
|
|
82
|
-
| `--flag` | yes | boolean options |
|
|
83
|
-
| `--flag=true` | no | boolean options are flag-only |
|
|
84
|
-
| `-f` | no | short aliases are not supported |
|
|
85
|
-
| `--no-cache` | no | negative boolean flags are not supported |
|
|
86
|
-
| repeated options | no | duplicates are rejected |
|
|
87
|
-
| multiple values | no | arrays are not supported |
|
|
377
|
+
**Option names are exact.** `icore` does not normalize `camelCase` to
|
|
378
|
+
`kebab-case`. Use quoted object keys when your public CLI option contains
|
|
379
|
+
`-`.
|
|
88
380
|
|
|
89
|
-
|
|
381
|
+
Each option can define an optional short alias:
|
|
90
382
|
|
|
91
|
-
|
|
92
|
-
|
|
383
|
+
```ts
|
|
384
|
+
const schema = {
|
|
385
|
+
name: {
|
|
386
|
+
type: 'string',
|
|
387
|
+
alias: 'n'
|
|
388
|
+
},
|
|
389
|
+
upper: {
|
|
390
|
+
type: 'boolean',
|
|
391
|
+
alias: 'u'
|
|
392
|
+
}
|
|
393
|
+
} as const;
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Aliases must be a single ASCII letter and unique within the schema. Parsed
|
|
397
|
+
values are always returned by long option name.
|
|
93
398
|
|
|
94
|
-
|
|
399
|
+
#### `type: 'string'`
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
const schema = {
|
|
403
|
+
name: {
|
|
404
|
+
type: 'string',
|
|
405
|
+
required: true
|
|
406
|
+
},
|
|
407
|
+
style: {
|
|
408
|
+
type: 'string',
|
|
409
|
+
choices: ['short', 'long'],
|
|
410
|
+
default: 'short'
|
|
411
|
+
}
|
|
412
|
+
} as const;
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
String options reject missing required values, blank strings such as `--name=`,
|
|
416
|
+
boolean flag form, and values outside `choices`.
|
|
417
|
+
|
|
418
|
+
#### `type: 'boolean'`
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
const schema = {
|
|
422
|
+
upper: {
|
|
423
|
+
type: 'boolean'
|
|
424
|
+
}
|
|
425
|
+
} as const;
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Boolean options accept **flag form**, explicit `true` / `false` values, and
|
|
429
|
+
schema-known negation:
|
|
430
|
+
|
|
431
|
+
```sh
|
|
432
|
+
--upper
|
|
433
|
+
--upper=true
|
|
434
|
+
--upper=false
|
|
435
|
+
--no-upper
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Invalid explicit values are rejected:
|
|
439
|
+
|
|
440
|
+
```sh
|
|
441
|
+
--upper=yes
|
|
442
|
+
--upper=
|
|
443
|
+
```
|
|
95
444
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
- Runtime dependencies: none.
|
|
445
|
+
`--upper false` keeps `--upper` as `true` and leaves `false` as a positional
|
|
446
|
+
argument.
|
|
99
447
|
|
|
100
|
-
|
|
448
|
+
#### `type: 'number'`
|
|
101
449
|
|
|
102
|
-
|
|
450
|
+
```ts
|
|
451
|
+
const schema = {
|
|
452
|
+
limit: {
|
|
453
|
+
type: 'number',
|
|
454
|
+
integer: true,
|
|
455
|
+
min: 1,
|
|
456
|
+
max: 1000,
|
|
457
|
+
default: 100
|
|
458
|
+
}
|
|
459
|
+
} as const;
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Number options parse decimal numeric values and can validate integer and range
|
|
463
|
+
constraints. Defaults are validated with the same rules as user-provided values.
|
|
464
|
+
|
|
465
|
+
### Type Inference
|
|
466
|
+
|
|
467
|
+
Use `InferOptions` when you need the parsed option type explicitly.
|
|
468
|
+
|
|
469
|
+
```ts
|
|
470
|
+
import type { InferOptions } from 'icore';
|
|
471
|
+
|
|
472
|
+
const schema = {
|
|
473
|
+
name: {
|
|
474
|
+
type: 'string',
|
|
475
|
+
default: 'world'
|
|
476
|
+
},
|
|
477
|
+
upper: {
|
|
478
|
+
type: 'boolean'
|
|
479
|
+
}
|
|
480
|
+
} as const;
|
|
481
|
+
|
|
482
|
+
type Options = InferOptions<typeof schema>;
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
`Options` is equivalent to:
|
|
486
|
+
|
|
487
|
+
```ts
|
|
488
|
+
type Options = {
|
|
489
|
+
name: string;
|
|
490
|
+
upper: boolean | undefined;
|
|
491
|
+
};
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**Required options and options with defaults are always present.** Optional
|
|
495
|
+
options without defaults are returned as `T | undefined`.
|
|
496
|
+
|
|
497
|
+
Use `InferProvidedOptions` when you need the option presence type explicitly.
|
|
498
|
+
|
|
499
|
+
```ts
|
|
500
|
+
import type { InferProvidedOptions } from 'icore';
|
|
501
|
+
|
|
502
|
+
type Provided = InferProvidedOptions<typeof schema>;
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
`Provided` maps every schema option to `boolean`. `true` means the user
|
|
506
|
+
specified that option explicitly; defaults keep the flag `false`.
|
|
507
|
+
|
|
508
|
+
Use `MergeOptionsSchemas` when you need the merged schema type explicitly.
|
|
509
|
+
|
|
510
|
+
```ts
|
|
511
|
+
import type { MergeOptionsSchemas } from 'icore';
|
|
512
|
+
|
|
513
|
+
type Schema = MergeOptionsSchemas<[typeof nameOptions, typeof greetingOptions]>;
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Use `CommandName` when you need the inferred command name type explicitly.
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
import type { CommandName } from 'icore';
|
|
520
|
+
|
|
521
|
+
type Name = CommandName<typeof helloFormalCommand>;
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
`Name` is equivalent to:
|
|
525
|
+
|
|
526
|
+
```ts
|
|
527
|
+
type Name = 'hello formal';
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Facade of arguments
|
|
531
|
+
|
|
532
|
+
Supports a practical GNU-style option syntax:
|
|
533
|
+
|
|
534
|
+
- long options: `--name value`, `--name=value`;
|
|
535
|
+
- boolean flags: `--flag`, `--flag=true`, `--flag=false`, `--no-flag`;
|
|
536
|
+
- short aliases: `-f`, `-n value`;
|
|
537
|
+
- option terminator: `--`.
|
|
538
|
+
|
|
539
|
+
Use `--` to stop option parsing. The terminator itself is not included in
|
|
540
|
+
positionals; every following token is treated as positional, even when it starts
|
|
541
|
+
with `-`.
|
|
542
|
+
|
|
543
|
+
Short syntax is supported only for aliases declared in the option schema.
|
|
544
|
+
Boolean aliases use flag form, such as `-f`; string and number aliases use a
|
|
545
|
+
separate value, such as `-n value`.
|
|
546
|
+
|
|
547
|
+
Attached short values such as `-nvalue` and grouped short booleans such as
|
|
548
|
+
`-abc` are not supported yet. Unknown short tokens remain positional for
|
|
549
|
+
compatibility.
|
|
550
|
+
|
|
551
|
+
Negated syntax such as `--no-cache` is interpreted as `cache: false` when
|
|
552
|
+
`cache` is a known boolean option. Unknown negated options and negation for
|
|
553
|
+
string or number options are rejected.
|
|
554
|
+
|
|
555
|
+
### Error Messages
|
|
556
|
+
|
|
557
|
+
`icore` throws regular `Error` objects with predictable user-facing messages.
|
|
558
|
+
Applications should treat these messages as **display text**, not as a
|
|
559
|
+
**machine-readable API**.
|
|
560
|
+
|
|
561
|
+
Applications can catch these errors and decide how to print them. For example,
|
|
562
|
+
after printing `error.message`, terminal output can look like this:
|
|
563
|
+
|
|
564
|
+
```console
|
|
565
|
+
$ node cli.js hello --unknown
|
|
566
|
+
Unexpected argument '--unknown'
|
|
567
|
+
|
|
568
|
+
$ node cli.js hello --upper=yes
|
|
569
|
+
Expected '--upper' as boolean flag
|
|
570
|
+
|
|
571
|
+
$ node cli.js hello --name=
|
|
572
|
+
Expected '--name' as string
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Project Boundary
|
|
576
|
+
|
|
577
|
+
`icore` is intended to be a **small CLI mechanics module**. It should **not**
|
|
578
|
+
grow into a domain-specific framework for a particular SDK or API.
|
|
579
|
+
|
|
580
|
+
Good responsibilities for `icore`:
|
|
581
|
+
|
|
582
|
+
- option schema evaluation;
|
|
583
|
+
- command path checking;
|
|
584
|
+
- common argument errors;
|
|
585
|
+
- typed command handler input.
|