icore 0.1.38 → 1.0.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/dist/argv.d.ts +14 -0
- package/dist/argv.d.ts.map +1 -0
- package/dist/argv.js +62 -0
- package/dist/argv.js.map +1 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +36 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +81 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +132 -0
- package/dist/commands.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/options.d.ts +119 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +132 -0
- package/dist/options.js.map +1 -0
- package/package.json +23 -25
- package/readme.md +591 -0
- package/README.md +0 -267
- package/index.js +0 -18
- package/src/application.js +0 -219
- package/src/async-function.js +0 -3
- package/src/inquiry.js +0 -141
- package/src/route.js +0 -109
package/readme.md
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# icore
|
|
2
|
+
|
|
3
|
+
Declarative command line interface mechanics for Node.js.
|
|
4
|
+
|
|
5
|
+
`icore` helps describe CLI commands with small option schemas and keeps command
|
|
6
|
+
handlers focused on application work. It standardizes argument parsing,
|
|
7
|
+
primitive option validation, defaults, choices, numeric ranges, and positional
|
|
8
|
+
argument checks. It can also resolve commands from a registry and report whether
|
|
9
|
+
each option was provided explicitly by the user or filled from a default.
|
|
10
|
+
|
|
11
|
+
### How it works?
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
It does not try to model your business domain. API calls, request building,
|
|
16
|
+
response mapping, and output formatting should stay in the application that uses
|
|
17
|
+
`icore`.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm install icore
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Requirements
|
|
26
|
+
|
|
27
|
+
- Node.js `>=20.19.0`
|
|
28
|
+
- TypeScript is supported through bundled declaration files.
|
|
29
|
+
|
|
30
|
+
## Basic Usage
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { defineCommand, runCommand } from 'icore';
|
|
34
|
+
|
|
35
|
+
const command = defineCommand({
|
|
36
|
+
path: ['users', 'get-accounts'],
|
|
37
|
+
options: {
|
|
38
|
+
format: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
choices: ['json', 'table'],
|
|
41
|
+
default: 'table'
|
|
42
|
+
},
|
|
43
|
+
insecure: {
|
|
44
|
+
type: 'boolean'
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
async handle({ options, context }) {
|
|
48
|
+
const response = await context.sdk.users.getAccounts({});
|
|
49
|
+
|
|
50
|
+
return context.formatAccounts(response.accounts, options.format);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const output = await runCommand(
|
|
55
|
+
command,
|
|
56
|
+
['users', 'get-accounts', '--format', 'json'],
|
|
57
|
+
{
|
|
58
|
+
sdk,
|
|
59
|
+
formatAccounts
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The command handler receives parsed options, user-provided option metadata,
|
|
65
|
+
remaining positionals, and caller provided context.
|
|
66
|
+
|
|
67
|
+
## Design Goals
|
|
68
|
+
|
|
69
|
+
- describe CLI mechanics declaratively;
|
|
70
|
+
- use literal option types: `type: 'string' | 'boolean' | 'number'`;
|
|
71
|
+
- keep handlers free from repetitive option parsing;
|
|
72
|
+
- keep domain and API semantics outside the framework;
|
|
73
|
+
- provide predictable user-facing errors;
|
|
74
|
+
- avoid runtime dependencies.
|
|
75
|
+
|
|
76
|
+
## What icore Handles
|
|
77
|
+
|
|
78
|
+
`icore` handles generic CLI mechanics:
|
|
79
|
+
|
|
80
|
+
- parsing long options;
|
|
81
|
+
- validating known options;
|
|
82
|
+
- rejecting duplicated options;
|
|
83
|
+
- checking required options;
|
|
84
|
+
- applying and validating defaults;
|
|
85
|
+
- validating string choices;
|
|
86
|
+
- validating boolean flag form;
|
|
87
|
+
- composing option schemas;
|
|
88
|
+
- defining command registries;
|
|
89
|
+
- resolving commands by path;
|
|
90
|
+
- preserving user-provided option metadata;
|
|
91
|
+
- parsing numbers;
|
|
92
|
+
- validating integer, minimum, and maximum numeric constraints;
|
|
93
|
+
- checking command path and extra positional arguments.
|
|
94
|
+
|
|
95
|
+
## What icore Does Not Handle
|
|
96
|
+
|
|
97
|
+
`icore` intentionally does not handle application-specific behavior:
|
|
98
|
+
|
|
99
|
+
- building API request DTOs;
|
|
100
|
+
- calling SDKs or network clients;
|
|
101
|
+
- managing database, HTTP, or gRPC lifecycle;
|
|
102
|
+
- checking business invariants such as `from <= to`;
|
|
103
|
+
- resolving mutually exclusive command modes;
|
|
104
|
+
- formatting output as JSON, tables, CSV, or other application formats.
|
|
105
|
+
|
|
106
|
+
Keep those decisions near the command handler or in your application layer.
|
|
107
|
+
|
|
108
|
+
## Option Schemas
|
|
109
|
+
|
|
110
|
+
Options are described as plain objects.
|
|
111
|
+
|
|
112
|
+
Option names are exact. `icore` does not normalize camelCase to kebab-case or
|
|
113
|
+
kebab-case to camelCase. Use quoted object keys when your public CLI option
|
|
114
|
+
contains `-`.
|
|
115
|
+
|
|
116
|
+
### String Options
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const schema = {
|
|
120
|
+
token: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
required: true
|
|
123
|
+
},
|
|
124
|
+
format: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
choices: ['json', 'table'],
|
|
127
|
+
default: 'table'
|
|
128
|
+
}
|
|
129
|
+
} as const;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
String options reject missing required values, blank strings, boolean flag form,
|
|
133
|
+
and values outside `choices`.
|
|
134
|
+
|
|
135
|
+
### Boolean Options
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const schema = {
|
|
139
|
+
insecure: {
|
|
140
|
+
type: 'boolean'
|
|
141
|
+
}
|
|
142
|
+
} as const;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Boolean options accept flag form only:
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
--insecure
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Explicit values are rejected:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
--insecure true
|
|
155
|
+
--insecure=true
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Number Options
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const schema = {
|
|
162
|
+
limit: {
|
|
163
|
+
type: 'number',
|
|
164
|
+
integer: true,
|
|
165
|
+
min: 1,
|
|
166
|
+
max: 1000,
|
|
167
|
+
default: 100
|
|
168
|
+
}
|
|
169
|
+
} as const;
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Number options parse decimal numeric values and can validate integer and range
|
|
173
|
+
constraints. Defaults are validated with the same rules as user-provided values.
|
|
174
|
+
|
|
175
|
+
## API
|
|
176
|
+
|
|
177
|
+
### `parseArgv(args, schema?)`
|
|
178
|
+
|
|
179
|
+
Parses raw CLI arguments into positionals and raw option values.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { parseArgv } from 'icore';
|
|
183
|
+
|
|
184
|
+
const argv = parseArgv([
|
|
185
|
+
'users',
|
|
186
|
+
'get-accounts',
|
|
187
|
+
'--format=json',
|
|
188
|
+
'--insecure'
|
|
189
|
+
]);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Result:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
{
|
|
196
|
+
positionals: ['users', 'get-accounts'],
|
|
197
|
+
options: {
|
|
198
|
+
format: 'json',
|
|
199
|
+
insecure: true
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
When an option schema is provided, boolean options are parsed as flag-only
|
|
205
|
+
options without consuming the following positional argument:
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
const argv = parseArgv([
|
|
209
|
+
'users',
|
|
210
|
+
'get-accounts',
|
|
211
|
+
'--insecure',
|
|
212
|
+
'extra'
|
|
213
|
+
], {
|
|
214
|
+
insecure: {
|
|
215
|
+
type: 'boolean'
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Result:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
{
|
|
224
|
+
positionals: ['users', 'get-accounts', 'extra'],
|
|
225
|
+
options: {
|
|
226
|
+
insecure: true
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### `parseOptions(schema, values)`
|
|
232
|
+
|
|
233
|
+
Validates raw option values using an option schema and returns typed options.
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
import { parseOptions } from 'icore';
|
|
237
|
+
|
|
238
|
+
const options = parseOptions({
|
|
239
|
+
format: {
|
|
240
|
+
type: 'string',
|
|
241
|
+
choices: ['json', 'table'],
|
|
242
|
+
default: 'table'
|
|
243
|
+
},
|
|
244
|
+
depth: {
|
|
245
|
+
type: 'number',
|
|
246
|
+
integer: true,
|
|
247
|
+
min: 1,
|
|
248
|
+
required: true
|
|
249
|
+
}
|
|
250
|
+
} as const, {
|
|
251
|
+
depth: '10'
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Result:
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
{
|
|
259
|
+
format: 'table',
|
|
260
|
+
depth: 10
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### `parseOptionsDetailed(schema, values)`
|
|
265
|
+
|
|
266
|
+
Validates raw option values and returns parsed options together with
|
|
267
|
+
user-provided metadata.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
import { parseOptionsDetailed } from 'icore';
|
|
271
|
+
|
|
272
|
+
const result = parseOptionsDetailed({
|
|
273
|
+
token: {
|
|
274
|
+
type: 'string',
|
|
275
|
+
required: true
|
|
276
|
+
},
|
|
277
|
+
format: {
|
|
278
|
+
type: 'string',
|
|
279
|
+
choices: ['json', 'table'],
|
|
280
|
+
default: 'table'
|
|
281
|
+
}
|
|
282
|
+
} as const, {
|
|
283
|
+
token: 'secret'
|
|
284
|
+
});
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Result:
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
{
|
|
291
|
+
options: {
|
|
292
|
+
token: 'secret',
|
|
293
|
+
format: 'table'
|
|
294
|
+
},
|
|
295
|
+
provided: {
|
|
296
|
+
token: true,
|
|
297
|
+
format: false
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
`provided` is useful when a default value and an omitted option have different
|
|
303
|
+
application-level meaning.
|
|
304
|
+
|
|
305
|
+
### `defineCommand(command)`
|
|
306
|
+
|
|
307
|
+
Defines a command while preserving its option schema types.
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
import { defineCommand } from 'icore';
|
|
311
|
+
|
|
312
|
+
const command = defineCommand({
|
|
313
|
+
path: ['marketdata', 'get-order-book'],
|
|
314
|
+
options: {
|
|
315
|
+
'instrument-id': {
|
|
316
|
+
type: 'string',
|
|
317
|
+
required: true
|
|
318
|
+
},
|
|
319
|
+
depth: {
|
|
320
|
+
type: 'number',
|
|
321
|
+
integer: true,
|
|
322
|
+
min: 1,
|
|
323
|
+
required: true
|
|
324
|
+
},
|
|
325
|
+
format: {
|
|
326
|
+
type: 'string',
|
|
327
|
+
choices: ['json', 'table'],
|
|
328
|
+
default: 'table'
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
async handle({ options, context }) {
|
|
332
|
+
const response = await context.sdk.marketdata.getOrderBook({
|
|
333
|
+
instrumentId: options['instrument-id'],
|
|
334
|
+
depth: options.depth
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return context.formatOrderBook(response, options.format);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### `defineCommandRegistry(commands)`
|
|
343
|
+
|
|
344
|
+
Defines a command registry while preserving literal command path types.
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
import { defineCommandRegistry } from 'icore';
|
|
348
|
+
|
|
349
|
+
const registry = defineCommandRegistry([
|
|
350
|
+
usersGetAccountsCommand,
|
|
351
|
+
marketdataGetOrderBookCommand
|
|
352
|
+
] as const);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The registry exposes ordered commands and derived command names:
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
registry.commandNames;
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Result:
|
|
362
|
+
|
|
363
|
+
```ts
|
|
364
|
+
[
|
|
365
|
+
'users get-accounts',
|
|
366
|
+
'marketdata get-order-book'
|
|
367
|
+
]
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Duplicate command paths are rejected.
|
|
371
|
+
|
|
372
|
+
### `isCommandName(registry, value)`
|
|
373
|
+
|
|
374
|
+
Checks whether an unknown value is a command name registered in the registry.
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
if (isCommandName(registry, value)) {
|
|
378
|
+
// value is narrowed to the registry command name union.
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### `resolveCommand(registry, positionals)`
|
|
383
|
+
|
|
384
|
+
Resolves a command from already parsed positional arguments.
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
import { resolveCommand } from 'icore';
|
|
388
|
+
|
|
389
|
+
const resolved = resolveCommand(registry, [
|
|
390
|
+
'users',
|
|
391
|
+
'get-accounts',
|
|
392
|
+
'extra'
|
|
393
|
+
]);
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Result:
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
{
|
|
400
|
+
name: 'users get-accounts',
|
|
401
|
+
path: ['users', 'get-accounts'],
|
|
402
|
+
command: usersGetAccountsCommand,
|
|
403
|
+
positionals: ['extra']
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
When several command paths match, the most specific command wins. For example,
|
|
408
|
+
`users get-accounts` is preferred over `users`.
|
|
409
|
+
|
|
410
|
+
### `resolveCommandFromArgs(registry, args)`
|
|
411
|
+
|
|
412
|
+
Resolves a command from raw CLI arguments. Each candidate command is parsed with
|
|
413
|
+
its own option schema, so boolean flags do not accidentally consume command path
|
|
414
|
+
segments.
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
const resolved = resolveCommandFromArgs(registry, [
|
|
418
|
+
'--verbose',
|
|
419
|
+
'users',
|
|
420
|
+
'get-accounts'
|
|
421
|
+
]);
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### `runCommandFromRegistry(registry, args, context)`
|
|
425
|
+
|
|
426
|
+
Resolves a command from a registry and runs its handler.
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
const output = await runCommandFromRegistry(
|
|
430
|
+
registry,
|
|
431
|
+
['users', 'get-accounts', '--format', 'json'],
|
|
432
|
+
context
|
|
433
|
+
);
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
This is registry-level mechanics only. Application-specific setup, API request
|
|
437
|
+
building, and output formatting still belong outside `icore`.
|
|
438
|
+
|
|
439
|
+
### `mergeOptionsSchema(...schemas)`
|
|
440
|
+
|
|
441
|
+
Merges multiple option schemas while preserving literal option definition types.
|
|
442
|
+
Later schemas override earlier schemas with the same option name.
|
|
443
|
+
|
|
444
|
+
```ts
|
|
445
|
+
import { mergeOptionsSchema } from 'icore';
|
|
446
|
+
|
|
447
|
+
const sdkOptions = {
|
|
448
|
+
token: {
|
|
449
|
+
type: 'string',
|
|
450
|
+
required: true
|
|
451
|
+
}
|
|
452
|
+
} as const;
|
|
453
|
+
|
|
454
|
+
const formatOptions = {
|
|
455
|
+
format: {
|
|
456
|
+
type: 'string',
|
|
457
|
+
choices: ['json', 'table'],
|
|
458
|
+
default: 'table'
|
|
459
|
+
}
|
|
460
|
+
} as const;
|
|
461
|
+
|
|
462
|
+
const options = mergeOptionsSchema(sdkOptions, formatOptions);
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### `runCommand(command, args, context)`
|
|
466
|
+
|
|
467
|
+
Parses arguments, validates options, checks command positionals, and runs the
|
|
468
|
+
handler.
|
|
469
|
+
|
|
470
|
+
```ts
|
|
471
|
+
const output = await runCommand(
|
|
472
|
+
command,
|
|
473
|
+
[
|
|
474
|
+
'marketdata',
|
|
475
|
+
'get-order-book',
|
|
476
|
+
'--instrument-id',
|
|
477
|
+
'instrument-id',
|
|
478
|
+
'--depth',
|
|
479
|
+
'10'
|
|
480
|
+
],
|
|
481
|
+
context
|
|
482
|
+
);
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
By default, extra positionals are rejected. A command can opt in to extra
|
|
486
|
+
positionals with `allowExtraPositionals: true`.
|
|
487
|
+
|
|
488
|
+
## Type Inference
|
|
489
|
+
|
|
490
|
+
Use `InferOptions` when you need the parsed option type explicitly.
|
|
491
|
+
|
|
492
|
+
```ts
|
|
493
|
+
import type { InferOptions } from 'icore';
|
|
494
|
+
|
|
495
|
+
const schema = {
|
|
496
|
+
format: {
|
|
497
|
+
type: 'string',
|
|
498
|
+
choices: ['json', 'table'],
|
|
499
|
+
default: 'table'
|
|
500
|
+
},
|
|
501
|
+
dryRun: {
|
|
502
|
+
type: 'boolean'
|
|
503
|
+
}
|
|
504
|
+
} as const;
|
|
505
|
+
|
|
506
|
+
type Options = InferOptions<typeof schema>;
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
`Options` is equivalent to:
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
type Options = {
|
|
513
|
+
format: 'json' | 'table';
|
|
514
|
+
dryRun: boolean | undefined;
|
|
515
|
+
};
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
Required options and options with defaults are always present. Optional options
|
|
519
|
+
without defaults are returned as `T | undefined`.
|
|
520
|
+
|
|
521
|
+
Use `InferProvidedOptions` when you need the option presence type explicitly.
|
|
522
|
+
|
|
523
|
+
```ts
|
|
524
|
+
import type { InferProvidedOptions } from 'icore';
|
|
525
|
+
|
|
526
|
+
type Provided = InferProvidedOptions<typeof schema>;
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
`Provided` maps every schema option to `boolean`. `true` means the user
|
|
530
|
+
specified that option explicitly; defaults keep the flag `false`.
|
|
531
|
+
|
|
532
|
+
Use `MergeOptionsSchemas` when you need the merged schema type explicitly.
|
|
533
|
+
|
|
534
|
+
```ts
|
|
535
|
+
import type { MergeOptionsSchemas } from 'icore';
|
|
536
|
+
|
|
537
|
+
type Schema = MergeOptionsSchemas<[typeof sdkOptions, typeof formatOptions]>;
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
Use `CommandName` when you need the inferred command name type explicitly.
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
import type { CommandName } from 'icore';
|
|
544
|
+
|
|
545
|
+
type Name = CommandName<typeof usersGetAccountsCommand>;
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
`Name` is equivalent to:
|
|
549
|
+
|
|
550
|
+
```ts
|
|
551
|
+
type Name = 'users get-accounts';
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
## Error Messages
|
|
555
|
+
|
|
556
|
+
`icore` throws regular `Error` objects with stable messages.
|
|
557
|
+
|
|
558
|
+
Examples:
|
|
559
|
+
|
|
560
|
+
```txt
|
|
561
|
+
Unexpected argument '--unknown'
|
|
562
|
+
Unexpected duplicate argument '--format'
|
|
563
|
+
Unexpected duplicate command 'users get-accounts'
|
|
564
|
+
Unknown command: users get-unknown
|
|
565
|
+
Expected required argument '--token'
|
|
566
|
+
Expected '--format' as one of: json, table
|
|
567
|
+
Expected '--depth' as integer
|
|
568
|
+
Expected '--depth' to be greater than or equal to 1
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
Applications can catch these errors and decide how to print them.
|
|
572
|
+
|
|
573
|
+
## Project Boundary
|
|
574
|
+
|
|
575
|
+
`icore` is intended to be a small CLI mechanics module. It should not grow into a
|
|
576
|
+
domain-specific framework for a particular SDK or API.
|
|
577
|
+
|
|
578
|
+
Good responsibilities for `icore`:
|
|
579
|
+
|
|
580
|
+
- option schema evaluation;
|
|
581
|
+
- command path checking;
|
|
582
|
+
- common argument errors;
|
|
583
|
+
- typed command handler input.
|
|
584
|
+
|
|
585
|
+
Responsibilities that should stay outside `icore`:
|
|
586
|
+
|
|
587
|
+
- business validation;
|
|
588
|
+
- SDK lifecycle management;
|
|
589
|
+
- provider-specific request modes;
|
|
590
|
+
- generated contract mapping;
|
|
591
|
+
- presentation formatting.
|