icore 1.0.15 → 1.0.17
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/CHANGELOG.md +220 -0
- package/dist/{argv.d.ts → argv/parser.d.ts} +3 -1
- package/dist/{argv.js → argv/parser.js} +5 -5
- package/dist/{commands.d.ts → command/mechanics.d.ts} +73 -6
- package/dist/{commands.js → command/mechanics.js} +53 -15
- package/dist/{errors.d.ts → errors/icore-error.d.ts} +2 -0
- package/dist/{errors.js → errors/icore-error.js} +2 -0
- package/dist/index.d.ts +28 -1
- package/dist/index.js +61 -17
- package/dist/options/parser.d.ts +43 -0
- package/dist/{options.js → options/parser.js} +27 -17
- package/dist/{options.d.ts → options/schema.d.ts} +16 -23
- package/dist/options/schema.js +23 -0
- package/dist/output/facade.d.ts +28 -0
- package/dist/output/facade.js +32 -0
- package/dist/output/node-writer.d.ts +17 -0
- package/dist/output/node-writer.js +25 -0
- package/dist/output/text-writer.d.ts +29 -0
- package/dist/output/text-writer.js +49 -0
- package/dist/presentation/facade.d.ts +39 -0
- package/dist/presentation/facade.js +47 -0
- package/dist/presentation/format-options.d.ts +31 -0
- package/dist/presentation/format-options.js +37 -0
- package/dist/presentation/renderers/csv.d.ts +18 -0
- package/dist/presentation/renderers/csv.js +35 -0
- package/dist/presentation/renderers/json.d.ts +13 -0
- package/dist/presentation/renderers/json.js +18 -0
- package/dist/presentation/renderers/table.d.ts +14 -0
- package/dist/presentation/renderers/table.js +29 -0
- package/dist/presentation/result-renderer.d.ts +25 -0
- package/dist/presentation/result-renderer.js +184 -0
- package/dist/presentation/view.d.ts +58 -0
- package/dist/presentation/view.js +56 -0
- package/dist/terminal/app.d.ts +70 -0
- package/dist/terminal/app.js +100 -0
- package/examples/cli-argument-syntax.md +218 -0
- package/examples/command-resolution.md +174 -0
- package/examples/custom-command-flow.md +109 -0
- package/examples/option-schemas.md +206 -0
- package/examples/output-writers.md +128 -0
- package/examples/practical-cli-patterns.md +385 -0
- package/examples/presentation-output.md +66 -0
- package/examples/presentation-primitives.md +190 -0
- package/examples/readme.md +48 -0
- package/examples/terminal-app.md +118 -0
- package/examples/two-phase-primitives.md +282 -0
- package/package.json +9 -4
- package/readme.md +278 -299
- package/dist/cli.d.ts +0 -14
- package/dist/cli.js +0 -32
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
Historical entries before this file was introduced were reconstructed from npm
|
|
9
|
+
publish metadata and local git history. Older entries are intentionally
|
|
10
|
+
conservative.
|
|
11
|
+
|
|
12
|
+
## [Unreleased]
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Added `createCommand` as a semantic command mechanics facade.
|
|
17
|
+
- Added `createCommands` as a high-level command mechanics facade.
|
|
18
|
+
- Added `createPresentation` and `PresentationResult` for terminal view-model rendering.
|
|
19
|
+
- Added semantic `Presentation` view factory methods such as `presentation.records(...)`.
|
|
20
|
+
- Added `createOutput` as a stdout/stderr output boundary facade.
|
|
21
|
+
- Added semantic `Output.write()` and `Output.error()` methods.
|
|
22
|
+
- Added `createTerminalApp` to compose command, presentation, and output mechanics.
|
|
23
|
+
- Added generic terminal presentation renderers for JSON, CSV, and text tables.
|
|
24
|
+
- Added reusable stdout/stderr text writers with backpressure handling.
|
|
25
|
+
- Added shared `presentationFormatOptions` for common `--format` command options.
|
|
26
|
+
- Added machine-readable `IcoreError` codes and details.
|
|
27
|
+
- Added `parseOptionsSubsetDetailed` for validating known option subsets while preserving unknown raw options.
|
|
28
|
+
- Added opt-in `strict: true` command resolution for rejecting options before command paths.
|
|
29
|
+
- Added `strict: true` support to direct `runCommand` execution.
|
|
30
|
+
- Added typed prepared command `payload` returned from `prepare` and passed to `handle`.
|
|
31
|
+
- Added public `CommandPayload`, `CommandContext`, and `CommandResult` helper types.
|
|
32
|
+
- Added `isPreparedCommandName` for narrowing prepared command unions by name.
|
|
33
|
+
- Added this changelog.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Changed `PreparedCommand` typing to preserve payload correlation when narrowing registry unions by command name.
|
|
38
|
+
- Changed output writers to await promise-returning custom sinks.
|
|
39
|
+
- Reorganized internal source files by CLI framework responsibility without changing the root public API.
|
|
40
|
+
- Split option schema contracts from option value parsing internals.
|
|
41
|
+
- Changed npm package contents to include `CHANGELOG.md`.
|
|
42
|
+
- Removed the redundant `cli` barrel so `index` is the only package entrypoint.
|
|
43
|
+
|
|
44
|
+
### Removed
|
|
45
|
+
|
|
46
|
+
- Removed explicit boolean values such as `--flag=true` and `--flag=false`; use `--flag` and `--no-flag`.
|
|
47
|
+
|
|
48
|
+
## [1.0.12] - 2026-07-02
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Replaced the preliminary flag-only boolean option naming with `syntax: 'flag'`.
|
|
53
|
+
- Documented flag-only boolean option behavior.
|
|
54
|
+
|
|
55
|
+
## [1.0.11] - 2026-07-02
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- Added preliminary flag-only boolean option support.
|
|
60
|
+
|
|
61
|
+
## [1.0.10] - 2026-07-02
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
|
|
65
|
+
- Added two-phase command execution.
|
|
66
|
+
- Added `PreparedCommandInput`.
|
|
67
|
+
- Added `PreparedCommand`.
|
|
68
|
+
- Added `prepareCommandFromArgs`.
|
|
69
|
+
- Added `runPreparedCommand`.
|
|
70
|
+
- Added command `metadata`.
|
|
71
|
+
- Added command `prepare` hook.
|
|
72
|
+
- Added focused tests for prepare-time validation and handler safety.
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
|
|
76
|
+
- Changed `runCommand` and `runCommandFromRegistry` to use the prepare-and-run flow internally.
|
|
77
|
+
|
|
78
|
+
## [1.0.9] - 2026-07-02
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
|
|
82
|
+
- Refined npm package metadata.
|
|
83
|
+
- Updated repository metadata for npm.
|
|
84
|
+
- Simplified published package contents.
|
|
85
|
+
|
|
86
|
+
## [1.0.8] - 2026-07-02
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- Updated package author metadata.
|
|
91
|
+
- Normalized README heading structure.
|
|
92
|
+
|
|
93
|
+
## [1.0.7] - 2026-07-02
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
- Renamed README examples from `upper` to `uppercase`.
|
|
98
|
+
- Cleaned duplicated command test coverage without changing public behavior.
|
|
99
|
+
|
|
100
|
+
## [1.0.6] - 2026-07-02
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
- Added explicit long boolean values such as `--flag=true` and `--flag=false`.
|
|
105
|
+
- Added schema-known boolean negation such as `--no-flag`.
|
|
106
|
+
- Added short option aliases such as `-f` and `-n value`.
|
|
107
|
+
- Added alias validation and duplicate detection between short and long option forms.
|
|
108
|
+
- Documented supported option syntax.
|
|
109
|
+
|
|
110
|
+
## [1.0.5] - 2026-07-01
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- Rebuilt README as the main public documentation entry point.
|
|
115
|
+
|
|
116
|
+
### Removed
|
|
117
|
+
|
|
118
|
+
- Removed separate generated reference docs from the published documentation flow.
|
|
119
|
+
|
|
120
|
+
## [1.0.4] - 2026-07-01
|
|
121
|
+
|
|
122
|
+
### Changed
|
|
123
|
+
|
|
124
|
+
- Reorganized README and documentation references.
|
|
125
|
+
|
|
126
|
+
## [1.0.3] - 2026-07-01
|
|
127
|
+
|
|
128
|
+
### Added
|
|
129
|
+
|
|
130
|
+
- Added README table of contents.
|
|
131
|
+
|
|
132
|
+
### Changed
|
|
133
|
+
|
|
134
|
+
- Polished README formatting and emphasis.
|
|
135
|
+
|
|
136
|
+
## [1.0.2] - 2026-06-30
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
|
|
140
|
+
- Added module boundary comments to production source files.
|
|
141
|
+
|
|
142
|
+
### Changed
|
|
143
|
+
|
|
144
|
+
- Clarified CLI scope and supported syntax in README.
|
|
145
|
+
- Updated package description and keywords.
|
|
146
|
+
|
|
147
|
+
## [1.0.1] - 2026-06-30
|
|
148
|
+
|
|
149
|
+
### Changed
|
|
150
|
+
|
|
151
|
+
- Published documentation updates after the first stable release.
|
|
152
|
+
- No dedicated version commit is present in local git history for this patch.
|
|
153
|
+
|
|
154
|
+
## [1.0.0] - 2026-06-30
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
|
|
158
|
+
- First stable release of the new `icore` CLI mechanics package.
|
|
159
|
+
- Added declarative option parsing and validation.
|
|
160
|
+
- Added schema-aware argv parsing.
|
|
161
|
+
- Added option presence metadata through `parseOptionsDetailed`.
|
|
162
|
+
- Added option schema composition through `mergeOptionsSchema`.
|
|
163
|
+
- Added command registry routing.
|
|
164
|
+
- Added typed command handler input.
|
|
165
|
+
- Added CommonJS package entry points and TypeScript declarations.
|
|
166
|
+
|
|
167
|
+
### Changed
|
|
168
|
+
|
|
169
|
+
- Lowered the runtime Node.js engine to `>=16.9.0`.
|
|
170
|
+
|
|
171
|
+
## [1.0.0-alpha] - 2026-06-28
|
|
172
|
+
|
|
173
|
+
### Added
|
|
174
|
+
|
|
175
|
+
- Started the new CLI mechanics codebase after pruning the legacy package code.
|
|
176
|
+
- Added the initial TypeScript build, test, and lint setup for the new package.
|
|
177
|
+
|
|
178
|
+
## [0.1.38] - 2019-06-12
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
|
|
182
|
+
- Added legacy tests and documentation.
|
|
183
|
+
|
|
184
|
+
### Changed
|
|
185
|
+
|
|
186
|
+
- Final legacy web-framework line release.
|
|
187
|
+
- Updated the legacy package description.
|
|
188
|
+
|
|
189
|
+
### Removed
|
|
190
|
+
|
|
191
|
+
- Trimmed legacy runtime dependencies.
|
|
192
|
+
|
|
193
|
+
## [0.0.37 and earlier]
|
|
194
|
+
|
|
195
|
+
### Added
|
|
196
|
+
|
|
197
|
+
- Original legacy npm package line published between 2017 and 2019.
|
|
198
|
+
- Legacy history is preserved for package provenance.
|
|
199
|
+
|
|
200
|
+
### Changed
|
|
201
|
+
|
|
202
|
+
- Detailed changelog entries were not maintained for these releases.
|
|
203
|
+
|
|
204
|
+
[Unreleased]: https://github.com/woodger/icore/commits/develop
|
|
205
|
+
[1.0.12]: https://www.npmjs.com/package/icore/v/1.0.12
|
|
206
|
+
[1.0.11]: https://www.npmjs.com/package/icore/v/1.0.11
|
|
207
|
+
[1.0.10]: https://www.npmjs.com/package/icore/v/1.0.10
|
|
208
|
+
[1.0.9]: https://www.npmjs.com/package/icore/v/1.0.9
|
|
209
|
+
[1.0.8]: https://www.npmjs.com/package/icore/v/1.0.8
|
|
210
|
+
[1.0.7]: https://www.npmjs.com/package/icore/v/1.0.7
|
|
211
|
+
[1.0.6]: https://www.npmjs.com/package/icore/v/1.0.6
|
|
212
|
+
[1.0.5]: https://www.npmjs.com/package/icore/v/1.0.5
|
|
213
|
+
[1.0.4]: https://www.npmjs.com/package/icore/v/1.0.4
|
|
214
|
+
[1.0.3]: https://www.npmjs.com/package/icore/v/1.0.3
|
|
215
|
+
[1.0.2]: https://www.npmjs.com/package/icore/v/1.0.2
|
|
216
|
+
[1.0.1]: https://www.npmjs.com/package/icore/v/1.0.1
|
|
217
|
+
[1.0.0]: https://www.npmjs.com/package/icore/v/1.0.0
|
|
218
|
+
[1.0.0-alpha]: https://www.npmjs.com/package/icore/v/1.0.0-alpha
|
|
219
|
+
[0.1.38]: https://www.npmjs.com/package/icore/v/0.1.38
|
|
220
|
+
[0.0.37 and earlier]: https://www.npmjs.com/package/icore?activeTab=versions
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
*
|
|
10
10
|
* This file must not contain typed option validation or command resolution.
|
|
11
11
|
*/
|
|
12
|
-
import type { OptionsSchema, RawOptionValue } from '
|
|
12
|
+
import type { OptionsSchema, RawOptionValue } from '../options/schema';
|
|
13
13
|
/**
|
|
14
14
|
* Parsed CLI arguments split into positional command path segments and raw
|
|
15
15
|
* named options.
|
|
16
16
|
*/
|
|
17
17
|
export type ParsedArgv = {
|
|
18
|
+
/** Non-option tokens. */
|
|
18
19
|
positionals: string[];
|
|
20
|
+
/** Unvalidated option values. */
|
|
19
21
|
options: Record<string, RawOptionValue>;
|
|
20
22
|
};
|
|
21
23
|
/**
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.parseArgv = parseArgv;
|
|
15
|
-
const
|
|
15
|
+
const icore_error_1 = require("../errors/icore-error");
|
|
16
16
|
/**
|
|
17
17
|
* Parses raw CLI arguments into positionals and raw long-option values.
|
|
18
18
|
*/
|
|
@@ -140,24 +140,24 @@ function isShortOptionToken(arg) {
|
|
|
140
140
|
return arg.length === 2 && arg.startsWith('-') && !arg.startsWith('--');
|
|
141
141
|
}
|
|
142
142
|
function createDuplicateArgumentError(name) {
|
|
143
|
-
return new
|
|
143
|
+
return new icore_error_1.IcoreError('DUPLICATE_ARGUMENT', `Unexpected duplicate argument '--${name}'`, {
|
|
144
144
|
argument: `--${name}`,
|
|
145
145
|
option: name
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
function createUnexpectedArgumentError(argument) {
|
|
149
|
-
return new
|
|
149
|
+
return new icore_error_1.IcoreError('UNEXPECTED_ARGUMENT', `Unexpected argument '${argument}'`, {
|
|
150
150
|
argument
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
153
|
function createDuplicateAliasError(alias) {
|
|
154
|
-
return new
|
|
154
|
+
return new icore_error_1.IcoreError('DUPLICATE_ALIAS', `Unexpected duplicate alias '-${alias}'`, {
|
|
155
155
|
alias,
|
|
156
156
|
argument: `-${alias}`
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
159
|
function createInvalidOptionAliasError(name, alias) {
|
|
160
|
-
return new
|
|
160
|
+
return new icore_error_1.IcoreError('INVALID_OPTION_ALIAS', `Expected alias for '--${name}' as single ASCII letter`, {
|
|
161
161
|
argument: `--${name}`,
|
|
162
162
|
option: name,
|
|
163
163
|
alias
|
|
@@ -10,26 +10,32 @@
|
|
|
10
10
|
* This file must not contain raw token parsing, option schema validation,
|
|
11
11
|
* domain behavior, SDK calls, or output formatting.
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import type { InferOptions, InferProvidedOptions, OptionsSchema } from '../options/schema';
|
|
14
14
|
/**
|
|
15
15
|
* Input produced after command path and option validation, before runtime
|
|
16
16
|
* context is attached.
|
|
17
17
|
*/
|
|
18
18
|
export type PreparedCommandInput<TSchema extends OptionsSchema> = {
|
|
19
|
+
/** Parsed option values. */
|
|
19
20
|
options: InferOptions<TSchema>;
|
|
21
|
+
/** Explicit option presence metadata. */
|
|
20
22
|
provided: InferProvidedOptions<TSchema>;
|
|
23
|
+
/** Positionals after the command path. */
|
|
21
24
|
positionals: string[];
|
|
22
25
|
};
|
|
23
26
|
/**
|
|
24
27
|
* Input passed to a command handler after command path and option validation.
|
|
25
28
|
*/
|
|
26
29
|
export type CommandInput<TSchema extends OptionsSchema, TContext, TPayload = void> = PreparedCommandInput<TSchema> & {
|
|
30
|
+
/** Application runtime context. */
|
|
27
31
|
context: TContext;
|
|
28
32
|
} & ([
|
|
29
33
|
TPayload
|
|
30
34
|
] extends [void] ? {
|
|
35
|
+
/** Optional prepared payload. */
|
|
31
36
|
payload?: TPayload;
|
|
32
37
|
} : {
|
|
38
|
+
/** Prepared payload. */
|
|
33
39
|
payload: TPayload;
|
|
34
40
|
});
|
|
35
41
|
/**
|
|
@@ -40,11 +46,17 @@ export type CommandInput<TSchema extends OptionsSchema, TContext, TPayload = voi
|
|
|
40
46
|
* formatting.
|
|
41
47
|
*/
|
|
42
48
|
export type CommandDefinition<TSchema extends OptionsSchema, TContext, TResult, TPath extends readonly [string, ...string[]] = readonly [string, ...string[]], TMetadata = unknown, TPayload = void> = {
|
|
49
|
+
/** Command path segments. */
|
|
43
50
|
path: TPath;
|
|
51
|
+
/** Command option schema. */
|
|
44
52
|
options: TSchema;
|
|
53
|
+
/** Caller-owned static metadata. */
|
|
45
54
|
metadata?: TMetadata;
|
|
55
|
+
/** Allows extra positionals. */
|
|
46
56
|
allowExtraPositionals?: boolean;
|
|
57
|
+
/** Prepares payload before runtime context. */
|
|
47
58
|
prepare?(input: PreparedCommandInput<TSchema>): TPayload | Promise<TPayload>;
|
|
59
|
+
/** Runs application command behavior. */
|
|
48
60
|
handle(input: CommandInput<TSchema, TContext, TPayload>): TResult | Promise<TResult>;
|
|
49
61
|
};
|
|
50
62
|
type AnyCommandInput = PreparedCommandInput<OptionsSchema> & {
|
|
@@ -78,9 +90,18 @@ type CommandDefinitionParts<TCommand extends AnyCommandDefinition> = TCommand ex
|
|
|
78
90
|
metadata: TCommand['metadata'];
|
|
79
91
|
payload: unknown;
|
|
80
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* Infers the runtime context type required by a command.
|
|
95
|
+
*/
|
|
81
96
|
export type CommandContext<TCommand extends AnyCommandDefinition> = CommandDefinitionParts<TCommand>['context'];
|
|
97
|
+
/**
|
|
98
|
+
* Infers the awaited command handler result type.
|
|
99
|
+
*/
|
|
82
100
|
export type CommandResult<TCommand extends AnyCommandDefinition> = Awaited<CommandDefinitionParts<TCommand>['result']>;
|
|
83
101
|
type CommandSchema<TCommand extends AnyCommandDefinition> = CommandDefinitionParts<TCommand>['schema'];
|
|
102
|
+
/**
|
|
103
|
+
* Infers the payload type produced by a command prepare hook.
|
|
104
|
+
*/
|
|
84
105
|
export type CommandPayload<TCommand extends AnyCommandDefinition> = CommandDefinitionParts<TCommand>['payload'];
|
|
85
106
|
/**
|
|
86
107
|
* Infers the public command name from a command path.
|
|
@@ -90,39 +111,77 @@ export type CommandName<TCommand extends AnyCommandDefinition> = CommandPathName
|
|
|
90
111
|
* Declarative command registry used to resolve command paths.
|
|
91
112
|
*/
|
|
92
113
|
export type CommandRegistry<TCommands extends readonly AnyCommandDefinition[]> = {
|
|
114
|
+
/** Registered command definitions. */
|
|
93
115
|
commands: TCommands;
|
|
116
|
+
/** Derived public command names. */
|
|
94
117
|
commandNames: readonly CommandName<TCommands[number]>[];
|
|
95
118
|
};
|
|
119
|
+
/**
|
|
120
|
+
* High-level command mechanics facade for terminal applications.
|
|
121
|
+
*/
|
|
122
|
+
export type Commands<TCommands extends readonly AnyCommandDefinition[]> = {
|
|
123
|
+
/** Original command definitions. */
|
|
124
|
+
definitions: TCommands;
|
|
125
|
+
/** Public command names. */
|
|
126
|
+
names: readonly CommandName<TCommands[number]>[];
|
|
127
|
+
/** Lower-level command registry. */
|
|
128
|
+
registry: CommandRegistry<TCommands>;
|
|
129
|
+
/** Resolves from positionals. */
|
|
130
|
+
resolve(positionals: readonly string[]): ResolvedCommand<TCommands[number]>;
|
|
131
|
+
/** Resolves from raw argv. */
|
|
132
|
+
resolveFromArgs(args: readonly string[]): ResolvedCommand<TCommands[number]>;
|
|
133
|
+
/** Prepares without runtime context. */
|
|
134
|
+
prepare(args: readonly string[], options?: CommandResolutionOptions): Promise<PreparedCommand<TCommands[number]>>;
|
|
135
|
+
/** Runs a prepared command. */
|
|
136
|
+
run(prepared: PreparedCommand<TCommands[number]>, context: CommandContext<TCommands[number]>): Promise<CommandResult<TCommands[number]>>;
|
|
137
|
+
/** Resolves, prepares, and runs. */
|
|
138
|
+
runFromArgs(args: readonly string[], context: CommandContext<TCommands[number]>, options?: CommandResolutionOptions): Promise<CommandResult<TCommands[number]>>;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Semantic facade for command mechanics.
|
|
142
|
+
*/
|
|
143
|
+
export type Command = {
|
|
144
|
+
define: typeof defineCommand;
|
|
145
|
+
registry: typeof createCommands;
|
|
146
|
+
run: typeof runCommand;
|
|
147
|
+
};
|
|
96
148
|
/**
|
|
97
149
|
* Options for command resolution from raw CLI arguments.
|
|
98
150
|
*/
|
|
99
151
|
export type CommandResolutionOptions = {
|
|
100
|
-
/**
|
|
101
|
-
* When enabled, command path must appear before options. Options before the
|
|
102
|
-
* command path are rejected instead of participating in legacy candidate
|
|
103
|
-
* schema parsing.
|
|
104
|
-
*/
|
|
152
|
+
/** Rejects options before command path. */
|
|
105
153
|
strict?: boolean;
|
|
106
154
|
};
|
|
107
155
|
/**
|
|
108
156
|
* Result of resolving a command from user positionals.
|
|
109
157
|
*/
|
|
110
158
|
export type ResolvedCommand<TCommand extends AnyCommandDefinition> = {
|
|
159
|
+
/** Space-joined command name. */
|
|
111
160
|
name: CommandName<TCommand>;
|
|
161
|
+
/** Literal command path. */
|
|
112
162
|
path: TCommand['path'];
|
|
163
|
+
/** Selected command definition. */
|
|
113
164
|
command: TCommand;
|
|
165
|
+
/** Positionals after the command path. */
|
|
114
166
|
positionals: string[];
|
|
115
167
|
};
|
|
116
168
|
/**
|
|
117
169
|
* Command resolved and validated without runtime context.
|
|
118
170
|
*/
|
|
119
171
|
export type PreparedCommand<TCommand extends AnyCommandDefinition> = TCommand extends AnyCommandDefinition ? {
|
|
172
|
+
/** Space-joined command name. */
|
|
120
173
|
name: CommandName<TCommand>;
|
|
174
|
+
/** Literal command path. */
|
|
121
175
|
path: TCommand['path'];
|
|
176
|
+
/** Selected command definition. */
|
|
122
177
|
command: TCommand;
|
|
178
|
+
/** Parsed option values. */
|
|
123
179
|
options: InferOptions<CommandSchema<TCommand>>;
|
|
180
|
+
/** Explicit option presence metadata. */
|
|
124
181
|
provided: InferProvidedOptions<CommandSchema<TCommand>>;
|
|
182
|
+
/** Positionals after the command path. */
|
|
125
183
|
positionals: string[];
|
|
184
|
+
/** Prepared payload. */
|
|
126
185
|
payload: CommandPayload<TCommand>;
|
|
127
186
|
} : never;
|
|
128
187
|
/**
|
|
@@ -133,6 +192,14 @@ export declare function defineCommand<const TSchema extends OptionsSchema, const
|
|
|
133
192
|
* Defines a command registry while preserving literal command path types.
|
|
134
193
|
*/
|
|
135
194
|
export declare function defineCommandRegistry<const TCommands extends readonly AnyCommandDefinition[]>(commands: TCommands): CommandRegistry<TCommands>;
|
|
195
|
+
/**
|
|
196
|
+
* Creates a command mechanics facade from declarative command definitions.
|
|
197
|
+
*/
|
|
198
|
+
export declare function createCommands<const TCommands extends readonly AnyCommandDefinition[]>(definitions: TCommands): Commands<TCommands>;
|
|
199
|
+
/**
|
|
200
|
+
* Creates a semantic command mechanics facade.
|
|
201
|
+
*/
|
|
202
|
+
export declare function createCommand(): Command;
|
|
136
203
|
/**
|
|
137
204
|
* Checks whether a value is a command name registered in the given registry.
|
|
138
205
|
*/
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.defineCommand = defineCommand;
|
|
16
16
|
exports.defineCommandRegistry = defineCommandRegistry;
|
|
17
|
+
exports.createCommands = createCommands;
|
|
18
|
+
exports.createCommand = createCommand;
|
|
17
19
|
exports.isCommandName = isCommandName;
|
|
18
20
|
exports.isPreparedCommandName = isPreparedCommandName;
|
|
19
21
|
exports.resolveCommand = resolveCommand;
|
|
@@ -22,9 +24,9 @@ exports.prepareCommandFromArgs = prepareCommandFromArgs;
|
|
|
22
24
|
exports.runPreparedCommand = runPreparedCommand;
|
|
23
25
|
exports.runCommandFromRegistry = runCommandFromRegistry;
|
|
24
26
|
exports.runCommand = runCommand;
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
27
|
+
const parser_1 = require("../argv/parser");
|
|
28
|
+
const icore_error_1 = require("../errors/icore-error");
|
|
29
|
+
const parser_2 = require("../options/parser");
|
|
28
30
|
/**
|
|
29
31
|
* Defines a command while preserving literal option schema types.
|
|
30
32
|
*/
|
|
@@ -42,6 +44,42 @@ function defineCommandRegistry(commands) {
|
|
|
42
44
|
commandNames: commandNames
|
|
43
45
|
};
|
|
44
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a command mechanics facade from declarative command definitions.
|
|
49
|
+
*/
|
|
50
|
+
function createCommands(definitions) {
|
|
51
|
+
const registry = defineCommandRegistry(definitions);
|
|
52
|
+
return {
|
|
53
|
+
definitions,
|
|
54
|
+
names: registry.commandNames,
|
|
55
|
+
registry,
|
|
56
|
+
resolve(positionals) {
|
|
57
|
+
return resolveCommand(registry, positionals);
|
|
58
|
+
},
|
|
59
|
+
resolveFromArgs(args) {
|
|
60
|
+
return resolveCommandFromArgs(registry, args);
|
|
61
|
+
},
|
|
62
|
+
prepare(args, options) {
|
|
63
|
+
return prepareCommandFromArgs(registry, args, options);
|
|
64
|
+
},
|
|
65
|
+
run(prepared, context) {
|
|
66
|
+
return runPreparedCommand(prepared, context);
|
|
67
|
+
},
|
|
68
|
+
runFromArgs(args, context, options) {
|
|
69
|
+
return runCommandFromRegistry(registry, args, context, options);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a semantic command mechanics facade.
|
|
75
|
+
*/
|
|
76
|
+
function createCommand() {
|
|
77
|
+
return {
|
|
78
|
+
define: defineCommand,
|
|
79
|
+
registry: createCommands,
|
|
80
|
+
run: runCommand
|
|
81
|
+
};
|
|
82
|
+
}
|
|
45
83
|
/**
|
|
46
84
|
* Checks whether a value is a command name registered in the given registry.
|
|
47
85
|
*/
|
|
@@ -72,13 +110,13 @@ function resolveCommand(registry, positionals) {
|
|
|
72
110
|
*/
|
|
73
111
|
function resolveCommandFromArgs(registry, args) {
|
|
74
112
|
for (const command of commandsBySpecificity(registry.commands)) {
|
|
75
|
-
const argv = (0,
|
|
113
|
+
const argv = (0, parser_1.parseArgv)(args, command.options);
|
|
76
114
|
const resolved = resolveCommandCandidate(command, argv.positionals);
|
|
77
115
|
if (resolved !== undefined) {
|
|
78
116
|
return resolved;
|
|
79
117
|
}
|
|
80
118
|
}
|
|
81
|
-
throw createUnknownCommandError((0,
|
|
119
|
+
throw createUnknownCommandError((0, parser_1.parseArgv)(args).positionals);
|
|
82
120
|
}
|
|
83
121
|
/**
|
|
84
122
|
* Resolves and validates a command without requiring runtime context.
|
|
@@ -88,13 +126,13 @@ async function prepareCommandFromArgs(registry, args, options = {}) {
|
|
|
88
126
|
return prepareCommandFromArgsStrict(registry, args);
|
|
89
127
|
}
|
|
90
128
|
for (const command of commandsBySpecificity(registry.commands)) {
|
|
91
|
-
const argv = (0,
|
|
129
|
+
const argv = (0, parser_1.parseArgv)(args, command.options);
|
|
92
130
|
const resolved = resolveCommandCandidate(command, argv.positionals);
|
|
93
131
|
if (resolved !== undefined) {
|
|
94
132
|
return prepareResolvedCommand(resolved, argv.options);
|
|
95
133
|
}
|
|
96
134
|
}
|
|
97
|
-
throw createUnknownCommandError((0,
|
|
135
|
+
throw createUnknownCommandError((0, parser_1.parseArgv)(args).positionals);
|
|
98
136
|
}
|
|
99
137
|
/**
|
|
100
138
|
* Runs a prepared command with caller-provided runtime context.
|
|
@@ -128,7 +166,7 @@ async function prepareCommand(command, args, options = {}) {
|
|
|
128
166
|
if (options.strict === true) {
|
|
129
167
|
assertNoOptionBeforeCommand(args);
|
|
130
168
|
}
|
|
131
|
-
const argv = (0,
|
|
169
|
+
const argv = (0, parser_1.parseArgv)(args, command.options);
|
|
132
170
|
const extraPositionals = resolveCommandPositionals(command.path, argv.positionals);
|
|
133
171
|
const resolved = {
|
|
134
172
|
name: commandPathToName(command.path),
|
|
@@ -143,7 +181,7 @@ async function prepareCommandFromArgsStrict(registry, args) {
|
|
|
143
181
|
if (command === undefined) {
|
|
144
182
|
throw createUnknownCommandError(commandPositionalsBeforeOptions(args));
|
|
145
183
|
}
|
|
146
|
-
const argv = (0,
|
|
184
|
+
const argv = (0, parser_1.parseArgv)(args, command.options);
|
|
147
185
|
const resolved = resolveCommandCandidate(command, argv.positionals);
|
|
148
186
|
if (resolved === undefined) {
|
|
149
187
|
throw createUnknownCommandError(argv.positionals);
|
|
@@ -154,13 +192,13 @@ async function prepareResolvedCommand(resolved, rawOptions) {
|
|
|
154
192
|
const { command } = resolved;
|
|
155
193
|
if (resolved.positionals.length > 0 && command.allowExtraPositionals !== true) {
|
|
156
194
|
const positional = resolved.positionals[0] ?? '';
|
|
157
|
-
throw new
|
|
195
|
+
throw new icore_error_1.IcoreError('UNEXPECTED_POSITIONAL', `Unexpected positional argument for '${command.path.join(' ')}': ${positional}`, {
|
|
158
196
|
command: command.path.join(' '),
|
|
159
197
|
positional,
|
|
160
198
|
positionals: [...resolved.positionals]
|
|
161
199
|
});
|
|
162
200
|
}
|
|
163
|
-
const parsed = (0,
|
|
201
|
+
const parsed = (0, parser_2.parseOptionsDetailed)(command.options, rawOptions);
|
|
164
202
|
const input = {
|
|
165
203
|
options: parsed.options,
|
|
166
204
|
provided: parsed.provided,
|
|
@@ -181,7 +219,7 @@ function resolveCommandPositionals(path, positionals) {
|
|
|
181
219
|
for (let index = 0; index < path.length; index += 1) {
|
|
182
220
|
if (positionals[index] !== path[index]) {
|
|
183
221
|
const command = path.join(' ');
|
|
184
|
-
throw new
|
|
222
|
+
throw new icore_error_1.IcoreError('UNKNOWN_COMMAND', `Expected command '${command}'`, {
|
|
185
223
|
command,
|
|
186
224
|
path: [...path],
|
|
187
225
|
positionals: [...positionals]
|
|
@@ -266,18 +304,18 @@ function isOptionBeforeCommand(arg) {
|
|
|
266
304
|
}
|
|
267
305
|
function createUnknownCommandError(positionals) {
|
|
268
306
|
const command = formatCommandPositionals(positionals);
|
|
269
|
-
return new
|
|
307
|
+
return new icore_error_1.IcoreError('UNKNOWN_COMMAND', `Unknown command: ${command}`, {
|
|
270
308
|
command,
|
|
271
309
|
positionals: [...positionals]
|
|
272
310
|
});
|
|
273
311
|
}
|
|
274
312
|
function createUnexpectedArgumentError(argument) {
|
|
275
|
-
return new
|
|
313
|
+
return new icore_error_1.IcoreError('UNEXPECTED_ARGUMENT', `Unexpected argument '${argument}'`, {
|
|
276
314
|
argument
|
|
277
315
|
});
|
|
278
316
|
}
|
|
279
317
|
function createDuplicateCommandError(command) {
|
|
280
|
-
return new
|
|
318
|
+
return new icore_error_1.IcoreError('DUPLICATE_COMMAND', `Unexpected duplicate command '${command}'`, {
|
|
281
319
|
command
|
|
282
320
|
});
|
|
283
321
|
}
|
|
@@ -21,7 +21,9 @@ export type IcoreErrorDetails = Readonly<Record<string, unknown>>;
|
|
|
21
21
|
* resolution, and schema configuration failures.
|
|
22
22
|
*/
|
|
23
23
|
export declare class IcoreError extends Error {
|
|
24
|
+
/** Stable machine-readable code. */
|
|
24
25
|
readonly code: IcoreErrorCode;
|
|
26
|
+
/** Structured error context. */
|
|
25
27
|
readonly details: IcoreErrorDetails;
|
|
26
28
|
constructor(code: IcoreErrorCode, message: string, details?: IcoreErrorDetails);
|
|
27
29
|
}
|
|
@@ -16,7 +16,9 @@ exports.IcoreError = void 0;
|
|
|
16
16
|
* resolution, and schema configuration failures.
|
|
17
17
|
*/
|
|
18
18
|
class IcoreError extends Error {
|
|
19
|
+
/** Stable machine-readable code. */
|
|
19
20
|
code;
|
|
21
|
+
/** Structured error context. */
|
|
20
22
|
details;
|
|
21
23
|
constructor(code, message, details = {}) {
|
|
22
24
|
super(message);
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The package entrypoint exposes the supported command mechanics API.
|
|
3
|
+
*
|
|
4
|
+
* Allowed here:
|
|
5
|
+
* - re-exporting public argv parser contracts;
|
|
6
|
+
* - re-exporting public option schema contracts;
|
|
7
|
+
* - re-exporting public command registry contracts;
|
|
8
|
+
* - re-exporting public presentation and output contracts;
|
|
9
|
+
* - re-exporting public terminal app composition contracts;
|
|
10
|
+
*
|
|
11
|
+
* This file must not contain parser, validator, or command runtime logic.
|
|
12
|
+
*/
|
|
13
|
+
export { parseArgv, type ParsedArgv } from './argv/parser';
|
|
14
|
+
export { createCommand, createCommands, defineCommand, defineCommandRegistry, isCommandName, isPreparedCommandName, prepareCommandFromArgs, resolveCommand, resolveCommandFromArgs, runCommand, runPreparedCommand, runCommandFromRegistry, type Command, type CommandDefinition, type CommandContext, type CommandInput, type CommandName, type CommandPayload, type CommandRegistry, type CommandResolutionOptions, type CommandResult, type Commands, type PreparedCommand, type PreparedCommandInput, type ResolvedCommand } from './command/mechanics';
|
|
15
|
+
export { IcoreError, type IcoreErrorCode, type IcoreErrorDetails } from './errors/icore-error';
|
|
16
|
+
export { parseOptions, parseOptionsDetailed, parseOptionsSubsetDetailed, type ParseOptionsResult, type ParseOptionsSubsetResult } from './options/parser';
|
|
17
|
+
export { mergeOptionsSchema, type BooleanOption, type InferOptions, type InferProvidedOptions, type MergeOptionsSchemas, type NumberOption, type OptionDefinition, type OptionsSchema, type RawOptionValue, type StringOption } from './options/schema';
|
|
18
|
+
export { createPresentation, type Presentation, type PresentationRenderers } from './presentation/facade';
|
|
19
|
+
export { isPresentationFormat, presentationFormatOptions, presentationFormats, type PresentationFormat } from './presentation/format-options';
|
|
20
|
+
export { renderCsv, renderCsvRow } from './presentation/renderers/csv';
|
|
21
|
+
export { renderJson } from './presentation/renderers/json';
|
|
22
|
+
export { renderTextTable } from './presentation/renderers/table';
|
|
23
|
+
export { isPresentationResult, renderPresentationResult } from './presentation/result-renderer';
|
|
24
|
+
export { type CsvCell, type CsvRow, type CsvPresentationView, type EmptyPresentationView, type PresentationRecord, type PresentationResult, type PresentationView, type PresentationViewFactory, type RecordPresentationView, type RecordsPresentationView, type TablePresentationView, type TextPresentationView, type TextTableRow } from './presentation/view';
|
|
25
|
+
export { createOutput, type Output, type OutputOptions } from './output/facade';
|
|
26
|
+
export { createStderrWriter, createStdoutWriter } from './output/node-writer';
|
|
27
|
+
export { createBackpressureTextWriter, type BackpressureTextSink, type TextWriter } from './output/text-writer';
|
|
28
|
+
export { createTerminalApp, type TerminalApp, type TerminalAppOptions, type TerminalCommandOutput } from './terminal/app';
|