@ykdz/template 0.0.38 → 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.
Files changed (220) hide show
  1. package/dist/application.d.ts +1 -52
  2. package/dist/application.js +0 -81
  3. package/dist/cli.js +14 -28
  4. package/dist/input-schemas.d.ts +30 -0
  5. package/dist/input-schemas.js +75 -0
  6. package/dist/main.d.ts +3 -14
  7. package/dist/main.js +496 -378
  8. package/dist/result-schemas.d.ts +222 -0
  9. package/dist/result-schemas.js +74 -0
  10. package/dist/standard-schema.d.ts +3 -0
  11. package/dist/standard-schema.js +29 -0
  12. package/node_modules/@standard-schema/spec/LICENSE +21 -0
  13. package/node_modules/@standard-schema/spec/README.md +198 -0
  14. package/node_modules/@standard-schema/spec/dist/index.cjs +18 -0
  15. package/node_modules/@standard-schema/spec/dist/index.d.cts +119 -0
  16. package/node_modules/@standard-schema/spec/dist/index.d.ts +119 -0
  17. package/node_modules/@standard-schema/spec/dist/index.js +0 -0
  18. package/node_modules/@standard-schema/spec/package.json +52 -0
  19. package/node_modules/@types/node/LICENSE +21 -0
  20. package/node_modules/@types/node/README.md +15 -0
  21. package/node_modules/@types/node/assert/strict.d.ts +111 -0
  22. package/node_modules/@types/node/assert.d.ts +1115 -0
  23. package/node_modules/@types/node/async_hooks.d.ts +619 -0
  24. package/node_modules/@types/node/buffer.buffer.d.ts +477 -0
  25. package/node_modules/@types/node/buffer.d.ts +1941 -0
  26. package/node_modules/@types/node/child_process.d.ts +1480 -0
  27. package/node_modules/@types/node/cluster.d.ts +578 -0
  28. package/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
  29. package/node_modules/@types/node/console.d.ts +453 -0
  30. package/node_modules/@types/node/constants.d.ts +21 -0
  31. package/node_modules/@types/node/crypto.d.ts +5484 -0
  32. package/node_modules/@types/node/dgram.d.ts +715 -0
  33. package/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
  34. package/node_modules/@types/node/dns/promises.d.ts +503 -0
  35. package/node_modules/@types/node/dns.d.ts +923 -0
  36. package/node_modules/@types/node/domain.d.ts +166 -0
  37. package/node_modules/@types/node/events.d.ts +967 -0
  38. package/node_modules/@types/node/fs/promises.d.ts +1354 -0
  39. package/node_modules/@types/node/fs.d.ts +4777 -0
  40. package/node_modules/@types/node/globals.d.ts +170 -0
  41. package/node_modules/@types/node/globals.typedarray.d.ts +41 -0
  42. package/node_modules/@types/node/http.d.ts +2246 -0
  43. package/node_modules/@types/node/http2.d.ts +2882 -0
  44. package/node_modules/@types/node/https.d.ts +585 -0
  45. package/node_modules/@types/node/index.d.ts +101 -0
  46. package/node_modules/@types/node/inspector.d.ts +323 -0
  47. package/node_modules/@types/node/inspector.generated.d.ts +4406 -0
  48. package/node_modules/@types/node/module.d.ts +844 -0
  49. package/node_modules/@types/node/net.d.ts +1197 -0
  50. package/node_modules/@types/node/os.d.ts +507 -0
  51. package/node_modules/@types/node/package.json +140 -0
  52. package/node_modules/@types/node/path.d.ts +200 -0
  53. package/node_modules/@types/node/perf_hooks.d.ts +1054 -0
  54. package/node_modules/@types/node/process.d.ts +2101 -0
  55. package/node_modules/@types/node/punycode.d.ts +117 -0
  56. package/node_modules/@types/node/querystring.d.ts +152 -0
  57. package/node_modules/@types/node/readline/promises.d.ts +161 -0
  58. package/node_modules/@types/node/readline.d.ts +600 -0
  59. package/node_modules/@types/node/repl.d.ts +438 -0
  60. package/node_modules/@types/node/sea.d.ts +162 -0
  61. package/node_modules/@types/node/sqlite.d.ts +1182 -0
  62. package/node_modules/@types/node/stream/consumers.d.ts +45 -0
  63. package/node_modules/@types/node/stream/promises.d.ts +90 -0
  64. package/node_modules/@types/node/stream/web.d.ts +596 -0
  65. package/node_modules/@types/node/stream.d.ts +1707 -0
  66. package/node_modules/@types/node/string_decoder.d.ts +67 -0
  67. package/node_modules/@types/node/test.d.ts +2656 -0
  68. package/node_modules/@types/node/timers/promises.d.ts +108 -0
  69. package/node_modules/@types/node/timers.d.ts +285 -0
  70. package/node_modules/@types/node/tls.d.ts +1314 -0
  71. package/node_modules/@types/node/trace_events.d.ts +197 -0
  72. package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +473 -0
  73. package/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
  74. package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
  75. package/node_modules/@types/node/ts5.6/index.d.ts +103 -0
  76. package/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
  77. package/node_modules/@types/node/ts5.7/index.d.ts +103 -0
  78. package/node_modules/@types/node/tty.d.ts +209 -0
  79. package/node_modules/@types/node/url.d.ts +1103 -0
  80. package/node_modules/@types/node/util.d.ts +2376 -0
  81. package/node_modules/@types/node/v8.d.ts +1010 -0
  82. package/node_modules/@types/node/vm.d.ts +1160 -0
  83. package/node_modules/@types/node/wasi.d.ts +202 -0
  84. package/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
  85. package/node_modules/@types/node/web-globals/crypto.d.ts +32 -0
  86. package/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  87. package/node_modules/@types/node/web-globals/events.d.ts +97 -0
  88. package/node_modules/@types/node/web-globals/fetch.d.ts +62 -0
  89. package/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
  90. package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
  91. package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
  92. package/node_modules/@types/node/worker_threads.d.ts +894 -0
  93. package/node_modules/@types/node/zlib.d.ts +768 -0
  94. package/node_modules/@valibot/to-json-schema/LICENSE.md +9 -0
  95. package/node_modules/@valibot/to-json-schema/README.md +475 -0
  96. package/node_modules/@valibot/to-json-schema/dist/index.cjs +800 -0
  97. package/node_modules/@valibot/to-json-schema/dist/index.d.cts +991 -0
  98. package/node_modules/@valibot/to-json-schema/dist/index.d.mts +991 -0
  99. package/node_modules/@valibot/to-json-schema/dist/index.min.cjs +1 -0
  100. package/node_modules/@valibot/to-json-schema/dist/index.min.mjs +1 -0
  101. package/node_modules/@valibot/to-json-schema/dist/index.mjs +795 -0
  102. package/node_modules/@valibot/to-json-schema/package.json +75 -0
  103. package/node_modules/@ykdz/cli-contract/LICENSE +21 -0
  104. package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.d.ts +17 -0
  105. package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.js +55 -0
  106. package/node_modules/@ykdz/cli-contract/dist/cli-contract.d.ts +1164 -0
  107. package/node_modules/@ykdz/cli-contract/dist/cli-contract.js +1408 -0
  108. package/node_modules/@ykdz/cli-contract/dist/cli-execution.d.ts +54 -0
  109. package/node_modules/@ykdz/cli-contract/dist/cli-execution.js +708 -0
  110. package/node_modules/@ykdz/cli-contract/dist/cli-invocation.d.ts +174 -0
  111. package/node_modules/@ykdz/cli-contract/dist/cli-invocation.js +524 -0
  112. package/node_modules/@ykdz/cli-contract/dist/cli-write-error.d.ts +10 -0
  113. package/node_modules/@ykdz/cli-contract/dist/cli-write-error.js +14 -0
  114. package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.d.ts +260 -0
  115. package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.js +130 -0
  116. package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.d.ts +63 -0
  117. package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.js +17 -0
  118. package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.d.ts +6 -0
  119. package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.js +532 -0
  120. package/node_modules/@ykdz/cli-contract/dist/contract-schema.d.ts +14 -0
  121. package/node_modules/@ykdz/cli-contract/dist/contract-schema.js +1 -0
  122. package/node_modules/@ykdz/cli-contract/dist/description.d.ts +2 -0
  123. package/node_modules/@ykdz/cli-contract/dist/description.js +13 -0
  124. package/node_modules/@ykdz/cli-contract/dist/index.d.ts +8 -0
  125. package/node_modules/@ykdz/cli-contract/dist/index.js +7 -0
  126. package/node_modules/@ykdz/cli-contract/dist/json-value.d.ts +4 -0
  127. package/node_modules/@ykdz/cli-contract/dist/json-value.js +64 -0
  128. package/node_modules/@ykdz/cli-contract/dist/node.d.ts +21 -0
  129. package/node_modules/@ykdz/cli-contract/dist/node.js +109 -0
  130. package/node_modules/@ykdz/cli-contract/dist/outcome-fact.d.ts +162 -0
  131. package/node_modules/@ykdz/cli-contract/dist/outcome-fact.js +113 -0
  132. package/node_modules/@ykdz/cli-contract/dist/outcome-wire.d.ts +53 -0
  133. package/node_modules/@ykdz/cli-contract/dist/outcome-wire.js +189 -0
  134. package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.d.ts +16 -0
  135. package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.js +45 -0
  136. package/node_modules/@ykdz/cli-contract/package.json +69 -0
  137. package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.d.ts +20 -0
  138. package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.js +5 -0
  139. package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.d.ts +19 -0
  140. package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.js +1 -1
  141. package/node_modules/@ykdz/template-builtin-presets/dist/src/index.d.ts +2 -1
  142. package/node_modules/@ykdz/template-builtin-presets/dist/src/index.js +2 -1
  143. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-cli/definition.js +9 -5
  144. package/node_modules/@ykdz/template-builtin-presets/package.json +2 -1
  145. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/AGENTS.md.template +3 -3
  146. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/artifact.ts +128 -59
  147. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/handoff.ts +80 -8
  148. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/readiness.ts +7 -3
  149. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/cli.ts +9 -19
  150. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/main.ts +144 -60
  151. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/standard-schema.ts +37 -0
  152. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/lookup.journey.ts +71 -0
  153. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/integration/command.test.ts +118 -59
  154. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +2 -1
  155. package/node_modules/@ykdz/template-core/dist/project-blueprint.d.ts +15 -0
  156. package/node_modules/@ykdz/template-core/dist/project-blueprint.js +1 -1
  157. package/node_modules/undici-types/LICENSE +21 -0
  158. package/node_modules/undici-types/README.md +6 -0
  159. package/node_modules/undici-types/agent.d.ts +32 -0
  160. package/node_modules/undici-types/api.d.ts +43 -0
  161. package/node_modules/undici-types/balanced-pool.d.ts +30 -0
  162. package/node_modules/undici-types/cache-interceptor.d.ts +179 -0
  163. package/node_modules/undici-types/cache.d.ts +36 -0
  164. package/node_modules/undici-types/client-stats.d.ts +15 -0
  165. package/node_modules/undici-types/client.d.ts +123 -0
  166. package/node_modules/undici-types/connector.d.ts +36 -0
  167. package/node_modules/undici-types/content-type.d.ts +21 -0
  168. package/node_modules/undici-types/cookies.d.ts +30 -0
  169. package/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
  170. package/node_modules/undici-types/dispatcher.d.ts +279 -0
  171. package/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
  172. package/node_modules/undici-types/errors.d.ts +177 -0
  173. package/node_modules/undici-types/eventsource.d.ts +66 -0
  174. package/node_modules/undici-types/fetch.d.ts +211 -0
  175. package/node_modules/undici-types/formdata.d.ts +108 -0
  176. package/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  177. package/node_modules/undici-types/global-origin.d.ts +7 -0
  178. package/node_modules/undici-types/h2c-client.d.ts +73 -0
  179. package/node_modules/undici-types/handlers.d.ts +15 -0
  180. package/node_modules/undici-types/header.d.ts +160 -0
  181. package/node_modules/undici-types/index.d.ts +91 -0
  182. package/node_modules/undici-types/interceptors.d.ts +80 -0
  183. package/node_modules/undici-types/mock-agent.d.ts +68 -0
  184. package/node_modules/undici-types/mock-call-history.d.ts +111 -0
  185. package/node_modules/undici-types/mock-client.d.ts +27 -0
  186. package/node_modules/undici-types/mock-errors.d.ts +12 -0
  187. package/node_modules/undici-types/mock-interceptor.d.ts +94 -0
  188. package/node_modules/undici-types/mock-pool.d.ts +27 -0
  189. package/node_modules/undici-types/package.json +55 -0
  190. package/node_modules/undici-types/patch.d.ts +29 -0
  191. package/node_modules/undici-types/pool-stats.d.ts +19 -0
  192. package/node_modules/undici-types/pool.d.ts +41 -0
  193. package/node_modules/undici-types/proxy-agent.d.ts +29 -0
  194. package/node_modules/undici-types/readable.d.ts +68 -0
  195. package/node_modules/undici-types/retry-agent.d.ts +8 -0
  196. package/node_modules/undici-types/retry-handler.d.ts +125 -0
  197. package/node_modules/undici-types/round-robin-pool.d.ts +41 -0
  198. package/node_modules/undici-types/snapshot-agent.d.ts +109 -0
  199. package/node_modules/undici-types/socks5-proxy-agent.d.ts +25 -0
  200. package/node_modules/undici-types/util.d.ts +18 -0
  201. package/node_modules/undici-types/utility.d.ts +7 -0
  202. package/node_modules/undici-types/webidl.d.ts +347 -0
  203. package/node_modules/undici-types/websocket.d.ts +188 -0
  204. package/package.json +5 -3
  205. package/dist/command-result.d.ts +0 -9
  206. package/dist/command-result.js +0 -231
  207. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/greet.journey.ts +0 -46
  208. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/unit/greet.test.ts +0 -15
  209. package/node_modules/commander/LICENSE +0 -22
  210. package/node_modules/commander/Readme.md +0 -1172
  211. package/node_modules/commander/index.js +0 -21
  212. package/node_modules/commander/lib/argument.js +0 -147
  213. package/node_modules/commander/lib/command.js +0 -2790
  214. package/node_modules/commander/lib/error.js +0 -36
  215. package/node_modules/commander/lib/help.js +0 -731
  216. package/node_modules/commander/lib/option.js +0 -377
  217. package/node_modules/commander/lib/suggestSimilar.js +0 -99
  218. package/node_modules/commander/package-support.json +0 -19
  219. package/node_modules/commander/package.json +0 -64
  220. package/node_modules/commander/typings/index.d.ts +0 -1113
@@ -0,0 +1,532 @@
1
+ import { isSingleLineText } from "#/description";
2
+ import { copyJsonObject, deepFreeze } from "#/json-value";
3
+ export function compileContractSchema(schema, target, issues, description) {
4
+ const initialIssueCount = issues.length;
5
+ const standard = schema?.["~standard"];
6
+ if (typeof standard !== "object" || standard === null) {
7
+ issues.push({
8
+ code: "missingSchemaCapability",
9
+ ...target,
10
+ capability: "standard",
11
+ });
12
+ return undefined;
13
+ }
14
+ if (typeof standard.validate !== "function") {
15
+ issues.push({
16
+ code: "missingSchemaCapability",
17
+ ...target,
18
+ capability: "validation",
19
+ });
20
+ return undefined;
21
+ }
22
+ if (typeof standard.jsonSchema !== "object" ||
23
+ standard.jsonSchema === null ||
24
+ typeof standard.jsonSchema.input !== "function" ||
25
+ typeof standard.jsonSchema.output !== "function") {
26
+ issues.push({
27
+ code: "missingSchemaCapability",
28
+ ...target,
29
+ capability: "jsonSchema",
30
+ });
31
+ return undefined;
32
+ }
33
+ const exportedInput = exportSchemaProjection(standard.jsonSchema.input, target, "input", issues);
34
+ const exportedOutput = exportSchemaProjection(standard.jsonSchema.output, target, "output", issues);
35
+ const copiedInputSchema = exportedInput === undefined
36
+ ? undefined
37
+ : copySchemaProjection(exportedInput, target, "input", issues);
38
+ const copiedOutputSchema = exportedOutput === undefined
39
+ ? undefined
40
+ : copySchemaProjection(exportedOutput, target, "output", issues);
41
+ const inputSchema = copiedInputSchema === undefined || description === undefined
42
+ ? copiedInputSchema
43
+ : projectRootDescription(copiedInputSchema, description);
44
+ const outputSchema = copiedOutputSchema === undefined || description === undefined
45
+ ? copiedOutputSchema
46
+ : projectRootDescription(copiedOutputSchema, description);
47
+ if (inputSchema === undefined || outputSchema === undefined) {
48
+ return undefined;
49
+ }
50
+ checkDraft202012(inputSchema, target, "input", issues);
51
+ checkDraft202012(outputSchema, target, "output", issues);
52
+ checkInputDefaults(inputSchema, outputSchema, target, issues);
53
+ return issues.length === initialIssueCount
54
+ ? { inputSchema, outputSchema }
55
+ : undefined;
56
+ }
57
+ export function projectFieldDescriptions(schema, fields) {
58
+ return deepFreeze({
59
+ inputSchema: projectPropertyDescriptions(schema.inputSchema, fields),
60
+ outputSchema: projectPropertyDescriptions(schema.outputSchema, fields),
61
+ });
62
+ }
63
+ export function compileInputFields(definitions, inputSchema, command, issues) {
64
+ collectFieldDescriptionIssues(definitions, command, issues);
65
+ if (inputSchema.type !== "object") {
66
+ issues.push({
67
+ code: "invalidInputSchemaShape",
68
+ command,
69
+ location: "input",
70
+ aspect: "type",
71
+ });
72
+ return [];
73
+ }
74
+ const schemaProperties = readSchemaProperties(inputSchema);
75
+ if (schemaProperties === undefined) {
76
+ issues.push({
77
+ code: "invalidInputSchemaShape",
78
+ command,
79
+ location: "input",
80
+ aspect: "properties",
81
+ });
82
+ return [];
83
+ }
84
+ // oxlint-disable-next-line unicorn/no-array-sort -- Object.keys 新建的数组只在此处使用,原地排序不会影响共享状态。
85
+ const schemaKeys = Object.keys(schemaProperties).sort();
86
+ // oxlint-disable-next-line unicorn/no-array-sort -- Object.keys 新建的数组只在此处使用,原地排序不会影响共享状态。
87
+ const fieldKeys = Object.keys(definitions).sort();
88
+ if (schemaKeys.join("\0") !== fieldKeys.join("\0")) {
89
+ issues.push({
90
+ code: "schemaFieldSetMismatch",
91
+ command,
92
+ location: "input",
93
+ missingFields: schemaKeys.filter((key) => !fieldKeys.includes(key)),
94
+ unexpectedFields: fieldKeys.filter((key) => !schemaKeys.includes(key)),
95
+ });
96
+ return [];
97
+ }
98
+ const required = readRequiredSchemaKeys(inputSchema);
99
+ if (required === undefined) {
100
+ issues.push({
101
+ code: "invalidInputSchemaShape",
102
+ command,
103
+ location: "input",
104
+ aspect: "required",
105
+ });
106
+ return [];
107
+ }
108
+ const incompatibleFields = fieldKeys.flatMap((field) => {
109
+ const kind = definitions[field]?.kind;
110
+ const expected = kind === "flag"
111
+ ? "boolean"
112
+ : kind === "repeatableOption" || kind === "variadicPositional"
113
+ ? "stringArray"
114
+ : "string";
115
+ return schemaPropertyAcceptsRawValue(schemaProperties[field], expected)
116
+ ? []
117
+ : [{ field, expected }];
118
+ });
119
+ if (incompatibleFields.length > 0) {
120
+ issues.push({
121
+ code: "schemaFieldDoesNotAcceptRawValue",
122
+ command,
123
+ location: "input",
124
+ fields: incompatibleFields,
125
+ });
126
+ return [];
127
+ }
128
+ const fields = Object.entries(definitions).map(([key, field]) => {
129
+ if (!/^[a-z][A-Za-z0-9]*$/.test(key)) {
130
+ issues.push({ code: "invalidFieldIdentity", command, field: key });
131
+ }
132
+ const invalidKind = readInvalidFieldKind(field);
133
+ if (invalidKind !== undefined) {
134
+ issues.push({
135
+ code: "invalidFieldKind",
136
+ command,
137
+ field: key,
138
+ expected: [
139
+ "positional",
140
+ "variadicPositional",
141
+ "flag",
142
+ "valueOption",
143
+ "repeatableOption",
144
+ ],
145
+ received: invalidKind,
146
+ });
147
+ return {
148
+ kind: "positional",
149
+ key,
150
+ description: readFieldDescription(field),
151
+ required: required.has(key),
152
+ };
153
+ }
154
+ if (field.kind !== "positional" &&
155
+ field.kind !== "variadicPositional" &&
156
+ !/^--[a-z0-9]+(?:-[a-z0-9]+)*$/.test(field.longOption)) {
157
+ issues.push({
158
+ code: "invalidFieldLongOption",
159
+ command,
160
+ field: key,
161
+ received: typeof field.longOption === "string" ? field.longOption : null,
162
+ });
163
+ }
164
+ if (field.kind !== "positional" &&
165
+ field.kind !== "variadicPositional" &&
166
+ field.shortAlias !== undefined &&
167
+ !/^-[A-Za-z0-9]$/.test(field.shortAlias)) {
168
+ issues.push({
169
+ code: "invalidFieldShortAlias",
170
+ command,
171
+ field: key,
172
+ received: typeof field.shortAlias === "string" ? field.shortAlias : null,
173
+ });
174
+ }
175
+ if (field.kind === "flag" &&
176
+ field.negatedLongOption !== undefined &&
177
+ !/^--[a-z0-9]+(?:-[a-z0-9]+)*$/.test(field.negatedLongOption)) {
178
+ issues.push({
179
+ code: "invalidFieldLongOption",
180
+ command,
181
+ field: key,
182
+ received: typeof field.negatedLongOption === "string"
183
+ ? field.negatedLongOption
184
+ : null,
185
+ });
186
+ }
187
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 字段 kind 与拼写已按声明检查,展开后保留对应联合成员。
188
+ return {
189
+ ...field,
190
+ key,
191
+ required: required.has(key),
192
+ ...readSchemaDefault(schemaProperties[key]),
193
+ ...readFieldChoices(schemaProperties[key], field.kind),
194
+ };
195
+ });
196
+ const fieldsByLongOption = new Map();
197
+ for (const field of fields) {
198
+ if (field.kind === "positional" || field.kind === "variadicPositional") {
199
+ continue;
200
+ }
201
+ for (const spelling of [
202
+ field.longOption,
203
+ field.kind === "flag" ? field.negatedLongOption : undefined,
204
+ ]) {
205
+ if (spelling === undefined)
206
+ continue;
207
+ const matchingFields = fieldsByLongOption.get(spelling) ?? [];
208
+ matchingFields.push(field);
209
+ fieldsByLongOption.set(spelling, matchingFields);
210
+ }
211
+ }
212
+ for (const [longOption, matchingFields] of fieldsByLongOption) {
213
+ if (matchingFields.length > 1) {
214
+ issues.push({
215
+ code: "duplicateFieldLongOption",
216
+ command,
217
+ longOption,
218
+ // oxlint-disable-next-line unicorn/no-array-sort -- 集合展开后是新数组,原地排序不修改源字段。
219
+ fields: [...new Set(matchingFields.map((field) => field.key))].sort(),
220
+ });
221
+ }
222
+ }
223
+ const fieldsByShortAlias = new Map();
224
+ for (const field of fields) {
225
+ if (field.kind === "positional" ||
226
+ field.kind === "variadicPositional" ||
227
+ field.shortAlias === undefined) {
228
+ continue;
229
+ }
230
+ const matchingFields = fieldsByShortAlias.get(field.shortAlias) ?? [];
231
+ matchingFields.push(field);
232
+ fieldsByShortAlias.set(field.shortAlias, matchingFields);
233
+ }
234
+ for (const [spelling, matchingFields] of fieldsByShortAlias) {
235
+ if (matchingFields.length > 1) {
236
+ issues.push({
237
+ code: "duplicateFieldOptionSpelling",
238
+ command,
239
+ spelling,
240
+ // oxlint-disable-next-line unicorn/no-array-sort -- map 新建的数组只用于本条问题,原地排序不修改源字段。
241
+ fields: matchingFields.map((field) => field.key).sort(),
242
+ });
243
+ }
244
+ }
245
+ let precedingOptionalField;
246
+ let variadicField;
247
+ for (const field of fields) {
248
+ if (field.kind !== "positional" && field.kind !== "variadicPositional") {
249
+ continue;
250
+ }
251
+ if (variadicField !== undefined) {
252
+ issues.push({
253
+ code: "positionalAfterVariadic",
254
+ command,
255
+ field: field.key,
256
+ variadicField,
257
+ });
258
+ }
259
+ if (field.kind === "variadicPositional")
260
+ variadicField ??= field.key;
261
+ if (!field.required) {
262
+ precedingOptionalField ??= field.key;
263
+ }
264
+ else if (precedingOptionalField !== undefined) {
265
+ issues.push({
266
+ code: "requiredPositionalAfterOptional",
267
+ command,
268
+ field: field.key,
269
+ precedingOptionalField,
270
+ });
271
+ }
272
+ }
273
+ return deepFreeze(fields);
274
+ }
275
+ function collectFieldDescriptionIssues(definitions, command, issues) {
276
+ for (const [field, definition] of Object.entries(definitions)) {
277
+ const description = readRawFieldDescription(definition);
278
+ if (isSingleLineText(description))
279
+ continue;
280
+ issues.push({
281
+ code: "invalidDescription",
282
+ command,
283
+ location: "field",
284
+ field,
285
+ received: typeof description === "string" ? description : null,
286
+ });
287
+ }
288
+ }
289
+ function projectRootDescription(schema, description) {
290
+ return deepFreeze({ ...schema, description });
291
+ }
292
+ function projectPropertyDescriptions(schema, fields) {
293
+ const properties = readSchemaProperties(schema);
294
+ if (properties === undefined)
295
+ return schema;
296
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 来源是已复制的 JSON Schema 属性,替换值仍是 JSON 值。
297
+ const projectedProperties = Object.fromEntries(Object.entries(properties).map(([key, property]) => {
298
+ const field = fields.find((candidate) => candidate.key === key);
299
+ if (field === undefined)
300
+ return [key, property];
301
+ if (property === true)
302
+ return [key, { description: field.description }];
303
+ if (typeof property !== "object" ||
304
+ property === null ||
305
+ Array.isArray(property)) {
306
+ return [key, property];
307
+ }
308
+ return [
309
+ key,
310
+ Object.assign({}, property, { description: field.description }),
311
+ ];
312
+ }));
313
+ return deepFreeze({ ...schema, properties: projectedProperties });
314
+ }
315
+ function readInvalidFieldKind(field) {
316
+ if (typeof field !== "object" || field === null || !("kind" in field)) {
317
+ return null;
318
+ }
319
+ const kind = field.kind;
320
+ return kind === "positional" ||
321
+ kind === "variadicPositional" ||
322
+ kind === "flag" ||
323
+ kind === "valueOption" ||
324
+ kind === "repeatableOption"
325
+ ? undefined
326
+ : typeof kind === "string"
327
+ ? kind
328
+ : null;
329
+ }
330
+ function readFieldDescription(field) {
331
+ return typeof field === "object" &&
332
+ field !== null &&
333
+ "description" in field &&
334
+ typeof field.description === "string"
335
+ ? field.description
336
+ : "";
337
+ }
338
+ function readRawFieldDescription(field) {
339
+ return typeof field === "object" && field !== null && "description" in field
340
+ ? field.description
341
+ : undefined;
342
+ }
343
+ function copySchemaProjection(value, target, projection, issues) {
344
+ try {
345
+ return copyJsonObject(value);
346
+ }
347
+ catch {
348
+ issues.push({ code: "invalidSchemaProjection", ...target, projection });
349
+ return undefined;
350
+ }
351
+ }
352
+ function exportSchemaProjection(exporter, target, projection, issues) {
353
+ try {
354
+ return exporter({ target: "draft-2020-12" });
355
+ }
356
+ catch {
357
+ issues.push({ code: "schemaExportFailed", ...target, projection });
358
+ return undefined;
359
+ }
360
+ }
361
+ function checkDraft202012(schema, target, projection, issues) {
362
+ const dialect = schema.$schema;
363
+ if (dialect !== "https://json-schema.org/draft/2020-12/schema") {
364
+ issues.push({
365
+ code: "schemaDialectMismatch",
366
+ ...target,
367
+ projection,
368
+ received: typeof dialect === "string" ? dialect : null,
369
+ });
370
+ }
371
+ }
372
+ function checkInputDefaults(inputSchema, outputSchema, target, issues) {
373
+ if (target.location !== "input")
374
+ return;
375
+ const inputProperties = readSchemaProperties(inputSchema);
376
+ const inputRequired = readRequiredSchemaKeys(inputSchema);
377
+ const outputPropertiesValid = checkOutputSchemaProperties(outputSchema, target, issues);
378
+ const outputRequired = readOutputRequiredSchemaKeys(outputSchema, target, issues);
379
+ if (inputProperties === undefined ||
380
+ inputRequired === undefined ||
381
+ !outputPropertiesValid ||
382
+ outputRequired === undefined) {
383
+ return;
384
+ }
385
+ for (const field of outputRequired) {
386
+ if (!Object.hasOwn(inputProperties, field)) {
387
+ issues.push({
388
+ code: "outputRequiredFieldMissingFromInput",
389
+ command: target.command,
390
+ location: "input",
391
+ field,
392
+ });
393
+ continue;
394
+ }
395
+ if (inputRequired.has(field)) {
396
+ continue;
397
+ }
398
+ if (readSchemaDefault(inputProperties[field]) === undefined) {
399
+ issues.push({
400
+ code: "missingInputDefault",
401
+ command: target.command,
402
+ location: "input",
403
+ field,
404
+ });
405
+ }
406
+ }
407
+ }
408
+ function checkOutputSchemaProperties(schema, target, issues) {
409
+ const properties = schema.properties;
410
+ if (properties === undefined)
411
+ return true;
412
+ if (typeof properties !== "object" ||
413
+ properties === null ||
414
+ Array.isArray(properties)) {
415
+ issues.push({
416
+ code: "invalidOutputSchemaShape",
417
+ command: target.command,
418
+ location: "input",
419
+ aspect: "properties",
420
+ });
421
+ return false;
422
+ }
423
+ return true;
424
+ }
425
+ function readOutputRequiredSchemaKeys(schema, target, issues) {
426
+ const required = schema.required;
427
+ if (required === undefined)
428
+ return new Set();
429
+ if (!Array.isArray(required) ||
430
+ required.some((key) => typeof key !== "string")) {
431
+ issues.push({
432
+ code: "invalidOutputSchemaShape",
433
+ command: target.command,
434
+ location: "input",
435
+ aspect: "required",
436
+ });
437
+ return undefined;
438
+ }
439
+ return new Set(required);
440
+ }
441
+ function readSchemaProperties(schema) {
442
+ const properties = schema.properties;
443
+ if (typeof properties !== "object" ||
444
+ properties === null ||
445
+ Array.isArray(properties)) {
446
+ return undefined;
447
+ }
448
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 已在上方排除 null 和数组;TS 对只读数组联合仍需收窄。
449
+ return properties;
450
+ }
451
+ function readSchemaDefault(propertySchema) {
452
+ if (typeof propertySchema !== "object" ||
453
+ propertySchema === null ||
454
+ Array.isArray(propertySchema) ||
455
+ !Object.hasOwn(propertySchema, "default")) {
456
+ return undefined;
457
+ }
458
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 模式投影在进入本函数前已复制并验证为 JSON 值。
459
+ const defaultValue = propertySchema.default;
460
+ if (defaultValue === undefined)
461
+ return undefined;
462
+ return {
463
+ default: defaultValue,
464
+ };
465
+ }
466
+ function readFieldChoices(propertySchema, kind) {
467
+ const candidate = kind === "repeatableOption" || kind === "variadicPositional"
468
+ ? readDirectSchemaItems(propertySchema)
469
+ : propertySchema;
470
+ const values = readDirectStringEnum(candidate);
471
+ if (values === undefined) {
472
+ return undefined;
473
+ }
474
+ return { choices: values };
475
+ }
476
+ function readDirectSchemaItems(propertySchema) {
477
+ if (typeof propertySchema !== "object" ||
478
+ propertySchema === null ||
479
+ Array.isArray(propertySchema) ||
480
+ !Object.hasOwn(propertySchema, "items") ||
481
+ !("items" in propertySchema)) {
482
+ return undefined;
483
+ }
484
+ return propertySchema.items;
485
+ }
486
+ function readDirectStringEnum(schema) {
487
+ if (typeof schema !== "object" || schema === null || Array.isArray(schema)) {
488
+ return undefined;
489
+ }
490
+ if (["anyOf", "oneOf", "$ref", "if", "then", "else"].some((keyword) => Object.hasOwn(schema, keyword))) {
491
+ return undefined;
492
+ }
493
+ const values = "enum" in schema ? schema.enum : undefined;
494
+ if (!Array.isArray(values) ||
495
+ values.length === 0 ||
496
+ values.some((value) => typeof value !== "string")) {
497
+ return undefined;
498
+ }
499
+ return Object.freeze([...values]);
500
+ }
501
+ function readRequiredSchemaKeys(schema) {
502
+ const required = schema.required;
503
+ if (required === undefined) {
504
+ return new Set();
505
+ }
506
+ if (!Array.isArray(required) ||
507
+ required.some((key) => typeof key !== "string")) {
508
+ return undefined;
509
+ }
510
+ return new Set(required);
511
+ }
512
+ function schemaPropertyAcceptsRawValue(propertySchema, rawType) {
513
+ if (propertySchema === true) {
514
+ return true;
515
+ }
516
+ if (typeof propertySchema !== "object" ||
517
+ propertySchema === null ||
518
+ Array.isArray(propertySchema) ||
519
+ !("type" in propertySchema)) {
520
+ return false;
521
+ }
522
+ if (rawType === "stringArray") {
523
+ return ((propertySchema.type === "array" ||
524
+ (Array.isArray(propertySchema.type) &&
525
+ propertySchema.type.includes("array"))) &&
526
+ "items" in propertySchema &&
527
+ schemaPropertyAcceptsRawValue(propertySchema.items, "string"));
528
+ }
529
+ return (propertySchema.type === rawType ||
530
+ (Array.isArray(propertySchema.type) &&
531
+ propertySchema.type.includes(rawType)));
532
+ }
@@ -0,0 +1,14 @@
1
+ import type { StandardJSONSchemaV1, StandardSchemaV1 } from "@standard-schema/spec";
2
+ export type JsonPrimitive = boolean | null | number | string;
3
+ export type JsonValue = JsonPrimitive | readonly JsonValue[] | {
4
+ readonly [key: string]: JsonValue;
5
+ };
6
+ export type JsonObject = {
7
+ readonly [key: string]: JsonValue;
8
+ };
9
+ export interface ContractSchema<Input = unknown, Output = Input> {
10
+ readonly "~standard": StandardSchemaV1.Props<Input, Output> & StandardJSONSchemaV1.Props<Input, Output>;
11
+ }
12
+ export type ContractSchemaInput<Schema> = Schema extends ContractSchema<infer Input, unknown> ? Input : never;
13
+ export type ContractSchemaOutput<Schema> = Schema extends ContractSchema<unknown, infer Output> ? Output : never;
14
+ export type EmptyCliInput = Readonly<Record<string, never>>;
@@ -0,0 +1,2 @@
1
+ export declare function isSingleLineText(value: unknown): value is string;
2
+ export declare function copySingleLineText(value: unknown, label: string): string;
@@ -0,0 +1,13 @@
1
+ export function isSingleLineText(value) {
2
+ return (typeof value === "string" &&
3
+ value.length > 0 &&
4
+ !value.includes("\r") &&
5
+ !value.includes("\n") &&
6
+ !value.includes("\0"));
7
+ }
8
+ export function copySingleLineText(value, label) {
9
+ if (!isSingleLineText(value)) {
10
+ throw new TypeError(`${label}必须是合法单行文本`);
11
+ }
12
+ return value;
13
+ }
@@ -0,0 +1,8 @@
1
+ /** 完整示例:https://github.com/YKDZ/cli-contract/tree/v0.2.1/packages/example */
2
+ export { defineCli, helpCapability, outputCapability, versionCapability, type CliContract, type CliContractDependencies, type CliContractRawInput, type CliContractResult, type CliContractRoot, type CliGrammar, type CliManifest, type CommandGrammar, type CommandGroupDefinition, type CommandGroupGrammar, type CommandGroupManifest, type CommandWireManifest, type CanonicalLongOption, type CompletionFact, type CompletionHandlerContext, type CompletionOutcome, type CompletionRootCliDefinition, type CompletionRootCommandDefinition, type ContractTypeError, type DataFact, type DataFactUnion, type DataHandlerContext, type DataOutcome, type DataRootCliDefinition, type DataRootCommandDefinition, type DataVariantDefinition, type DataVariantDefinitions, type StreamHandlerContext, type StreamOutcome, type StreamRecordDefinition, type StreamRecordDefinitions, type StreamRecordFact, type StreamRecordFactUnion, type StreamRootCliDefinition, type StreamRootCommandDefinition, type StreamSuccessFact, type DefineCli, type DefineCommand, type FailureFact, type FailureFactUnion, type FailureOutcome, type FailureVariantDefinition, type FailureVariantDefinitions, type FailureVariantManifest, type FieldDefinition, type FieldDefinitions, type FieldDefinitionsForInput, type FieldGrammar, type ForbiddenCombinationUsageConstraint, type ForbiddenCombinationValue, type FlagDefinition, type FlagGrammar, type HelpCapability, type HelpCapabilityDefinition, type HelpFactWording, type HelpHeadings, type HierarchyCliGrammar, type HierarchyCliManifest, type OutcomeFact, type OutputCapability, type OutputFormat, text, type SilentText, type TextLine, type TextLines, type PositionalDefinition, type PositionalGrammar, type RepeatableOptionDefinition, type RepeatableOptionGrammar, type RequiresUsageConstraint, type RawFieldInput, type RawValueOptionInput, type RawValueOptionInputForSchema, type RootCliDefinition, type RootGroupDefinition, type RootGroupGrammar, type RootCommandDefinition, type RootCommandGrammar, type RootCommandManifest, type ExecutableCommandDefinition, type ExecutableCommandGrammar, type ExecutableCommandManifest, type ShortOptionAlias, type SchemaManifest, type ValueOptionDefinition, type ValueOptionDefinitions, type ValueOptionDefinitionsForInput, type ValueOptionGrammar, type VersionCapability, type VersionCapabilityDefinition, type VariadicPositionalDefinition, type VariadicPositionalGrammar, type UsageConstraint, type UsageConstraintGrammar, type ExclusiveUsageConstraint, } from "#/cli-contract";
3
+ export { executeCli, type CliOutput, type CliOutputDestination, type CliTermination, type ExecuteCliOptions, type WriteCliOutput, } from "#/cli-execution";
4
+ export { CliWriteError } from "#/cli-write-error";
5
+ export { parseCliInvocation, type CliInvocation, type CommandUsage, type ConflictingFlagIssue, type ConflictingOutputFormatIssue, type ExclusiveUsageConstraintIssue, type ForbiddenUsageCombinationIssue, type HelpRequest, type InputRejectedIssue, type InvalidFieldChoiceIssue, type InvalidOutputFormatIssue, type MissingOptionValueIssue, type MissingRequiredFieldIssue, type NonEmptyUsageIssues, type OptionOccurrenceEvidence, type ParsedInvocation, type RepeatedOptionIssue, type RequiredByUsageConstraintIssue, type SchemaIssueEvidence, type UnexpectedPositionalIssue, type UnexpectedOptionValueIssue, type UnknownOptionIssue, type UnknownCommandIssue, type UsageIssue, type UsageFailure, type VersionRequest, } from "#/cli-invocation";
6
+ export { ContractExecutionError, type ContractExecutionIssue, } from "#/contract-execution-error";
7
+ export { ContractDefinitionError, type ContractDefinitionIssue, type SchemaDefinitionTarget, } from "#/contract-definition-error";
8
+ export type { ContractSchema, ContractSchemaInput, ContractSchemaOutput, EmptyCliInput, JsonObject, JsonPrimitive, JsonValue, } from "#/contract-schema";
@@ -0,0 +1,7 @@
1
+ /** 完整示例:https://github.com/YKDZ/cli-contract/tree/v0.2.1/packages/example */
2
+ export { defineCli, helpCapability, outputCapability, versionCapability, text, } from "#/cli-contract";
3
+ export { executeCli, } from "#/cli-execution";
4
+ export { CliWriteError } from "#/cli-write-error";
5
+ export { parseCliInvocation, } from "#/cli-invocation";
6
+ export { ContractExecutionError, } from "#/contract-execution-error";
7
+ export { ContractDefinitionError, } from "#/contract-definition-error";
@@ -0,0 +1,4 @@
1
+ import type { JsonObject, JsonValue } from "#/contract-schema";
2
+ export declare function copyJsonObject(value: Record<string, unknown>): JsonObject;
3
+ export declare function copyJsonValue(value: unknown): JsonValue;
4
+ export declare function deepFreeze<const Value>(value: Value): Readonly<Value>;
@@ -0,0 +1,64 @@
1
+ export function copyJsonObject(value) {
2
+ const copy = copyJsonValue(value);
3
+ if (typeof copy !== "object" || copy === null || Array.isArray(copy)) {
4
+ throw new TypeError("invalidJsonSchemaObject");
5
+ }
6
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 上方已排除 null 和数组,复制结果只能是 JSON object。
7
+ return copy;
8
+ }
9
+ export function copyJsonValue(value) {
10
+ return copyJsonValueWithAncestors(value, new WeakSet());
11
+ }
12
+ export function deepFreeze(value) {
13
+ if (typeof value !== "object" || value === null || Object.isFrozen(value)) {
14
+ return value;
15
+ }
16
+ for (const item of Object.values(value)) {
17
+ deepFreeze(item);
18
+ }
19
+ return Object.freeze(value);
20
+ }
21
+ function copyJsonValueWithAncestors(value, ancestors) {
22
+ if (value === null ||
23
+ typeof value === "boolean" ||
24
+ typeof value === "string") {
25
+ return value;
26
+ }
27
+ if (typeof value === "number") {
28
+ if (!Number.isFinite(value)) {
29
+ throw new TypeError("nonFiniteJsonNumber");
30
+ }
31
+ return value;
32
+ }
33
+ if (typeof value !== "object") {
34
+ throw new TypeError("nonJsonValue");
35
+ }
36
+ if (ancestors.has(value)) {
37
+ throw new TypeError("cyclicJsonValue");
38
+ }
39
+ if (!Array.isArray(value) &&
40
+ Object.getPrototypeOf(value) !== Object.prototype &&
41
+ Object.getPrototypeOf(value) !== null) {
42
+ throw new TypeError("invalidJsonObject");
43
+ }
44
+ if (Object.getOwnPropertySymbols(value).length > 0) {
45
+ throw new TypeError("symbolKeyInJsonObject");
46
+ }
47
+ ancestors.add(value);
48
+ const copy = Array.isArray(value)
49
+ ? copyJsonArray(value, ancestors)
50
+ : Object.fromEntries(Object.entries(value).map(([key, item]) => [
51
+ key,
52
+ copyJsonValueWithAncestors(item, ancestors),
53
+ ]));
54
+ ancestors.delete(value);
55
+ return deepFreeze(copy);
56
+ }
57
+ function copyJsonArray(value, ancestors) {
58
+ return Array.from({ length: value.length }, (_, index) => {
59
+ if (!(index in value)) {
60
+ throw new TypeError("sparseJsonArray");
61
+ }
62
+ return copyJsonValueWithAncestors(value[index], ancestors);
63
+ });
64
+ }
@@ -0,0 +1,21 @@
1
+ /** 完整示例:https://github.com/YKDZ/cli-contract/tree/v0.2.1/packages/example */
2
+ /// <reference types="node" preserve="true" />
3
+ import type { Writable } from "node:stream";
4
+ import type { WriteCliOutput } from "#/cli-execution";
5
+ export interface NodeCliOutputOptions {
6
+ readonly stdout: Writable;
7
+ readonly stderr: Writable;
8
+ }
9
+ /**
10
+ * 将调用方提供的 Writable 接到核心输出端口,按核心选择的 stdout/stderr 路由写入。
11
+ * 每次写入等待 callback;write 返回 false 时还等待 drain,以承接执行内核的顺序与背压。
12
+ *
13
+ * 适配器不读取全局 process,也不关闭流、设置退出状态或接管 CLI 框架生命周期。
14
+ * 宿主应等待 executeCli 完成,再处理退出;写入异常交回调用方,不自动忽略 EPIPE。
15
+ */
16
+ export declare function nodeCliOutput({ stdout, stderr, }: NodeCliOutputOptions): WriteCliOutput;
17
+ /**
18
+ * 检查错误对象及其 cause 链是否携带 EPIPE,可用于识别 CliWriteError 保留的断管原因。
19
+ * 这里只检测断管,不吞掉异常、恢复写入或决定进程退出码;其他异常仍由宿主处理。
20
+ */
21
+ export declare function isNodeBrokenPipe(error: unknown): boolean;