@alpacakit/channels 0.1.0-beta.36 → 0.1.0-beta.39
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/README.md +204 -723
- package/dist/binding-compiler.d.ts +12 -2
- package/dist/binding-compiler.d.ts.map +1 -1
- package/dist/binding-compiler.js +25 -0
- package/dist/cli-coercion.d.ts +1 -1
- package/dist/cli-coercion.d.ts.map +1 -1
- package/dist/cli-coercion.js +14 -29
- package/dist/cli-compiler.d.ts +4 -17
- package/dist/cli-compiler.d.ts.map +1 -1
- package/dist/cli-compiler.js +78 -39
- package/dist/cli-help-projection.d.ts.map +1 -1
- package/dist/cli-help-projection.js +41 -36
- package/dist/cli-model.d.ts +50 -65
- package/dist/cli-model.d.ts.map +1 -1
- package/dist/cli-model.js +26 -34
- package/dist/cli-tree.d.ts +6 -3
- package/dist/cli-tree.d.ts.map +1 -1
- package/dist/cli-tree.js +161 -387
- package/dist/cli.d.ts +1 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -5
- package/dist/codecs.d.ts +20 -18
- package/dist/codecs.d.ts.map +1 -1
- package/dist/codecs.js +21 -31
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +8 -3
- package/dist/definition-error.d.ts +5 -0
- package/dist/definition-error.d.ts.map +1 -0
- package/dist/definition-error.js +8 -0
- package/dist/factory.d.ts +25 -11
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +28 -18
- package/dist/http-compiler.d.ts +15 -0
- package/dist/http-compiler.d.ts.map +1 -0
- package/dist/http-compiler.js +37 -0
- package/dist/http-model.d.ts +42 -0
- package/dist/http-model.d.ts.map +1 -0
- package/dist/http-model.js +20 -0
- package/dist/http-tree.d.ts +7 -0
- package/dist/http-tree.d.ts.map +1 -0
- package/dist/http-tree.js +181 -0
- package/dist/http.d.ts +3 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +2 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/input-compiler.d.ts +13 -0
- package/dist/input-compiler.d.ts.map +1 -0
- package/dist/input-compiler.js +122 -0
- package/dist/introspection.d.ts +1 -1
- package/dist/introspection.d.ts.map +1 -1
- package/dist/introspection.js +30 -16
- package/dist/mcp.d.ts +25 -24
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +87 -65
- package/dist/model.d.ts +44 -42
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +44 -9
- package/dist/owned.d.ts +12 -0
- package/dist/owned.d.ts.map +1 -0
- package/dist/owned.js +61 -0
- package/dist/registration.d.ts +41 -0
- package/dist/registration.d.ts.map +1 -0
- package/dist/registration.js +14 -0
- package/dist/runtime.d.ts +2 -35
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -127
- package/dist/schema.d.ts +11 -8
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +110 -47
- package/dist/string-coercion.d.ts +4 -0
- package/dist/string-coercion.d.ts.map +1 -0
- package/dist/string-coercion.js +24 -0
- package/dist/tree-internal.d.ts +4 -2
- package/dist/tree-internal.d.ts.map +1 -1
- package/dist/tree-internal.js +5 -2
- package/dist/values.d.ts +1 -6
- package/dist/values.d.ts.map +1 -1
- package/dist/values.js +1 -6
- package/examples/README.md +28 -0
- package/examples/book-search.ts +151 -0
- package/examples/greeting.ts +193 -0
- package/package.json +9 -4
- package/dist/cli-application.d.ts +0 -40
- package/dist/cli-application.d.ts.map +0 -1
- package/dist/cli-application.js +0 -90
- package/dist/cli-executor.d.ts +0 -25
- package/dist/cli-executor.d.ts.map +0 -1
- package/dist/cli-executor.js +0 -44
- package/dist/cli-presentation.d.ts +0 -32
- package/dist/cli-presentation.d.ts.map +0 -1
- package/dist/cli-presentation.js +0 -293
- package/dist/cli-result-envelope.d.ts +0 -104
- package/dist/cli-result-envelope.d.ts.map +0 -1
- package/dist/cli-result-envelope.js +0 -137
- package/dist/cli-schema.d.ts +0 -4
- package/dist/cli-schema.d.ts.map +0 -1
- package/dist/cli-schema.js +0 -7
package/dist/cli-tree.js
CHANGED
|
@@ -1,423 +1,197 @@
|
|
|
1
1
|
import { coerceCliArgvValue } from "./cli-coercion.js";
|
|
2
|
-
import {
|
|
2
|
+
import { compileCliBinding, projectCliParameters, } from "./cli-compiler.js";
|
|
3
3
|
import { createCliHelpSurface, validateCliCommandHelp, validateCliHelpExamples, } from "./cli-help-projection.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { EntryTreeDefinitionError, findChannelBinding, formatTreePath,
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
optionPrefix: "-",
|
|
13
|
-
positionalSeparator: "--",
|
|
14
|
-
repeatedValueSeparator: ",",
|
|
15
|
-
};
|
|
16
|
-
const CLI_ARGUMENT_TOKEN_KIND = {
|
|
17
|
-
option: "option",
|
|
18
|
-
positionalSeparator: "positional_separator",
|
|
19
|
-
value: "value",
|
|
20
|
-
};
|
|
21
|
-
const CLI_PARSE_RESULT_KIND = {
|
|
22
|
-
parsed: "parsed",
|
|
23
|
-
raw: "raw",
|
|
24
|
-
};
|
|
25
|
-
const CLI_TREE_VALIDATION_ISSUE = {
|
|
26
|
-
subcommandHintWithoutChildren: "CLI subcommand hint requires at least one child command",
|
|
27
|
-
};
|
|
28
|
-
const EMPTY_CLI_GROUP_HELP = {
|
|
4
|
+
import { CLI_ARG_KIND, } from "./cli-model.js";
|
|
5
|
+
import { compileInputPlan } from "./input-compiler.js";
|
|
6
|
+
import { ownedArray, ownedRecord } from "./owned.js";
|
|
7
|
+
import { packRegistrationCollection, } from "./registration.js";
|
|
8
|
+
import { EntryTreeDefinitionError, findChannelBinding, formatTreePath, isEntryTreeDefinition, validateEntryTreeStructure, } from "./schema.js";
|
|
9
|
+
import { isChannelPayload, PAYLOAD_KIND } from "./tree-internal.js";
|
|
10
|
+
import { CHANNEL } from "./values.js";
|
|
11
|
+
const EMPTY_CLI_GROUP_HELP = ownedRecord({
|
|
29
12
|
subcommandHint: null,
|
|
30
|
-
examples: [],
|
|
31
|
-
};
|
|
32
|
-
export function
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
function listCliEndpointLocations(root) {
|
|
43
|
-
const locations = [];
|
|
44
|
-
const visited = new Set();
|
|
45
|
-
const pending = [root];
|
|
46
|
-
while (pending.length > 0) {
|
|
47
|
-
const node = pending.pop();
|
|
48
|
-
if (!node || visited.has(node)) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
visited.add(node);
|
|
52
|
-
if (node.endpoint !== null) {
|
|
53
|
-
locations.push({
|
|
54
|
-
endpoint: node.endpoint.endpoint,
|
|
55
|
-
path: node.path.slice(1),
|
|
56
|
-
binding: node.endpoint.binding,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
pending.push(...node.childByToken.values());
|
|
60
|
-
}
|
|
61
|
-
return locations;
|
|
62
|
-
}
|
|
63
|
-
function compileCliTree(tree) {
|
|
64
|
-
const issues = [...validateEntryTreeStructure(tree)];
|
|
65
|
-
const nodeRecords = new Map();
|
|
66
|
-
const nodeQueue = [{ node: tree.root, parentPath: [], root: true }];
|
|
67
|
-
for (const current of nodeQueue) {
|
|
68
|
-
const segment = cliSegmentFor(current.node, current.parentPath, current.root, issues);
|
|
69
|
-
const path = current.root
|
|
70
|
-
? [current.node.name]
|
|
71
|
-
: [...current.parentPath, segment.token];
|
|
72
|
-
nodeRecords.set(current.node, {
|
|
73
|
-
path,
|
|
74
|
-
segment,
|
|
75
|
-
endpoint: cliEndpointFor(current.node, path, issues),
|
|
76
|
-
});
|
|
77
|
-
nodeQueue.push(...current.node.children.map((node) => ({
|
|
78
|
-
node,
|
|
79
|
-
parentPath: path,
|
|
80
|
-
root: false,
|
|
81
|
-
})));
|
|
82
|
-
}
|
|
83
|
-
const publicNodes = new Map();
|
|
84
|
-
const pending = [];
|
|
85
|
-
visitEntryTree(tree, {
|
|
86
|
-
visitNode(node) {
|
|
87
|
-
pending.push(node);
|
|
88
|
-
},
|
|
89
|
-
visitEndpoint() { },
|
|
90
|
-
});
|
|
91
|
-
for (let index = pending.length - 1; index >= 0; index -= 1) {
|
|
92
|
-
const node = pending[index];
|
|
93
|
-
if (!node) {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
const record = nodeRecords.get(node);
|
|
97
|
-
if (!record) {
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
const children = node.children.flatMap((child) => {
|
|
101
|
-
const compiled = publicNodes.get(child);
|
|
102
|
-
return compiled ? [compiled] : [];
|
|
103
|
-
});
|
|
104
|
-
if (record.segment.help.subcommandHint !== null && children.length === 0) {
|
|
105
|
-
issues.push(`${formatTreePath(record.path)}: ${CLI_TREE_VALIDATION_ISSUE.subcommandHintWithoutChildren}`);
|
|
106
|
-
}
|
|
107
|
-
if (record.endpoint === null &&
|
|
108
|
-
children.length === 0 &&
|
|
109
|
-
node !== tree.root) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
validateCliChildren(record.path, children, issues);
|
|
113
|
-
if (record.endpoint !== null &&
|
|
114
|
-
record.endpoint.positionals.length > 0 &&
|
|
115
|
-
children.length > 0) {
|
|
116
|
-
issues.push(`${formatTreePath(record.path)}: executable CLI node cannot have both positionals and children`);
|
|
117
|
-
}
|
|
118
|
-
const childByToken = new Map();
|
|
119
|
-
for (const child of children) {
|
|
120
|
-
childByToken.set(child.segment.token, child);
|
|
121
|
-
}
|
|
122
|
-
const compiledNode = {
|
|
123
|
-
path: record.path,
|
|
124
|
-
segment: record.segment,
|
|
125
|
-
endpoint: record.endpoint,
|
|
126
|
-
childByToken,
|
|
127
|
-
help: createCliHelpSurface({
|
|
128
|
-
node,
|
|
129
|
-
segment: record.segment,
|
|
130
|
-
endpoint: record.endpoint,
|
|
131
|
-
childHelp: children.map((child) => child.help),
|
|
132
|
-
root: node === tree.root,
|
|
133
|
-
}),
|
|
134
|
-
};
|
|
135
|
-
publicNodes.set(node, compiledNode);
|
|
136
|
-
}
|
|
13
|
+
examples: ownedArray([]),
|
|
14
|
+
});
|
|
15
|
+
export function collectCliCommands(source) {
|
|
16
|
+
const structuralIssues = validateEntryTreeStructure(source);
|
|
17
|
+
if (structuralIssues.length > 0) {
|
|
18
|
+
throw new EntryTreeDefinitionError(structuralIssues);
|
|
19
|
+
}
|
|
20
|
+
const issues = [];
|
|
21
|
+
const root = isEntryTreeDefinition(source)
|
|
22
|
+
? compileTreeRoot(source.root, issues)
|
|
23
|
+
: compileVirtualRoot(source, issues);
|
|
137
24
|
if (issues.length > 0) {
|
|
138
25
|
throw new EntryTreeDefinitionError(issues);
|
|
139
26
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (!root) {
|
|
163
|
-
validateCliCommandToken(segment.token, path, issues);
|
|
164
|
-
}
|
|
165
|
-
return segment;
|
|
27
|
+
return ownedRecord({ root });
|
|
28
|
+
}
|
|
29
|
+
function compileTreeRoot(root, issues) {
|
|
30
|
+
const segment = cliSegmentFor(root, [], issues);
|
|
31
|
+
return compileNode(root, segment, [], true, issues);
|
|
32
|
+
}
|
|
33
|
+
function compileVirtualRoot(node, issues) {
|
|
34
|
+
const segment = cliSegmentFor(node, [node.name], issues);
|
|
35
|
+
const child = compileNode(node, segment, [segment.token], false, issues);
|
|
36
|
+
const help = emptyVirtualRootHelp(child.help);
|
|
37
|
+
return ownedRecord({
|
|
38
|
+
token: "",
|
|
39
|
+
path: ownedArray([]),
|
|
40
|
+
description: "",
|
|
41
|
+
documentation: ownedRecord({
|
|
42
|
+
remarks: ownedArray([]),
|
|
43
|
+
relatedDocs: ownedArray([]),
|
|
44
|
+
}),
|
|
45
|
+
help,
|
|
46
|
+
commands: packRegistrationCollection([]),
|
|
47
|
+
children: ownedArray([child]),
|
|
48
|
+
});
|
|
166
49
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
50
|
+
function compileNode(node, segment, path, root, issues) {
|
|
51
|
+
const token = segment.token;
|
|
52
|
+
validateCliToken(token, path, issues);
|
|
53
|
+
const compiledEndpoint = cliEndpointFor(node, path, issues);
|
|
54
|
+
const children = node.children.map((child) => {
|
|
55
|
+
const childSegment = cliSegmentFor(child, [...path, child.name], issues);
|
|
56
|
+
return compileNode(child, childSegment, [...path, childSegment.token], false, issues);
|
|
57
|
+
});
|
|
58
|
+
validateChildTokens(path, children, issues);
|
|
59
|
+
if (segment.help.subcommandHint !== null && children.length === 0) {
|
|
60
|
+
issues.push(`${formatTreePath(path)}: CLI subcommand hint requires children`);
|
|
61
|
+
}
|
|
62
|
+
const help = createCliHelpSurface({
|
|
63
|
+
node,
|
|
64
|
+
segment,
|
|
65
|
+
endpoint: compiledEndpoint,
|
|
66
|
+
childHelp: children.map((child) => child.help),
|
|
67
|
+
root,
|
|
68
|
+
});
|
|
69
|
+
const registrations = compiledEndpoint === null
|
|
70
|
+
? []
|
|
71
|
+
: [createCliRegistration(compiledEndpoint, path)];
|
|
72
|
+
return ownedRecord({
|
|
73
|
+
token,
|
|
74
|
+
path: ownedArray(path),
|
|
75
|
+
description: node.description,
|
|
76
|
+
documentation: node.documentation,
|
|
77
|
+
help,
|
|
78
|
+
commands: packRegistrationCollection(registrations),
|
|
79
|
+
children: ownedArray(children),
|
|
80
|
+
});
|
|
175
81
|
}
|
|
176
82
|
function cliEndpointFor(node, path, issues) {
|
|
177
|
-
const endpoints =
|
|
83
|
+
const endpoints = [
|
|
84
|
+
...new Set(node.endpoints.filter((endpoint) => endpoint.channels.some((binding) => binding.channel === CHANNEL.cli))),
|
|
85
|
+
];
|
|
86
|
+
const location = formatTreePath(path);
|
|
178
87
|
if (endpoints.length > 1) {
|
|
179
|
-
issues.push(`${
|
|
88
|
+
issues.push(`${location}: different CLI endpoints occupy the same path`);
|
|
180
89
|
}
|
|
181
90
|
const endpoint = endpoints[0];
|
|
182
|
-
if (
|
|
91
|
+
if (endpoint === undefined) {
|
|
183
92
|
return null;
|
|
184
93
|
}
|
|
185
94
|
const channelBinding = findChannelBinding(endpoint, CHANNEL.cli);
|
|
186
|
-
if (
|
|
187
|
-
issues.push(`${
|
|
95
|
+
if (channelBinding === null || !isCliChannelBinding(channelBinding)) {
|
|
96
|
+
issues.push(`${location}: invalid CLI endpoint binding`);
|
|
188
97
|
return null;
|
|
189
98
|
}
|
|
190
|
-
const
|
|
191
|
-
const compiled = compileCliBinding(endpoint, channelBinding.binding, location, issues);
|
|
99
|
+
const compiled = compileCliBinding(endpoint, channelBinding.binding, `${location}#${endpoint.entry.name}`, issues);
|
|
192
100
|
validateCliCommandHelp(compiled, location, issues);
|
|
193
101
|
return compiled;
|
|
194
102
|
}
|
|
195
|
-
function
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
function resolveCli(root, argv) {
|
|
209
|
-
let node = root;
|
|
210
|
-
let index = 0;
|
|
211
|
-
while (index < argv.length) {
|
|
212
|
-
const token = argv[index];
|
|
213
|
-
if (token === undefined) {
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
if (classifyCliArgumentToken(token) !== CLI_ARGUMENT_TOKEN_KIND.value) {
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
const child = node.childByToken.get(token);
|
|
220
|
-
if (!child) {
|
|
221
|
-
break;
|
|
103
|
+
function createCliRegistration(compiled, path) {
|
|
104
|
+
const input = compileInputPlan({
|
|
105
|
+
entry: compiled.endpoint.entry,
|
|
106
|
+
bindings: compiled.parameterBindings,
|
|
107
|
+
});
|
|
108
|
+
const rows = new Map(compiled.binding.parameters.map((row) => [row.parameterName, row]));
|
|
109
|
+
const parseOptions = (raw) => input.parseCoerced(raw, (parameter, value) => {
|
|
110
|
+
const row = rows.get(parameter.name);
|
|
111
|
+
if (row === undefined) {
|
|
112
|
+
throw new Error(`Missing compiled CLI binding for ${parameter.name}`);
|
|
222
113
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
path: node.path,
|
|
243
|
-
token: unmatchedToken,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
const compiledEndpoint = node.endpoint;
|
|
247
|
-
const rawResult = parseCliArguments(compiledEndpoint, argv.slice(index));
|
|
248
|
-
switch (rawResult.kind) {
|
|
249
|
-
case CLI_ROUTER_RESULT_KIND.invalidInput:
|
|
250
|
-
case CLI_ROUTER_RESULT_KIND.invalidParameter:
|
|
251
|
-
return { ...rawResult, path: node.path };
|
|
252
|
-
case CLI_PARSE_RESULT_KIND.raw:
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
const endpoint = compiledEndpoint.endpoint;
|
|
256
|
-
const decoded = decodeEntryInput({
|
|
257
|
-
entry: endpoint.entry,
|
|
258
|
-
parameterNames: endpoint.entry.parameters.map((parameter) => parameter.name),
|
|
259
|
-
raw: rawResult.raw,
|
|
260
|
-
coerce: (parameter, rawValue) => coerceCliArgvValue(parameter.codec.shape, rawValue, cliCoercionFor(compiledEndpoint, parameter.name)),
|
|
114
|
+
return coerceCliValue(parameter, row, value);
|
|
115
|
+
});
|
|
116
|
+
const channelBinding = findChannelBinding(compiled.endpoint, CHANNEL.cli);
|
|
117
|
+
if (channelBinding === null) {
|
|
118
|
+
throw new Error("Compiled CLI endpoint lost its binding");
|
|
119
|
+
}
|
|
120
|
+
return ownedRecord({
|
|
121
|
+
endpoint: compiled.endpoint,
|
|
122
|
+
entry: compiled.endpoint.entry,
|
|
123
|
+
binding: channelBinding,
|
|
124
|
+
path: ownedArray(path),
|
|
125
|
+
parameters: projectCliParameters(compiled),
|
|
126
|
+
input: ownedRecord({
|
|
127
|
+
schema: input.schema,
|
|
128
|
+
parse: input.parse,
|
|
129
|
+
project: input.project,
|
|
130
|
+
parseOptions,
|
|
131
|
+
}),
|
|
132
|
+
handler: compiled.endpoint.handler,
|
|
261
133
|
});
|
|
262
|
-
switch (decoded.kind) {
|
|
263
|
-
case ENTRY_DECODE_RESULT_KIND.resolved:
|
|
264
|
-
return {
|
|
265
|
-
kind: CLI_ROUTER_RESULT_KIND.resolved,
|
|
266
|
-
path: node.path,
|
|
267
|
-
endpoint,
|
|
268
|
-
projection: decoded.projection,
|
|
269
|
-
};
|
|
270
|
-
case ENTRY_DECODE_RESULT_KIND.invalidInput:
|
|
271
|
-
return {
|
|
272
|
-
kind: CLI_ROUTER_RESULT_KIND.invalidInput,
|
|
273
|
-
path: node.path,
|
|
274
|
-
issues: decoded.issues,
|
|
275
|
-
};
|
|
276
|
-
case ENTRY_DECODE_RESULT_KIND.invalidParameter:
|
|
277
|
-
return {
|
|
278
|
-
kind: CLI_ROUTER_RESULT_KIND.invalidParameter,
|
|
279
|
-
path: node.path,
|
|
280
|
-
parameterName: decoded.parameterName,
|
|
281
|
-
issues: decoded.issues,
|
|
282
|
-
};
|
|
283
|
-
case ENTRY_DECODE_RESULT_KIND.internalError:
|
|
284
|
-
return {
|
|
285
|
-
kind: CLI_ROUTER_RESULT_KIND.internalError,
|
|
286
|
-
path: node.path,
|
|
287
|
-
error: decoded.error,
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
134
|
}
|
|
291
|
-
function
|
|
292
|
-
|
|
135
|
+
function coerceCliValue(parameter, row, raw) {
|
|
136
|
+
const expanded = row.kind === CLI_ARG_KIND.option && row.repeatable && row.coercion === null
|
|
137
|
+
? expandCommaSeparated(raw)
|
|
138
|
+
: raw;
|
|
139
|
+
return coerceCliArgvValue(parameter.name, parameter.codec.shape, expanded, row.coercion);
|
|
293
140
|
}
|
|
294
|
-
function
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
let positionalOnly = false;
|
|
298
|
-
for (let index = 0; index < argv.length; index += 1) {
|
|
299
|
-
const token = argv[index];
|
|
300
|
-
if (token === undefined) {
|
|
301
|
-
continue;
|
|
302
|
-
}
|
|
303
|
-
if (!positionalOnly) {
|
|
304
|
-
switch (classifyCliArgumentToken(token)) {
|
|
305
|
-
case CLI_ARGUMENT_TOKEN_KIND.positionalSeparator:
|
|
306
|
-
positionalOnly = true;
|
|
307
|
-
continue;
|
|
308
|
-
case CLI_ARGUMENT_TOKEN_KIND.option: {
|
|
309
|
-
const parsed = parseCliOption({ endpoint, argv, index, raw });
|
|
310
|
-
switch (parsed.kind) {
|
|
311
|
-
case CLI_ROUTER_RESULT_KIND.invalidInput:
|
|
312
|
-
case CLI_ROUTER_RESULT_KIND.invalidParameter:
|
|
313
|
-
return parsed;
|
|
314
|
-
case CLI_PARSE_RESULT_KIND.parsed:
|
|
315
|
-
if (parsed.consumedNext) {
|
|
316
|
-
index += 1;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
case CLI_ARGUMENT_TOKEN_KIND.value:
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
positionalValues.push(token);
|
|
326
|
-
}
|
|
327
|
-
return bindCliPositionals(endpoint, positionalValues, raw);
|
|
141
|
+
function expandCommaSeparated(raw) {
|
|
142
|
+
const values = Array.isArray(raw) ? raw : [raw];
|
|
143
|
+
return values.flatMap((value) => typeof value === "string" ? value.split(",") : [value]);
|
|
328
144
|
}
|
|
329
|
-
function
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
if (!action) {
|
|
334
|
-
return invalidCliInput(`Unknown option ${flag}`);
|
|
335
|
-
}
|
|
336
|
-
if (action.kind === CLI_OPTION_ACTION_KIND.setBoolean) {
|
|
337
|
-
return setCliBooleanValue(input.raw, action, flag, inlineValue);
|
|
145
|
+
function cliSegmentFor(node, path, issues) {
|
|
146
|
+
const override = node.segments.find((row) => row.channel === CHANNEL.cli);
|
|
147
|
+
if (override === undefined) {
|
|
148
|
+
return ownedRecord({ token: node.name, help: EMPTY_CLI_GROUP_HELP });
|
|
338
149
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return invalidCliParameter(option.parameter.name, `${flag} requires a value`);
|
|
150
|
+
if (!isCliSegment(override.segment)) {
|
|
151
|
+
issues.push(`${formatTreePath(path)}: invalid CLI segment override`);
|
|
152
|
+
return ownedRecord({ token: node.name, help: EMPTY_CLI_GROUP_HELP });
|
|
343
153
|
}
|
|
344
|
-
|
|
345
|
-
return
|
|
346
|
-
kind: CLI_PARSE_RESULT_KIND.parsed,
|
|
347
|
-
consumedNext: inlineValue === undefined,
|
|
348
|
-
};
|
|
154
|
+
validateCliHelpExamples(override.segment.help.examples, formatTreePath(path), issues);
|
|
155
|
+
return override.segment;
|
|
349
156
|
}
|
|
350
|
-
function
|
|
351
|
-
if (
|
|
352
|
-
|
|
157
|
+
function validateCliToken(token, path, issues) {
|
|
158
|
+
if (token.length === 0 || /\s/u.test(token)) {
|
|
159
|
+
issues.push(`${formatTreePath(path)}: CLI token must be non-empty and contain no whitespace`);
|
|
353
160
|
}
|
|
354
|
-
raw.set(action.parameterName, action.value);
|
|
355
|
-
return { kind: CLI_PARSE_RESULT_KIND.parsed, consumedNext: false };
|
|
356
161
|
}
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
for (const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
raw.set(positional.parameter.name, values);
|
|
364
|
-
}
|
|
365
|
-
positionalIndex = positionalValues.length;
|
|
162
|
+
function validateChildTokens(path, children, issues) {
|
|
163
|
+
const owners = new Map();
|
|
164
|
+
for (const child of children) {
|
|
165
|
+
const owner = owners.get(child.token);
|
|
166
|
+
if (owner !== undefined) {
|
|
167
|
+
issues.push(`${formatTreePath(path)}: CLI child token ${JSON.stringify(child.token)} collides between ${owner} and ${child.description}`);
|
|
366
168
|
}
|
|
367
169
|
else {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
appendOptionValues(raw, option.parameter.name, [value]);
|
|
387
|
-
return;
|
|
388
|
-
case CLI_OPTION_VALUE_MODE.commaOrRepeat:
|
|
389
|
-
appendOptionValues(raw, option.parameter.name, value.split(CLI_ARGUMENT_SYNTAX.repeatedValueSeparator));
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
function appendOptionValues(raw, parameterName, values) {
|
|
394
|
-
const current = raw.get(parameterName);
|
|
395
|
-
raw.set(parameterName, Array.isArray(current) ? [...current, ...values] : values);
|
|
396
|
-
}
|
|
397
|
-
function splitOptionToken(token) {
|
|
398
|
-
const equalsIndex = token.indexOf(CLI_ARGUMENT_SYNTAX.inlineValueSeparator);
|
|
399
|
-
return equalsIndex < 0
|
|
400
|
-
? [token, undefined]
|
|
401
|
-
: [token.slice(0, equalsIndex), token.slice(equalsIndex + 1)];
|
|
170
|
+
owners.set(child.token, child.description);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function emptyVirtualRootHelp(child) {
|
|
175
|
+
return ownedRecord({
|
|
176
|
+
name: "",
|
|
177
|
+
token: null,
|
|
178
|
+
description: "",
|
|
179
|
+
optionGroups: ownedArray([]),
|
|
180
|
+
positionals: ownedArray([]),
|
|
181
|
+
children: ownedArray([child]),
|
|
182
|
+
remarks: ownedArray([]),
|
|
183
|
+
relatedDocs: ownedArray([]),
|
|
184
|
+
usages: ownedArray(["<command>"]),
|
|
185
|
+
examples: ownedArray([]),
|
|
186
|
+
subcommandHint: null,
|
|
187
|
+
});
|
|
402
188
|
}
|
|
403
|
-
function
|
|
404
|
-
|
|
405
|
-
return CLI_ARGUMENT_TOKEN_KIND.positionalSeparator;
|
|
406
|
-
}
|
|
407
|
-
return token.startsWith(CLI_ARGUMENT_SYNTAX.optionPrefix)
|
|
408
|
-
? CLI_ARGUMENT_TOKEN_KIND.option
|
|
409
|
-
: CLI_ARGUMENT_TOKEN_KIND.value;
|
|
189
|
+
function isCliEntryBinding(value) {
|
|
190
|
+
return isChannelPayload(PAYLOAD_KIND.cliBinding, value);
|
|
410
191
|
}
|
|
411
|
-
function
|
|
412
|
-
return
|
|
413
|
-
kind: CLI_ROUTER_RESULT_KIND.invalidInput,
|
|
414
|
-
issues: [issue],
|
|
415
|
-
};
|
|
192
|
+
function isCliChannelBinding(binding) {
|
|
193
|
+
return binding.channel === CHANNEL.cli && isCliEntryBinding(binding.binding);
|
|
416
194
|
}
|
|
417
|
-
function
|
|
418
|
-
return
|
|
419
|
-
kind: CLI_ROUTER_RESULT_KIND.invalidParameter,
|
|
420
|
-
parameterName,
|
|
421
|
-
issues: [issue],
|
|
422
|
-
};
|
|
195
|
+
function isCliSegment(value) {
|
|
196
|
+
return isChannelPayload(PAYLOAD_KIND.cliSegment, value);
|
|
423
197
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
export * from "./cli-application.js";
|
|
2
|
-
export * from "./cli-executor.js";
|
|
3
1
|
export * from "./cli-model.js";
|
|
4
|
-
export
|
|
5
|
-
export * from "./cli-result-envelope.js";
|
|
6
|
-
export { createCliRouter } from "./cli-tree.js";
|
|
2
|
+
export { collectCliCommands } from "./cli-tree.js";
|
|
7
3
|
export { CLI_BOOLEAN_MODE, CLI_HELP_USAGE_KIND, CLI_OPTION_KIND, CLI_OPTION_VALUE_MODE, } from "./cli-values.js";
|
|
8
4
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
export * from "./cli-application.js";
|
|
2
|
-
export * from "./cli-executor.js";
|
|
3
1
|
export * from "./cli-model.js";
|
|
4
|
-
export
|
|
5
|
-
export * from "./cli-result-envelope.js";
|
|
6
|
-
export { createCliRouter } from "./cli-tree.js";
|
|
2
|
+
export { collectCliCommands } from "./cli-tree.js";
|
|
7
3
|
export { CLI_BOOLEAN_MODE, CLI_HELP_USAGE_KIND, CLI_OPTION_KIND, CLI_OPTION_VALUE_MODE, } from "./cli-values.js";
|
package/dist/codecs.d.ts
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
|
+
import type { JsonValue } from "@alpacakit/core";
|
|
1
2
|
import { z } from "zod";
|
|
2
|
-
import type { ValueCodec,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
readonly
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
declare function
|
|
3
|
+
import type { ValueCodec, ValueShapeFor } from "./model.js";
|
|
4
|
+
type JsonInput<Raw> = Raw extends JsonValue ? Raw : JsonValue;
|
|
5
|
+
declare function defineValueCodec<Raw, Value extends JsonValue>(input: {
|
|
6
|
+
readonly schema: z.ZodType<Value, Raw>;
|
|
7
|
+
readonly shape: ValueShapeFor<JsonInput<Raw>>;
|
|
8
|
+
}): ValueCodec<Raw, Value>;
|
|
9
|
+
declare function stringCodec(): ValueCodec<string, string>;
|
|
10
|
+
declare function booleanCodec(): ValueCodec<boolean, boolean>;
|
|
9
11
|
declare function positiveIntegerCodec(input?: {
|
|
10
12
|
readonly max: number | null;
|
|
11
|
-
}): ValueCodec<number>;
|
|
12
|
-
declare function stringEnumCodec<const Values extends readonly [string, ...string[]]>(values: Values): ValueCodec<Values[number]>;
|
|
13
|
-
declare function stringEnumListCodec<const Values extends readonly [string, ...string[]]>(values: Values): ValueCodec<readonly Values[number][]>;
|
|
14
|
-
declare function stringListCodec(): ValueCodec<readonly string[]>;
|
|
13
|
+
}): ValueCodec<number, number>;
|
|
14
|
+
declare function stringEnumCodec<const Values extends readonly [string, ...string[]]>(values: Values): ValueCodec<Values[number], Values[number]>;
|
|
15
|
+
declare function stringEnumListCodec<const Values extends readonly [string, ...string[]]>(values: Values): ValueCodec<readonly Values[number][], readonly Values[number][]>;
|
|
16
|
+
declare function stringListCodec(): ValueCodec<readonly string[], readonly string[]>;
|
|
15
17
|
export declare const codecs: {
|
|
16
|
-
define: typeof defineValueCodec;
|
|
17
|
-
string: typeof stringCodec;
|
|
18
|
-
stringList: typeof stringListCodec;
|
|
19
|
-
boolean: typeof booleanCodec;
|
|
20
|
-
positiveInteger: typeof positiveIntegerCodec;
|
|
21
|
-
stringEnum: typeof stringEnumCodec;
|
|
22
|
-
stringEnumList: typeof stringEnumListCodec;
|
|
18
|
+
readonly define: typeof defineValueCodec;
|
|
19
|
+
readonly string: typeof stringCodec;
|
|
20
|
+
readonly stringList: typeof stringListCodec;
|
|
21
|
+
readonly boolean: typeof booleanCodec;
|
|
22
|
+
readonly positiveInteger: typeof positiveIntegerCodec;
|
|
23
|
+
readonly stringEnum: typeof stringEnumCodec;
|
|
24
|
+
readonly stringEnumList: typeof stringEnumListCodec;
|
|
23
25
|
};
|
|
24
26
|
export {};
|
|
25
27
|
//# sourceMappingURL=codecs.d.ts.map
|