padrone 1.8.2 → 2.0.0

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 (333) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +2 -2
  3. package/dist/codegen/code-builder.d.mts +10 -0
  4. package/dist/codegen/code-builder.d.mts.map +1 -0
  5. package/dist/codegen/code-builder.mjs +185 -0
  6. package/dist/codegen/code-builder.mjs.map +1 -0
  7. package/dist/codegen/discovery.d.mts +44 -0
  8. package/dist/codegen/discovery.d.mts.map +1 -0
  9. package/dist/codegen/discovery.mjs +179 -0
  10. package/dist/codegen/discovery.mjs.map +1 -0
  11. package/dist/codegen/file-emitter.d.mts +10 -0
  12. package/dist/codegen/file-emitter.d.mts.map +1 -0
  13. package/dist/codegen/file-emitter.mjs +58 -0
  14. package/dist/codegen/file-emitter.mjs.map +1 -0
  15. package/dist/codegen/generators/barrel-file.d.mts +10 -0
  16. package/dist/codegen/generators/barrel-file.d.mts.map +1 -0
  17. package/dist/codegen/generators/barrel-file.mjs +16 -0
  18. package/dist/codegen/generators/barrel-file.mjs.map +1 -0
  19. package/dist/codegen/generators/command-file.d.mts +25 -0
  20. package/dist/codegen/generators/command-file.d.mts.map +1 -0
  21. package/dist/codegen/generators/command-file.mjs +130 -0
  22. package/dist/codegen/generators/command-file.mjs.map +1 -0
  23. package/dist/codegen/generators/command-tree.d.mts +17 -0
  24. package/dist/codegen/generators/command-tree.d.mts.map +1 -0
  25. package/dist/codegen/generators/command-tree.mjs +72 -0
  26. package/dist/codegen/generators/command-tree.mjs.map +1 -0
  27. package/dist/codegen/index.d.mts +15 -330
  28. package/dist/codegen/index.mjs +13 -1507
  29. package/dist/codegen/parsers/bash.d.mts +19 -0
  30. package/dist/codegen/parsers/bash.d.mts.map +1 -0
  31. package/dist/codegen/parsers/bash.mjs +112 -0
  32. package/dist/codegen/parsers/bash.mjs.map +1 -0
  33. package/dist/codegen/parsers/fish.d.mts +13 -0
  34. package/dist/codegen/parsers/fish.d.mts.map +1 -0
  35. package/dist/codegen/parsers/fish.mjs +108 -0
  36. package/dist/codegen/parsers/fish.mjs.map +1 -0
  37. package/dist/codegen/parsers/help.d.mts +15 -0
  38. package/dist/codegen/parsers/help.d.mts.map +1 -0
  39. package/dist/codegen/parsers/help.mjs +271 -0
  40. package/dist/codegen/parsers/help.mjs.map +1 -0
  41. package/dist/codegen/parsers/merge.d.mts +14 -0
  42. package/dist/codegen/parsers/merge.d.mts.map +1 -0
  43. package/dist/codegen/parsers/merge.mjs +76 -0
  44. package/dist/codegen/parsers/merge.mjs.map +1 -0
  45. package/dist/codegen/parsers/zsh.d.mts +16 -0
  46. package/dist/codegen/parsers/zsh.d.mts.map +1 -0
  47. package/dist/codegen/parsers/zsh.mjs +161 -0
  48. package/dist/codegen/parsers/zsh.mjs.map +1 -0
  49. package/dist/codegen/schema-to-code.d.mts +24 -0
  50. package/dist/codegen/schema-to-code.d.mts.map +1 -0
  51. package/dist/codegen/schema-to-code.mjs +147 -0
  52. package/dist/codegen/schema-to-code.mjs.map +1 -0
  53. package/dist/codegen/template.d.mts +18 -0
  54. package/dist/codegen/template.d.mts.map +1 -0
  55. package/dist/codegen/template.mjs +37 -0
  56. package/dist/codegen/template.mjs.map +1 -0
  57. package/dist/codegen/types.d.mts +144 -0
  58. package/dist/codegen/types.d.mts.map +1 -0
  59. package/dist/completion.d.mts +2 -0
  60. package/dist/completion.mjs +2 -0
  61. package/dist/core/args.d.mts +3 -0
  62. package/dist/{args-DrCXxXeP.mjs → core/args.mjs} +49 -113
  63. package/dist/core/args.mjs.map +1 -0
  64. package/dist/core/commands.d.mts +13 -0
  65. package/dist/core/commands.d.mts.map +1 -0
  66. package/dist/{commands-DLR0rFgq.mjs → core/commands.mjs} +4 -232
  67. package/dist/core/commands.mjs.map +1 -0
  68. package/dist/core/create.d.mts +63 -0
  69. package/dist/core/create.d.mts.map +1 -0
  70. package/dist/core/create.mjs +230 -0
  71. package/dist/core/create.mjs.map +1 -0
  72. package/dist/core/default-runtime.mjs +198 -0
  73. package/dist/core/default-runtime.mjs.map +1 -0
  74. package/dist/core/errors.d.mts +107 -0
  75. package/dist/core/errors.d.mts.map +1 -0
  76. package/dist/{errors-DA4KzK1M.mjs → core/errors.mjs} +2 -2
  77. package/dist/core/errors.mjs.map +1 -0
  78. package/dist/core/exec.mjs +191 -0
  79. package/dist/core/exec.mjs.map +1 -0
  80. package/dist/core/interceptors.d.mts +33 -0
  81. package/dist/core/interceptors.d.mts.map +1 -0
  82. package/dist/core/interceptors.mjs +253 -0
  83. package/dist/core/interceptors.mjs.map +1 -0
  84. package/dist/core/parse.mjs +181 -0
  85. package/dist/core/parse.mjs.map +1 -0
  86. package/dist/core/program-methods.mjs +256 -0
  87. package/dist/core/program-methods.mjs.map +1 -0
  88. package/dist/core/results.d.mts +13 -0
  89. package/dist/core/results.d.mts.map +1 -0
  90. package/dist/core/results.mjs +150 -0
  91. package/dist/core/results.mjs.map +1 -0
  92. package/dist/core/runtime.d.mts +213 -0
  93. package/dist/core/runtime.d.mts.map +1 -0
  94. package/dist/core/runtime.mjs +10 -0
  95. package/dist/core/runtime.mjs.map +1 -0
  96. package/dist/core/validate.mjs +220 -0
  97. package/dist/core/validate.mjs.map +1 -0
  98. package/dist/docs/index.d.mts +1 -1
  99. package/dist/docs/index.d.mts.map +1 -1
  100. package/dist/docs/index.mjs +2 -2
  101. package/dist/docs/index.mjs.map +1 -1
  102. package/dist/extension/auto-output.d.mts +53 -0
  103. package/dist/extension/auto-output.d.mts.map +1 -0
  104. package/dist/extension/auto-output.mjs +116 -0
  105. package/dist/extension/auto-output.mjs.map +1 -0
  106. package/dist/extension/color.d.mts +19 -0
  107. package/dist/extension/color.d.mts.map +1 -0
  108. package/dist/extension/color.mjs +37 -0
  109. package/dist/extension/color.mjs.map +1 -0
  110. package/dist/extension/completion.d.mts +25 -0
  111. package/dist/extension/completion.d.mts.map +1 -0
  112. package/dist/extension/completion.mjs +40 -0
  113. package/dist/extension/completion.mjs.map +1 -0
  114. package/dist/extension/config.d.mts +55 -0
  115. package/dist/extension/config.d.mts.map +1 -0
  116. package/dist/extension/config.mjs +162 -0
  117. package/dist/extension/config.mjs.map +1 -0
  118. package/dist/extension/env.d.mts +42 -0
  119. package/dist/extension/env.d.mts.map +1 -0
  120. package/dist/extension/env.mjs +44 -0
  121. package/dist/extension/env.mjs.map +1 -0
  122. package/dist/extension/help.d.mts +29 -0
  123. package/dist/extension/help.d.mts.map +1 -0
  124. package/dist/extension/help.mjs +161 -0
  125. package/dist/extension/help.mjs.map +1 -0
  126. package/dist/extension/index.d.mts +18 -0
  127. package/dist/extension/ink.d.mts +31 -0
  128. package/dist/extension/ink.d.mts.map +1 -0
  129. package/dist/extension/ink.mjs +69 -0
  130. package/dist/extension/ink.mjs.map +1 -0
  131. package/dist/extension/interactive.d.mts +16 -0
  132. package/dist/extension/interactive.d.mts.map +1 -0
  133. package/dist/extension/interactive.mjs +89 -0
  134. package/dist/extension/interactive.mjs.map +1 -0
  135. package/dist/extension/logger.d.mts +67 -0
  136. package/dist/extension/logger.d.mts.map +1 -0
  137. package/dist/extension/logger.mjs +188 -0
  138. package/dist/extension/logger.mjs.map +1 -0
  139. package/dist/extension/man.d.mts +25 -0
  140. package/dist/extension/man.d.mts.map +1 -0
  141. package/dist/extension/man.mjs +41 -0
  142. package/dist/extension/man.mjs.map +1 -0
  143. package/dist/extension/mcp.d.mts +28 -0
  144. package/dist/extension/mcp.d.mts.map +1 -0
  145. package/dist/extension/mcp.mjs +44 -0
  146. package/dist/extension/mcp.mjs.map +1 -0
  147. package/dist/extension/progress-renderer.d.mts +13 -0
  148. package/dist/extension/progress-renderer.d.mts.map +1 -0
  149. package/dist/extension/progress-renderer.mjs +351 -0
  150. package/dist/extension/progress-renderer.mjs.map +1 -0
  151. package/dist/extension/progress.d.mts +76 -0
  152. package/dist/extension/progress.d.mts.map +1 -0
  153. package/dist/extension/progress.mjs +225 -0
  154. package/dist/extension/progress.mjs.map +1 -0
  155. package/dist/extension/repl.d.mts +26 -0
  156. package/dist/extension/repl.d.mts.map +1 -0
  157. package/dist/extension/repl.mjs +67 -0
  158. package/dist/extension/repl.mjs.map +1 -0
  159. package/dist/extension/serve.d.mts +27 -0
  160. package/dist/extension/serve.d.mts.map +1 -0
  161. package/dist/extension/serve.mjs +41 -0
  162. package/dist/extension/serve.mjs.map +1 -0
  163. package/dist/extension/signal.d.mts +19 -0
  164. package/dist/extension/signal.d.mts.map +1 -0
  165. package/dist/extension/signal.mjs +81 -0
  166. package/dist/extension/signal.mjs.map +1 -0
  167. package/dist/extension/stdin.d.mts +19 -0
  168. package/dist/extension/stdin.d.mts.map +1 -0
  169. package/dist/extension/stdin.mjs +52 -0
  170. package/dist/extension/stdin.mjs.map +1 -0
  171. package/dist/extension/suggestions.d.mts +6 -0
  172. package/dist/extension/suggestions.d.mts.map +1 -0
  173. package/dist/extension/suggestions.mjs +113 -0
  174. package/dist/extension/suggestions.mjs.map +1 -0
  175. package/dist/extension/timing.d.mts +27 -0
  176. package/dist/extension/timing.d.mts.map +1 -0
  177. package/dist/extension/timing.mjs +71 -0
  178. package/dist/extension/timing.mjs.map +1 -0
  179. package/dist/extension/tracing.d.mts +85 -0
  180. package/dist/extension/tracing.d.mts.map +1 -0
  181. package/dist/extension/tracing.mjs +107 -0
  182. package/dist/extension/tracing.mjs.map +1 -0
  183. package/dist/extension/update-check.d.mts +20 -0
  184. package/dist/extension/update-check.d.mts.map +1 -0
  185. package/dist/extension/update-check.mjs +62 -0
  186. package/dist/extension/update-check.mjs.map +1 -0
  187. package/dist/extension/utils.mjs +43 -0
  188. package/dist/extension/utils.mjs.map +1 -0
  189. package/dist/extension/version.d.mts +20 -0
  190. package/dist/extension/version.d.mts.map +1 -0
  191. package/dist/extension/version.mjs +51 -0
  192. package/dist/extension/version.mjs.map +1 -0
  193. package/dist/{completion-UnBKfGuk.mjs → feature/completion.mjs} +4 -3
  194. package/dist/feature/completion.mjs.map +1 -0
  195. package/dist/feature/interactive.mjs +145 -0
  196. package/dist/feature/interactive.mjs.map +1 -0
  197. package/dist/feature/mcp.d.mts +18 -0
  198. package/dist/feature/mcp.d.mts.map +1 -0
  199. package/dist/{mcp-D6PdtjIs.mjs → feature/mcp.mjs} +6 -6
  200. package/dist/feature/mcp.mjs.map +1 -0
  201. package/dist/feature/repl-loop.mjs +217 -0
  202. package/dist/feature/repl-loop.mjs.map +1 -0
  203. package/dist/feature/serve.d.mts +18 -0
  204. package/dist/feature/serve.d.mts.map +1 -0
  205. package/dist/{serve-PaCLsNoD.mjs → feature/serve.mjs} +7 -7
  206. package/dist/feature/serve.mjs.map +1 -0
  207. package/dist/feature/test.d.mts +109 -0
  208. package/dist/feature/test.d.mts.map +1 -0
  209. package/dist/feature/test.mjs +116 -0
  210. package/dist/feature/test.mjs.map +1 -0
  211. package/dist/feature/update-check.d.mts +35 -0
  212. package/dist/feature/update-check.d.mts.map +1 -0
  213. package/dist/{update-check-CZ2VqjnV.mjs → feature/update-check.mjs} +2 -2
  214. package/dist/feature/update-check.mjs.map +1 -0
  215. package/dist/feature/wrap.d.mts +58 -0
  216. package/dist/feature/wrap.d.mts.map +1 -0
  217. package/dist/feature/wrap.mjs +77 -0
  218. package/dist/feature/wrap.mjs.map +1 -0
  219. package/dist/index.d.mts +38 -901
  220. package/dist/index.mjs +25 -4337
  221. package/dist/ink.d.mts +2 -0
  222. package/dist/ink.mjs +2 -0
  223. package/dist/man.d.mts +2 -0
  224. package/dist/man.mjs +2 -0
  225. package/dist/mcp.d.mts +3 -0
  226. package/dist/mcp.mjs +2 -0
  227. package/dist/output/colorizer.d.mts +28 -0
  228. package/dist/output/colorizer.d.mts.map +1 -0
  229. package/dist/output/colorizer.mjs +94 -0
  230. package/dist/output/colorizer.mjs.map +1 -0
  231. package/dist/{formatter-CY3KrOEd.d.mts → output/formatter.d.mts} +2 -28
  232. package/dist/output/formatter.d.mts.map +1 -0
  233. package/dist/output/formatter.mjs +360 -0
  234. package/dist/output/formatter.mjs.map +1 -0
  235. package/dist/output/help.d.mts +18 -0
  236. package/dist/output/help.d.mts.map +1 -0
  237. package/dist/output/help.mjs +267 -0
  238. package/dist/output/help.mjs.map +1 -0
  239. package/dist/output/output-indicator.d.mts +27 -0
  240. package/dist/output/output-indicator.d.mts.map +1 -0
  241. package/dist/output/output-indicator.mjs +54 -0
  242. package/dist/output/output-indicator.mjs.map +1 -0
  243. package/dist/output/primitives.d.mts +33 -0
  244. package/dist/output/primitives.d.mts.map +1 -0
  245. package/dist/output/primitives.mjs +206 -0
  246. package/dist/output/primitives.mjs.map +1 -0
  247. package/dist/output/styling.d.mts +38 -0
  248. package/dist/output/styling.d.mts.map +1 -0
  249. package/dist/output/styling.mjs +146 -0
  250. package/dist/output/styling.mjs.map +1 -0
  251. package/dist/schema/zod.d.mts +6 -0
  252. package/dist/schema/zod.d.mts.map +1 -0
  253. package/dist/schema/zod.mjs +50 -0
  254. package/dist/schema/zod.mjs.map +1 -0
  255. package/dist/serve.d.mts +2 -0
  256. package/dist/serve.mjs +2 -0
  257. package/dist/test.d.mts +2 -109
  258. package/dist/test.mjs +1 -115
  259. package/dist/tracing.d.mts +2 -0
  260. package/dist/tracing.mjs +2 -0
  261. package/dist/types/args-meta.d.mts +129 -0
  262. package/dist/types/args-meta.d.mts.map +1 -0
  263. package/dist/types/builder.d.mts +212 -0
  264. package/dist/types/builder.d.mts.map +1 -0
  265. package/dist/types/command.d.mts +112 -0
  266. package/dist/types/command.d.mts.map +1 -0
  267. package/dist/types/index.d.mts +8 -0
  268. package/dist/types/interceptor.d.mts +232 -0
  269. package/dist/types/interceptor.d.mts.map +1 -0
  270. package/dist/types/preferences.d.mts +79 -0
  271. package/dist/types/preferences.d.mts.map +1 -0
  272. package/dist/types/result.d.mts +61 -0
  273. package/dist/types/result.d.mts.map +1 -0
  274. package/dist/types/schema.d.mts +24 -0
  275. package/dist/types/schema.d.mts.map +1 -0
  276. package/dist/util/dotenv.mjs +174 -0
  277. package/dist/util/dotenv.mjs.map +1 -0
  278. package/dist/util/shell-utils.mjs +80 -0
  279. package/dist/util/shell-utils.mjs.map +1 -0
  280. package/dist/util/stream.d.mts +33 -0
  281. package/dist/util/stream.d.mts.map +1 -0
  282. package/dist/{stream-DC4H8YTx.mjs → util/stream.mjs} +2 -2
  283. package/dist/util/stream.mjs.map +1 -0
  284. package/dist/util/type-helpers.d.mts +74 -0
  285. package/dist/util/type-helpers.d.mts.map +1 -0
  286. package/dist/util/type-utils.d.mts +186 -0
  287. package/dist/util/type-utils.d.mts.map +1 -0
  288. package/dist/util/utils.mjs +43 -0
  289. package/dist/util/utils.mjs.map +1 -0
  290. package/dist/zod.d.mts +1 -32
  291. package/dist/zod.mjs +1 -49
  292. package/package.json +65 -17
  293. package/src/completion.ts +2 -0
  294. package/src/core/args.ts +63 -37
  295. package/src/core/runtime.ts +11 -2
  296. package/src/extension/completion.ts +3 -0
  297. package/src/extension/index.ts +0 -12
  298. package/src/extension/ink.ts +2 -1
  299. package/src/extension/man.ts +3 -0
  300. package/src/extension/mcp.ts +3 -0
  301. package/src/extension/progress-renderer.ts +32 -8
  302. package/src/extension/progress.ts +19 -9
  303. package/src/extension/serve.ts +3 -0
  304. package/src/extension/tracing.ts +2 -0
  305. package/src/index.ts +1 -20
  306. package/src/ink.ts +2 -0
  307. package/src/man.ts +2 -0
  308. package/src/mcp.ts +3 -0
  309. package/src/serve.ts +2 -0
  310. package/src/tracing.ts +9 -0
  311. package/src/types/builder.ts +2 -2
  312. package/src/zod.ts +1 -1
  313. package/dist/args-DrCXxXeP.mjs.map +0 -1
  314. package/dist/codegen/index.d.mts.map +0 -1
  315. package/dist/codegen/index.mjs.map +0 -1
  316. package/dist/commands-DLR0rFgq.mjs.map +0 -1
  317. package/dist/completion-UnBKfGuk.mjs.map +0 -1
  318. package/dist/errors-DA4KzK1M.mjs.map +0 -1
  319. package/dist/formatter-CY3KrOEd.d.mts.map +0 -1
  320. package/dist/help-B-ZMYyn-.mjs +0 -892
  321. package/dist/help-B-ZMYyn-.mjs.map +0 -1
  322. package/dist/index-D-Dpz7l_.d.mts +0 -1427
  323. package/dist/index-D-Dpz7l_.d.mts.map +0 -1
  324. package/dist/index.d.mts.map +0 -1
  325. package/dist/index.mjs.map +0 -1
  326. package/dist/mcp-D6PdtjIs.mjs.map +0 -1
  327. package/dist/serve-PaCLsNoD.mjs.map +0 -1
  328. package/dist/stream-DC4H8YTx.mjs.map +0 -1
  329. package/dist/test.d.mts.map +0 -1
  330. package/dist/test.mjs.map +0 -1
  331. package/dist/update-check-CZ2VqjnV.mjs.map +0 -1
  332. package/dist/zod.d.mts.map +0 -1
  333. package/dist/zod.mjs.map +0 -1
@@ -0,0 +1,76 @@
1
+ //#region src/codegen/parsers/merge.ts
2
+ /**
3
+ * Deep-merge multiple CommandMeta from different sources.
4
+ * Deduplicates fields, resolves conflicts, and combines subcommands.
5
+ *
6
+ * Later sources take precedence for descriptions and types,
7
+ * unless the earlier source was more specific (non-ambiguous).
8
+ */
9
+ function mergeCommandMeta(...sources) {
10
+ if (sources.length === 0) return { name: "" };
11
+ if (sources.length === 1) return sources[0];
12
+ const result = { name: "" };
13
+ for (const source of sources) {
14
+ if (source.name && !result.name) result.name = source.name;
15
+ if (source.description) result.description = source.description;
16
+ if (source.aliases) result.aliases = [.../* @__PURE__ */ new Set([...result.aliases || [], ...source.aliases])];
17
+ if (source.examples) result.examples = [.../* @__PURE__ */ new Set([...result.examples || [], ...source.examples])];
18
+ if (source.deprecated !== void 0) result.deprecated = source.deprecated;
19
+ if (source.arguments) result.arguments = mergeFields(result.arguments || [], source.arguments);
20
+ if (source.positionals) result.positionals = mergeFields(result.positionals || [], source.positionals);
21
+ if (source.subcommands) result.subcommands = mergeSubcommands(result.subcommands || [], source.subcommands);
22
+ }
23
+ if (result.aliases?.length === 0) delete result.aliases;
24
+ if (result.examples?.length === 0) delete result.examples;
25
+ if (result.arguments?.length === 0) delete result.arguments;
26
+ if (result.positionals?.length === 0) delete result.positionals;
27
+ if (result.subcommands?.length === 0) delete result.subcommands;
28
+ return result;
29
+ }
30
+ /**
31
+ * Merge two arrays of FieldMeta by name.
32
+ * Later fields take precedence unless earlier was non-ambiguous.
33
+ */
34
+ function mergeFields(existing, incoming) {
35
+ const map = /* @__PURE__ */ new Map();
36
+ for (const field of existing) map.set(field.name, { ...field });
37
+ for (const field of incoming) {
38
+ const prev = map.get(field.name);
39
+ if (!prev) {
40
+ map.set(field.name, { ...field });
41
+ continue;
42
+ }
43
+ const merged = { ...prev };
44
+ if (field.type !== "unknown") {
45
+ if (prev.ambiguous || !field.ambiguous) {
46
+ merged.type = field.type;
47
+ merged.ambiguous = field.ambiguous;
48
+ }
49
+ }
50
+ if (field.description) merged.description = field.description;
51
+ if (field.default !== void 0) merged.default = field.default;
52
+ if (field.required !== void 0) merged.required = field.required;
53
+ if (field.aliases) merged.aliases = [.../* @__PURE__ */ new Set([...prev.aliases || [], ...field.aliases])];
54
+ if (field.enumValues) merged.enumValues = [.../* @__PURE__ */ new Set([...prev.enumValues || [], ...field.enumValues])];
55
+ if (field.items) merged.items = field.items;
56
+ map.set(field.name, merged);
57
+ }
58
+ return [...map.values()];
59
+ }
60
+ /**
61
+ * Merge two arrays of CommandMeta by name, recursively.
62
+ */
63
+ function mergeSubcommands(existing, incoming) {
64
+ const map = /* @__PURE__ */ new Map();
65
+ for (const cmd of existing) map.set(cmd.name, cmd);
66
+ for (const cmd of incoming) {
67
+ const prev = map.get(cmd.name);
68
+ if (!prev) map.set(cmd.name, cmd);
69
+ else map.set(cmd.name, mergeCommandMeta(prev, cmd));
70
+ }
71
+ return [...map.values()];
72
+ }
73
+ //#endregion
74
+ export { mergeCommandMeta };
75
+
76
+ //# sourceMappingURL=merge.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.mjs","names":[],"sources":["../../../src/codegen/parsers/merge.ts"],"sourcesContent":["import type { CommandMeta, FieldMeta } from '../types.ts';\n\n/**\n * Deep-merge multiple CommandMeta from different sources.\n * Deduplicates fields, resolves conflicts, and combines subcommands.\n *\n * Later sources take precedence for descriptions and types,\n * unless the earlier source was more specific (non-ambiguous).\n */\nexport function mergeCommandMeta(...sources: CommandMeta[]): CommandMeta {\n if (sources.length === 0) {\n return { name: '' };\n }\n\n if (sources.length === 1) {\n return sources[0]!;\n }\n\n const result: CommandMeta = { name: '' };\n\n for (const source of sources) {\n // Name: first non-empty wins\n if (source.name && !result.name) {\n result.name = source.name;\n }\n\n // Description: last non-empty wins\n if (source.description) {\n result.description = source.description;\n }\n\n // Aliases: merge and deduplicate\n if (source.aliases) {\n result.aliases = [...new Set([...(result.aliases || []), ...source.aliases])];\n }\n\n // Examples: merge and deduplicate\n if (source.examples) {\n result.examples = [...new Set([...(result.examples || []), ...source.examples])];\n }\n\n // Deprecated: last truthy wins\n if (source.deprecated !== undefined) {\n result.deprecated = source.deprecated;\n }\n\n // Arguments: merge by name\n if (source.arguments) {\n result.arguments = mergeFields(result.arguments || [], source.arguments);\n }\n\n // Positionals: merge by name\n if (source.positionals) {\n result.positionals = mergeFields(result.positionals || [], source.positionals);\n }\n\n // Subcommands: merge recursively by name\n if (source.subcommands) {\n result.subcommands = mergeSubcommands(result.subcommands || [], source.subcommands);\n }\n }\n\n // Clean up empty arrays\n if (result.aliases?.length === 0) delete result.aliases;\n if (result.examples?.length === 0) delete result.examples;\n if (result.arguments?.length === 0) delete result.arguments;\n if (result.positionals?.length === 0) delete result.positionals;\n if (result.subcommands?.length === 0) delete result.subcommands;\n\n return result;\n}\n\n/**\n * Merge two arrays of FieldMeta by name.\n * Later fields take precedence unless earlier was non-ambiguous.\n */\nfunction mergeFields(existing: FieldMeta[], incoming: FieldMeta[]): FieldMeta[] {\n const map = new Map<string, FieldMeta>();\n\n for (const field of existing) {\n map.set(field.name, { ...field });\n }\n\n for (const field of incoming) {\n const prev = map.get(field.name);\n if (!prev) {\n map.set(field.name, { ...field });\n continue;\n }\n\n // Merge the fields\n const merged: FieldMeta = { ...prev };\n\n // Type: prefer non-ambiguous source\n if (field.type !== 'unknown') {\n if (prev.ambiguous || !field.ambiguous) {\n merged.type = field.type;\n merged.ambiguous = field.ambiguous;\n }\n }\n\n // Description: last non-empty wins\n if (field.description) {\n merged.description = field.description;\n }\n\n // Default: last non-undefined wins\n if (field.default !== undefined) {\n merged.default = field.default;\n }\n\n // Required: last defined wins\n if (field.required !== undefined) {\n merged.required = field.required;\n }\n\n // Aliases: merge and deduplicate\n if (field.aliases) {\n merged.aliases = [...new Set([...(prev.aliases || []), ...field.aliases])];\n }\n\n // Enum values: merge and deduplicate\n if (field.enumValues) {\n merged.enumValues = [...new Set([...(prev.enumValues || []), ...field.enumValues])];\n }\n\n // Items: last non-empty wins\n if (field.items) {\n merged.items = field.items;\n }\n\n map.set(field.name, merged);\n }\n\n return [...map.values()];\n}\n\n/**\n * Merge two arrays of CommandMeta by name, recursively.\n */\nfunction mergeSubcommands(existing: CommandMeta[], incoming: CommandMeta[]): CommandMeta[] {\n const map = new Map<string, CommandMeta>();\n\n for (const cmd of existing) {\n map.set(cmd.name, cmd);\n }\n\n for (const cmd of incoming) {\n const prev = map.get(cmd.name);\n if (!prev) {\n map.set(cmd.name, cmd);\n } else {\n map.set(cmd.name, mergeCommandMeta(prev, cmd));\n }\n }\n\n return [...map.values()];\n}\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { CommandMeta } from "../types.mjs";
2
+
3
+ //#region src/codegen/parsers/zsh.d.ts
4
+ /**
5
+ * Parse zsh completion function definitions into CommandMeta.
6
+ *
7
+ * Zsh completions typically use _arguments or compadd:
8
+ * _arguments \
9
+ * '-v[verbose mode]' \
10
+ * '--output=[output file]:filename:_files' \
11
+ * '1:command:(start stop restart)'
12
+ */
13
+ declare function parseZshCompletions(text: string): CommandMeta;
14
+ //#endregion
15
+ export { parseZshCompletions };
16
+ //# sourceMappingURL=zsh.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zsh.d.mts","names":[],"sources":["../../../src/codegen/parsers/zsh.ts"],"mappings":";;;;;AAWA;;;;AAA8D;;;iBAA9C,mBAAA,CAAoB,IAAA,WAAe,WAAW"}
@@ -0,0 +1,161 @@
1
+ //#region src/codegen/parsers/zsh.ts
2
+ /**
3
+ * Parse zsh completion function definitions into CommandMeta.
4
+ *
5
+ * Zsh completions typically use _arguments or compadd:
6
+ * _arguments \
7
+ * '-v[verbose mode]' \
8
+ * '--output=[output file]:filename:_files' \
9
+ * '1:command:(start stop restart)'
10
+ */
11
+ function parseZshCompletions(text) {
12
+ const result = {
13
+ name: "",
14
+ arguments: [],
15
+ positionals: [],
16
+ subcommands: []
17
+ };
18
+ const compdefMatch = text.match(/#compdef\s+(\S+)/);
19
+ if (compdefMatch) result.name = compdefMatch[1];
20
+ else {
21
+ const funcMatch = text.match(/^_(\w+)\s*\(\)/m);
22
+ if (funcMatch) result.name = funcMatch[1];
23
+ }
24
+ const argumentsBlocks = findArgumentsBlocks(text);
25
+ for (const block of argumentsBlocks) {
26
+ const specs = parseArgumentSpecs(block);
27
+ for (const spec of specs) if (spec.positional) result.positionals.push(spec);
28
+ else result.arguments.push(spec);
29
+ }
30
+ const subcommands = findSubcommands(text);
31
+ result.subcommands.push(...subcommands);
32
+ if (result.arguments.length === 0) delete result.arguments;
33
+ if (result.positionals.length === 0) delete result.positionals;
34
+ if (result.subcommands.length === 0) delete result.subcommands;
35
+ return result;
36
+ }
37
+ /**
38
+ * Extract _arguments blocks from zsh completion text.
39
+ * Handles backslash continuation lines.
40
+ */
41
+ function findArgumentsBlocks(text) {
42
+ const blocks = [];
43
+ const lines = text.replace(/\\\n\s*/g, " ").split("\n");
44
+ for (const line of lines) {
45
+ const match = line.match(/_arguments\s+(.+)/);
46
+ if (match) blocks.push(match[1]);
47
+ }
48
+ return blocks;
49
+ }
50
+ /**
51
+ * Parse individual argument specs from an _arguments line.
52
+ */
53
+ function parseArgumentSpecs(block) {
54
+ const results = [];
55
+ const specs = extractQuotedStrings(block);
56
+ for (const spec of specs) {
57
+ const field = parseZshSpec(spec);
58
+ if (field) results.push(field);
59
+ }
60
+ return results;
61
+ }
62
+ /**
63
+ * Extract single-quoted strings from an _arguments block.
64
+ */
65
+ function extractQuotedStrings(text) {
66
+ const strings = [];
67
+ const regex = /'([^']+)'/g;
68
+ let match;
69
+ while ((match = regex.exec(text)) !== null) strings.push(match[1]);
70
+ return strings;
71
+ }
72
+ /**
73
+ * Parse a single zsh argument spec.
74
+ *
75
+ * Formats:
76
+ * '-v[verbose mode]' → boolean flag
77
+ * '--output=[output file]:filename:_files' → string with value
78
+ * '(-v --verbose)'{-v,--verbose}'[verbose mode]' → flag with aliases
79
+ * '*--flag[repeatable]' → array
80
+ * '1:command:(start stop restart)' → positional enum
81
+ * ':filename:_files' → positional
82
+ */
83
+ function parseZshSpec(spec) {
84
+ const positionalMatch = spec.match(/^(\d+)?:([^:]*):(.*)$/);
85
+ if (positionalMatch) {
86
+ const description = positionalMatch[2] || void 0;
87
+ const enumMatch = positionalMatch[3]?.match(/^\(([^)]+)\)$/);
88
+ if (enumMatch) {
89
+ const values = enumMatch[1].split(/\s+/);
90
+ return {
91
+ name: description?.toLowerCase().replace(/\s+/g, "_") || `arg${positionalMatch[1] || "0"}`,
92
+ type: "enum",
93
+ enumValues: values,
94
+ description,
95
+ positional: true
96
+ };
97
+ }
98
+ return {
99
+ name: description?.toLowerCase().replace(/\s+/g, "_") || `arg${positionalMatch[1] || "0"}`,
100
+ type: "string",
101
+ description,
102
+ positional: true,
103
+ ambiguous: true
104
+ };
105
+ }
106
+ const repeatable = spec.startsWith("*");
107
+ const flagMatch = (repeatable ? spec.slice(1) : spec).match(/^(-{1,2}[\w-]+)(?:=?)(?:\[([^\]]*)\])?(?::([^:]*):?(.*))?$/);
108
+ if (!flagMatch) return null;
109
+ const rawName = flagMatch[1];
110
+ const description = flagMatch[2] || void 0;
111
+ const valueName = flagMatch[3] || void 0;
112
+ const name = rawName.replace(/^-+/, "").replace(/-([a-z])/g, (_, c) => c.toUpperCase());
113
+ let type = rawName.includes("=") || !!valueName ? "string" : "boolean";
114
+ if (repeatable) type = "array";
115
+ let enumValues;
116
+ if (flagMatch[4]) {
117
+ const enumMatch = flagMatch[4].match(/^\(([^)]+)\)$/);
118
+ if (enumMatch) {
119
+ enumValues = enumMatch[1].split(/\s+/);
120
+ type = "enum";
121
+ }
122
+ }
123
+ return {
124
+ name,
125
+ type,
126
+ description,
127
+ enumValues
128
+ };
129
+ }
130
+ /**
131
+ * Find subcommand definitions from _describe calls or case statements.
132
+ */
133
+ function findSubcommands(text) {
134
+ const subcommands = [];
135
+ const seen = /* @__PURE__ */ new Set();
136
+ const describeRegex = /\(([^)]+)\)/g;
137
+ const joined = text.replace(/\\\n\s*/g, " ");
138
+ let match;
139
+ while ((match = describeRegex.exec(joined)) !== null) {
140
+ const content = match[1];
141
+ const entries = content.match(/'([^']+)'/g) || content.match(/"([^"]+)"/g);
142
+ if (!entries) continue;
143
+ for (const entry of entries) {
144
+ const parts = entry.replace(/^['"]|['"]$/g, "").split(":");
145
+ if (parts.length >= 2 && /^[\w-]+$/.test(parts[0])) {
146
+ const name = parts[0];
147
+ if (seen.has(name)) continue;
148
+ seen.add(name);
149
+ subcommands.push({
150
+ name,
151
+ description: parts.slice(1).join(":")
152
+ });
153
+ }
154
+ }
155
+ }
156
+ return subcommands;
157
+ }
158
+ //#endregion
159
+ export { parseZshCompletions };
160
+
161
+ //# sourceMappingURL=zsh.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zsh.mjs","names":[],"sources":["../../../src/codegen/parsers/zsh.ts"],"sourcesContent":["import type { CommandMeta, FieldMeta } from '../types.ts';\n\n/**\n * Parse zsh completion function definitions into CommandMeta.\n *\n * Zsh completions typically use _arguments or compadd:\n * _arguments \\\n * '-v[verbose mode]' \\\n * '--output=[output file]:filename:_files' \\\n * '1:command:(start stop restart)'\n */\nexport function parseZshCompletions(text: string): CommandMeta {\n const result: CommandMeta = {\n name: '',\n arguments: [],\n positionals: [],\n subcommands: [],\n };\n\n // Try to detect command name from function name: _command() or #compdef command\n const compdefMatch = text.match(/#compdef\\s+(\\S+)/);\n if (compdefMatch) {\n result.name = compdefMatch[1]!;\n } else {\n const funcMatch = text.match(/^_(\\w+)\\s*\\(\\)/m);\n if (funcMatch) {\n result.name = funcMatch[1]!;\n }\n }\n\n // Find _arguments blocks\n const argumentsBlocks = findArgumentsBlocks(text);\n\n for (const block of argumentsBlocks) {\n const specs = parseArgumentSpecs(block);\n for (const spec of specs) {\n if (spec.positional) {\n result.positionals!.push(spec);\n } else {\n result.arguments!.push(spec);\n }\n }\n }\n\n // Find subcommand definitions from case statements or _describe\n const subcommands = findSubcommands(text);\n result.subcommands!.push(...subcommands);\n\n if (result.arguments!.length === 0) delete result.arguments;\n if (result.positionals!.length === 0) delete result.positionals;\n if (result.subcommands!.length === 0) delete result.subcommands;\n\n return result;\n}\n\n/**\n * Extract _arguments blocks from zsh completion text.\n * Handles backslash continuation lines.\n */\nfunction findArgumentsBlocks(text: string): string[] {\n const blocks: string[] = [];\n\n // Join continuation lines\n const joined = text.replace(/\\\\\\n\\s*/g, ' ');\n const lines = joined.split('\\n');\n\n for (const line of lines) {\n const match = line.match(/_arguments\\s+(.+)/);\n if (match) {\n blocks.push(match[1]!);\n }\n }\n\n return blocks;\n}\n\n/**\n * Parse individual argument specs from an _arguments line.\n */\nfunction parseArgumentSpecs(block: string): FieldMeta[] {\n const results: FieldMeta[] = [];\n\n // Split into individual specs (quoted strings)\n const specs = extractQuotedStrings(block);\n\n for (const spec of specs) {\n const field = parseZshSpec(spec);\n if (field) results.push(field);\n }\n\n return results;\n}\n\n/**\n * Extract single-quoted strings from an _arguments block.\n */\nfunction extractQuotedStrings(text: string): string[] {\n const strings: string[] = [];\n const regex = /'([^']+)'/g;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(text)) !== null) {\n strings.push(match[1]!);\n }\n\n return strings;\n}\n\n/**\n * Parse a single zsh argument spec.\n *\n * Formats:\n * '-v[verbose mode]' → boolean flag\n * '--output=[output file]:filename:_files' → string with value\n * '(-v --verbose)'{-v,--verbose}'[verbose mode]' → flag with aliases\n * '*--flag[repeatable]' → array\n * '1:command:(start stop restart)' → positional enum\n * ':filename:_files' → positional\n */\nfunction parseZshSpec(spec: string): FieldMeta | null {\n // Positional argument: 'N:description:action' or ':description:action'\n const positionalMatch = spec.match(/^(\\d+)?:([^:]*):(.*)$/);\n if (positionalMatch) {\n const description = positionalMatch[2] || undefined;\n\n // Check for enum values in (val1 val2 val3)\n const enumMatch = positionalMatch[3]?.match(/^\\(([^)]+)\\)$/);\n if (enumMatch) {\n const values = enumMatch[1]!.split(/\\s+/);\n return {\n name: description?.toLowerCase().replace(/\\s+/g, '_') || `arg${positionalMatch[1] || '0'}`,\n type: 'enum',\n enumValues: values,\n description,\n positional: true,\n };\n }\n\n return {\n name: description?.toLowerCase().replace(/\\s+/g, '_') || `arg${positionalMatch[1] || '0'}`,\n type: 'string',\n description,\n positional: true,\n ambiguous: true,\n };\n }\n\n // Flag argument\n const repeatable = spec.startsWith('*');\n const flagSpec = repeatable ? spec.slice(1) : spec;\n\n // Extract flag name and description\n // Pattern: --flag=[description]:value_description:action\n // Pattern: -f[description]\n const flagMatch = flagSpec.match(/^(-{1,2}[\\w-]+)(?:=?)(?:\\[([^\\]]*)\\])?(?::([^:]*):?(.*))?$/);\n if (!flagMatch) return null;\n\n const rawName = flagMatch[1]!;\n const description = flagMatch[2] || undefined;\n const valueName = flagMatch[3] || undefined;\n\n const name = rawName.replace(/^-+/, '').replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n const hasValue = rawName.includes('=') || !!valueName;\n let type: FieldMeta['type'] = hasValue ? 'string' : 'boolean';\n\n if (repeatable) type = 'array';\n\n // Check for enum values\n let enumValues: string[] | undefined;\n if (flagMatch[4]) {\n const enumMatch = flagMatch[4].match(/^\\(([^)]+)\\)$/);\n if (enumMatch) {\n enumValues = enumMatch[1]!.split(/\\s+/);\n type = 'enum';\n }\n }\n\n return {\n name,\n type,\n description,\n enumValues,\n };\n}\n\n/**\n * Find subcommand definitions from _describe calls or case statements.\n */\nfunction findSubcommands(text: string): CommandMeta[] {\n const subcommands: CommandMeta[] = [];\n const seen = new Set<string>();\n\n // Look for _describe patterns: _describe 'command' commands\n // where commands is an array like: ('start:start the service' 'stop:stop the service')\n const describeRegex = /\\(([^)]+)\\)/g;\n const joined = text.replace(/\\\\\\n\\s*/g, ' ');\n\n // Look for arrays of 'name:description' patterns near _describe\n let match: RegExpExecArray | null;\n while ((match = describeRegex.exec(joined)) !== null) {\n const content = match[1]!;\n const entries = content.match(/'([^']+)'/g) || content.match(/\"([^\"]+)\"/g);\n if (!entries) continue;\n\n for (const entry of entries) {\n const clean = entry.replace(/^['\"]|['\"]$/g, '');\n const parts = clean.split(':');\n if (parts.length >= 2 && /^[\\w-]+$/.test(parts[0]!)) {\n const name = parts[0]!;\n if (seen.has(name)) continue;\n seen.add(name);\n subcommands.push({\n name,\n description: parts.slice(1).join(':'),\n });\n }\n }\n }\n\n return subcommands;\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { FieldMeta } from "./types.mjs";
2
+ import { StandardSchemaV1 } from "@standard-schema/spec";
3
+
4
+ //#region src/codegen/schema-to-code.d.ts
5
+ interface SchemaToCodeResult {
6
+ /** The generated Zod source code */
7
+ code: string;
8
+ /** Imports needed (e.g. ['z']) */
9
+ imports: string[];
10
+ }
11
+ /**
12
+ * Generate Zod source code from a Standard Schema instance by introspecting
13
+ * its `~standard.jsonSchema` interface.
14
+ */
15
+ declare function schemaToCode(schema: StandardSchemaV1): SchemaToCodeResult;
16
+ /**
17
+ * Build a real Zod schema from FieldMeta objects.
18
+ * Returns the schema as Zod source code, since we can't dynamically import Zod here
19
+ * (codegen has no runtime dependency on padrone's main entry point).
20
+ */
21
+ declare function fieldMetaToCode(fields: FieldMeta[]): SchemaToCodeResult;
22
+ //#endregion
23
+ export { fieldMetaToCode, schemaToCode };
24
+ //# sourceMappingURL=schema-to-code.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-to-code.d.mts","names":[],"sources":["../../src/codegen/schema-to-code.ts"],"mappings":";;;;UAIU,kBAAA;;EAER,IAAA;EAF0B;EAI1B,OAAO;AAAA;AAAA;AAkDT;;;AAlDS,iBAkDO,YAAA,CAAa,MAAA,EAAQ,gBAAA,GAAmB,kBAAkB;;;;;AAAA;iBAkC1D,eAAA,CAAgB,MAAA,EAAQ,SAAA,KAAc,kBAAkB"}
@@ -0,0 +1,147 @@
1
+ import { getJsonSchema } from "../core/args.mjs";
2
+ //#region src/codegen/schema-to-code.ts
3
+ /**
4
+ * Convert a JSON Schema property to Zod code.
5
+ */
6
+ function jsonSchemaPropertyToZod(prop, required, ambiguous) {
7
+ let code;
8
+ const type = prop.type;
9
+ const enumValues = prop.enum;
10
+ if (enumValues && enumValues.length > 0) code = `z.enum([${enumValues.map((v) => JSON.stringify(v)).join(", ")}])`;
11
+ else if (type === "string") code = "z.string()";
12
+ else if (type === "number" || type === "integer") code = "z.number()";
13
+ else if (type === "boolean") code = "z.boolean()";
14
+ else if (type === "array") {
15
+ const items = prop.items;
16
+ code = `${items ? jsonSchemaPropertyToZod(items, true) : "z.unknown()"}.array()`;
17
+ } else code = "z.unknown()";
18
+ if (prop.default !== void 0) code += `.default(${JSON.stringify(prop.default)})`;
19
+ else if (!required) code += ".optional()";
20
+ if (prop.description) code += `.describe(${JSON.stringify(prop.description)})`;
21
+ if (ambiguous) code += " /* TODO: verify type */";
22
+ return code;
23
+ }
24
+ /**
25
+ * Generate Zod source code from a Standard Schema instance by introspecting
26
+ * its `~standard.jsonSchema` interface.
27
+ */
28
+ function schemaToCode(schema) {
29
+ try {
30
+ return jsonSchemaToCode(getJsonSchema(schema));
31
+ } catch {
32
+ return {
33
+ code: "z.unknown()",
34
+ imports: ["z"]
35
+ };
36
+ }
37
+ }
38
+ function jsonSchemaToCode(jsonSchema) {
39
+ if (jsonSchema.type === "object" && jsonSchema.properties) {
40
+ const properties = jsonSchema.properties;
41
+ const required = new Set(jsonSchema.required || []);
42
+ return {
43
+ code: `z.object({\n${Object.entries(properties).map(([key, prop]) => {
44
+ return ` ${key}: ${jsonSchemaPropertyToZod(prop, required.has(key))},`;
45
+ }).join("\n")}\n})`,
46
+ imports: ["z"]
47
+ };
48
+ }
49
+ return {
50
+ code: jsonSchemaPropertyToZod(jsonSchema, true),
51
+ imports: ["z"]
52
+ };
53
+ }
54
+ /**
55
+ * Build a real Zod schema from FieldMeta objects.
56
+ * Returns the schema as Zod source code, since we can't dynamically import Zod here
57
+ * (codegen has no runtime dependency on padrone's main entry point).
58
+ */
59
+ function fieldMetaToCode(fields) {
60
+ return {
61
+ code: `z.object({\n${fields.map((field) => {
62
+ let code;
63
+ switch (field.type) {
64
+ case "string":
65
+ code = "z.string()";
66
+ break;
67
+ case "number":
68
+ code = "z.number()";
69
+ break;
70
+ case "boolean":
71
+ code = "z.boolean()";
72
+ break;
73
+ case "array":
74
+ code = `${(field.items || "string") === "number" ? "z.number()" : "z.string()"}.array()`;
75
+ break;
76
+ case "enum":
77
+ if (field.enumValues && field.enumValues.length > 0) code = `z.enum([${field.enumValues.map((v) => JSON.stringify(v)).join(", ")}])`;
78
+ else code = "z.string()";
79
+ break;
80
+ default:
81
+ code = "z.unknown()";
82
+ break;
83
+ }
84
+ if (field.default !== void 0) code += `.default(${JSON.stringify(field.default)})`;
85
+ else if (!field.required) code += ".optional()";
86
+ if (field.description) code += `.describe(${JSON.stringify(field.description)})`;
87
+ if (field.ambiguous) code += " /* TODO: verify type */";
88
+ return ` ${needsQuoting(field.name) ? JSON.stringify(field.name) : field.name}: ${code},`;
89
+ }).join("\n")}\n})`,
90
+ imports: ["z"]
91
+ };
92
+ }
93
+ const JS_RESERVED = /* @__PURE__ */ new Set([
94
+ "break",
95
+ "case",
96
+ "catch",
97
+ "continue",
98
+ "debugger",
99
+ "default",
100
+ "delete",
101
+ "do",
102
+ "else",
103
+ "export",
104
+ "extends",
105
+ "finally",
106
+ "for",
107
+ "function",
108
+ "if",
109
+ "import",
110
+ "in",
111
+ "instanceof",
112
+ "new",
113
+ "return",
114
+ "super",
115
+ "switch",
116
+ "this",
117
+ "throw",
118
+ "try",
119
+ "typeof",
120
+ "var",
121
+ "void",
122
+ "while",
123
+ "with",
124
+ "yield",
125
+ "class",
126
+ "const",
127
+ "enum",
128
+ "let",
129
+ "static",
130
+ "implements",
131
+ "interface",
132
+ "package",
133
+ "private",
134
+ "protected",
135
+ "public",
136
+ "await",
137
+ "async"
138
+ ]);
139
+ /** Returns true if the name needs quoting to be a valid JS object key. */
140
+ function needsQuoting(name) {
141
+ if (JS_RESERVED.has(name)) return true;
142
+ return !/^[a-zA-Z_$][\w$]*$/.test(name);
143
+ }
144
+ //#endregion
145
+ export { fieldMetaToCode, schemaToCode };
146
+
147
+ //# sourceMappingURL=schema-to-code.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-to-code.mjs","names":[],"sources":["../../src/codegen/schema-to-code.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { getJsonSchema } from '../core/args.ts';\nimport type { FieldMeta } from './types.ts';\n\ninterface SchemaToCodeResult {\n /** The generated Zod source code */\n code: string;\n /** Imports needed (e.g. ['z']) */\n imports: string[];\n}\n\n/**\n * Convert a JSON Schema property to Zod code.\n */\nfunction jsonSchemaPropertyToZod(prop: Record<string, any>, required: boolean, ambiguous?: boolean): string {\n let code: string;\n\n const type = prop.type as string | undefined;\n const enumValues = prop.enum as unknown[] | undefined;\n\n if (enumValues && enumValues.length > 0) {\n const values = enumValues.map((v) => JSON.stringify(v)).join(', ');\n code = `z.enum([${values}])`;\n } else if (type === 'string') {\n code = 'z.string()';\n } else if (type === 'number' || type === 'integer') {\n code = 'z.number()';\n } else if (type === 'boolean') {\n code = 'z.boolean()';\n } else if (type === 'array') {\n const items = prop.items as Record<string, any> | undefined;\n const itemCode = items ? jsonSchemaPropertyToZod(items, true) : 'z.unknown()';\n code = `${itemCode}.array()`;\n } else {\n code = 'z.unknown()';\n }\n\n if (prop.default !== undefined) {\n code += `.default(${JSON.stringify(prop.default)})`;\n } else if (!required) {\n code += '.optional()';\n }\n\n if (prop.description) {\n code += `.describe(${JSON.stringify(prop.description)})`;\n }\n\n if (ambiguous) {\n code += ' /* TODO: verify type */';\n }\n\n return code;\n}\n\n/**\n * Generate Zod source code from a Standard Schema instance by introspecting\n * its `~standard.jsonSchema` interface.\n */\nexport function schemaToCode(schema: StandardSchemaV1): SchemaToCodeResult {\n try {\n const jsonSchema = getJsonSchema(schema as any) as Record<string, any>;\n return jsonSchemaToCode(jsonSchema);\n } catch {\n return { code: 'z.unknown()', imports: ['z'] };\n }\n}\n\nfunction jsonSchemaToCode(jsonSchema: Record<string, any>): SchemaToCodeResult {\n if (jsonSchema.type === 'object' && jsonSchema.properties) {\n const properties = jsonSchema.properties as Record<string, any>;\n const required = new Set((jsonSchema.required as string[]) || []);\n\n const entries = Object.entries(properties).map(([key, prop]) => {\n const isRequired = required.has(key);\n const zodCode = jsonSchemaPropertyToZod(prop as Record<string, any>, isRequired);\n return ` ${key}: ${zodCode},`;\n });\n\n const code = `z.object({\\n${entries.join('\\n')}\\n})`;\n return { code, imports: ['z'] };\n }\n\n // Fallback for non-object schemas\n const code = jsonSchemaPropertyToZod(jsonSchema, true);\n return { code, imports: ['z'] };\n}\n\n/**\n * Build a real Zod schema from FieldMeta objects.\n * Returns the schema as Zod source code, since we can't dynamically import Zod here\n * (codegen has no runtime dependency on padrone's main entry point).\n */\nexport function fieldMetaToCode(fields: FieldMeta[]): SchemaToCodeResult {\n const entries = fields.map((field) => {\n let code: string;\n\n switch (field.type) {\n case 'string':\n code = 'z.string()';\n break;\n case 'number':\n code = 'z.number()';\n break;\n case 'boolean':\n code = 'z.boolean()';\n break;\n case 'array': {\n const itemType = field.items || 'string';\n const itemCode = itemType === 'number' ? 'z.number()' : 'z.string()';\n code = `${itemCode}.array()`;\n break;\n }\n case 'enum':\n if (field.enumValues && field.enumValues.length > 0) {\n const values = field.enumValues.map((v) => JSON.stringify(v)).join(', ');\n code = `z.enum([${values}])`;\n } else {\n code = 'z.string()';\n }\n break;\n default:\n code = 'z.unknown()';\n break;\n }\n\n if (field.default !== undefined) {\n code += `.default(${JSON.stringify(field.default)})`;\n } else if (!field.required) {\n code += '.optional()';\n }\n\n if (field.description) {\n code += `.describe(${JSON.stringify(field.description)})`;\n }\n\n if (field.ambiguous) {\n code += ' /* TODO: verify type */';\n }\n\n const key = needsQuoting(field.name) ? JSON.stringify(field.name) : field.name;\n return ` ${key}: ${code},`;\n });\n\n const code = `z.object({\\n${entries.join('\\n')}\\n})`;\n return { code, imports: ['z'] };\n}\n\nconst JS_RESERVED = new Set([\n 'break',\n 'case',\n 'catch',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'export',\n 'extends',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'import',\n 'in',\n 'instanceof',\n 'new',\n 'return',\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield',\n 'class',\n 'const',\n 'enum',\n 'let',\n 'static',\n 'implements',\n 'interface',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'await',\n 'async',\n]);\n\n/** Returns true if the name needs quoting to be a valid JS object key. */\nfunction needsQuoting(name: string): boolean {\n if (JS_RESERVED.has(name)) return true;\n // Must be a valid identifier: starts with letter/$/_, contains only word chars\n return !/^[a-zA-Z_$][\\w$]*$/.test(name);\n}\n"],"mappings":";;;;;AAcA,SAAS,wBAAwB,MAA2B,UAAmB,WAA6B;CAC1G,IAAI;CAEJ,MAAM,OAAO,KAAK;CAClB,MAAM,aAAa,KAAK;CAExB,IAAI,cAAc,WAAW,SAAS,GAEpC,OAAO,WADQ,WAAW,KAAK,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IACtC,EAAE;MACpB,IAAI,SAAS,UAClB,OAAO;MACF,IAAI,SAAS,YAAY,SAAS,WACvC,OAAO;MACF,IAAI,SAAS,WAClB,OAAO;MACF,IAAI,SAAS,SAAS;EAC3B,MAAM,QAAQ,KAAK;EAEnB,OAAO,GADU,QAAQ,wBAAwB,OAAO,IAAI,IAAI,cAC7C;CACrB,OACE,OAAO;CAGT,IAAI,KAAK,YAAY,KAAA,GACnB,QAAQ,YAAY,KAAK,UAAU,KAAK,OAAO,EAAE;MAC5C,IAAI,CAAC,UACV,QAAQ;CAGV,IAAI,KAAK,aACP,QAAQ,aAAa,KAAK,UAAU,KAAK,WAAW,EAAE;CAGxD,IAAI,WACF,QAAQ;CAGV,OAAO;AACT;;;;;AAMA,SAAgB,aAAa,QAA8C;CACzE,IAAI;EAEF,OAAO,iBADY,cAAc,MACA,CAAC;CACpC,QAAQ;EACN,OAAO;GAAE,MAAM;GAAe,SAAS,CAAC,GAAG;EAAE;CAC/C;AACF;AAEA,SAAS,iBAAiB,YAAqD;CAC7E,IAAI,WAAW,SAAS,YAAY,WAAW,YAAY;EACzD,MAAM,aAAa,WAAW;EAC9B,MAAM,WAAW,IAAI,IAAK,WAAW,YAAyB,CAAC,CAAC;EAShE,OAAO;GAAE,MAAA,eAPO,OAAO,QAAQ,UAAU,CAAC,CAAC,KAAK,CAAC,KAAK,UAAU;IAG9D,OAAO,KAAK,IAAI,IADA,wBAAwB,MADrB,SAAS,IAAI,GAC8C,CACpD,EAAE;GAC9B,CAEkC,CAAC,CAAC,KAAK,IAAI,EAAE;GAChC,SAAS,CAAC,GAAG;EAAE;CAChC;CAIA,OAAO;EAAE,MADI,wBAAwB,YAAY,IACrC;EAAG,SAAS,CAAC,GAAG;CAAE;AAChC;;;;;;AAOA,SAAgB,gBAAgB,QAAyC;CAoDvE,OAAO;EAAE,MAAA,eAnDO,OAAO,KAAK,UAAU;GACpC,IAAI;GAEJ,QAAQ,MAAM,MAAd;IACE,KAAK;KACH,OAAO;KACP;IACF,KAAK;KACH,OAAO;KACP;IACF,KAAK;KACH,OAAO;KACP;IACF,KAAK;KAGH,OAAO,IAFU,MAAM,SAAS,cACF,WAAW,eAAe,aACrC;KACnB;IAEF,KAAK;KACH,IAAI,MAAM,cAAc,MAAM,WAAW,SAAS,GAEhD,OAAO,WADQ,MAAM,WAAW,KAAK,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IAC5C,EAAE;UAEzB,OAAO;KAET;IACF;KACE,OAAO;KACP;GACJ;GAEA,IAAI,MAAM,YAAY,KAAA,GACpB,QAAQ,YAAY,KAAK,UAAU,MAAM,OAAO,EAAE;QAC7C,IAAI,CAAC,MAAM,UAChB,QAAQ;GAGV,IAAI,MAAM,aACR,QAAQ,aAAa,KAAK,UAAU,MAAM,WAAW,EAAE;GAGzD,IAAI,MAAM,WACR,QAAQ;GAIV,OAAO,KADK,aAAa,MAAM,IAAI,IAAI,KAAK,UAAU,MAAM,IAAI,IAAI,MAAM,KAC1D,IAAI,KAAK;EAC3B,CAEkC,CAAC,CAAC,KAAK,IAAI,EAAE;EAChC,SAAS,CAAC,GAAG;CAAE;AAChC;AAEA,MAAM,8BAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,SAAS,aAAa,MAAuB;CAC3C,IAAI,YAAY,IAAI,IAAI,GAAG,OAAO;CAElC,OAAO,CAAC,qBAAqB,KAAK,IAAI;AACxC"}
@@ -0,0 +1,18 @@
1
+ //#region src/codegen/template.d.ts
2
+ /**
3
+ * Lightweight string template engine.
4
+ *
5
+ * Syntax:
6
+ * - `{{var}}` — interpolation
7
+ * - `{{#arr}}...{{/arr}}` — iteration (`.` refers to current item)
8
+ * - `{{#bool}}...{{/bool}}` — conditional blocks
9
+ * - `{{>partial}}` — include a named sub-template
10
+ */
11
+ type TemplateRenderer = (data: Record<string, unknown>, partials?: Record<string, string>) => string;
12
+ /**
13
+ * Compile a template string into a reusable render function.
14
+ */
15
+ declare function template(text: string): TemplateRenderer;
16
+ //#endregion
17
+ export { template };
18
+ //# sourceMappingURL=template.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.mts","names":[],"sources":["../../src/codegen/template.ts"],"mappings":";;;;;;;;;;KAUK,gBAAA,IAAoB,IAAA,EAAM,MAAA,mBAAyB,QAAA,GAAW,MAAM;AAAgB;AAKzF;;AALyF,iBAKzE,QAAA,CAAS,IAAA,WAAe,gBAAgB"}
@@ -0,0 +1,37 @@
1
+ //#region src/codegen/template.ts
2
+ /**
3
+ * Compile a template string into a reusable render function.
4
+ */
5
+ function template(text) {
6
+ return (data, partials) => {
7
+ return render(text, data, partials);
8
+ };
9
+ }
10
+ function render(text, data, partials) {
11
+ let result = text;
12
+ result = result.replace(/\{\{#(\w+)\}\}([\s\S]*?)\{\{\/\1\}\}/g, (_match, key, body) => {
13
+ const value = data[key];
14
+ if (value === void 0 || value === null || value === false) return "";
15
+ if (Array.isArray(value)) return value.map((item) => {
16
+ if (typeof item === "object" && item !== null) return render(body, item, partials);
17
+ return body.replace(/\{\{\.\}\}/g, String(item));
18
+ }).join("");
19
+ if (typeof value === "object") return render(body, value, partials);
20
+ return render(body, data, partials);
21
+ });
22
+ if (partials) result = result.replace(/\{\{>(\w+)\}\}/g, (_match, name) => {
23
+ const partialText = partials[name];
24
+ if (!partialText) return "";
25
+ return render(partialText, data, partials);
26
+ });
27
+ result = result.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
28
+ const value = data[key];
29
+ if (value === void 0 || value === null) return "";
30
+ return String(value);
31
+ });
32
+ return result;
33
+ }
34
+ //#endregion
35
+ export { template };
36
+
37
+ //# sourceMappingURL=template.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.mjs","names":[],"sources":["../../src/codegen/template.ts"],"sourcesContent":["/**\n * Lightweight string template engine.\n *\n * Syntax:\n * - `{{var}}` — interpolation\n * - `{{#arr}}...{{/arr}}` — iteration (`.` refers to current item)\n * - `{{#bool}}...{{/bool}}` — conditional blocks\n * - `{{>partial}}` — include a named sub-template\n */\n\ntype TemplateRenderer = (data: Record<string, unknown>, partials?: Record<string, string>) => string;\n\n/**\n * Compile a template string into a reusable render function.\n */\nexport function template(text: string): TemplateRenderer {\n return (data: Record<string, unknown>, partials?: Record<string, string>) => {\n return render(text, data, partials);\n };\n}\n\nfunction render(text: string, data: Record<string, unknown>, partials?: Record<string, string>): string {\n let result = text;\n\n // Process block sections: {{#key}}...{{/key}}\n result = result.replace(/\\{\\{#(\\w+)\\}\\}([\\s\\S]*?)\\{\\{\\/\\1\\}\\}/g, (_match, key: string, body: string) => {\n const value = data[key];\n\n if (value === undefined || value === null || value === false) {\n return '';\n }\n\n if (Array.isArray(value)) {\n return value\n .map((item) => {\n if (typeof item === 'object' && item !== null) {\n return render(body, item as Record<string, unknown>, partials);\n }\n // For primitive items, replace {{.}} with the item value\n return body.replace(/\\{\\{\\.\\}\\}/g, String(item));\n })\n .join('');\n }\n\n // Truthy conditional\n if (typeof value === 'object') {\n return render(body, value as Record<string, unknown>, partials);\n }\n return render(body, data, partials);\n });\n\n // Process partials: {{>partialName}}\n if (partials) {\n result = result.replace(/\\{\\{>(\\w+)\\}\\}/g, (_match, name: string) => {\n const partialText = partials[name];\n if (!partialText) return '';\n return render(partialText, data, partials);\n });\n }\n\n // Process interpolation: {{var}}\n result = result.replace(/\\{\\{(\\w+)\\}\\}/g, (_match, key: string) => {\n const value = data[key];\n if (value === undefined || value === null) return '';\n return String(value);\n });\n\n return result;\n}\n"],"mappings":";;;;AAeA,SAAgB,SAAS,MAAgC;CACvD,QAAQ,MAA+B,aAAsC;EAC3E,OAAO,OAAO,MAAM,MAAM,QAAQ;CACpC;AACF;AAEA,SAAS,OAAO,MAAc,MAA+B,UAA2C;CACtG,IAAI,SAAS;CAGb,SAAS,OAAO,QAAQ,0CAA0C,QAAQ,KAAa,SAAiB;EACtG,MAAM,QAAQ,KAAK;EAEnB,IAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,OACrD,OAAO;EAGT,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MACJ,KAAK,SAAS;GACb,IAAI,OAAO,SAAS,YAAY,SAAS,MACvC,OAAO,OAAO,MAAM,MAAiC,QAAQ;GAG/D,OAAO,KAAK,QAAQ,eAAe,OAAO,IAAI,CAAC;EACjD,CAAC,CAAC,CACD,KAAK,EAAE;EAIZ,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,MAAM,OAAkC,QAAQ;EAEhE,OAAO,OAAO,MAAM,MAAM,QAAQ;CACpC,CAAC;CAGD,IAAI,UACF,SAAS,OAAO,QAAQ,oBAAoB,QAAQ,SAAiB;EACnE,MAAM,cAAc,SAAS;EAC7B,IAAI,CAAC,aAAa,OAAO;EACzB,OAAO,OAAO,aAAa,MAAM,QAAQ;CAC3C,CAAC;CAIH,SAAS,OAAO,QAAQ,mBAAmB,QAAQ,QAAgB;EACjE,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO;EAClD,OAAO,OAAO,KAAK;CACrB,CAAC;CAED,OAAO;AACT"}