@geekmidas/cli 0.3.0 → 0.5.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 (309) hide show
  1. package/README.md +488 -71
  2. package/dist/CronGenerator-BPTqNYOR.d.cts +14 -0
  3. package/dist/{CronGenerator-Bh26MaNA.mjs → CronGenerator-CCRYptuT.mjs} +2 -2
  4. package/dist/{CronGenerator-Bh26MaNA.mjs.map → CronGenerator-CCRYptuT.mjs.map} +1 -1
  5. package/dist/{CronGenerator-C6MF8rlG.cjs → CronGenerator-D4TWXQbh.cjs} +2 -2
  6. package/dist/{CronGenerator-C6MF8rlG.cjs.map → CronGenerator-D4TWXQbh.cjs.map} +1 -1
  7. package/dist/CronGenerator-YAj59JUd.d.mts +14 -0
  8. package/dist/EndpointGenerator-ChAD1INz.d.cts +19 -0
  9. package/dist/EndpointGenerator-Cj3O1U8-.d.mts +19 -0
  10. package/dist/{EndpointGenerator-CWh18d92.mjs → EndpointGenerator-DGivkPLT.mjs} +77 -7
  11. package/dist/EndpointGenerator-DGivkPLT.mjs.map +1 -0
  12. package/dist/{EndpointGenerator-C73wNoih.cjs → EndpointGenerator-npWEDoK2.cjs} +77 -7
  13. package/dist/EndpointGenerator-npWEDoK2.cjs.map +1 -0
  14. package/dist/FunctionGenerator-429-9NER.d.cts +14 -0
  15. package/dist/FunctionGenerator-BQ4ehoID.d.mts +14 -0
  16. package/dist/{FunctionGenerator-BNE_GC7N.mjs → FunctionGenerator-CVk0h8tO.mjs} +2 -2
  17. package/dist/{FunctionGenerator-BNE_GC7N.mjs.map → FunctionGenerator-CVk0h8tO.mjs.map} +1 -1
  18. package/dist/{FunctionGenerator-FgZUTd8L.cjs → FunctionGenerator-DYTnyr4c.cjs} +2 -2
  19. package/dist/{FunctionGenerator-FgZUTd8L.cjs.map → FunctionGenerator-DYTnyr4c.cjs.map} +1 -1
  20. package/dist/Generator-BjHK_qce.d.mts +27 -0
  21. package/dist/{Generator-UanJW0_V.mjs → Generator-CDt4pB3W.mjs} +1 -1
  22. package/dist/{Generator-UanJW0_V.mjs.map → Generator-CDt4pB3W.mjs.map} +1 -1
  23. package/dist/{Generator-CDoEXCDg.cjs → Generator-CLVplqm2.cjs} +1 -1
  24. package/dist/{Generator-CDoEXCDg.cjs.map → Generator-CLVplqm2.cjs.map} +1 -1
  25. package/dist/Generator-DxQMCQp7.d.cts +27 -0
  26. package/dist/OpenApiTsGenerator-Be-sKGTT.cjs +501 -0
  27. package/dist/OpenApiTsGenerator-Be-sKGTT.cjs.map +1 -0
  28. package/dist/OpenApiTsGenerator-C4mHHaku.mjs +495 -0
  29. package/dist/OpenApiTsGenerator-C4mHHaku.mjs.map +1 -0
  30. package/dist/SubscriberGenerator-7uX42xyG.d.mts +15 -0
  31. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs → SubscriberGenerator-DABaJXML.mjs} +2 -2
  32. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs.map → SubscriberGenerator-DABaJXML.mjs.map} +1 -1
  33. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs → SubscriberGenerator-D_zpNGFr.cjs} +2 -2
  34. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs.map → SubscriberGenerator-D_zpNGFr.cjs.map} +1 -1
  35. package/dist/SubscriberGenerator-Dtb3HS4i.d.cts +15 -0
  36. package/dist/api-B3SCEHPf.cjs +190 -0
  37. package/dist/api-B3SCEHPf.cjs.map +1 -0
  38. package/dist/api-BKIN0s0S.mjs +184 -0
  39. package/dist/api-BKIN0s0S.mjs.map +1 -0
  40. package/dist/build/index.cjs +11 -10
  41. package/dist/build/index.d.cts +7 -0
  42. package/dist/build/index.d.mts +7 -0
  43. package/dist/build/index.mjs +11 -10
  44. package/dist/build/manifests.cjs +1 -1
  45. package/dist/build/manifests.d.cts +13 -0
  46. package/dist/build/manifests.d.mts +13 -0
  47. package/dist/build/manifests.mjs +1 -1
  48. package/dist/build/providerResolver.cjs +1 -1
  49. package/dist/build/providerResolver.d.cts +23 -0
  50. package/dist/build/providerResolver.d.mts +23 -0
  51. package/dist/build/providerResolver.mjs +1 -1
  52. package/dist/build/types.d.cts +3 -0
  53. package/dist/build/types.d.mts +3 -0
  54. package/dist/{build-C6uEGRj8.mjs → build-B8C_qHir.mjs} +15 -13
  55. package/dist/build-B8C_qHir.mjs.map +1 -0
  56. package/dist/{build-CBYBPZpC.cjs → build-D0Wr49bf.cjs} +15 -13
  57. package/dist/build-D0Wr49bf.cjs.map +1 -0
  58. package/dist/config-Ba-Gbpbc.d.cts +11 -0
  59. package/dist/config-Bq72aj8e.mjs +75 -0
  60. package/dist/config-Bq72aj8e.mjs.map +1 -0
  61. package/dist/config-CFls09Ey.cjs +93 -0
  62. package/dist/config-CFls09Ey.cjs.map +1 -0
  63. package/dist/config-CLEDqKO3.cjs +157 -0
  64. package/dist/config-CLEDqKO3.cjs.map +1 -0
  65. package/dist/config-DBsmMDhf.d.mts +11 -0
  66. package/dist/config-Dp8RonV_.mjs +151 -0
  67. package/dist/config-Dp8RonV_.mjs.map +1 -0
  68. package/dist/config.cjs +4 -2
  69. package/dist/config.d.cts +48 -0
  70. package/dist/config.d.mts +48 -0
  71. package/dist/config.mjs +2 -2
  72. package/dist/dev/index.cjs +12 -10
  73. package/dist/dev/index.d.cts +36 -0
  74. package/dist/dev/index.d.mts +36 -0
  75. package/dist/dev/index.mjs +10 -10
  76. package/dist/dev-B734w3L1.mjs +343 -0
  77. package/dist/dev-B734w3L1.mjs.map +1 -0
  78. package/dist/{dev-DbtyToc7.cjs → dev-DHqYn8k4.cjs} +161 -47
  79. package/dist/dev-DHqYn8k4.cjs.map +1 -0
  80. package/dist/docker-5d8Yh5_X.cjs +119 -0
  81. package/dist/docker-5d8Yh5_X.cjs.map +1 -0
  82. package/dist/docker-DlUqdFle.mjs +113 -0
  83. package/dist/docker-DlUqdFle.mjs.map +1 -0
  84. package/dist/env-B-OKjgI4.cjs +144 -0
  85. package/dist/env-B-OKjgI4.cjs.map +1 -0
  86. package/dist/env-HfuJRlg5.d.cts +11 -0
  87. package/dist/env-nd-iQPYM.d.mts +11 -0
  88. package/dist/env-tv1HlZlw.mjs +138 -0
  89. package/dist/env-tv1HlZlw.mjs.map +1 -0
  90. package/dist/generators/CronGenerator.cjs +2 -2
  91. package/dist/generators/CronGenerator.d.cts +5 -0
  92. package/dist/generators/CronGenerator.d.mts +5 -0
  93. package/dist/generators/CronGenerator.mjs +2 -2
  94. package/dist/generators/EndpointGenerator.cjs +2 -2
  95. package/dist/generators/EndpointGenerator.d.cts +5 -0
  96. package/dist/generators/EndpointGenerator.d.mts +5 -0
  97. package/dist/generators/EndpointGenerator.mjs +2 -2
  98. package/dist/generators/FunctionGenerator.cjs +2 -2
  99. package/dist/generators/FunctionGenerator.d.cts +5 -0
  100. package/dist/generators/FunctionGenerator.d.mts +5 -0
  101. package/dist/generators/FunctionGenerator.mjs +2 -2
  102. package/dist/generators/Generator.cjs +1 -1
  103. package/dist/generators/Generator.d.cts +4 -0
  104. package/dist/generators/Generator.d.mts +4 -0
  105. package/dist/generators/Generator.mjs +1 -1
  106. package/dist/generators/OpenApiTsGenerator.cjs +3 -0
  107. package/dist/generators/OpenApiTsGenerator.d.cts +44 -0
  108. package/dist/generators/OpenApiTsGenerator.d.mts +44 -0
  109. package/dist/generators/OpenApiTsGenerator.mjs +3 -0
  110. package/dist/generators/SubscriberGenerator.cjs +2 -2
  111. package/dist/generators/SubscriberGenerator.d.cts +5 -0
  112. package/dist/generators/SubscriberGenerator.d.mts +5 -0
  113. package/dist/generators/SubscriberGenerator.mjs +2 -2
  114. package/dist/generators/index.cjs +6 -6
  115. package/dist/generators/index.d.cts +8 -0
  116. package/dist/generators/index.d.mts +8 -0
  117. package/dist/generators/index.mjs +6 -6
  118. package/dist/index-C523No_B.d.mts +64 -0
  119. package/dist/index-DrzN4xkQ.d.cts +64 -0
  120. package/dist/index.cjs +56 -18
  121. package/dist/index.cjs.map +1 -1
  122. package/dist/index.d.cts +1 -0
  123. package/dist/index.d.mts +1 -0
  124. package/dist/index.mjs +56 -18
  125. package/dist/index.mjs.map +1 -1
  126. package/dist/init/generators/config.cjs +3 -0
  127. package/dist/init/generators/config.d.cts +3 -0
  128. package/dist/init/generators/config.d.mts +3 -0
  129. package/dist/init/generators/config.mjs +3 -0
  130. package/dist/init/generators/docker.cjs +3 -0
  131. package/dist/init/generators/docker.d.cts +11 -0
  132. package/dist/init/generators/docker.d.mts +11 -0
  133. package/dist/init/generators/docker.mjs +3 -0
  134. package/dist/init/generators/env.cjs +3 -0
  135. package/dist/init/generators/env.d.cts +3 -0
  136. package/dist/init/generators/env.d.mts +3 -0
  137. package/dist/init/generators/env.mjs +3 -0
  138. package/dist/init/generators/index.cjs +9 -0
  139. package/dist/init/generators/index.d.cts +6 -0
  140. package/dist/init/generators/index.d.mts +6 -0
  141. package/dist/init/generators/index.mjs +6 -0
  142. package/dist/init/generators/models.cjs +3 -0
  143. package/dist/init/generators/models.d.cts +11 -0
  144. package/dist/init/generators/models.d.mts +11 -0
  145. package/dist/init/generators/models.mjs +3 -0
  146. package/dist/init/generators/monorepo.cjs +3 -0
  147. package/dist/init/generators/monorepo.d.cts +11 -0
  148. package/dist/init/generators/monorepo.d.mts +11 -0
  149. package/dist/init/generators/monorepo.mjs +3 -0
  150. package/dist/init/generators/package.cjs +3 -0
  151. package/dist/init/generators/package.d.cts +3 -0
  152. package/dist/init/generators/package.d.mts +3 -0
  153. package/dist/init/generators/package.mjs +3 -0
  154. package/dist/init/generators/source.cjs +3 -0
  155. package/dist/init/generators/source.d.cts +3 -0
  156. package/dist/init/generators/source.d.mts +3 -0
  157. package/dist/init/generators/source.mjs +3 -0
  158. package/dist/init/index.cjs +16 -0
  159. package/dist/init/index.d.cts +17 -0
  160. package/dist/init/index.d.mts +17 -0
  161. package/dist/init/index.mjs +16 -0
  162. package/dist/init/templates/api.cjs +3 -0
  163. package/dist/init/templates/api.d.cts +7 -0
  164. package/dist/init/templates/api.d.mts +7 -0
  165. package/dist/init/templates/api.mjs +3 -0
  166. package/dist/init/templates/index.cjs +10 -0
  167. package/dist/init/templates/index.d.cts +2 -0
  168. package/dist/init/templates/index.d.mts +2 -0
  169. package/dist/init/templates/index.mjs +7 -0
  170. package/dist/init/templates/minimal.cjs +3 -0
  171. package/dist/init/templates/minimal.d.cts +7 -0
  172. package/dist/init/templates/minimal.d.mts +7 -0
  173. package/dist/init/templates/minimal.mjs +3 -0
  174. package/dist/init/templates/serverless.cjs +3 -0
  175. package/dist/init/templates/serverless.d.cts +7 -0
  176. package/dist/init/templates/serverless.d.mts +7 -0
  177. package/dist/init/templates/serverless.mjs +3 -0
  178. package/dist/init/templates/worker.cjs +3 -0
  179. package/dist/init/templates/worker.d.cts +7 -0
  180. package/dist/init/templates/worker.d.mts +7 -0
  181. package/dist/init/templates/worker.mjs +3 -0
  182. package/dist/init/utils.cjs +7 -0
  183. package/dist/init/utils.d.cts +25 -0
  184. package/dist/init/utils.d.mts +25 -0
  185. package/dist/init/utils.mjs +3 -0
  186. package/dist/init-CtOnZn3G.mjs +145 -0
  187. package/dist/init-CtOnZn3G.mjs.map +1 -0
  188. package/dist/init-qLFsWR-R.cjs +151 -0
  189. package/dist/init-qLFsWR-R.cjs.map +1 -0
  190. package/dist/{manifests-C2eMoMUm.mjs → manifests-DIA_2QYd.mjs} +1 -1
  191. package/dist/{manifests-C2eMoMUm.mjs.map → manifests-DIA_2QYd.mjs.map} +1 -1
  192. package/dist/{manifests-CK1VV_pM.cjs → manifests-VJ9-2JpW.cjs} +1 -1
  193. package/dist/{manifests-CK1VV_pM.cjs.map → manifests-VJ9-2JpW.cjs.map} +1 -1
  194. package/dist/minimal-Bdhhpp7v.cjs +93 -0
  195. package/dist/minimal-Bdhhpp7v.cjs.map +1 -0
  196. package/dist/minimal-C4GsE45s.mjs +87 -0
  197. package/dist/minimal-C4GsE45s.mjs.map +1 -0
  198. package/dist/models-DyNwdOcz.cjs +121 -0
  199. package/dist/models-DyNwdOcz.cjs.map +1 -0
  200. package/dist/models-cvNg6Oea.mjs +115 -0
  201. package/dist/models-cvNg6Oea.mjs.map +1 -0
  202. package/dist/monorepo-Cknwzj5C.mjs +184 -0
  203. package/dist/monorepo-Cknwzj5C.mjs.map +1 -0
  204. package/dist/monorepo-sEK8gW59.cjs +190 -0
  205. package/dist/monorepo-sEK8gW59.cjs.map +1 -0
  206. package/dist/openapi-BQWPWyNB.cjs +56 -0
  207. package/dist/openapi-BQWPWyNB.cjs.map +1 -0
  208. package/dist/openapi-DBX8cJJ8.mjs +50 -0
  209. package/dist/openapi-DBX8cJJ8.mjs.map +1 -0
  210. package/dist/{openapi-react-query-D9Z7lh0p.cjs → openapi-react-query-DxHjXQvg.cjs} +1 -1
  211. package/dist/{openapi-react-query-D9Z7lh0p.cjs.map → openapi-react-query-DxHjXQvg.cjs.map} +1 -1
  212. package/dist/{openapi-react-query-MEBlYIM1.mjs → openapi-react-query-o7Mp1Jd5.mjs} +1 -1
  213. package/dist/{openapi-react-query-MEBlYIM1.mjs.map → openapi-react-query-o7Mp1Jd5.mjs.map} +1 -1
  214. package/dist/openapi-react-query.cjs +1 -1
  215. package/dist/openapi-react-query.d.cts +11 -0
  216. package/dist/openapi-react-query.d.mts +11 -0
  217. package/dist/openapi-react-query.mjs +1 -1
  218. package/dist/openapi.cjs +5 -4
  219. package/dist/openapi.d.cts +11 -0
  220. package/dist/openapi.d.mts +11 -0
  221. package/dist/openapi.mjs +5 -4
  222. package/dist/package-C7WhWU8m.d.mts +11 -0
  223. package/dist/package-CIfmeuSW.mjs +51 -0
  224. package/dist/package-CIfmeuSW.mjs.map +1 -0
  225. package/dist/package-DvWEMz6z.d.cts +11 -0
  226. package/dist/package-PP-o1nvq.cjs +57 -0
  227. package/dist/package-PP-o1nvq.cjs.map +1 -0
  228. package/dist/{providerResolver-B_TjNF0_.mjs → providerResolver-DEVKngbC.mjs} +1 -1
  229. package/dist/{providerResolver-B_TjNF0_.mjs.map → providerResolver-DEVKngbC.mjs.map} +1 -1
  230. package/dist/{providerResolver-DgvzNfP4.cjs → providerResolver-DOTbN9jo.cjs} +1 -1
  231. package/dist/{providerResolver-DgvzNfP4.cjs.map → providerResolver-DOTbN9jo.cjs.map} +1 -1
  232. package/dist/serverless-DkHBF2vC.mjs +108 -0
  233. package/dist/serverless-DkHBF2vC.mjs.map +1 -0
  234. package/dist/serverless-Yav3GRVz.cjs +114 -0
  235. package/dist/serverless-Yav3GRVz.cjs.map +1 -0
  236. package/dist/source-D6v2BnKT.d.mts +11 -0
  237. package/dist/source-D8fK9qRo.d.cts +11 -0
  238. package/dist/source-DT5Xhiob.cjs +17 -0
  239. package/dist/source-DT5Xhiob.cjs.map +1 -0
  240. package/dist/source-DnaH_MLA.mjs +11 -0
  241. package/dist/source-DnaH_MLA.mjs.map +1 -0
  242. package/dist/templates-CBFUwpBy.mjs +64 -0
  243. package/dist/templates-CBFUwpBy.mjs.map +1 -0
  244. package/dist/templates-DM_rtYYW.cjs +87 -0
  245. package/dist/templates-DM_rtYYW.cjs.map +1 -0
  246. package/dist/types-C4KITv-y.d.mts +51 -0
  247. package/dist/types-Cxl8-uwV.d.mts +129 -0
  248. package/dist/types-DB99_qIy.d.cts +129 -0
  249. package/dist/types-DLFN49M3.d.cts +51 -0
  250. package/dist/types.d.cts +2 -0
  251. package/dist/types.d.mts +2 -0
  252. package/dist/utils-BX3F4fT8.cjs +99 -0
  253. package/dist/utils-BX3F4fT8.cjs.map +1 -0
  254. package/dist/utils-C31-SWHP.mjs +69 -0
  255. package/dist/utils-C31-SWHP.mjs.map +1 -0
  256. package/dist/worker--8O5a3Hv.cjs +150 -0
  257. package/dist/worker--8O5a3Hv.cjs.map +1 -0
  258. package/dist/worker-Jme7uOOJ.mjs +144 -0
  259. package/dist/worker-Jme7uOOJ.mjs.map +1 -0
  260. package/docs/OPENAPI_TYPESCRIPT_DESIGN.md +408 -0
  261. package/package.json +19 -4
  262. package/src/__tests__/loadEnvFiles.spec.ts +131 -0
  263. package/src/__tests__/openapi.spec.ts +78 -63
  264. package/src/build/index.ts +14 -16
  265. package/src/build/types.ts +18 -2
  266. package/src/config.ts +61 -2
  267. package/src/dev/__tests__/index.spec.ts +98 -1
  268. package/src/dev/index.ts +229 -42
  269. package/src/generators/EndpointGenerator.ts +98 -5
  270. package/src/generators/OpenApiTsGenerator.ts +798 -0
  271. package/src/index.ts +32 -3
  272. package/src/init/__tests__/generators.spec.ts +366 -0
  273. package/src/init/__tests__/init.spec.ts +341 -0
  274. package/src/init/__tests__/utils.spec.ts +104 -0
  275. package/src/init/generators/config.ts +192 -0
  276. package/src/init/generators/docker.ts +134 -0
  277. package/src/init/generators/env.ts +182 -0
  278. package/src/init/generators/index.ts +4 -0
  279. package/src/init/generators/models.ts +129 -0
  280. package/src/init/generators/monorepo.ts +211 -0
  281. package/src/init/generators/package.ts +81 -0
  282. package/src/init/generators/source.ts +15 -0
  283. package/src/init/index.ts +206 -0
  284. package/src/init/templates/api.ts +218 -0
  285. package/src/init/templates/index.ts +108 -0
  286. package/src/init/templates/minimal.ts +102 -0
  287. package/src/init/templates/serverless.ts +129 -0
  288. package/src/init/templates/worker.ts +169 -0
  289. package/src/init/utils.ts +98 -0
  290. package/src/openapi.ts +36 -15
  291. package/src/types.ts +43 -0
  292. package/tsdown.config.ts +1 -1
  293. package/dist/EndpointGenerator-C73wNoih.cjs.map +0 -1
  294. package/dist/EndpointGenerator-CWh18d92.mjs.map +0 -1
  295. package/dist/build-C6uEGRj8.mjs.map +0 -1
  296. package/dist/build-CBYBPZpC.cjs.map +0 -1
  297. package/dist/config-D1EpSGk6.cjs +0 -36
  298. package/dist/config-D1EpSGk6.cjs.map +0 -1
  299. package/dist/config-U-mdW-7Y.mjs +0 -30
  300. package/dist/config-U-mdW-7Y.mjs.map +0 -1
  301. package/dist/dev-DbtyToc7.cjs.map +0 -1
  302. package/dist/dev-DnGYXuMn.mjs +0 -241
  303. package/dist/dev-DnGYXuMn.mjs.map +0 -1
  304. package/dist/openapi-BTHbPrxS.mjs +0 -36
  305. package/dist/openapi-BTHbPrxS.mjs.map +0 -1
  306. package/dist/openapi-CewcfoRH.cjs +0 -42
  307. package/dist/openapi-CewcfoRH.cjs.map +0 -1
  308. /package/dist/{generators-CEKtVh81.cjs → generators-3IemvCLk.cjs} +0 -0
  309. /package/dist/{generators-CsLujGXs.mjs → generators-FNpdfN6J.mjs} +0 -0
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import { Command } from 'commander';
4
4
  import pkg from '../package.json' assert { type: 'json' };
5
5
  import { buildCommand } from './build/index.ts';
6
6
  import { devCommand } from './dev/index.ts';
7
+ import { type InitOptions, initCommand } from './init/index.ts';
7
8
  import { generateReactQueryCommand } from './openapi-react-query.ts';
8
9
  import { openapiCommand } from './openapi.ts';
9
10
  import type { LegacyProvider, MainProvider } from './types.ts';
@@ -16,6 +17,31 @@ program
16
17
  .version(pkg.version)
17
18
  .option('--cwd <path>', 'Change working directory');
18
19
 
20
+ program
21
+ .command('init')
22
+ .description('Scaffold a new project')
23
+ .argument('[name]', 'Project name')
24
+ .option(
25
+ '--template <template>',
26
+ 'Project template (minimal, api, serverless, worker)',
27
+ )
28
+ .option('--skip-install', 'Skip dependency installation', false)
29
+ .option('-y, --yes', 'Skip prompts, use defaults', false)
30
+ .option('--monorepo', 'Setup as monorepo with packages/models', false)
31
+ .option('--api-path <path>', 'API app path in monorepo (default: apps/api)')
32
+ .action(async (name: string | undefined, options: InitOptions) => {
33
+ try {
34
+ const globalOptions = program.opts();
35
+ if (globalOptions.cwd) {
36
+ process.chdir(globalOptions.cwd);
37
+ }
38
+ await initCommand(name, options);
39
+ } catch (error) {
40
+ console.error('Init failed:', (error as Error).message);
41
+ process.exit(1);
42
+ }
43
+ });
44
+
19
45
  program
20
46
  .command('build')
21
47
  .description('Build handlers from endpoints, functions, and crons')
@@ -143,13 +169,16 @@ program
143
169
 
144
170
  program
145
171
  .command('openapi')
146
- .description('Generate OpenAPI 3.0 specification from endpoints')
172
+ .description(
173
+ 'Generate OpenAPI specification from endpoints (TypeScript by default)',
174
+ )
147
175
  .option(
148
176
  '--output <path>',
149
177
  'Output file path for the OpenAPI spec',
150
- 'openapi.json',
178
+ 'openapi.ts',
151
179
  )
152
- .action(async (options: { output?: string }) => {
180
+ .option('--json', 'Generate JSON instead of TypeScript (legacy)', false)
181
+ .action(async (options: { output?: string; json?: boolean }) => {
153
182
  try {
154
183
  const globalOptions = program.opts();
155
184
  if (globalOptions.cwd) {
@@ -0,0 +1,366 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { generateConfigFiles } from '../generators/config.js';
3
+ import { generateDockerFiles } from '../generators/docker.js';
4
+ import { generateEnvFiles } from '../generators/env.js';
5
+ import { generateModelsPackage } from '../generators/models.js';
6
+ import { generateMonorepoFiles } from '../generators/monorepo.js';
7
+ import { generatePackageJson } from '../generators/package.js';
8
+ import type { TemplateOptions } from '../templates/index.js';
9
+ import { minimalTemplate } from '../templates/minimal.js';
10
+ import { serverlessTemplate } from '../templates/serverless.js';
11
+ import { workerTemplate } from '../templates/worker.js';
12
+
13
+ const baseOptions: TemplateOptions = {
14
+ name: 'test-project',
15
+ template: 'minimal',
16
+ telescope: true,
17
+ database: true,
18
+ routeStyle: 'file-based',
19
+ monorepo: false,
20
+ apiPath: '',
21
+ };
22
+
23
+ describe('generatePackageJson', () => {
24
+ it('should generate package.json with correct name', () => {
25
+ const files = generatePackageJson(baseOptions, minimalTemplate);
26
+ expect(files).toHaveLength(1);
27
+ expect(files[0].path).toBe('package.json');
28
+
29
+ const pkg = JSON.parse(files[0].content);
30
+ expect(pkg.name).toBe('test-project');
31
+ expect(pkg.type).toBe('module');
32
+ expect(pkg.private).toBe(true);
33
+ });
34
+
35
+ it('should include telescope when enabled', () => {
36
+ const files = generatePackageJson(baseOptions, minimalTemplate);
37
+ const pkg = JSON.parse(files[0].content);
38
+ expect(pkg.dependencies['@geekmidas/telescope']).toBe('workspace:*');
39
+ });
40
+
41
+ it('should include database dependencies when enabled', () => {
42
+ const files = generatePackageJson(baseOptions, minimalTemplate);
43
+ const pkg = JSON.parse(files[0].content);
44
+ expect(pkg.dependencies['@geekmidas/db']).toBe('workspace:*');
45
+ expect(pkg.dependencies['kysely']).toBeDefined();
46
+ expect(pkg.dependencies['pg']).toBeDefined();
47
+ });
48
+
49
+ it('should exclude telescope when disabled', () => {
50
+ const options = { ...baseOptions, telescope: false };
51
+ const files = generatePackageJson(options, minimalTemplate);
52
+ const pkg = JSON.parse(files[0].content);
53
+ expect(pkg.dependencies['@geekmidas/telescope']).toBeUndefined();
54
+ });
55
+
56
+ it('should use workspace:* for @geekmidas packages', () => {
57
+ const files = generatePackageJson(baseOptions, minimalTemplate);
58
+ const pkg = JSON.parse(files[0].content);
59
+ expect(pkg.dependencies['@geekmidas/constructs']).toBe('workspace:*');
60
+ expect(pkg.dependencies['@geekmidas/envkit']).toBe('workspace:*');
61
+ expect(pkg.dependencies['@geekmidas/logger']).toBe('workspace:*');
62
+ });
63
+
64
+ it('should use tilde versions for external packages', () => {
65
+ const files = generatePackageJson(baseOptions, minimalTemplate);
66
+ const pkg = JSON.parse(files[0].content);
67
+ expect(pkg.dependencies['hono']).toMatch(/^~/);
68
+ expect(pkg.dependencies['pino']).toMatch(/^~/);
69
+ expect(pkg.devDependencies['typescript']).toMatch(/^~/);
70
+ });
71
+
72
+ it('should include biome and turbo for non-monorepo', () => {
73
+ const files = generatePackageJson(baseOptions, minimalTemplate);
74
+ const pkg = JSON.parse(files[0].content);
75
+ expect(pkg.devDependencies['@biomejs/biome']).toBeDefined();
76
+ expect(pkg.devDependencies['turbo']).toBeDefined();
77
+ expect(pkg.scripts['lint']).toBeDefined();
78
+ expect(pkg.scripts['fmt']).toBeDefined();
79
+ });
80
+
81
+ it('should exclude biome and turbo for monorepo apps', () => {
82
+ const options: TemplateOptions = {
83
+ ...baseOptions,
84
+ monorepo: true,
85
+ apiPath: 'apps/api',
86
+ };
87
+ const files = generatePackageJson(options, minimalTemplate);
88
+ const pkg = JSON.parse(files[0].content);
89
+ expect(pkg.devDependencies['@biomejs/biome']).toBeUndefined();
90
+ expect(pkg.devDependencies['turbo']).toBeUndefined();
91
+ expect(pkg.scripts['lint']).toBeUndefined();
92
+ expect(pkg.scripts['fmt']).toBeUndefined();
93
+ });
94
+
95
+ it('should include models package for monorepo apps', () => {
96
+ const options: TemplateOptions = {
97
+ ...baseOptions,
98
+ monorepo: true,
99
+ apiPath: 'apps/api',
100
+ };
101
+ const files = generatePackageJson(options, minimalTemplate);
102
+ const pkg = JSON.parse(files[0].content);
103
+ expect(pkg.dependencies['@test-project/models']).toBe('workspace:*');
104
+ expect(pkg.dependencies['zod']).toBeUndefined(); // zod is in models
105
+ });
106
+
107
+ it('should use scoped package name for monorepo apps', () => {
108
+ const options: TemplateOptions = {
109
+ ...baseOptions,
110
+ monorepo: true,
111
+ apiPath: 'apps/api',
112
+ };
113
+ const files = generatePackageJson(options, minimalTemplate);
114
+ const pkg = JSON.parse(files[0].content);
115
+ expect(pkg.name).toBe('@test-project/api');
116
+ });
117
+ });
118
+
119
+ describe('generateConfigFiles', () => {
120
+ it('should generate gkm.config.ts and tsconfig.json for non-monorepo', () => {
121
+ const files = generateConfigFiles(baseOptions, minimalTemplate);
122
+ const paths = files.map((f) => f.path);
123
+ expect(paths).toContain('gkm.config.ts');
124
+ expect(paths).toContain('tsconfig.json');
125
+ expect(paths).toContain('biome.json');
126
+ expect(paths).toContain('turbo.json');
127
+ });
128
+
129
+ it('should only generate gkm.config.ts and tsconfig.json for monorepo', () => {
130
+ const options: TemplateOptions = {
131
+ ...baseOptions,
132
+ monorepo: true,
133
+ apiPath: 'apps/api',
134
+ };
135
+ const files = generateConfigFiles(options, minimalTemplate);
136
+ const paths = files.map((f) => f.path);
137
+ expect(paths).toContain('gkm.config.ts');
138
+ expect(paths).toContain('tsconfig.json');
139
+ expect(paths).not.toContain('biome.json');
140
+ expect(paths).not.toContain('turbo.json');
141
+ });
142
+
143
+ it('should include telescope config when enabled', () => {
144
+ const files = generateConfigFiles(baseOptions, minimalTemplate);
145
+ const gkmConfig = files.find((f) => f.path === 'gkm.config.ts');
146
+ expect(gkmConfig?.content).toContain('telescope');
147
+ });
148
+
149
+ it('should include functions config for serverless template', () => {
150
+ const options = { ...baseOptions, template: 'serverless' as const };
151
+ const files = generateConfigFiles(options, serverlessTemplate);
152
+ const gkmConfig = files.find((f) => f.path === 'gkm.config.ts');
153
+ expect(gkmConfig?.content).toContain('functions');
154
+ });
155
+
156
+ it('should include paths config for monorepo apps', () => {
157
+ const options: TemplateOptions = {
158
+ ...baseOptions,
159
+ monorepo: true,
160
+ apiPath: 'apps/api',
161
+ };
162
+ const files = generateConfigFiles(options, minimalTemplate);
163
+ const tsConfig = files.find((f) => f.path === 'tsconfig.json');
164
+ const config = JSON.parse(tsConfig!.content);
165
+ expect(config.extends).toBe('../../tsconfig.json');
166
+ expect(config.compilerOptions.paths).toBeDefined();
167
+ expect(config.compilerOptions.paths['@test-project/*']).toBeDefined();
168
+ });
169
+ });
170
+
171
+ describe('generateEnvFiles', () => {
172
+ it('should generate all env files for non-monorepo', () => {
173
+ const files = generateEnvFiles(baseOptions, minimalTemplate);
174
+ const paths = files.map((f) => f.path);
175
+ expect(paths).toContain('.env');
176
+ expect(paths).toContain('.env.example');
177
+ expect(paths).toContain('.env.development');
178
+ expect(paths).toContain('.env.test');
179
+ expect(paths).toContain('.gitignore');
180
+ });
181
+
182
+ it('should not generate .gitignore for monorepo', () => {
183
+ const options: TemplateOptions = {
184
+ ...baseOptions,
185
+ monorepo: true,
186
+ apiPath: 'apps/api',
187
+ };
188
+ const files = generateEnvFiles(options, minimalTemplate);
189
+ const paths = files.map((f) => f.path);
190
+ expect(paths).not.toContain('.gitignore');
191
+ });
192
+
193
+ it('should include DATABASE_URL when database is enabled', () => {
194
+ const files = generateEnvFiles(baseOptions, minimalTemplate);
195
+ const envFile = files.find((f) => f.path === '.env');
196
+ expect(envFile?.content).toContain('DATABASE_URL');
197
+ });
198
+
199
+ it('should include RABBITMQ_URL for worker template', () => {
200
+ const options = { ...baseOptions, template: 'worker' as const };
201
+ const files = generateEnvFiles(options, workerTemplate);
202
+ const envFile = files.find((f) => f.path === '.env');
203
+ expect(envFile?.content).toContain('RABBITMQ_URL');
204
+ });
205
+ });
206
+
207
+ describe('generateDockerFiles', () => {
208
+ it('should generate docker-compose.yml', () => {
209
+ const files = generateDockerFiles(baseOptions, minimalTemplate);
210
+ expect(files).toHaveLength(1);
211
+ expect(files[0].path).toBe('docker-compose.yml');
212
+ });
213
+
214
+ it('should include postgres when database is enabled', () => {
215
+ const files = generateDockerFiles(baseOptions, minimalTemplate);
216
+ expect(files[0].content).toContain('postgres');
217
+ expect(files[0].content).toContain('5432');
218
+ });
219
+
220
+ it('should include redis', () => {
221
+ const files = generateDockerFiles(baseOptions, minimalTemplate);
222
+ expect(files[0].content).toContain('redis');
223
+ expect(files[0].content).toContain('6379');
224
+ });
225
+
226
+ it('should include serverless-redis-http for serverless template', () => {
227
+ const options = { ...baseOptions, template: 'serverless' as const };
228
+ const files = generateDockerFiles(options, serverlessTemplate);
229
+ expect(files[0].content).toContain('hiett/serverless-redis-http');
230
+ expect(files[0].content).toContain('8079');
231
+ });
232
+
233
+ it('should include rabbitmq for worker template', () => {
234
+ const options = { ...baseOptions, template: 'worker' as const };
235
+ const files = generateDockerFiles(options, workerTemplate);
236
+ expect(files[0].content).toContain('rabbitmq');
237
+ expect(files[0].content).toContain('5672');
238
+ expect(files[0].content).toContain('15672');
239
+ });
240
+ });
241
+
242
+ describe('generateMonorepoFiles', () => {
243
+ it('should return empty array for non-monorepo', () => {
244
+ const files = generateMonorepoFiles(baseOptions, minimalTemplate);
245
+ expect(files).toHaveLength(0);
246
+ });
247
+
248
+ it('should generate root files for monorepo', () => {
249
+ const options: TemplateOptions = {
250
+ ...baseOptions,
251
+ monorepo: true,
252
+ apiPath: 'apps/api',
253
+ };
254
+ const files = generateMonorepoFiles(options, minimalTemplate);
255
+ const paths = files.map((f) => f.path);
256
+ expect(paths).toContain('package.json');
257
+ expect(paths).toContain('pnpm-workspace.yaml');
258
+ expect(paths).toContain('tsconfig.json');
259
+ expect(paths).toContain('biome.json');
260
+ expect(paths).toContain('turbo.json');
261
+ expect(paths).toContain('.gitignore');
262
+ });
263
+
264
+ it('should include correct workspace paths', () => {
265
+ const options: TemplateOptions = {
266
+ ...baseOptions,
267
+ monorepo: true,
268
+ apiPath: 'apps/api',
269
+ };
270
+ const files = generateMonorepoFiles(options, minimalTemplate);
271
+ const workspace = files.find((f) => f.path === 'pnpm-workspace.yaml');
272
+ expect(workspace?.content).toContain("'apps/*'");
273
+ expect(workspace?.content).toContain("'packages/*'");
274
+ });
275
+
276
+ it('should include root scripts', () => {
277
+ const options: TemplateOptions = {
278
+ ...baseOptions,
279
+ monorepo: true,
280
+ apiPath: 'apps/api',
281
+ };
282
+ const files = generateMonorepoFiles(options, minimalTemplate);
283
+ const pkgJson = files.find((f) => f.path === 'package.json');
284
+ const pkg = JSON.parse(pkgJson!.content);
285
+ expect(pkg.scripts.dev).toBe('turbo dev');
286
+ expect(pkg.scripts.build).toBe('turbo build');
287
+ expect(pkg.scripts.lint).toBe('biome lint .');
288
+ });
289
+ });
290
+
291
+ describe('generateModelsPackage', () => {
292
+ it('should return empty array for non-monorepo', () => {
293
+ const files = generateModelsPackage(baseOptions);
294
+ expect(files).toHaveLength(0);
295
+ });
296
+
297
+ it('should generate models package for monorepo', () => {
298
+ const options: TemplateOptions = {
299
+ ...baseOptions,
300
+ monorepo: true,
301
+ apiPath: 'apps/api',
302
+ };
303
+ const files = generateModelsPackage(options);
304
+ const paths = files.map((f) => f.path);
305
+ expect(paths).toContain('packages/models/package.json');
306
+ expect(paths).toContain('packages/models/tsconfig.json');
307
+ expect(paths).toContain('packages/models/src/index.ts');
308
+ });
309
+
310
+ it('should use correct package name', () => {
311
+ const options: TemplateOptions = {
312
+ ...baseOptions,
313
+ monorepo: true,
314
+ apiPath: 'apps/api',
315
+ };
316
+ const files = generateModelsPackage(options);
317
+ const pkgJson = files.find(
318
+ (f) => f.path === 'packages/models/package.json',
319
+ );
320
+ const pkg = JSON.parse(pkgJson!.content);
321
+ expect(pkg.name).toBe('@test-project/models');
322
+ });
323
+
324
+ it('should include zod as dependency', () => {
325
+ const options: TemplateOptions = {
326
+ ...baseOptions,
327
+ monorepo: true,
328
+ apiPath: 'apps/api',
329
+ };
330
+ const files = generateModelsPackage(options);
331
+ const pkgJson = files.find(
332
+ (f) => f.path === 'packages/models/package.json',
333
+ );
334
+ const pkg = JSON.parse(pkgJson!.content);
335
+ expect(pkg.dependencies.zod).toBeDefined();
336
+ });
337
+
338
+ it('should include example schemas', () => {
339
+ const options: TemplateOptions = {
340
+ ...baseOptions,
341
+ monorepo: true,
342
+ apiPath: 'apps/api',
343
+ };
344
+ const files = generateModelsPackage(options);
345
+ const indexTs = files.find(
346
+ (f) => f.path === 'packages/models/src/index.ts',
347
+ );
348
+ expect(indexTs?.content).toContain('userSchema');
349
+ expect(indexTs?.content).toContain('paginationSchema');
350
+ expect(indexTs?.content).toContain("import { z } from 'zod'");
351
+ });
352
+
353
+ it('should extend root tsconfig', () => {
354
+ const options: TemplateOptions = {
355
+ ...baseOptions,
356
+ monorepo: true,
357
+ apiPath: 'apps/api',
358
+ };
359
+ const files = generateModelsPackage(options);
360
+ const tsConfig = files.find(
361
+ (f) => f.path === 'packages/models/tsconfig.json',
362
+ );
363
+ const config = JSON.parse(tsConfig!.content);
364
+ expect(config.extends).toBe('../../tsconfig.json');
365
+ });
366
+ });