@ykdz/template 0.0.37 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/application.d.ts +1 -52
- package/dist/application.js +0 -81
- package/dist/cli.js +14 -28
- package/dist/input-schemas.d.ts +30 -0
- package/dist/input-schemas.js +75 -0
- package/dist/main.d.ts +3 -14
- package/dist/main.js +496 -378
- package/dist/result-schemas.d.ts +222 -0
- package/dist/result-schemas.js +74 -0
- package/dist/standard-schema.d.ts +3 -0
- package/dist/standard-schema.js +29 -0
- package/node_modules/@standard-schema/spec/LICENSE +21 -0
- package/node_modules/@standard-schema/spec/README.md +198 -0
- package/node_modules/@standard-schema/spec/dist/index.cjs +18 -0
- package/node_modules/@standard-schema/spec/dist/index.d.cts +119 -0
- package/node_modules/@standard-schema/spec/dist/index.d.ts +119 -0
- package/node_modules/@standard-schema/spec/dist/index.js +0 -0
- package/node_modules/@standard-schema/spec/package.json +52 -0
- package/node_modules/@types/node/LICENSE +21 -0
- package/node_modules/@types/node/README.md +15 -0
- package/node_modules/@types/node/assert/strict.d.ts +111 -0
- package/node_modules/@types/node/assert.d.ts +1115 -0
- package/node_modules/@types/node/async_hooks.d.ts +619 -0
- package/node_modules/@types/node/buffer.buffer.d.ts +477 -0
- package/node_modules/@types/node/buffer.d.ts +1941 -0
- package/node_modules/@types/node/child_process.d.ts +1480 -0
- package/node_modules/@types/node/cluster.d.ts +578 -0
- package/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
- package/node_modules/@types/node/console.d.ts +453 -0
- package/node_modules/@types/node/constants.d.ts +21 -0
- package/node_modules/@types/node/crypto.d.ts +5484 -0
- package/node_modules/@types/node/dgram.d.ts +715 -0
- package/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
- package/node_modules/@types/node/dns/promises.d.ts +503 -0
- package/node_modules/@types/node/dns.d.ts +923 -0
- package/node_modules/@types/node/domain.d.ts +166 -0
- package/node_modules/@types/node/events.d.ts +967 -0
- package/node_modules/@types/node/fs/promises.d.ts +1354 -0
- package/node_modules/@types/node/fs.d.ts +4777 -0
- package/node_modules/@types/node/globals.d.ts +170 -0
- package/node_modules/@types/node/globals.typedarray.d.ts +41 -0
- package/node_modules/@types/node/http.d.ts +2246 -0
- package/node_modules/@types/node/http2.d.ts +2882 -0
- package/node_modules/@types/node/https.d.ts +585 -0
- package/node_modules/@types/node/index.d.ts +101 -0
- package/node_modules/@types/node/inspector.d.ts +323 -0
- package/node_modules/@types/node/inspector.generated.d.ts +4406 -0
- package/node_modules/@types/node/module.d.ts +844 -0
- package/node_modules/@types/node/net.d.ts +1197 -0
- package/node_modules/@types/node/os.d.ts +507 -0
- package/node_modules/@types/node/package.json +140 -0
- package/node_modules/@types/node/path.d.ts +200 -0
- package/node_modules/@types/node/perf_hooks.d.ts +1054 -0
- package/node_modules/@types/node/process.d.ts +2101 -0
- package/node_modules/@types/node/punycode.d.ts +117 -0
- package/node_modules/@types/node/querystring.d.ts +152 -0
- package/node_modules/@types/node/readline/promises.d.ts +161 -0
- package/node_modules/@types/node/readline.d.ts +600 -0
- package/node_modules/@types/node/repl.d.ts +438 -0
- package/node_modules/@types/node/sea.d.ts +162 -0
- package/node_modules/@types/node/sqlite.d.ts +1182 -0
- package/node_modules/@types/node/stream/consumers.d.ts +45 -0
- package/node_modules/@types/node/stream/promises.d.ts +90 -0
- package/node_modules/@types/node/stream/web.d.ts +596 -0
- package/node_modules/@types/node/stream.d.ts +1707 -0
- package/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/node_modules/@types/node/test.d.ts +2656 -0
- package/node_modules/@types/node/timers/promises.d.ts +108 -0
- package/node_modules/@types/node/timers.d.ts +285 -0
- package/node_modules/@types/node/tls.d.ts +1314 -0
- package/node_modules/@types/node/trace_events.d.ts +197 -0
- package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +473 -0
- package/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
- package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
- package/node_modules/@types/node/ts5.6/index.d.ts +103 -0
- package/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
- package/node_modules/@types/node/ts5.7/index.d.ts +103 -0
- package/node_modules/@types/node/tty.d.ts +209 -0
- package/node_modules/@types/node/url.d.ts +1103 -0
- package/node_modules/@types/node/util.d.ts +2376 -0
- package/node_modules/@types/node/v8.d.ts +1010 -0
- package/node_modules/@types/node/vm.d.ts +1160 -0
- package/node_modules/@types/node/wasi.d.ts +202 -0
- package/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
- package/node_modules/@types/node/web-globals/crypto.d.ts +32 -0
- package/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
- package/node_modules/@types/node/web-globals/events.d.ts +97 -0
- package/node_modules/@types/node/web-globals/fetch.d.ts +62 -0
- package/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
- package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
- package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
- package/node_modules/@types/node/worker_threads.d.ts +894 -0
- package/node_modules/@types/node/zlib.d.ts +768 -0
- package/node_modules/@valibot/to-json-schema/LICENSE.md +9 -0
- package/node_modules/@valibot/to-json-schema/README.md +475 -0
- package/node_modules/@valibot/to-json-schema/dist/index.cjs +800 -0
- package/node_modules/@valibot/to-json-schema/dist/index.d.cts +991 -0
- package/node_modules/@valibot/to-json-schema/dist/index.d.mts +991 -0
- package/node_modules/@valibot/to-json-schema/dist/index.min.cjs +1 -0
- package/node_modules/@valibot/to-json-schema/dist/index.min.mjs +1 -0
- package/node_modules/@valibot/to-json-schema/dist/index.mjs +795 -0
- package/node_modules/@valibot/to-json-schema/package.json +75 -0
- package/node_modules/@ykdz/cli-contract/LICENSE +21 -0
- package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.d.ts +17 -0
- package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.js +55 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-contract.d.ts +1164 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-contract.js +1408 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-execution.d.ts +54 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-execution.js +708 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-invocation.d.ts +174 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-invocation.js +524 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-write-error.d.ts +10 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-write-error.js +14 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.d.ts +260 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.js +130 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.d.ts +63 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.js +17 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.d.ts +6 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.js +532 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema.d.ts +14 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema.js +1 -0
- package/node_modules/@ykdz/cli-contract/dist/description.d.ts +2 -0
- package/node_modules/@ykdz/cli-contract/dist/description.js +13 -0
- package/node_modules/@ykdz/cli-contract/dist/index.d.ts +8 -0
- package/node_modules/@ykdz/cli-contract/dist/index.js +7 -0
- package/node_modules/@ykdz/cli-contract/dist/json-value.d.ts +4 -0
- package/node_modules/@ykdz/cli-contract/dist/json-value.js +64 -0
- package/node_modules/@ykdz/cli-contract/dist/node.d.ts +21 -0
- package/node_modules/@ykdz/cli-contract/dist/node.js +109 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-fact.d.ts +162 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-fact.js +113 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-wire.d.ts +53 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-wire.js +189 -0
- package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.d.ts +16 -0
- package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.js +45 -0
- package/node_modules/@ykdz/cli-contract/package.json +69 -0
- package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.d.ts +20 -0
- package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.js +27 -28
- package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.d.ts +19 -0
- package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.js +1 -1
- package/node_modules/@ykdz/template-builtin-presets/dist/src/index.d.ts +2 -1
- package/node_modules/@ykdz/template-builtin-presets/dist/src/index.js +2 -1
- package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-cli/definition.js +9 -5
- package/node_modules/@ykdz/template-builtin-presets/dist/src/vike-app/definition.js +0 -4
- package/node_modules/@ykdz/template-builtin-presets/package.json +2 -1
- package/node_modules/@ykdz/template-builtin-presets/templates/foundation/AGENTS.md.template +10 -4
- package/node_modules/@ykdz/template-builtin-presets/templates/foundation/devcontainer.json +3 -0
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/artifact.ts +128 -59
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/handoff.ts +80 -8
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/readiness.ts +7 -3
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/cli.ts +9 -19
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/main.ts +144 -60
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/standard-schema.ts +37 -0
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/lookup.journey.ts +71 -0
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/integration/command.test.ts +118 -59
- package/node_modules/@ykdz/template-core/dist/package-contribution.d.ts +0 -1
- package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +2 -1
- package/node_modules/@ykdz/template-core/dist/project-blueprint.d.ts +15 -0
- package/node_modules/@ykdz/template-core/dist/project-blueprint.js +1 -1
- package/node_modules/@ykdz/template-core/dist/project-github.d.ts +1 -1
- package/node_modules/undici-types/LICENSE +21 -0
- package/node_modules/undici-types/README.md +6 -0
- package/node_modules/undici-types/agent.d.ts +32 -0
- package/node_modules/undici-types/api.d.ts +43 -0
- package/node_modules/undici-types/balanced-pool.d.ts +30 -0
- package/node_modules/undici-types/cache-interceptor.d.ts +179 -0
- package/node_modules/undici-types/cache.d.ts +36 -0
- package/node_modules/undici-types/client-stats.d.ts +15 -0
- package/node_modules/undici-types/client.d.ts +123 -0
- package/node_modules/undici-types/connector.d.ts +36 -0
- package/node_modules/undici-types/content-type.d.ts +21 -0
- package/node_modules/undici-types/cookies.d.ts +30 -0
- package/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
- package/node_modules/undici-types/dispatcher.d.ts +279 -0
- package/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
- package/node_modules/undici-types/errors.d.ts +177 -0
- package/node_modules/undici-types/eventsource.d.ts +66 -0
- package/node_modules/undici-types/fetch.d.ts +211 -0
- package/node_modules/undici-types/formdata.d.ts +108 -0
- package/node_modules/undici-types/global-dispatcher.d.ts +9 -0
- package/node_modules/undici-types/global-origin.d.ts +7 -0
- package/node_modules/undici-types/h2c-client.d.ts +73 -0
- package/node_modules/undici-types/handlers.d.ts +15 -0
- package/node_modules/undici-types/header.d.ts +160 -0
- package/node_modules/undici-types/index.d.ts +91 -0
- package/node_modules/undici-types/interceptors.d.ts +80 -0
- package/node_modules/undici-types/mock-agent.d.ts +68 -0
- package/node_modules/undici-types/mock-call-history.d.ts +111 -0
- package/node_modules/undici-types/mock-client.d.ts +27 -0
- package/node_modules/undici-types/mock-errors.d.ts +12 -0
- package/node_modules/undici-types/mock-interceptor.d.ts +94 -0
- package/node_modules/undici-types/mock-pool.d.ts +27 -0
- package/node_modules/undici-types/package.json +55 -0
- package/node_modules/undici-types/patch.d.ts +29 -0
- package/node_modules/undici-types/pool-stats.d.ts +19 -0
- package/node_modules/undici-types/pool.d.ts +41 -0
- package/node_modules/undici-types/proxy-agent.d.ts +29 -0
- package/node_modules/undici-types/readable.d.ts +68 -0
- package/node_modules/undici-types/retry-agent.d.ts +8 -0
- package/node_modules/undici-types/retry-handler.d.ts +125 -0
- package/node_modules/undici-types/round-robin-pool.d.ts +41 -0
- package/node_modules/undici-types/snapshot-agent.d.ts +109 -0
- package/node_modules/undici-types/socks5-proxy-agent.d.ts +25 -0
- package/node_modules/undici-types/util.d.ts +18 -0
- package/node_modules/undici-types/utility.d.ts +7 -0
- package/node_modules/undici-types/webidl.d.ts +347 -0
- package/node_modules/undici-types/websocket.d.ts +188 -0
- package/package.json +5 -3
- package/dist/command-result.d.ts +0 -9
- package/dist/command-result.js +0 -231
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/greet.journey.ts +0 -46
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/unit/greet.test.ts +0 -15
- package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/devcontainer/docker-client.Dockerfile +0 -3
- package/node_modules/commander/LICENSE +0 -22
- package/node_modules/commander/Readme.md +0 -1172
- package/node_modules/commander/index.js +0 -21
- package/node_modules/commander/lib/argument.js +0 -147
- package/node_modules/commander/lib/command.js +0 -2790
- package/node_modules/commander/lib/error.js +0 -36
- package/node_modules/commander/lib/help.js +0 -731
- package/node_modules/commander/lib/option.js +0 -377
- package/node_modules/commander/lib/suggestSimilar.js +0 -99
- package/node_modules/commander/package-support.json +0 -19
- package/node_modules/commander/package.json +0 -64
- package/node_modules/commander/typings/index.d.ts +0 -1113
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
import { getCompiledCli, isCompiledExecutable, } from "#/cli-contract";
|
|
2
|
+
import { ContractExecutionError } from "#/contract-execution-error";
|
|
3
|
+
const cliInvocationType = Symbol("CliInvocation.type");
|
|
4
|
+
const invocationContracts = new WeakMap();
|
|
5
|
+
/**
|
|
6
|
+
* 将宿主提供的参数 token 同步、无副作用地解析为同一契约的调用事实。
|
|
7
|
+
* 参数从命令路径或字段开始,不包含 Node 可执行文件和脚本路径;来源与 shell 拆词由宿主负责。
|
|
8
|
+
*
|
|
9
|
+
* 解析器检查调用语法与用法约束,保留帮助、版本和用法失败等闭合分支;
|
|
10
|
+
* 已解析的 raw input 尚未经过契约模式验证。它不读取进程或环境,不执行 handler,也不写输出。
|
|
11
|
+
* 将返回值交给 {@link executeCli},由执行内核完成后续验证与投影。
|
|
12
|
+
*/
|
|
13
|
+
export function parseCliInvocation(cliContract, argv) {
|
|
14
|
+
const compiled = getCompiledCli(cliContract);
|
|
15
|
+
const input = {};
|
|
16
|
+
const occurrencesByField = new Map();
|
|
17
|
+
const valueOccurrencesByField = new Map();
|
|
18
|
+
const outputOccurrences = [];
|
|
19
|
+
let selected = compiled.commands[compiled.root];
|
|
20
|
+
if (selected === undefined)
|
|
21
|
+
throw new ContractExecutionError([{ code: "invalidCliContract" }]);
|
|
22
|
+
let position = 0;
|
|
23
|
+
while (!isCompiledExecutable(selected)) {
|
|
24
|
+
const token = argv[position];
|
|
25
|
+
if (token === undefined) {
|
|
26
|
+
return bindInvocation(cliContract, {
|
|
27
|
+
kind: "help",
|
|
28
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 命令 id 来自当前 Contract 编译结果,泛型身份在此恢复。
|
|
29
|
+
command: selected.id,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const eager = detectEagerControl(compiled, token);
|
|
33
|
+
if (eager !== undefined) {
|
|
34
|
+
return bindInvocation(cliContract, {
|
|
35
|
+
kind: eager,
|
|
36
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 命令 id 来自当前 Contract 编译结果,泛型身份在此恢复。
|
|
37
|
+
command: selected.id,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const output = consumeOutputControl(compiled, argv, position, outputOccurrences);
|
|
41
|
+
if (output.kind === "issue") {
|
|
42
|
+
return usageFailure(cliContract,
|
|
43
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 命令 id 来自当前 Contract 编译结果,泛型身份在此恢复。
|
|
44
|
+
selected.id,
|
|
45
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- usage 与同一已编译命令一同产生,泛型身份在此恢复。
|
|
46
|
+
selected.usage, output.issue);
|
|
47
|
+
}
|
|
48
|
+
if (output.kind === "consumed") {
|
|
49
|
+
position = output.nextPosition;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (token.startsWith("-") && token !== "-") {
|
|
53
|
+
const option = consumeOption(compiled, [], argv, position, input, occurrencesByField, valueOccurrencesByField);
|
|
54
|
+
if (option.kind === "issue") {
|
|
55
|
+
return usageFailure(cliContract,
|
|
56
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 命令 id 来自当前 Contract 编译结果,泛型身份在此恢复。
|
|
57
|
+
selected.id,
|
|
58
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- usage 与同一已编译命令一同产生,泛型身份在此恢复。
|
|
59
|
+
selected.usage, option.issue);
|
|
60
|
+
}
|
|
61
|
+
position = option.nextPosition;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const child = Object.values(compiled.commands).find((candidate) => candidate.parent === selected?.id &&
|
|
65
|
+
(candidate.name === token || candidate.aliases.includes(token)));
|
|
66
|
+
if (child === undefined) {
|
|
67
|
+
const selectedId = selected.id;
|
|
68
|
+
const issue = {
|
|
69
|
+
code: "unknownCommand",
|
|
70
|
+
position,
|
|
71
|
+
command: token,
|
|
72
|
+
...suggestionProperty("suggestedCommand", selectUniqueNeighbor(token, Object.values(compiled.commands)
|
|
73
|
+
.filter((candidate) => candidate.parent === selectedId)
|
|
74
|
+
.flatMap((candidate) => [candidate.name, ...candidate.aliases]))),
|
|
75
|
+
};
|
|
76
|
+
return usageFailure(cliContract,
|
|
77
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 命令 id 来自当前 Contract 编译结果,泛型身份在此恢复。
|
|
78
|
+
selected.id,
|
|
79
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- usage 与同一已编译命令一同产生,泛型身份在此恢复。
|
|
80
|
+
selected.usage, issue);
|
|
81
|
+
}
|
|
82
|
+
selected = child;
|
|
83
|
+
position += 1;
|
|
84
|
+
}
|
|
85
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 命令 id 来自当前 Contract 编译结果,泛型身份在此恢复。
|
|
86
|
+
const command = selected.id;
|
|
87
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- usage 与同一已编译命令一同产生,泛型身份在此恢复。
|
|
88
|
+
const usage = selected.usage;
|
|
89
|
+
const fields = selected.fields;
|
|
90
|
+
const positionals = fields.filter((field) => field.kind === "positional" || field.kind === "variadicPositional");
|
|
91
|
+
let positionalIndex = 0;
|
|
92
|
+
let optionsEnabled = true;
|
|
93
|
+
for (; position < argv.length; position += 1) {
|
|
94
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- position 受 argv.length 限制,argv 的公共类型保证元素为字符串。
|
|
95
|
+
const token = argv[position];
|
|
96
|
+
if (optionsEnabled && token === "--") {
|
|
97
|
+
optionsEnabled = false;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const eager = optionsEnabled
|
|
101
|
+
? detectEagerControl(compiled, token)
|
|
102
|
+
: undefined;
|
|
103
|
+
if (eager !== undefined) {
|
|
104
|
+
return bindInvocation(cliContract, {
|
|
105
|
+
kind: eager,
|
|
106
|
+
command,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (optionsEnabled) {
|
|
110
|
+
const output = consumeOutputControl(compiled, argv, position, outputOccurrences);
|
|
111
|
+
if (output.kind === "issue") {
|
|
112
|
+
return usageFailure(cliContract, command, usage, output.issue);
|
|
113
|
+
}
|
|
114
|
+
if (output.kind === "consumed") {
|
|
115
|
+
position = output.nextPosition - 1;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (optionsEnabled && token.startsWith("-") && token !== "-") {
|
|
120
|
+
const option = consumeOption(compiled, fields, argv, position, input, occurrencesByField, valueOccurrencesByField);
|
|
121
|
+
if (option.kind === "issue") {
|
|
122
|
+
return usageFailure(cliContract, command, usage, option.issue);
|
|
123
|
+
}
|
|
124
|
+
position = option.nextPosition - 1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const positional = positionals[positionalIndex];
|
|
128
|
+
if (positional === undefined) {
|
|
129
|
+
return unexpectedPositional(cliContract, command, usage, position, token);
|
|
130
|
+
}
|
|
131
|
+
if (positional.kind === "variadicPositional") {
|
|
132
|
+
const values = input[positional.key];
|
|
133
|
+
input[positional.key] = Array.isArray(values)
|
|
134
|
+
? [...values, token]
|
|
135
|
+
: [token];
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
input[positional.key] = token;
|
|
139
|
+
positionalIndex += 1;
|
|
140
|
+
}
|
|
141
|
+
addFieldValueOccurrence(valueOccurrencesByField, positional.key, position, token);
|
|
142
|
+
}
|
|
143
|
+
const structuralIssues = collectStructuralIssues(fields, input, occurrencesByField, valueOccurrencesByField, selected.usageConstraints);
|
|
144
|
+
if (structuralIssues.length > 0) {
|
|
145
|
+
return usageFailureFromIssues(cliContract, command, usage,
|
|
146
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- structuralIssues.length 已检查为正数。
|
|
147
|
+
structuralIssues);
|
|
148
|
+
}
|
|
149
|
+
return bindInvocation(cliContract, {
|
|
150
|
+
kind: "parsed",
|
|
151
|
+
command,
|
|
152
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- raw input 由此 Contract 的字段语法解析并冻结,泛型形状在此恢复。
|
|
153
|
+
input: freezeRawInput(input),
|
|
154
|
+
outputFormat: outputOccurrences[0]?.format ??
|
|
155
|
+
compiled.contract.grammar.controls.output.defaultFormat,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function detectEagerControl(compiled, token) {
|
|
159
|
+
const help = compiled.contract.grammar.controls.help;
|
|
160
|
+
if (token === help.longOption || token === help.shortAlias) {
|
|
161
|
+
return "help";
|
|
162
|
+
}
|
|
163
|
+
const version = compiled.contract.grammar.controls.version;
|
|
164
|
+
return version !== undefined &&
|
|
165
|
+
(token === version.longOption || token === version.shortAlias)
|
|
166
|
+
? "version"
|
|
167
|
+
: undefined;
|
|
168
|
+
}
|
|
169
|
+
function consumeOutputControl(compiled, argv, position, occurrences) {
|
|
170
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 调用点均传入当前位置的 argv token,公共类型保证字符串。
|
|
171
|
+
const token = argv[position];
|
|
172
|
+
const option = readOptionToken(token);
|
|
173
|
+
const output = compiled.contract.grammar.controls.output;
|
|
174
|
+
if (output.selector === option.spelling) {
|
|
175
|
+
const nextToken = argv[position + 1];
|
|
176
|
+
if (option.value === undefined &&
|
|
177
|
+
nextToken !== undefined &&
|
|
178
|
+
detectEagerControl(compiled, nextToken) !== undefined) {
|
|
179
|
+
return { kind: "consumed", nextPosition: position + 1 };
|
|
180
|
+
}
|
|
181
|
+
const value = option.value ?? argv[position + 1];
|
|
182
|
+
if (value === undefined ||
|
|
183
|
+
!isOutputFormat(value) ||
|
|
184
|
+
!output.formats.includes(value)) {
|
|
185
|
+
return {
|
|
186
|
+
kind: "issue",
|
|
187
|
+
issue: {
|
|
188
|
+
code: "invalidOutputFormat",
|
|
189
|
+
position,
|
|
190
|
+
option: option.spelling,
|
|
191
|
+
received: value ?? null,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const nextPosition = option.value === undefined ? position + 2 : position + 1;
|
|
196
|
+
return selectOutputFormat(occurrences, {
|
|
197
|
+
position,
|
|
198
|
+
option: option.spelling,
|
|
199
|
+
format: value,
|
|
200
|
+
}, nextPosition);
|
|
201
|
+
}
|
|
202
|
+
const format = output.compatibilityFlags?.[option.spelling];
|
|
203
|
+
if (format === undefined)
|
|
204
|
+
return { kind: "notControl" };
|
|
205
|
+
if (option.value !== undefined) {
|
|
206
|
+
return {
|
|
207
|
+
kind: "issue",
|
|
208
|
+
issue: {
|
|
209
|
+
code: "invalidOutputFormat",
|
|
210
|
+
position,
|
|
211
|
+
option: option.spelling,
|
|
212
|
+
received: option.value,
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return selectOutputFormat(occurrences, { position, option: option.spelling, format }, position + 1);
|
|
217
|
+
}
|
|
218
|
+
function isOutputFormat(value) {
|
|
219
|
+
return value === "structured" || value === "text";
|
|
220
|
+
}
|
|
221
|
+
function selectOutputFormat(occurrences, occurrence, nextPosition) {
|
|
222
|
+
occurrences.push(occurrence);
|
|
223
|
+
if (occurrences.length === 1)
|
|
224
|
+
return { kind: "consumed", nextPosition };
|
|
225
|
+
return {
|
|
226
|
+
kind: "issue",
|
|
227
|
+
issue: {
|
|
228
|
+
code: "conflictingOutputFormat",
|
|
229
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 此前已排除单次出现,冲突证据至少有两项。
|
|
230
|
+
occurrences: Object.freeze([
|
|
231
|
+
...occurrences,
|
|
232
|
+
]),
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function consumeOption(compiled, fields, argv, position, input, occurrencesByField, valueOccurrencesByField) {
|
|
237
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 调用点均传入当前位置的 argv token,公共类型保证字符串。
|
|
238
|
+
const token = argv[position];
|
|
239
|
+
const option = readOptionToken(token);
|
|
240
|
+
const field = fields.find((candidate) => candidate.kind !== "positional" &&
|
|
241
|
+
candidate.kind !== "variadicPositional" &&
|
|
242
|
+
(candidate.longOption === option.spelling ||
|
|
243
|
+
candidate.shortAlias === option.spelling ||
|
|
244
|
+
(candidate.kind === "flag" &&
|
|
245
|
+
candidate.negatedLongOption === option.spelling)));
|
|
246
|
+
if (field === undefined) {
|
|
247
|
+
return {
|
|
248
|
+
kind: "issue",
|
|
249
|
+
issue: {
|
|
250
|
+
code: "unknownOption",
|
|
251
|
+
position,
|
|
252
|
+
option: token,
|
|
253
|
+
...suggestionProperty("suggestedOption", token.startsWith("--")
|
|
254
|
+
? selectUniqueNeighbor(option.spelling, longOptionsInScope(compiled, fields))
|
|
255
|
+
: undefined),
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
if (field.kind === "flag") {
|
|
260
|
+
if (option.value !== undefined) {
|
|
261
|
+
return {
|
|
262
|
+
kind: "issue",
|
|
263
|
+
issue: {
|
|
264
|
+
code: "unexpectedOptionValue",
|
|
265
|
+
position,
|
|
266
|
+
field: field.key,
|
|
267
|
+
option: option.spelling,
|
|
268
|
+
value: option.value,
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const polarity = option.spelling === field.negatedLongOption ? "negative" : "positive";
|
|
273
|
+
input[field.key] = polarity === "positive";
|
|
274
|
+
addOptionOccurrence(occurrencesByField, field.key, position, option.spelling, polarity);
|
|
275
|
+
return { kind: "consumed", nextPosition: position + 1 };
|
|
276
|
+
}
|
|
277
|
+
if (option.value !== undefined) {
|
|
278
|
+
addOptionValue(input, field.key, option.value, field.kind);
|
|
279
|
+
addFieldValueOccurrence(valueOccurrencesByField, field.key, position, option.value);
|
|
280
|
+
addOptionOccurrence(occurrencesByField, field.key, position, option.spelling, "value");
|
|
281
|
+
return { kind: "consumed", nextPosition: position + 1 };
|
|
282
|
+
}
|
|
283
|
+
const value = argv[position + 1];
|
|
284
|
+
if (value !== undefined &&
|
|
285
|
+
detectEagerControl(compiled, value) !== undefined) {
|
|
286
|
+
return { kind: "consumed", nextPosition: position + 1 };
|
|
287
|
+
}
|
|
288
|
+
if (value === undefined || (value.startsWith("-") && value !== "-")) {
|
|
289
|
+
return {
|
|
290
|
+
kind: "issue",
|
|
291
|
+
issue: {
|
|
292
|
+
code: "missingOptionValue",
|
|
293
|
+
position,
|
|
294
|
+
field: field.key,
|
|
295
|
+
option: option.spelling,
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
addOptionValue(input, field.key, value, field.kind);
|
|
300
|
+
addFieldValueOccurrence(valueOccurrencesByField, field.key, position + 1, value);
|
|
301
|
+
addOptionOccurrence(occurrencesByField, field.key, position, option.spelling, "value");
|
|
302
|
+
return { kind: "consumed", nextPosition: position + 2 };
|
|
303
|
+
}
|
|
304
|
+
function addFieldValueOccurrence(valueOccurrencesByField, field, position, value) {
|
|
305
|
+
const occurrences = valueOccurrencesByField.get(field) ?? [];
|
|
306
|
+
occurrences.push({ position, value });
|
|
307
|
+
valueOccurrencesByField.set(field, occurrences);
|
|
308
|
+
}
|
|
309
|
+
function addOptionOccurrence(occurrencesByField, field, position, option, polarity) {
|
|
310
|
+
const occurrences = occurrencesByField.get(field) ?? [];
|
|
311
|
+
occurrences.push({ position, option, polarity });
|
|
312
|
+
occurrencesByField.set(field, occurrences);
|
|
313
|
+
}
|
|
314
|
+
function collectStructuralIssues(fields, input, occurrencesByField, valueOccurrencesByField, usageConstraints) {
|
|
315
|
+
const fieldIssues = fields.flatMap((field) => {
|
|
316
|
+
const issues = [];
|
|
317
|
+
if (field.required && !Object.hasOwn(input, field.key)) {
|
|
318
|
+
issues.push({ code: "missingRequiredField", field: field.key });
|
|
319
|
+
}
|
|
320
|
+
const occurrences = occurrencesByField.get(field.key) ?? [];
|
|
321
|
+
if (field.kind !== "positional" &&
|
|
322
|
+
field.kind !== "variadicPositional" &&
|
|
323
|
+
field.kind !== "repeatableOption") {
|
|
324
|
+
if (field.kind === "flag") {
|
|
325
|
+
const positiveOccurrences = occurrences.filter(({ polarity }) => polarity === "positive");
|
|
326
|
+
const negativeOccurrences = occurrences.filter(({ polarity }) => polarity === "negative");
|
|
327
|
+
if (positiveOccurrences.length > 0 && negativeOccurrences.length > 0) {
|
|
328
|
+
issues.push({
|
|
329
|
+
code: "conflictingFlag",
|
|
330
|
+
field: field.key,
|
|
331
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 正负出现次数均已检查为正数。
|
|
332
|
+
positiveOccurrences: freezeOccurrenceEvidence(positiveOccurrences),
|
|
333
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 正负出现次数均已检查为正数。
|
|
334
|
+
negativeOccurrences: freezeOccurrenceEvidence(negativeOccurrences),
|
|
335
|
+
});
|
|
336
|
+
return issues;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (occurrences.length > 1) {
|
|
340
|
+
issues.push({
|
|
341
|
+
code: "repeatedOption",
|
|
342
|
+
field: field.key,
|
|
343
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- occurrences.length 已检查大于一。
|
|
344
|
+
occurrences: freezeOccurrenceEvidence(occurrences),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (field.choices !== undefined) {
|
|
349
|
+
for (const occurrence of valueOccurrencesByField.get(field.key) ?? []) {
|
|
350
|
+
if (!field.choices.includes(occurrence.value)) {
|
|
351
|
+
issues.push({
|
|
352
|
+
code: "invalidFieldChoice",
|
|
353
|
+
position: occurrence.position,
|
|
354
|
+
field: field.key,
|
|
355
|
+
value: occurrence.value,
|
|
356
|
+
choices: Object.freeze([...field.choices]),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return issues;
|
|
362
|
+
});
|
|
363
|
+
const constraintIssues = usageConstraints.flatMap((constraint) => {
|
|
364
|
+
if (constraint.kind === "requires") {
|
|
365
|
+
return Object.hasOwn(input, constraint.field) &&
|
|
366
|
+
!Object.hasOwn(input, constraint.requires)
|
|
367
|
+
? [
|
|
368
|
+
{
|
|
369
|
+
code: "requiredByUsageConstraint",
|
|
370
|
+
field: constraint.field,
|
|
371
|
+
requires: constraint.requires,
|
|
372
|
+
},
|
|
373
|
+
]
|
|
374
|
+
: [];
|
|
375
|
+
}
|
|
376
|
+
if (constraint.kind === "exclusive") {
|
|
377
|
+
const present = constraint.fields.filter((field) => Object.hasOwn(input, field));
|
|
378
|
+
return present.length > 1
|
|
379
|
+
? [
|
|
380
|
+
{
|
|
381
|
+
code: "exclusiveUsageConstraint",
|
|
382
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- present.length 已检查大于一。
|
|
383
|
+
fields: Object.freeze(present),
|
|
384
|
+
},
|
|
385
|
+
]
|
|
386
|
+
: [];
|
|
387
|
+
}
|
|
388
|
+
return constraint.values.every(({ field, value }) => input[field] === value)
|
|
389
|
+
? [
|
|
390
|
+
{
|
|
391
|
+
code: "forbiddenUsageCombination",
|
|
392
|
+
values: constraint.values,
|
|
393
|
+
},
|
|
394
|
+
]
|
|
395
|
+
: [];
|
|
396
|
+
});
|
|
397
|
+
return [...fieldIssues, ...constraintIssues];
|
|
398
|
+
}
|
|
399
|
+
function freezeOccurrenceEvidence(occurrences) {
|
|
400
|
+
return Object.freeze(occurrences.map(({ position, option }) => Object.freeze({ position, option })));
|
|
401
|
+
}
|
|
402
|
+
function freezeRawInput(input) {
|
|
403
|
+
for (const value of Object.values(input)) {
|
|
404
|
+
if (Array.isArray(value))
|
|
405
|
+
Object.freeze(value);
|
|
406
|
+
}
|
|
407
|
+
return Object.freeze(input);
|
|
408
|
+
}
|
|
409
|
+
function addOptionValue(input, field, value, kind) {
|
|
410
|
+
if (kind === "valueOption") {
|
|
411
|
+
input[field] = value;
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const values = input[field];
|
|
415
|
+
input[field] = Array.isArray(values) ? [...values, value] : [value];
|
|
416
|
+
}
|
|
417
|
+
function readOptionToken(token) {
|
|
418
|
+
if (!token.startsWith("--"))
|
|
419
|
+
return { spelling: token };
|
|
420
|
+
const equals = token.indexOf("=");
|
|
421
|
+
return equals === -1
|
|
422
|
+
? { spelling: token }
|
|
423
|
+
: { spelling: token.slice(0, equals), value: token.slice(equals + 1) };
|
|
424
|
+
}
|
|
425
|
+
function longOptionsInScope(compiled, fields) {
|
|
426
|
+
return [
|
|
427
|
+
...fields.flatMap((field) => field.kind === "positional" || field.kind === "variadicPositional"
|
|
428
|
+
? []
|
|
429
|
+
: [
|
|
430
|
+
field.longOption,
|
|
431
|
+
...(field.kind === "flag" && field.negatedLongOption !== undefined
|
|
432
|
+
? [field.negatedLongOption]
|
|
433
|
+
: []),
|
|
434
|
+
]),
|
|
435
|
+
compiled.contract.grammar.controls.help.longOption,
|
|
436
|
+
...(compiled.contract.grammar.controls.version === undefined
|
|
437
|
+
? []
|
|
438
|
+
: [compiled.contract.grammar.controls.version.longOption]),
|
|
439
|
+
...(compiled.contract.grammar.controls.output.selector === undefined
|
|
440
|
+
? []
|
|
441
|
+
: [compiled.contract.grammar.controls.output.selector]),
|
|
442
|
+
...Object.keys(compiled.contract.grammar.controls.output.compatibilityFlags ?? {}),
|
|
443
|
+
];
|
|
444
|
+
}
|
|
445
|
+
function suggestionProperty(key, value) {
|
|
446
|
+
return value === undefined ? {} : { [key]: value };
|
|
447
|
+
}
|
|
448
|
+
function selectUniqueNeighbor(received, candidates) {
|
|
449
|
+
const receivedBody = visibleBody(received);
|
|
450
|
+
const scored = candidates.map((candidate) => ({
|
|
451
|
+
candidate,
|
|
452
|
+
distance: damerauLevenshteinDistance(receivedBody, visibleBody(candidate)),
|
|
453
|
+
}));
|
|
454
|
+
const nearestDistance = Math.min(...scored.map(({ distance }) => distance));
|
|
455
|
+
const nearest = scored.filter(({ distance }) => distance === nearestDistance);
|
|
456
|
+
if (nearest.length !== 1 ||
|
|
457
|
+
nearestDistance >
|
|
458
|
+
(Math.max(receivedBody.length, visibleBody(nearest[0].candidate).length) <= 4
|
|
459
|
+
? 1
|
|
460
|
+
: 2)) {
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
return nearest[0].candidate;
|
|
464
|
+
}
|
|
465
|
+
function visibleBody(spelling) {
|
|
466
|
+
return spelling.startsWith("--") ? spelling.slice(2) : spelling;
|
|
467
|
+
}
|
|
468
|
+
function damerauLevenshteinDistance(left, right) {
|
|
469
|
+
const maximumDistance = left.length + right.length;
|
|
470
|
+
const matrix = Array.from({ length: left.length + 2 }, () => Array(right.length + 2).fill(0));
|
|
471
|
+
matrix[0][0] = maximumDistance;
|
|
472
|
+
for (let index = 0; index <= left.length; index += 1) {
|
|
473
|
+
matrix[index + 1][0] = maximumDistance;
|
|
474
|
+
matrix[index + 1][1] = index;
|
|
475
|
+
}
|
|
476
|
+
for (let index = 0; index <= right.length; index += 1) {
|
|
477
|
+
matrix[0][index + 1] = maximumDistance;
|
|
478
|
+
matrix[1][index + 1] = index;
|
|
479
|
+
}
|
|
480
|
+
const lastRowByCharacter = new Map();
|
|
481
|
+
for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
|
|
482
|
+
let lastMatchingColumn = 0;
|
|
483
|
+
for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
|
|
484
|
+
const matchingRow = lastRowByCharacter.get(right[rightIndex - 1]) ?? 0;
|
|
485
|
+
const cost = left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1;
|
|
486
|
+
if (cost === 0)
|
|
487
|
+
lastMatchingColumn = rightIndex;
|
|
488
|
+
matrix[leftIndex + 1][rightIndex + 1] = Math.min(matrix[leftIndex][rightIndex] + cost, matrix[leftIndex + 1][rightIndex] + 1, matrix[leftIndex][rightIndex + 1] + 1, matrix[matchingRow][lastMatchingColumn] +
|
|
489
|
+
(leftIndex - matchingRow - 1) +
|
|
490
|
+
1 +
|
|
491
|
+
(rightIndex - lastMatchingColumn - 1));
|
|
492
|
+
}
|
|
493
|
+
lastRowByCharacter.set(left[leftIndex - 1], leftIndex);
|
|
494
|
+
}
|
|
495
|
+
return matrix[left.length + 1][right.length + 1];
|
|
496
|
+
}
|
|
497
|
+
function unexpectedPositional(contract, command, usage, position, value) {
|
|
498
|
+
return usageFailure(contract, command, usage, {
|
|
499
|
+
code: "unexpectedPositional",
|
|
500
|
+
position,
|
|
501
|
+
value,
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
function usageFailure(contract, command, usage, issue) {
|
|
505
|
+
return usageFailureFromIssues(contract, command, usage, [issue]);
|
|
506
|
+
}
|
|
507
|
+
function usageFailureFromIssues(contract, command, usage, issues) {
|
|
508
|
+
return bindInvocation(contract, {
|
|
509
|
+
kind: "usageFailure",
|
|
510
|
+
command,
|
|
511
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 输入参数是非空元组,映射后长度不变。
|
|
512
|
+
issues: Object.freeze(issues.map((issue) => Object.freeze(issue))),
|
|
513
|
+
usage,
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
export function invocationBelongsTo(invocation, contract) {
|
|
517
|
+
return invocationContracts.get(invocation) === contract;
|
|
518
|
+
}
|
|
519
|
+
function bindInvocation(contract, invocation) {
|
|
520
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 调用事实由本工厂签发并登记到 invocationContracts。
|
|
521
|
+
const bound = Object.freeze(invocation);
|
|
522
|
+
invocationContracts.set(bound, contract);
|
|
523
|
+
return bound;
|
|
524
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CliOutputDestination } from "#/cli-execution";
|
|
2
|
+
/**
|
|
3
|
+
* 宿主输出端口未能完成写入,保留目的通道和原始 cause;它不是应用失败或正常终止结果。
|
|
4
|
+
* chunk 可能已部分写出,核心不自动重试,也不借失败端口补写诊断;后续处置由宿主决定。
|
|
5
|
+
*/
|
|
6
|
+
export declare class CliWriteError extends Error {
|
|
7
|
+
readonly destination: CliOutputDestination;
|
|
8
|
+
readonly cause: unknown;
|
|
9
|
+
constructor(destination: CliOutputDestination, cause: unknown);
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主输出端口未能完成写入,保留目的通道和原始 cause;它不是应用失败或正常终止结果。
|
|
3
|
+
* chunk 可能已部分写出,核心不自动重试,也不借失败端口补写诊断;后续处置由宿主决定。
|
|
4
|
+
*/
|
|
5
|
+
export class CliWriteError extends Error {
|
|
6
|
+
destination;
|
|
7
|
+
cause;
|
|
8
|
+
constructor(destination, cause) {
|
|
9
|
+
super("cliWriteError", { cause });
|
|
10
|
+
this.name = "CliWriteError";
|
|
11
|
+
this.destination = destination;
|
|
12
|
+
this.cause = cause;
|
|
13
|
+
}
|
|
14
|
+
}
|