@alpacakit/channels 0.1.0-beta.37 → 0.2.0-beta.2
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 -38
- package/dist/cli-presentation.d.ts.map +0 -1
- package/dist/cli-presentation.js +0 -301
- 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
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Consumer-owned adapters over the implemented public collectors.
|
|
2
|
+
import {
|
|
3
|
+
codecs,
|
|
4
|
+
defineEntry,
|
|
5
|
+
defineEntryEndpoint,
|
|
6
|
+
defineEntryNode,
|
|
7
|
+
defineEntryTree,
|
|
8
|
+
defineParameter,
|
|
9
|
+
EntryInputError,
|
|
10
|
+
optional,
|
|
11
|
+
} from "@alpacakit/channels";
|
|
12
|
+
import { bindCliEntry, collectCliCommands } from "@alpacakit/channels/cli";
|
|
13
|
+
import { bindHttpEntry, collectHttpRoutes } from "@alpacakit/channels/http";
|
|
14
|
+
import { bindMcpEntry, collectMcpTools } from "@alpacakit/channels/mcp";
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
import { Command, CommanderError, Option } from "commander";
|
|
17
|
+
import { Hono } from "hono";
|
|
18
|
+
|
|
19
|
+
export const GreetEntry = defineEntry({
|
|
20
|
+
name: "greet",
|
|
21
|
+
parameters: [
|
|
22
|
+
defineParameter({
|
|
23
|
+
name: "name",
|
|
24
|
+
codec: codecs.string(),
|
|
25
|
+
requirement: optional({ default: "world" }),
|
|
26
|
+
description: "Person to greet",
|
|
27
|
+
}),
|
|
28
|
+
],
|
|
29
|
+
project: ({ values }) => ({ name: values.name }),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export type GreetingContext = {
|
|
33
|
+
readonly greeting: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function greet(
|
|
37
|
+
input: ReturnType<typeof GreetEntry.project>,
|
|
38
|
+
context: GreetingContext,
|
|
39
|
+
) {
|
|
40
|
+
return { message: `${context.greeting}, ${input.name}!` };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const GreetEndpoint = defineEntryEndpoint(GreetEntry, {
|
|
44
|
+
handler: greet,
|
|
45
|
+
channels: [
|
|
46
|
+
bindHttpEntry({ method: "GET" }),
|
|
47
|
+
bindMcpEntry({ name: "greet" }),
|
|
48
|
+
bindCliEntry({
|
|
49
|
+
parameters: [{ kind: "option", parameterName: "name" }],
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const AppTree = defineEntryTree(
|
|
55
|
+
defineEntryNode({
|
|
56
|
+
name: "demo",
|
|
57
|
+
description: "Greeting example",
|
|
58
|
+
children: [
|
|
59
|
+
defineEntryNode({
|
|
60
|
+
name: "greet",
|
|
61
|
+
description: "Greet someone",
|
|
62
|
+
endpoints: [GreetEndpoint],
|
|
63
|
+
}),
|
|
64
|
+
],
|
|
65
|
+
}),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
export function createHttpApp() {
|
|
69
|
+
const app = new Hono();
|
|
70
|
+
collectHttpRoutes(AppTree).forEach((route) => {
|
|
71
|
+
app.on(route.method, route.path, async (context) => {
|
|
72
|
+
const input = route.input.parseQuery(context.req.queries());
|
|
73
|
+
const result = await route.handler(input, { greeting: "Hello" });
|
|
74
|
+
return context.json(result);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
app.onError((error, context) => {
|
|
78
|
+
if (error instanceof EntryInputError) {
|
|
79
|
+
return context.json({ error: "Check your input" }, 400);
|
|
80
|
+
}
|
|
81
|
+
console.error(error);
|
|
82
|
+
return context.json({ error: "Operation failed" }, 500);
|
|
83
|
+
});
|
|
84
|
+
return app;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createMcpServer() {
|
|
88
|
+
const server = new McpServer({ name: "demo", version: "1.0.0" });
|
|
89
|
+
collectMcpTools(AppTree).forEach((tool) => {
|
|
90
|
+
server.registerTool(
|
|
91
|
+
tool.name,
|
|
92
|
+
{ inputSchema: tool.input.schema },
|
|
93
|
+
async (values) => {
|
|
94
|
+
try {
|
|
95
|
+
// The SDK has already validated and transformed these values.
|
|
96
|
+
const input = tool.input.project(values);
|
|
97
|
+
const result = await tool.handler(input, { greeting: "Hello" });
|
|
98
|
+
return { content: [{ type: "text", text: result.message }] };
|
|
99
|
+
} catch (error) {
|
|
100
|
+
const expected = error instanceof EntryInputError;
|
|
101
|
+
if (!expected) {
|
|
102
|
+
console.error(error);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
isError: true,
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: expected ? "Check your input" : "Operation failed",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
return server;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function createCliProgram(
|
|
121
|
+
writeMessage: (message: string) => void = console.log,
|
|
122
|
+
) {
|
|
123
|
+
const view = collectCliCommands(AppTree);
|
|
124
|
+
const program = new Command()
|
|
125
|
+
.name(view.root.token)
|
|
126
|
+
.exitOverride()
|
|
127
|
+
.enablePositionalOptions();
|
|
128
|
+
|
|
129
|
+
function register(node: typeof view.root, command: Command): void {
|
|
130
|
+
command.description(node.description);
|
|
131
|
+
node.commands.forEach((spec) => {
|
|
132
|
+
// This example tree only uses value-taking options.
|
|
133
|
+
const mappings = spec.parameters.map((parameter) => {
|
|
134
|
+
if (parameter.kind !== "option" || parameter.optionKind !== "value") {
|
|
135
|
+
throw new Error("This example only handles value-taking options");
|
|
136
|
+
}
|
|
137
|
+
const option = new Option(
|
|
138
|
+
`${parameter.flags.join(", ")} <${parameter.valueName}>`,
|
|
139
|
+
parameter.description,
|
|
140
|
+
);
|
|
141
|
+
command.addOption(option);
|
|
142
|
+
return {
|
|
143
|
+
name: parameter.parameterName,
|
|
144
|
+
attribute: option.attributeName(),
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
command.action(async () => {
|
|
148
|
+
const raw = Object.fromEntries(
|
|
149
|
+
mappings
|
|
150
|
+
.filter(
|
|
151
|
+
(mapping) =>
|
|
152
|
+
command.getOptionValueSource(mapping.attribute) === "cli",
|
|
153
|
+
)
|
|
154
|
+
.map((mapping) => [
|
|
155
|
+
mapping.name,
|
|
156
|
+
command.getOptionValue(mapping.attribute),
|
|
157
|
+
]),
|
|
158
|
+
);
|
|
159
|
+
const input = spec.input.parseOptions(raw);
|
|
160
|
+
const result = await spec.handler(input, { greeting: "Hello" });
|
|
161
|
+
writeMessage(result.message);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
for (const child of node.children) {
|
|
165
|
+
register(child, command.command(child.token));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
register(view.root, program);
|
|
170
|
+
return program;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export async function runCli(argv: readonly string[]): Promise<void> {
|
|
174
|
+
try {
|
|
175
|
+
await createCliProgram().parseAsync([...argv], { from: "user" });
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (error instanceof CommanderError) {
|
|
178
|
+
process.exitCode = error.exitCode;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (error instanceof EntryInputError) {
|
|
182
|
+
console.error("Check your input");
|
|
183
|
+
process.exitCode = 2;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
console.error(error);
|
|
187
|
+
process.exitCode = 1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// CLI entrypoint: await runCli(process.argv.slice(2));
|
|
192
|
+
// HTTP host: mount createHttpApp() in the existing Hono application.
|
|
193
|
+
// MCP host: await createMcpServer().connect(theChosenTransport);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alpacakit/channels",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Neutral multi-channel entry definitions with CLI and
|
|
3
|
+
"version": "0.2.0-beta.2",
|
|
4
|
+
"description": "Neutral multi-channel entry definitions with CLI, MCP, and HTTP binding adapters.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public",
|
|
@@ -20,16 +20,21 @@
|
|
|
20
20
|
"./mcp": {
|
|
21
21
|
"types": "./dist/mcp.d.ts",
|
|
22
22
|
"import": "./dist/mcp.js"
|
|
23
|
+
},
|
|
24
|
+
"./http": {
|
|
25
|
+
"types": "./dist/http.d.ts",
|
|
26
|
+
"import": "./dist/http.js"
|
|
23
27
|
}
|
|
24
28
|
},
|
|
25
29
|
"types": "./dist/index.d.ts",
|
|
26
30
|
"files": [
|
|
27
31
|
"dist",
|
|
32
|
+
"examples",
|
|
28
33
|
"README*.md",
|
|
29
34
|
"LICENSE"
|
|
30
35
|
],
|
|
31
36
|
"dependencies": {
|
|
32
|
-
"@alpacakit/core": "0.
|
|
37
|
+
"@alpacakit/core": "0.2.0-beta.2"
|
|
33
38
|
},
|
|
34
39
|
"peerDependencies": {
|
|
35
40
|
"zod": "^4.3.6"
|
|
@@ -40,7 +45,7 @@
|
|
|
40
45
|
"zod": "4.3.6"
|
|
41
46
|
},
|
|
42
47
|
"scripts": {
|
|
43
|
-
"build": "tsc -p tsconfig.build.json",
|
|
48
|
+
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
|
|
44
49
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
45
50
|
"test": "vitest run"
|
|
46
51
|
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { CliCommandPath, CliLongOptionFlag, CliOptionFlag } from "./cli-model.js";
|
|
2
|
-
export declare const CLI_HELP_REQUEST_KIND: {
|
|
3
|
-
readonly path: "path";
|
|
4
|
-
};
|
|
5
|
-
export type CliHelpRequest = {
|
|
6
|
-
readonly kind: typeof CLI_HELP_REQUEST_KIND.path;
|
|
7
|
-
readonly path: CliCommandPath;
|
|
8
|
-
readonly all: boolean;
|
|
9
|
-
};
|
|
10
|
-
export type CliHelpRequestDefinition = {
|
|
11
|
-
readonly commandToken: string;
|
|
12
|
-
readonly optionTokens: readonly CliOptionFlag[];
|
|
13
|
-
readonly allToken: CliLongOptionFlag;
|
|
14
|
-
};
|
|
15
|
-
export declare function parseCliHelpRequest(argv: readonly string[], definition: CliHelpRequestDefinition): CliHelpRequest | null;
|
|
16
|
-
export declare const CLI_GLOBAL_OPTION_RESULT_KIND: {
|
|
17
|
-
readonly absent: "absent";
|
|
18
|
-
readonly invalid: "invalid";
|
|
19
|
-
readonly resolved: "resolved";
|
|
20
|
-
};
|
|
21
|
-
export declare const CLI_GLOBAL_OPTION_ISSUE_KIND: {
|
|
22
|
-
readonly duplicate: "duplicate";
|
|
23
|
-
readonly invalidValue: "invalid_value";
|
|
24
|
-
};
|
|
25
|
-
export type CliGlobalValueOptionDefinition<Value extends string = string> = {
|
|
26
|
-
readonly flag: CliLongOptionFlag;
|
|
27
|
-
readonly values: readonly Value[];
|
|
28
|
-
};
|
|
29
|
-
export type CliGlobalValueOptionResult<Value extends string = string> = {
|
|
30
|
-
readonly kind: typeof CLI_GLOBAL_OPTION_RESULT_KIND.absent;
|
|
31
|
-
} | {
|
|
32
|
-
readonly kind: typeof CLI_GLOBAL_OPTION_RESULT_KIND.invalid;
|
|
33
|
-
readonly issue: typeof CLI_GLOBAL_OPTION_ISSUE_KIND.duplicate | typeof CLI_GLOBAL_OPTION_ISSUE_KIND.invalidValue;
|
|
34
|
-
} | {
|
|
35
|
-
readonly kind: typeof CLI_GLOBAL_OPTION_RESULT_KIND.resolved;
|
|
36
|
-
readonly value: Value;
|
|
37
|
-
readonly argv: readonly string[];
|
|
38
|
-
};
|
|
39
|
-
export declare function extractCliGlobalValueOption<Value extends string>(argv: readonly string[], definition: CliGlobalValueOptionDefinition<Value>): CliGlobalValueOptionResult<Value>;
|
|
40
|
-
//# sourceMappingURL=cli-application.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli-application.d.ts","sourceRoot":"","sources":["../src/cli-application.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,aAAa,EACd,MAAM,gBAAgB,CAAC;AAOxB,eAAO,MAAM,qBAAqB;;CAExB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,CAAC,IAAI,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,SAAS,aAAa,EAAE,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;CACtC,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,UAAU,EAAE,wBAAwB,GACnC,cAAc,GAAG,IAAI,CAoBvB;AAiBD,eAAO,MAAM,6BAA6B;;;;CAIhC,CAAC;AAEX,eAAO,MAAM,4BAA4B;;;CAG/B,CAAC;AAEX,MAAM,MAAM,8BAA8B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI;IAC1E,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAChE;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,6BAA6B,CAAC,MAAM,CAAA;CAAE,GAC9D;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,6BAA6B,CAAC,OAAO,CAAC;IAC5D,QAAQ,CAAC,KAAK,EACV,OAAO,4BAA4B,CAAC,SAAS,GAC7C,OAAO,4BAA4B,CAAC,YAAY,CAAC;CACtD,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,6BAA6B,CAAC,QAAQ,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC,CAAC;AAEN,wBAAgB,2BAA2B,CAAC,KAAK,SAAS,MAAM,EAC9D,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,UAAU,EAAE,8BAA8B,CAAC,KAAK,CAAC,GAChD,0BAA0B,CAAC,KAAK,CAAC,CA4CnC"}
|
package/dist/cli-application.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
const CLI_APPLICATION_SYNTAX = {
|
|
2
|
-
optionPrefix: "-",
|
|
3
|
-
positionalSeparator: "--",
|
|
4
|
-
};
|
|
5
|
-
export const CLI_HELP_REQUEST_KIND = {
|
|
6
|
-
path: "path",
|
|
7
|
-
};
|
|
8
|
-
export function parseCliHelpRequest(argv, definition) {
|
|
9
|
-
if (argv.length === 0)
|
|
10
|
-
return pathHelpRequest([], false);
|
|
11
|
-
if (argv[0] === definition.commandToken) {
|
|
12
|
-
const args = argv.slice(1);
|
|
13
|
-
if (args.length === 1 &&
|
|
14
|
-
definition.optionTokens.includes(args[0])) {
|
|
15
|
-
return pathHelpRequest([], false);
|
|
16
|
-
}
|
|
17
|
-
if (args.at(-1) === definition.allToken) {
|
|
18
|
-
return createPathHelpRequest(args.slice(0, -1), true);
|
|
19
|
-
}
|
|
20
|
-
return createPathHelpRequest(args, false);
|
|
21
|
-
}
|
|
22
|
-
const helpToken = argv.at(-1);
|
|
23
|
-
if (!definition.optionTokens.includes(helpToken)) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
return createPathHelpRequest(argv.slice(0, -1), false);
|
|
27
|
-
}
|
|
28
|
-
function createPathHelpRequest(path, all) {
|
|
29
|
-
return path.every((token) => !token.startsWith(CLI_APPLICATION_SYNTAX.optionPrefix))
|
|
30
|
-
? pathHelpRequest(path, all)
|
|
31
|
-
: null;
|
|
32
|
-
}
|
|
33
|
-
function pathHelpRequest(path, all) {
|
|
34
|
-
return { kind: CLI_HELP_REQUEST_KIND.path, path, all };
|
|
35
|
-
}
|
|
36
|
-
export const CLI_GLOBAL_OPTION_RESULT_KIND = {
|
|
37
|
-
absent: "absent",
|
|
38
|
-
invalid: "invalid",
|
|
39
|
-
resolved: "resolved",
|
|
40
|
-
};
|
|
41
|
-
export const CLI_GLOBAL_OPTION_ISSUE_KIND = {
|
|
42
|
-
duplicate: "duplicate",
|
|
43
|
-
invalidValue: "invalid_value",
|
|
44
|
-
};
|
|
45
|
-
export function extractCliGlobalValueOption(argv, definition) {
|
|
46
|
-
const inlinePrefix = `${definition.flag}=`;
|
|
47
|
-
const values = [];
|
|
48
|
-
const normalized = [];
|
|
49
|
-
let optionsEnded = false;
|
|
50
|
-
for (let index = 0; index < argv.length; index += 1) {
|
|
51
|
-
const token = argv[index];
|
|
52
|
-
if (token === CLI_APPLICATION_SYNTAX.positionalSeparator) {
|
|
53
|
-
optionsEnded = true;
|
|
54
|
-
normalized.push(token);
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (!optionsEnded && token === definition.flag) {
|
|
58
|
-
values.push(argv[index + 1] ?? "");
|
|
59
|
-
index += 1;
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
if (!optionsEnded && token?.startsWith(inlinePrefix) === true) {
|
|
63
|
-
values.push(token.slice(inlinePrefix.length));
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (token !== undefined)
|
|
67
|
-
normalized.push(token);
|
|
68
|
-
}
|
|
69
|
-
if (values.length === 0) {
|
|
70
|
-
return { kind: CLI_GLOBAL_OPTION_RESULT_KIND.absent };
|
|
71
|
-
}
|
|
72
|
-
if (values.length > 1) {
|
|
73
|
-
return {
|
|
74
|
-
kind: CLI_GLOBAL_OPTION_RESULT_KIND.invalid,
|
|
75
|
-
issue: CLI_GLOBAL_OPTION_ISSUE_KIND.duplicate,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
const value = values[0];
|
|
79
|
-
if (!definition.values.includes(value)) {
|
|
80
|
-
return {
|
|
81
|
-
kind: CLI_GLOBAL_OPTION_RESULT_KIND.invalid,
|
|
82
|
-
issue: CLI_GLOBAL_OPTION_ISSUE_KIND.invalidValue,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
kind: CLI_GLOBAL_OPTION_RESULT_KIND.resolved,
|
|
87
|
-
value: value,
|
|
88
|
-
argv: normalized,
|
|
89
|
-
};
|
|
90
|
-
}
|
package/dist/cli-executor.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { CLI_ROUTER_RESULT_KIND, CliResolvedEndpointResult, CliRouter, CliRouterResult } from "./cli-model.js";
|
|
2
|
-
import type { EntryTreeEndpoint } from "./model.js";
|
|
3
|
-
type ResolvedCliResult = Extract<CliRouterResult, {
|
|
4
|
-
readonly kind: typeof CLI_ROUTER_RESULT_KIND.resolved;
|
|
5
|
-
}>;
|
|
6
|
-
export type CliEndpointHandlerBinding<Endpoint extends EntryTreeEndpoint = EntryTreeEndpoint, Result = unknown> = {
|
|
7
|
-
readonly endpoint: Endpoint;
|
|
8
|
-
readonly handler: (input: CliResolvedEndpointResult<Endpoint>) => Result | Promise<Result>;
|
|
9
|
-
};
|
|
10
|
-
export type CliEndpointHandlerRegistration<Result = unknown> = {
|
|
11
|
-
readonly endpoint: EntryTreeEndpoint;
|
|
12
|
-
readonly handler: (...args: never[]) => Result | Promise<Result>;
|
|
13
|
-
};
|
|
14
|
-
export declare class CliExecutorDefinitionError extends Error {
|
|
15
|
-
readonly issues: readonly string[];
|
|
16
|
-
constructor(issues: readonly string[]);
|
|
17
|
-
}
|
|
18
|
-
export declare function handleCliEndpoint<const Endpoint extends EntryTreeEndpoint, Result>(endpoint: Endpoint, handler: (input: CliResolvedEndpointResult<Endpoint>) => Result | Promise<Result>): CliEndpointHandlerBinding<Endpoint, Result>;
|
|
19
|
-
type CliHandlerResult<Bindings extends readonly CliEndpointHandlerRegistration[]> = Awaited<ReturnType<Bindings[number]["handler"]>>;
|
|
20
|
-
export type CliExecutor<Bindings extends readonly CliEndpointHandlerRegistration[]> = {
|
|
21
|
-
execute(result: ResolvedCliResult): Promise<CliHandlerResult<Bindings>>;
|
|
22
|
-
};
|
|
23
|
-
export declare function createCliExecutor<const Bindings extends readonly CliEndpointHandlerRegistration[]>(router: CliRouter, bindings: Bindings): CliExecutor<Bindings>;
|
|
24
|
-
export {};
|
|
25
|
-
//# sourceMappingURL=cli-executor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli-executor.d.ts","sourceRoot":"","sources":["../src/cli-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EACzB,SAAS,EACT,eAAe,EAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,KAAK,iBAAiB,GAAG,OAAO,CAC9B,eAAe,EACf;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,sBAAsB,CAAC,QAAQ,CAAA;CAAE,CAC1D,CAAC;AAEF,MAAM,MAAM,yBAAyB,CACnC,QAAQ,SAAS,iBAAiB,GAAG,iBAAiB,EACtD,MAAM,GAAG,OAAO,IACd;IACF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,CAChB,KAAK,EAAE,yBAAyB,CAAC,QAAQ,CAAC,KACvC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,8BAA8B,CAAC,MAAM,GAAG,OAAO,IAAI;IAC7D,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAClE,CAAC;AAEF,qBAAa,0BAA2B,SAAQ,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE;gBAAzB,MAAM,EAAE,SAAS,MAAM,EAAE;CAI/C;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,CAAC,QAAQ,SAAS,iBAAiB,EACxC,MAAM,EAEN,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,CACP,KAAK,EAAE,yBAAyB,CAAC,QAAQ,CAAC,KACvC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAC5B,yBAAyB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAE7C;AAED,KAAK,gBAAgB,CACnB,QAAQ,SAAS,SAAS,8BAA8B,EAAE,IACxD,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAErD,MAAM,MAAM,WAAW,CACrB,QAAQ,SAAS,SAAS,8BAA8B,EAAE,IACxD;IACF,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;CACzE,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,KAAK,CAAC,QAAQ,SAAS,SAAS,8BAA8B,EAAE,EAChE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAsC9D"}
|
package/dist/cli-executor.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export class CliExecutorDefinitionError extends Error {
|
|
2
|
-
issues;
|
|
3
|
-
constructor(issues) {
|
|
4
|
-
super(`Invalid CLI executor definition:\n${issues.join("\n")}`);
|
|
5
|
-
this.issues = issues;
|
|
6
|
-
this.name = CliExecutorDefinitionError.name;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
export function handleCliEndpoint(endpoint, handler) {
|
|
10
|
-
return { endpoint, handler };
|
|
11
|
-
}
|
|
12
|
-
export function createCliExecutor(router, bindings) {
|
|
13
|
-
const issues = [];
|
|
14
|
-
const routerEndpoints = new Set(router.endpoints);
|
|
15
|
-
const handlers = new Map();
|
|
16
|
-
for (const binding of bindings) {
|
|
17
|
-
if (!routerEndpoints.has(binding.endpoint)) {
|
|
18
|
-
issues.push(`handler endpoint ${binding.endpoint.entry.name} is not in the router`);
|
|
19
|
-
}
|
|
20
|
-
if (handlers.has(binding.endpoint)) {
|
|
21
|
-
issues.push(`duplicate handler for endpoint ${binding.endpoint.entry.name}`);
|
|
22
|
-
}
|
|
23
|
-
handlers.set(binding.endpoint, binding);
|
|
24
|
-
}
|
|
25
|
-
for (const endpoint of router.endpoints) {
|
|
26
|
-
if (!handlers.has(endpoint)) {
|
|
27
|
-
issues.push(`missing handler for endpoint ${endpoint.entry.name}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (issues.length > 0) {
|
|
31
|
-
throw new CliExecutorDefinitionError(issues);
|
|
32
|
-
}
|
|
33
|
-
const execute = async (result) => {
|
|
34
|
-
const binding = handlers.get(result.endpoint);
|
|
35
|
-
if (!binding) {
|
|
36
|
-
throw new CliExecutorDefinitionError([
|
|
37
|
-
`missing handler for endpoint ${result.endpoint.entry.name}`,
|
|
38
|
-
]);
|
|
39
|
-
}
|
|
40
|
-
const handler = binding.handler;
|
|
41
|
-
return await handler(result);
|
|
42
|
-
};
|
|
43
|
-
return { execute };
|
|
44
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { CLI_ROUTER_RESULT_KIND, type CliCommandPath, type CliHelpExample, type CliHelpOption, type CliHelpRenderContext, type CliHelpSurface, type CliHelpSurfaceLocation, type CliRouterResult } from "./cli-model.js";
|
|
2
|
-
import type { ParameterRequirementDescription } from "./introspection.js";
|
|
3
|
-
export type CliHelpOptionDescription = {
|
|
4
|
-
readonly names: string;
|
|
5
|
-
readonly description: string;
|
|
6
|
-
};
|
|
7
|
-
export declare function findCliHelpSurface(root: CliHelpSurface, commandPath: CliCommandPath): CliHelpSurface | null;
|
|
8
|
-
export declare function findCliHelpSurfaceLocation(root: CliHelpSurface, commandPath: CliCommandPath): CliHelpSurfaceLocation | null;
|
|
9
|
-
/**
|
|
10
|
-
* Rendered help always ends with exactly one newline. Help is written to a
|
|
11
|
-
* terminal, so the terminating newline belongs to the renderer: leaving it out
|
|
12
|
-
* makes every caller append the same one, and each one of them a place to
|
|
13
|
-
* forget it or to append two.
|
|
14
|
-
*/
|
|
15
|
-
export declare function renderCliHelp(surface: CliHelpSurface, context: CliHelpRenderContext): string;
|
|
16
|
-
export declare function listCliHelpSurfaces(root: CliHelpSurface): readonly CliHelpSurfaceLocation[];
|
|
17
|
-
export type CliHelpSurfaceProjection = {
|
|
18
|
-
include(location: CliHelpSurfaceLocation): boolean;
|
|
19
|
-
compare?(left: CliHelpSurfaceLocation, right: CliHelpSurfaceLocation): number;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Projects one immutable help tree without recreating its structural fields.
|
|
23
|
-
* The root is always retained; `include` and `compare` are applied to children.
|
|
24
|
-
*/
|
|
25
|
-
export declare function projectCliHelpSurface(root: CliHelpSurface, projection: CliHelpSurfaceProjection): CliHelpSurface;
|
|
26
|
-
export declare function describeCliHelpOption(option: CliHelpOption): CliHelpOptionDescription;
|
|
27
|
-
export declare function appendCliCommandPart(command: string, part: string): string;
|
|
28
|
-
export declare function formatDefaultCliSubcommandHint(programName: string): string;
|
|
29
|
-
export declare function formatCliRouterError(result: Extract<CliRouterResult, {
|
|
30
|
-
readonly kind: typeof CLI_ROUTER_RESULT_KIND.unknownCommand | typeof CLI_ROUTER_RESULT_KIND.incompleteCommand | typeof CLI_ROUTER_RESULT_KIND.invalidInput | typeof CLI_ROUTER_RESULT_KIND.invalidParameter;
|
|
31
|
-
}>): string;
|
|
32
|
-
export declare function formatCliHelpParameterDescription(input: {
|
|
33
|
-
readonly description: string;
|
|
34
|
-
readonly requirement: ParameterRequirementDescription;
|
|
35
|
-
readonly additionalDetails: readonly string[];
|
|
36
|
-
}): string;
|
|
37
|
-
export declare function renderCliHelpExamples(examples: readonly CliHelpExample[], executableName: string): readonly string[];
|
|
38
|
-
//# sourceMappingURL=cli-presentation.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli-presentation.d.ts","sourceRoot":"","sources":["../src/cli-presentation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAE3B,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AAmD1E,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,cAAc,GAC1B,cAAc,GAAG,IAAI,CAEvB;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,cAAc,GAC1B,sBAAsB,GAAG,IAAI,CAc/B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAYR;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,cAAc,GACnB,SAAS,sBAAsB,EAAE,CAanC;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC;IACnD,OAAO,CAAC,CAAC,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAAC;CAC/E,CAAC;AAEF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,cAAc,EACpB,UAAU,EAAE,wBAAwB,GACnC,cAAc,CAsBhB;AAmJD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,GACpB,wBAAwB,CAuB1B;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1E;AAED,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,CACb,eAAe,EACf;IACE,QAAQ,CAAC,IAAI,EACT,OAAO,sBAAsB,CAAC,cAAc,GAC5C,OAAO,sBAAsB,CAAC,iBAAiB,GAC/C,OAAO,sBAAsB,CAAC,YAAY,GAC1C,OAAO,sBAAsB,CAAC,gBAAgB,CAAC;CACpD,CACF,GACA,MAAM,CAcR;AAED,wBAAgB,iCAAiC,CAAC,KAAK,EAAE;IACvD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,+BAA+B,CAAC;IACtD,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/C,GAAG,MAAM,CAUT;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,cAAc,EAAE,MAAM,GACrB,SAAS,MAAM,EAAE,CAiBnB"}
|