@geekmidas/cli 0.4.0 → 0.5.1

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 (299) hide show
  1. package/dist/CronGenerator-BPTqNYOR.d.cts +14 -0
  2. package/dist/{CronGenerator-Bh26MaNA.mjs → CronGenerator-CCRYptuT.mjs} +2 -2
  3. package/dist/{CronGenerator-Bh26MaNA.mjs.map → CronGenerator-CCRYptuT.mjs.map} +1 -1
  4. package/dist/{CronGenerator-C6MF8rlG.cjs → CronGenerator-D4TWXQbh.cjs} +2 -2
  5. package/dist/{CronGenerator-C6MF8rlG.cjs.map → CronGenerator-D4TWXQbh.cjs.map} +1 -1
  6. package/dist/CronGenerator-YAj59JUd.d.mts +14 -0
  7. package/dist/EndpointGenerator-ChAD1INz.d.cts +19 -0
  8. package/dist/EndpointGenerator-Cj3O1U8-.d.mts +19 -0
  9. package/dist/{EndpointGenerator-CzDhG7Or.mjs → EndpointGenerator-DGivkPLT.mjs} +22 -6
  10. package/dist/EndpointGenerator-DGivkPLT.mjs.map +1 -0
  11. package/dist/{EndpointGenerator-BxNCkus4.cjs → EndpointGenerator-npWEDoK2.cjs} +22 -6
  12. package/dist/EndpointGenerator-npWEDoK2.cjs.map +1 -0
  13. package/dist/FunctionGenerator-429-9NER.d.cts +14 -0
  14. package/dist/FunctionGenerator-BQ4ehoID.d.mts +14 -0
  15. package/dist/{FunctionGenerator-BNE_GC7N.mjs → FunctionGenerator-CVk0h8tO.mjs} +2 -2
  16. package/dist/{FunctionGenerator-BNE_GC7N.mjs.map → FunctionGenerator-CVk0h8tO.mjs.map} +1 -1
  17. package/dist/{FunctionGenerator-FgZUTd8L.cjs → FunctionGenerator-DYTnyr4c.cjs} +2 -2
  18. package/dist/{FunctionGenerator-FgZUTd8L.cjs.map → FunctionGenerator-DYTnyr4c.cjs.map} +1 -1
  19. package/dist/Generator-BjHK_qce.d.mts +27 -0
  20. package/dist/{Generator-UanJW0_V.mjs → Generator-CDt4pB3W.mjs} +1 -1
  21. package/dist/{Generator-UanJW0_V.mjs.map → Generator-CDt4pB3W.mjs.map} +1 -1
  22. package/dist/{Generator-CDoEXCDg.cjs → Generator-CLVplqm2.cjs} +1 -1
  23. package/dist/{Generator-CDoEXCDg.cjs.map → Generator-CLVplqm2.cjs.map} +1 -1
  24. package/dist/Generator-DxQMCQp7.d.cts +27 -0
  25. package/dist/{OpenApiTsGenerator-NBNEoaeO.cjs → OpenApiTsGenerator-Be-sKGTT.cjs} +1 -1
  26. package/dist/{OpenApiTsGenerator-NBNEoaeO.cjs.map → OpenApiTsGenerator-Be-sKGTT.cjs.map} +1 -1
  27. package/dist/{OpenApiTsGenerator-q3aWNkuM.mjs → OpenApiTsGenerator-C4mHHaku.mjs} +1 -1
  28. package/dist/{OpenApiTsGenerator-q3aWNkuM.mjs.map → OpenApiTsGenerator-C4mHHaku.mjs.map} +1 -1
  29. package/dist/SubscriberGenerator-7uX42xyG.d.mts +15 -0
  30. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs → SubscriberGenerator-DABaJXML.mjs} +2 -2
  31. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs.map → SubscriberGenerator-DABaJXML.mjs.map} +1 -1
  32. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs → SubscriberGenerator-D_zpNGFr.cjs} +2 -2
  33. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs.map → SubscriberGenerator-D_zpNGFr.cjs.map} +1 -1
  34. package/dist/SubscriberGenerator-Dtb3HS4i.d.cts +15 -0
  35. package/dist/api-B3SCEHPf.cjs +190 -0
  36. package/dist/api-B3SCEHPf.cjs.map +1 -0
  37. package/dist/api-BKIN0s0S.mjs +184 -0
  38. package/dist/api-BKIN0s0S.mjs.map +1 -0
  39. package/dist/build/index.cjs +11 -10
  40. package/dist/build/index.d.cts +7 -0
  41. package/dist/build/index.d.mts +7 -0
  42. package/dist/build/index.mjs +11 -10
  43. package/dist/build/manifests.cjs +1 -1
  44. package/dist/build/manifests.d.cts +13 -0
  45. package/dist/build/manifests.d.mts +13 -0
  46. package/dist/build/manifests.mjs +1 -1
  47. package/dist/build/providerResolver.cjs +1 -1
  48. package/dist/build/providerResolver.d.cts +23 -0
  49. package/dist/build/providerResolver.d.mts +23 -0
  50. package/dist/build/providerResolver.mjs +1 -1
  51. package/dist/build/types.d.cts +3 -0
  52. package/dist/build/types.d.mts +3 -0
  53. package/dist/{build-DyDgu_D1.mjs → build-B8C_qHir.mjs} +15 -13
  54. package/dist/build-B8C_qHir.mjs.map +1 -0
  55. package/dist/{build-CWtHnJMQ.cjs → build-D0Wr49bf.cjs} +15 -13
  56. package/dist/build-D0Wr49bf.cjs.map +1 -0
  57. package/dist/config-Ba-Gbpbc.d.cts +11 -0
  58. package/dist/config-Bq72aj8e.mjs +75 -0
  59. package/dist/config-Bq72aj8e.mjs.map +1 -0
  60. package/dist/config-CFls09Ey.cjs +93 -0
  61. package/dist/config-CFls09Ey.cjs.map +1 -0
  62. package/dist/config-CLEDqKO3.cjs +157 -0
  63. package/dist/config-CLEDqKO3.cjs.map +1 -0
  64. package/dist/config-DBsmMDhf.d.mts +11 -0
  65. package/dist/config-Dp8RonV_.mjs +151 -0
  66. package/dist/config-Dp8RonV_.mjs.map +1 -0
  67. package/dist/config.cjs +4 -2
  68. package/dist/config.d.cts +48 -0
  69. package/dist/config.d.mts +48 -0
  70. package/dist/config.mjs +2 -2
  71. package/dist/dev/index.cjs +10 -9
  72. package/dist/dev/index.d.cts +36 -0
  73. package/dist/dev/index.d.mts +36 -0
  74. package/dist/dev/index.mjs +10 -10
  75. package/dist/{dev-CpA8AQPX.mjs → dev-B734w3L1.mjs} +93 -49
  76. package/dist/dev-B734w3L1.mjs.map +1 -0
  77. package/dist/{dev-CgDYC4o8.cjs → dev-DHqYn8k4.cjs} +71 -21
  78. package/dist/dev-DHqYn8k4.cjs.map +1 -0
  79. package/dist/docker-5d8Yh5_X.cjs +119 -0
  80. package/dist/docker-5d8Yh5_X.cjs.map +1 -0
  81. package/dist/docker-DlUqdFle.mjs +113 -0
  82. package/dist/docker-DlUqdFle.mjs.map +1 -0
  83. package/dist/env-B-OKjgI4.cjs +144 -0
  84. package/dist/env-B-OKjgI4.cjs.map +1 -0
  85. package/dist/env-HfuJRlg5.d.cts +11 -0
  86. package/dist/env-nd-iQPYM.d.mts +11 -0
  87. package/dist/env-tv1HlZlw.mjs +138 -0
  88. package/dist/env-tv1HlZlw.mjs.map +1 -0
  89. package/dist/generators/CronGenerator.cjs +2 -2
  90. package/dist/generators/CronGenerator.d.cts +5 -0
  91. package/dist/generators/CronGenerator.d.mts +5 -0
  92. package/dist/generators/CronGenerator.mjs +2 -2
  93. package/dist/generators/EndpointGenerator.cjs +2 -2
  94. package/dist/generators/EndpointGenerator.d.cts +5 -0
  95. package/dist/generators/EndpointGenerator.d.mts +5 -0
  96. package/dist/generators/EndpointGenerator.mjs +2 -2
  97. package/dist/generators/FunctionGenerator.cjs +2 -2
  98. package/dist/generators/FunctionGenerator.d.cts +5 -0
  99. package/dist/generators/FunctionGenerator.d.mts +5 -0
  100. package/dist/generators/FunctionGenerator.mjs +2 -2
  101. package/dist/generators/Generator.cjs +1 -1
  102. package/dist/generators/Generator.d.cts +4 -0
  103. package/dist/generators/Generator.d.mts +4 -0
  104. package/dist/generators/Generator.mjs +1 -1
  105. package/dist/generators/OpenApiTsGenerator.cjs +1 -1
  106. package/dist/generators/OpenApiTsGenerator.d.cts +44 -0
  107. package/dist/generators/OpenApiTsGenerator.d.mts +44 -0
  108. package/dist/generators/OpenApiTsGenerator.mjs +1 -1
  109. package/dist/generators/SubscriberGenerator.cjs +2 -2
  110. package/dist/generators/SubscriberGenerator.d.cts +5 -0
  111. package/dist/generators/SubscriberGenerator.d.mts +5 -0
  112. package/dist/generators/SubscriberGenerator.mjs +2 -2
  113. package/dist/generators/index.cjs +6 -6
  114. package/dist/generators/index.d.cts +8 -0
  115. package/dist/generators/index.d.mts +8 -0
  116. package/dist/generators/index.mjs +6 -6
  117. package/dist/index-C523No_B.d.mts +64 -0
  118. package/dist/index-DrzN4xkQ.d.cts +64 -0
  119. package/dist/index.cjs +48 -16
  120. package/dist/index.cjs.map +1 -1
  121. package/dist/index.d.cts +1 -0
  122. package/dist/index.d.mts +1 -0
  123. package/dist/index.mjs +48 -16
  124. package/dist/index.mjs.map +1 -1
  125. package/dist/init/generators/config.cjs +3 -0
  126. package/dist/init/generators/config.d.cts +3 -0
  127. package/dist/init/generators/config.d.mts +3 -0
  128. package/dist/init/generators/config.mjs +3 -0
  129. package/dist/init/generators/docker.cjs +3 -0
  130. package/dist/init/generators/docker.d.cts +11 -0
  131. package/dist/init/generators/docker.d.mts +11 -0
  132. package/dist/init/generators/docker.mjs +3 -0
  133. package/dist/init/generators/env.cjs +3 -0
  134. package/dist/init/generators/env.d.cts +3 -0
  135. package/dist/init/generators/env.d.mts +3 -0
  136. package/dist/init/generators/env.mjs +3 -0
  137. package/dist/init/generators/index.cjs +9 -0
  138. package/dist/init/generators/index.d.cts +6 -0
  139. package/dist/init/generators/index.d.mts +6 -0
  140. package/dist/init/generators/index.mjs +6 -0
  141. package/dist/init/generators/models.cjs +3 -0
  142. package/dist/init/generators/models.d.cts +11 -0
  143. package/dist/init/generators/models.d.mts +11 -0
  144. package/dist/init/generators/models.mjs +3 -0
  145. package/dist/init/generators/monorepo.cjs +3 -0
  146. package/dist/init/generators/monorepo.d.cts +11 -0
  147. package/dist/init/generators/monorepo.d.mts +11 -0
  148. package/dist/init/generators/monorepo.mjs +3 -0
  149. package/dist/init/generators/package.cjs +3 -0
  150. package/dist/init/generators/package.d.cts +3 -0
  151. package/dist/init/generators/package.d.mts +3 -0
  152. package/dist/init/generators/package.mjs +3 -0
  153. package/dist/init/generators/source.cjs +3 -0
  154. package/dist/init/generators/source.d.cts +3 -0
  155. package/dist/init/generators/source.d.mts +3 -0
  156. package/dist/init/generators/source.mjs +3 -0
  157. package/dist/init/index.cjs +16 -0
  158. package/dist/init/index.d.cts +17 -0
  159. package/dist/init/index.d.mts +17 -0
  160. package/dist/init/index.mjs +16 -0
  161. package/dist/init/templates/api.cjs +3 -0
  162. package/dist/init/templates/api.d.cts +7 -0
  163. package/dist/init/templates/api.d.mts +7 -0
  164. package/dist/init/templates/api.mjs +3 -0
  165. package/dist/init/templates/index.cjs +10 -0
  166. package/dist/init/templates/index.d.cts +2 -0
  167. package/dist/init/templates/index.d.mts +2 -0
  168. package/dist/init/templates/index.mjs +7 -0
  169. package/dist/init/templates/minimal.cjs +3 -0
  170. package/dist/init/templates/minimal.d.cts +7 -0
  171. package/dist/init/templates/minimal.d.mts +7 -0
  172. package/dist/init/templates/minimal.mjs +3 -0
  173. package/dist/init/templates/serverless.cjs +3 -0
  174. package/dist/init/templates/serverless.d.cts +7 -0
  175. package/dist/init/templates/serverless.d.mts +7 -0
  176. package/dist/init/templates/serverless.mjs +3 -0
  177. package/dist/init/templates/worker.cjs +3 -0
  178. package/dist/init/templates/worker.d.cts +7 -0
  179. package/dist/init/templates/worker.d.mts +7 -0
  180. package/dist/init/templates/worker.mjs +3 -0
  181. package/dist/init/utils.cjs +7 -0
  182. package/dist/init/utils.d.cts +25 -0
  183. package/dist/init/utils.d.mts +25 -0
  184. package/dist/init/utils.mjs +3 -0
  185. package/dist/init-CtOnZn3G.mjs +145 -0
  186. package/dist/init-CtOnZn3G.mjs.map +1 -0
  187. package/dist/init-qLFsWR-R.cjs +151 -0
  188. package/dist/init-qLFsWR-R.cjs.map +1 -0
  189. package/dist/{manifests-C2eMoMUm.mjs → manifests-DIA_2QYd.mjs} +1 -1
  190. package/dist/{manifests-C2eMoMUm.mjs.map → manifests-DIA_2QYd.mjs.map} +1 -1
  191. package/dist/{manifests-CK1VV_pM.cjs → manifests-VJ9-2JpW.cjs} +1 -1
  192. package/dist/{manifests-CK1VV_pM.cjs.map → manifests-VJ9-2JpW.cjs.map} +1 -1
  193. package/dist/minimal-Bdhhpp7v.cjs +93 -0
  194. package/dist/minimal-Bdhhpp7v.cjs.map +1 -0
  195. package/dist/minimal-C4GsE45s.mjs +87 -0
  196. package/dist/minimal-C4GsE45s.mjs.map +1 -0
  197. package/dist/models-DyNwdOcz.cjs +121 -0
  198. package/dist/models-DyNwdOcz.cjs.map +1 -0
  199. package/dist/models-cvNg6Oea.mjs +115 -0
  200. package/dist/models-cvNg6Oea.mjs.map +1 -0
  201. package/dist/monorepo-Cknwzj5C.mjs +184 -0
  202. package/dist/monorepo-Cknwzj5C.mjs.map +1 -0
  203. package/dist/monorepo-sEK8gW59.cjs +190 -0
  204. package/dist/monorepo-sEK8gW59.cjs.map +1 -0
  205. package/dist/{openapi-DhK4b0lB.cjs → openapi-BQWPWyNB.cjs} +4 -4
  206. package/dist/{openapi-DhK4b0lB.cjs.map → openapi-BQWPWyNB.cjs.map} +1 -1
  207. package/dist/{openapi-DRTRGhTt.mjs → openapi-DBX8cJJ8.mjs} +4 -4
  208. package/dist/{openapi-DRTRGhTt.mjs.map → openapi-DBX8cJJ8.mjs.map} +1 -1
  209. package/dist/{openapi-react-query-D9Z7lh0p.cjs → openapi-react-query-DxHjXQvg.cjs} +1 -1
  210. package/dist/{openapi-react-query-D9Z7lh0p.cjs.map → openapi-react-query-DxHjXQvg.cjs.map} +1 -1
  211. package/dist/{openapi-react-query-MEBlYIM1.mjs → openapi-react-query-o7Mp1Jd5.mjs} +1 -1
  212. package/dist/{openapi-react-query-MEBlYIM1.mjs.map → openapi-react-query-o7Mp1Jd5.mjs.map} +1 -1
  213. package/dist/openapi-react-query.cjs +1 -1
  214. package/dist/openapi-react-query.d.cts +11 -0
  215. package/dist/openapi-react-query.d.mts +11 -0
  216. package/dist/openapi-react-query.mjs +1 -1
  217. package/dist/openapi.cjs +5 -5
  218. package/dist/openapi.d.cts +11 -0
  219. package/dist/openapi.d.mts +11 -0
  220. package/dist/openapi.mjs +5 -5
  221. package/dist/package-C7WhWU8m.d.mts +11 -0
  222. package/dist/package-CIfmeuSW.mjs +51 -0
  223. package/dist/package-CIfmeuSW.mjs.map +1 -0
  224. package/dist/package-DvWEMz6z.d.cts +11 -0
  225. package/dist/package-PP-o1nvq.cjs +57 -0
  226. package/dist/package-PP-o1nvq.cjs.map +1 -0
  227. package/dist/{providerResolver-B_TjNF0_.mjs → providerResolver-DEVKngbC.mjs} +1 -1
  228. package/dist/{providerResolver-B_TjNF0_.mjs.map → providerResolver-DEVKngbC.mjs.map} +1 -1
  229. package/dist/{providerResolver-DgvzNfP4.cjs → providerResolver-DOTbN9jo.cjs} +1 -1
  230. package/dist/{providerResolver-DgvzNfP4.cjs.map → providerResolver-DOTbN9jo.cjs.map} +1 -1
  231. package/dist/serverless-DkHBF2vC.mjs +108 -0
  232. package/dist/serverless-DkHBF2vC.mjs.map +1 -0
  233. package/dist/serverless-Yav3GRVz.cjs +114 -0
  234. package/dist/serverless-Yav3GRVz.cjs.map +1 -0
  235. package/dist/source-D6v2BnKT.d.mts +11 -0
  236. package/dist/source-D8fK9qRo.d.cts +11 -0
  237. package/dist/source-DT5Xhiob.cjs +17 -0
  238. package/dist/source-DT5Xhiob.cjs.map +1 -0
  239. package/dist/source-DnaH_MLA.mjs +11 -0
  240. package/dist/source-DnaH_MLA.mjs.map +1 -0
  241. package/dist/templates-CBFUwpBy.mjs +64 -0
  242. package/dist/templates-CBFUwpBy.mjs.map +1 -0
  243. package/dist/templates-DM_rtYYW.cjs +87 -0
  244. package/dist/templates-DM_rtYYW.cjs.map +1 -0
  245. package/dist/types-C4KITv-y.d.mts +51 -0
  246. package/dist/types-Cxl8-uwV.d.mts +129 -0
  247. package/dist/types-DB99_qIy.d.cts +129 -0
  248. package/dist/types-DLFN49M3.d.cts +51 -0
  249. package/dist/types.d.cts +2 -0
  250. package/dist/types.d.mts +2 -0
  251. package/dist/utils-BX3F4fT8.cjs +99 -0
  252. package/dist/utils-BX3F4fT8.cjs.map +1 -0
  253. package/dist/utils-C31-SWHP.mjs +69 -0
  254. package/dist/utils-C31-SWHP.mjs.map +1 -0
  255. package/dist/worker--8O5a3Hv.cjs +150 -0
  256. package/dist/worker--8O5a3Hv.cjs.map +1 -0
  257. package/dist/worker-Jme7uOOJ.mjs +144 -0
  258. package/dist/worker-Jme7uOOJ.mjs.map +1 -0
  259. package/package.json +12 -4
  260. package/src/__tests__/loadEnvFiles.spec.ts +131 -0
  261. package/src/build/index.ts +14 -16
  262. package/src/build/types.ts +5 -0
  263. package/src/config.ts +57 -0
  264. package/src/dev/__tests__/index.spec.ts +114 -119
  265. package/src/dev/index.ts +77 -17
  266. package/src/generators/EndpointGenerator.ts +37 -8
  267. package/src/index.ts +26 -0
  268. package/src/init/__tests__/generators.spec.ts +366 -0
  269. package/src/init/__tests__/init.spec.ts +341 -0
  270. package/src/init/__tests__/utils.spec.ts +104 -0
  271. package/src/init/generators/config.ts +192 -0
  272. package/src/init/generators/docker.ts +134 -0
  273. package/src/init/generators/env.ts +182 -0
  274. package/src/init/generators/index.ts +4 -0
  275. package/src/init/generators/models.ts +129 -0
  276. package/src/init/generators/monorepo.ts +211 -0
  277. package/src/init/generators/package.ts +81 -0
  278. package/src/init/generators/source.ts +15 -0
  279. package/src/init/index.ts +206 -0
  280. package/src/init/templates/api.ts +218 -0
  281. package/src/init/templates/index.ts +108 -0
  282. package/src/init/templates/minimal.ts +102 -0
  283. package/src/init/templates/serverless.ts +129 -0
  284. package/src/init/templates/worker.ts +169 -0
  285. package/src/init/utils.ts +98 -0
  286. package/src/types.ts +22 -2
  287. package/tsdown.config.ts +1 -1
  288. package/dist/EndpointGenerator-BxNCkus4.cjs.map +0 -1
  289. package/dist/EndpointGenerator-CzDhG7Or.mjs.map +0 -1
  290. package/dist/build-CWtHnJMQ.cjs.map +0 -1
  291. package/dist/build-DyDgu_D1.mjs.map +0 -1
  292. package/dist/config-AFmFKmU0.mjs +0 -30
  293. package/dist/config-AFmFKmU0.mjs.map +0 -1
  294. package/dist/config-BVIJpAsa.cjs +0 -36
  295. package/dist/config-BVIJpAsa.cjs.map +0 -1
  296. package/dist/dev-CgDYC4o8.cjs.map +0 -1
  297. package/dist/dev-CpA8AQPX.mjs.map +0 -1
  298. /package/dist/{generators-CEKtVh81.cjs → generators-3IemvCLk.cjs} +0 -0
  299. /package/dist/{generators-CsLujGXs.mjs → generators-FNpdfN6J.mjs} +0 -0
@@ -0,0 +1,341 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir, readFile, rm } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
6
+ import { initCommand } from '../index.js';
7
+
8
+ describe('initCommand', () => {
9
+ let tempDir: string;
10
+ let originalCwd: string;
11
+
12
+ beforeEach(async () => {
13
+ tempDir = join(tmpdir(), `cli-init-test-${Date.now()}`);
14
+ await mkdir(tempDir, { recursive: true });
15
+ originalCwd = process.cwd();
16
+ process.chdir(tempDir);
17
+ });
18
+
19
+ afterEach(async () => {
20
+ process.chdir(originalCwd);
21
+ await rm(tempDir, { recursive: true, force: true });
22
+ });
23
+
24
+ describe('non-monorepo', () => {
25
+ it('should create project with minimal template', async () => {
26
+ await initCommand('my-api', {
27
+ template: 'minimal',
28
+ yes: true,
29
+ skipInstall: true,
30
+ });
31
+
32
+ const projectDir = join(tempDir, 'my-api');
33
+ expect(existsSync(projectDir)).toBe(true);
34
+ expect(existsSync(join(projectDir, 'package.json'))).toBe(true);
35
+ expect(existsSync(join(projectDir, 'gkm.config.ts'))).toBe(true);
36
+ expect(existsSync(join(projectDir, 'tsconfig.json'))).toBe(true);
37
+ expect(existsSync(join(projectDir, 'biome.json'))).toBe(true);
38
+ expect(existsSync(join(projectDir, 'turbo.json'))).toBe(true);
39
+ expect(existsSync(join(projectDir, 'docker-compose.yml'))).toBe(true);
40
+ expect(existsSync(join(projectDir, '.env'))).toBe(true);
41
+ expect(existsSync(join(projectDir, '.env.development'))).toBe(true);
42
+ expect(existsSync(join(projectDir, '.env.test'))).toBe(true);
43
+ expect(existsSync(join(projectDir, '.gitignore'))).toBe(true);
44
+ expect(existsSync(join(projectDir, 'src/config/env.ts'))).toBe(true);
45
+ expect(existsSync(join(projectDir, 'src/config/logger.ts'))).toBe(true);
46
+ expect(existsSync(join(projectDir, 'src/endpoints/health.ts'))).toBe(
47
+ true,
48
+ );
49
+ });
50
+
51
+ it('should create package.json with correct content', async () => {
52
+ await initCommand('my-api', {
53
+ template: 'minimal',
54
+ yes: true,
55
+ skipInstall: true,
56
+ });
57
+
58
+ const pkgPath = join(tempDir, 'my-api', 'package.json');
59
+ const content = await readFile(pkgPath, 'utf-8');
60
+ const pkg = JSON.parse(content);
61
+
62
+ expect(pkg.name).toBe('my-api');
63
+ expect(pkg.type).toBe('module');
64
+ expect(pkg.dependencies['@geekmidas/constructs']).toBe('workspace:*');
65
+ expect(pkg.dependencies['@geekmidas/telescope']).toBe('workspace:*');
66
+ expect(pkg.dependencies['zod']).toMatch(/^~/);
67
+ expect(pkg.devDependencies['@biomejs/biome']).toBeDefined();
68
+ expect(pkg.devDependencies['turbo']).toBeDefined();
69
+ expect(pkg.scripts.dev).toBe('gkm dev');
70
+ expect(pkg.scripts.lint).toBe('biome lint .');
71
+ });
72
+
73
+ it('should create gkm.config.ts with telescope when enabled', async () => {
74
+ await initCommand('my-api', {
75
+ template: 'minimal',
76
+ yes: true,
77
+ skipInstall: true,
78
+ });
79
+
80
+ const configPath = join(tempDir, 'my-api', 'gkm.config.ts');
81
+ const content = await readFile(configPath, 'utf-8');
82
+
83
+ expect(content).toContain("routes: './src/endpoints/**/*.ts'");
84
+ expect(content).toContain('telescope');
85
+ expect(content).toContain('/__telescope');
86
+ });
87
+
88
+ it('should create api template with user endpoints', async () => {
89
+ await initCommand('my-api', {
90
+ template: 'api',
91
+ yes: true,
92
+ skipInstall: true,
93
+ });
94
+
95
+ const projectDir = join(tempDir, 'my-api');
96
+ expect(existsSync(join(projectDir, 'src/endpoints/users/list.ts'))).toBe(
97
+ true,
98
+ );
99
+ expect(existsSync(join(projectDir, 'src/endpoints/users/get.ts'))).toBe(
100
+ true,
101
+ );
102
+ expect(existsSync(join(projectDir, 'src/services/database.ts'))).toBe(
103
+ true,
104
+ );
105
+ });
106
+
107
+ it('should create serverless template with functions', async () => {
108
+ await initCommand('my-api', {
109
+ template: 'serverless',
110
+ yes: true,
111
+ skipInstall: true,
112
+ });
113
+
114
+ const projectDir = join(tempDir, 'my-api');
115
+ expect(existsSync(join(projectDir, 'src/functions/hello.ts'))).toBe(true);
116
+
117
+ const configPath = join(projectDir, 'gkm.config.ts');
118
+ const content = await readFile(configPath, 'utf-8');
119
+ expect(content).toContain('functions');
120
+ });
121
+
122
+ it('should create worker template with crons and subscribers', async () => {
123
+ await initCommand('my-api', {
124
+ template: 'worker',
125
+ yes: true,
126
+ skipInstall: true,
127
+ });
128
+
129
+ const projectDir = join(tempDir, 'my-api');
130
+ expect(existsSync(join(projectDir, 'src/crons/cleanup.ts'))).toBe(true);
131
+ expect(
132
+ existsSync(join(projectDir, 'src/subscribers/user-events.ts')),
133
+ ).toBe(true);
134
+ expect(existsSync(join(projectDir, 'src/events/types.ts'))).toBe(true);
135
+
136
+ const configPath = join(projectDir, 'gkm.config.ts');
137
+ const content = await readFile(configPath, 'utf-8');
138
+ expect(content).toContain('crons');
139
+ expect(content).toContain('subscribers');
140
+ });
141
+ });
142
+
143
+ describe('monorepo', () => {
144
+ it('should create monorepo structure', async () => {
145
+ await initCommand('my-monorepo', {
146
+ template: 'minimal',
147
+ yes: true,
148
+ skipInstall: true,
149
+ monorepo: true,
150
+ apiPath: 'apps/api',
151
+ });
152
+
153
+ const projectDir = join(tempDir, 'my-monorepo');
154
+
155
+ // Root files
156
+ expect(existsSync(join(projectDir, 'package.json'))).toBe(true);
157
+ expect(existsSync(join(projectDir, 'pnpm-workspace.yaml'))).toBe(true);
158
+ expect(existsSync(join(projectDir, 'tsconfig.json'))).toBe(true);
159
+ expect(existsSync(join(projectDir, 'biome.json'))).toBe(true);
160
+ expect(existsSync(join(projectDir, 'turbo.json'))).toBe(true);
161
+ expect(existsSync(join(projectDir, '.gitignore'))).toBe(true);
162
+
163
+ // API app files
164
+ expect(existsSync(join(projectDir, 'apps/api/package.json'))).toBe(true);
165
+ expect(existsSync(join(projectDir, 'apps/api/gkm.config.ts'))).toBe(true);
166
+ expect(existsSync(join(projectDir, 'apps/api/tsconfig.json'))).toBe(true);
167
+ expect(
168
+ existsSync(join(projectDir, 'apps/api/src/endpoints/health.ts')),
169
+ ).toBe(true);
170
+
171
+ // Models package
172
+ expect(existsSync(join(projectDir, 'packages/models/package.json'))).toBe(
173
+ true,
174
+ );
175
+ expect(
176
+ existsSync(join(projectDir, 'packages/models/tsconfig.json')),
177
+ ).toBe(true);
178
+ expect(existsSync(join(projectDir, 'packages/models/src/index.ts'))).toBe(
179
+ true,
180
+ );
181
+ });
182
+
183
+ it('should create root package.json with turbo scripts', async () => {
184
+ await initCommand('my-monorepo', {
185
+ template: 'minimal',
186
+ yes: true,
187
+ skipInstall: true,
188
+ monorepo: true,
189
+ apiPath: 'apps/api',
190
+ });
191
+
192
+ const pkgPath = join(tempDir, 'my-monorepo', 'package.json');
193
+ const content = await readFile(pkgPath, 'utf-8');
194
+ const pkg = JSON.parse(content);
195
+
196
+ expect(pkg.name).toBe('my-monorepo');
197
+ expect(pkg.scripts.dev).toBe('turbo dev');
198
+ expect(pkg.scripts.build).toBe('turbo build');
199
+ expect(pkg.scripts.lint).toBe('biome lint .');
200
+ expect(pkg.devDependencies['@biomejs/biome']).toBeDefined();
201
+ expect(pkg.devDependencies['turbo']).toBeDefined();
202
+ });
203
+
204
+ it('should create API package.json with models dependency', async () => {
205
+ await initCommand('my-monorepo', {
206
+ template: 'minimal',
207
+ yes: true,
208
+ skipInstall: true,
209
+ monorepo: true,
210
+ apiPath: 'apps/api',
211
+ });
212
+
213
+ const pkgPath = join(tempDir, 'my-monorepo', 'apps/api/package.json');
214
+ const content = await readFile(pkgPath, 'utf-8');
215
+ const pkg = JSON.parse(content);
216
+
217
+ expect(pkg.name).toBe('@my-monorepo/api');
218
+ expect(pkg.dependencies['@my-monorepo/models']).toBe('workspace:*');
219
+ expect(pkg.dependencies['zod']).toBeUndefined(); // zod is in models
220
+ expect(pkg.devDependencies['@biomejs/biome']).toBeUndefined(); // at root
221
+ expect(pkg.devDependencies['turbo']).toBeUndefined(); // at root
222
+ });
223
+
224
+ it('should create API tsconfig with paths', async () => {
225
+ await initCommand('my-monorepo', {
226
+ template: 'minimal',
227
+ yes: true,
228
+ skipInstall: true,
229
+ monorepo: true,
230
+ apiPath: 'apps/api',
231
+ });
232
+
233
+ const tsConfigPath = join(
234
+ tempDir,
235
+ 'my-monorepo',
236
+ 'apps/api/tsconfig.json',
237
+ );
238
+ const content = await readFile(tsConfigPath, 'utf-8');
239
+ const config = JSON.parse(content);
240
+
241
+ expect(config.extends).toBe('../../tsconfig.json');
242
+ expect(config.compilerOptions.paths['@my-monorepo/*']).toEqual([
243
+ '../../packages/*/src',
244
+ ]);
245
+ });
246
+
247
+ it('should create models package with zod schemas', async () => {
248
+ await initCommand('my-monorepo', {
249
+ template: 'minimal',
250
+ yes: true,
251
+ skipInstall: true,
252
+ monorepo: true,
253
+ apiPath: 'apps/api',
254
+ });
255
+
256
+ const pkgPath = join(
257
+ tempDir,
258
+ 'my-monorepo',
259
+ 'packages/models/package.json',
260
+ );
261
+ const content = await readFile(pkgPath, 'utf-8');
262
+ const pkg = JSON.parse(content);
263
+
264
+ expect(pkg.name).toBe('@my-monorepo/models');
265
+ expect(pkg.dependencies.zod).toBeDefined();
266
+
267
+ const indexPath = join(
268
+ tempDir,
269
+ 'my-monorepo',
270
+ 'packages/models/src/index.ts',
271
+ );
272
+ const indexContent = await readFile(indexPath, 'utf-8');
273
+ expect(indexContent).toContain('userSchema');
274
+ expect(indexContent).toContain('paginationSchema');
275
+ });
276
+
277
+ it('should support custom API path', async () => {
278
+ await initCommand('my-monorepo', {
279
+ template: 'minimal',
280
+ yes: true,
281
+ skipInstall: true,
282
+ monorepo: true,
283
+ apiPath: 'services/backend',
284
+ });
285
+
286
+ const projectDir = join(tempDir, 'my-monorepo');
287
+ expect(
288
+ existsSync(join(projectDir, 'services/backend/package.json')),
289
+ ).toBe(true);
290
+ expect(
291
+ existsSync(join(projectDir, 'services/backend/gkm.config.ts')),
292
+ ).toBe(true);
293
+
294
+ const pkgPath = join(projectDir, 'services/backend/package.json');
295
+ const content = await readFile(pkgPath, 'utf-8');
296
+ const pkg = JSON.parse(content);
297
+ expect(pkg.name).toBe('@my-monorepo/backend');
298
+ });
299
+ });
300
+
301
+ describe('docker-compose', () => {
302
+ it('should include postgres for database-enabled projects', async () => {
303
+ await initCommand('my-api', {
304
+ template: 'minimal',
305
+ yes: true,
306
+ skipInstall: true,
307
+ });
308
+
309
+ const dockerPath = join(tempDir, 'my-api', 'docker-compose.yml');
310
+ const content = await readFile(dockerPath, 'utf-8');
311
+ expect(content).toContain('postgres:16-alpine');
312
+ expect(content).toContain('5432:5432');
313
+ });
314
+
315
+ it('should include serverless-redis-http for serverless template', async () => {
316
+ await initCommand('my-api', {
317
+ template: 'serverless',
318
+ yes: true,
319
+ skipInstall: true,
320
+ });
321
+
322
+ const dockerPath = join(tempDir, 'my-api', 'docker-compose.yml');
323
+ const content = await readFile(dockerPath, 'utf-8');
324
+ expect(content).toContain('hiett/serverless-redis-http');
325
+ });
326
+
327
+ it('should include rabbitmq for worker template', async () => {
328
+ await initCommand('my-api', {
329
+ template: 'worker',
330
+ yes: true,
331
+ skipInstall: true,
332
+ });
333
+
334
+ const dockerPath = join(tempDir, 'my-api', 'docker-compose.yml');
335
+ const content = await readFile(dockerPath, 'utf-8');
336
+ expect(content).toContain('rabbitmq:3-management-alpine');
337
+ expect(content).toContain('5672:5672');
338
+ expect(content).toContain('15672:15672');
339
+ });
340
+ });
341
+ });
@@ -0,0 +1,104 @@
1
+ import { mkdir, rm } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import {
6
+ checkDirectoryExists,
7
+ detectPackageManager,
8
+ validateProjectName,
9
+ } from '../utils.js';
10
+
11
+ describe('validateProjectName', () => {
12
+ it('should accept valid project names', () => {
13
+ expect(validateProjectName('my-project')).toBe(true);
14
+ expect(validateProjectName('my_project')).toBe(true);
15
+ expect(validateProjectName('myProject')).toBe(true);
16
+ expect(validateProjectName('my-project-123')).toBe(true);
17
+ expect(validateProjectName('project')).toBe(true);
18
+ });
19
+
20
+ it('should reject empty names', () => {
21
+ expect(validateProjectName('')).toBe('Project name is required');
22
+ });
23
+
24
+ it('should reject names with invalid characters', () => {
25
+ const result = validateProjectName('my project');
26
+ expect(result).toContain('can only contain');
27
+ });
28
+
29
+ it('should accept scoped package names', () => {
30
+ // @ / . are valid for scoped npm packages
31
+ expect(validateProjectName('@my/project')).toBe(true);
32
+ expect(validateProjectName('my.project')).toBe(true);
33
+ });
34
+
35
+ it('should reject names with other special characters', () => {
36
+ expect(validateProjectName('my$project')).toContain('can only contain');
37
+ expect(validateProjectName('my#project')).toContain('can only contain');
38
+ expect(validateProjectName('my!project')).toContain('can only contain');
39
+ });
40
+ });
41
+
42
+ describe('checkDirectoryExists', () => {
43
+ let tempDir: string;
44
+
45
+ beforeEach(async () => {
46
+ tempDir = join(tmpdir(), `cli-test-${Date.now()}`);
47
+ await mkdir(tempDir, { recursive: true });
48
+ });
49
+
50
+ afterEach(async () => {
51
+ await rm(tempDir, { recursive: true, force: true });
52
+ });
53
+
54
+ it('should return true for non-existent directory', () => {
55
+ expect(checkDirectoryExists('non-existent-dir', tempDir)).toBe(true);
56
+ });
57
+
58
+ it('should return error for existing directory', async () => {
59
+ const existingDir = 'existing-dir';
60
+ await mkdir(join(tempDir, existingDir));
61
+ const result = checkDirectoryExists(existingDir, tempDir);
62
+ expect(result).toContain('already exists');
63
+ });
64
+ });
65
+
66
+ describe('detectPackageManager', () => {
67
+ let tempDir: string;
68
+ let originalEnv: string | undefined;
69
+
70
+ beforeEach(async () => {
71
+ tempDir = join(tmpdir(), `cli-test-${Date.now()}`);
72
+ await mkdir(tempDir, { recursive: true });
73
+ originalEnv = process.env.npm_config_user_agent;
74
+ });
75
+
76
+ afterEach(async () => {
77
+ await rm(tempDir, { recursive: true, force: true });
78
+ if (originalEnv !== undefined) {
79
+ process.env.npm_config_user_agent = originalEnv;
80
+ } else {
81
+ delete process.env.npm_config_user_agent;
82
+ }
83
+ });
84
+
85
+ it('should detect pnpm from user agent', () => {
86
+ process.env.npm_config_user_agent = 'pnpm/8.0.0';
87
+ expect(detectPackageManager(tempDir)).toBe('pnpm');
88
+ });
89
+
90
+ it('should detect yarn from user agent', () => {
91
+ process.env.npm_config_user_agent = 'yarn/4.0.0';
92
+ expect(detectPackageManager(tempDir)).toBe('yarn');
93
+ });
94
+
95
+ it('should detect bun from user agent', () => {
96
+ process.env.npm_config_user_agent = 'bun/1.0.0';
97
+ expect(detectPackageManager(tempDir)).toBe('bun');
98
+ });
99
+
100
+ it('should default to npm when no lockfile or user agent', () => {
101
+ delete process.env.npm_config_user_agent;
102
+ expect(detectPackageManager(tempDir)).toBe('npm');
103
+ });
104
+ });
@@ -0,0 +1,192 @@
1
+ import type {
2
+ GeneratedFile,
3
+ TemplateConfig,
4
+ TemplateOptions,
5
+ } from '../templates/index.js';
6
+
7
+ /**
8
+ * Generate configuration files (gkm.config.ts, tsconfig.json, biome.json, turbo.json)
9
+ */
10
+ export function generateConfigFiles(
11
+ options: TemplateOptions,
12
+ template: TemplateConfig,
13
+ ): GeneratedFile[] {
14
+ const { telescope } = options;
15
+ const isServerless = template.name === 'serverless';
16
+ const hasWorker = template.name === 'worker';
17
+
18
+ // Build gkm.config.ts
19
+ let gkmConfig = `import { defineConfig } from '@geekmidas/cli';
20
+
21
+ export default defineConfig({
22
+ routes: './src/endpoints/**/*.ts',
23
+ envParser: './src/config/env',
24
+ logger: './src/config/logger',`;
25
+
26
+ if (isServerless || hasWorker) {
27
+ gkmConfig += `
28
+ functions: './src/functions/**/*.ts',`;
29
+ }
30
+
31
+ if (hasWorker) {
32
+ gkmConfig += `
33
+ crons: './src/crons/**/*.ts',
34
+ subscribers: './src/subscribers/**/*.ts',`;
35
+ }
36
+
37
+ if (telescope) {
38
+ gkmConfig += `
39
+ telescope: {
40
+ enabled: true,
41
+ path: '/__telescope',
42
+ },`;
43
+ }
44
+
45
+ gkmConfig += `
46
+ });
47
+ `;
48
+
49
+ // Build tsconfig.json - extends root for monorepo, standalone for non-monorepo
50
+ const tsConfig = options.monorepo
51
+ ? {
52
+ extends: '../../tsconfig.json',
53
+ compilerOptions: {
54
+ outDir: './dist',
55
+ rootDir: './src',
56
+ baseUrl: '.',
57
+ paths: {
58
+ [`@${options.name}/*`]: ['../../packages/*/src'],
59
+ },
60
+ },
61
+ include: ['src/**/*.ts'],
62
+ exclude: ['node_modules', 'dist'],
63
+ }
64
+ : {
65
+ compilerOptions: {
66
+ target: 'ES2022',
67
+ module: 'NodeNext',
68
+ moduleResolution: 'NodeNext',
69
+ lib: ['ES2022'],
70
+ strict: true,
71
+ esModuleInterop: true,
72
+ skipLibCheck: true,
73
+ forceConsistentCasingInFileNames: true,
74
+ resolveJsonModule: true,
75
+ declaration: true,
76
+ declarationMap: true,
77
+ outDir: './dist',
78
+ rootDir: './src',
79
+ },
80
+ include: ['src/**/*.ts'],
81
+ exclude: ['node_modules', 'dist'],
82
+ };
83
+
84
+ // Skip biome.json and turbo.json for monorepo (they're at root)
85
+ if (options.monorepo) {
86
+ return [
87
+ {
88
+ path: 'gkm.config.ts',
89
+ content: gkmConfig,
90
+ },
91
+ {
92
+ path: 'tsconfig.json',
93
+ content: JSON.stringify(tsConfig, null, 2) + '\n',
94
+ },
95
+ ];
96
+ }
97
+
98
+ // Build biome.json
99
+ const biomeConfig = {
100
+ $schema: 'https://biomejs.dev/schemas/1.9.4/schema.json',
101
+ vcs: {
102
+ enabled: true,
103
+ clientKind: 'git',
104
+ useIgnoreFile: true,
105
+ },
106
+ organizeImports: {
107
+ enabled: true,
108
+ },
109
+ formatter: {
110
+ enabled: true,
111
+ indentStyle: 'space',
112
+ indentWidth: 2,
113
+ lineWidth: 80,
114
+ },
115
+ javascript: {
116
+ formatter: {
117
+ quoteStyle: 'single',
118
+ trailingCommas: 'all',
119
+ semicolons: 'always',
120
+ arrowParentheses: 'always',
121
+ },
122
+ },
123
+ linter: {
124
+ enabled: true,
125
+ rules: {
126
+ recommended: true,
127
+ correctness: {
128
+ noUnusedImports: 'error',
129
+ noUnusedVariables: 'error',
130
+ },
131
+ style: {
132
+ noNonNullAssertion: 'off',
133
+ },
134
+ },
135
+ },
136
+ files: {
137
+ ignore: ['node_modules', 'dist', '.gkm', 'coverage'],
138
+ },
139
+ };
140
+
141
+ // Build turbo.json
142
+ const turboConfig = {
143
+ $schema: 'https://turbo.build/schema.json',
144
+ tasks: {
145
+ build: {
146
+ dependsOn: ['^build'],
147
+ outputs: ['dist/**'],
148
+ },
149
+ dev: {
150
+ cache: false,
151
+ persistent: true,
152
+ },
153
+ test: {
154
+ dependsOn: ['^build'],
155
+ cache: false,
156
+ },
157
+ 'test:once': {
158
+ dependsOn: ['^build'],
159
+ outputs: ['coverage/**'],
160
+ },
161
+ typecheck: {
162
+ dependsOn: ['^build'],
163
+ outputs: [],
164
+ },
165
+ lint: {
166
+ outputs: [],
167
+ },
168
+ fmt: {
169
+ outputs: [],
170
+ },
171
+ },
172
+ };
173
+
174
+ return [
175
+ {
176
+ path: 'gkm.config.ts',
177
+ content: gkmConfig,
178
+ },
179
+ {
180
+ path: 'tsconfig.json',
181
+ content: JSON.stringify(tsConfig, null, 2) + '\n',
182
+ },
183
+ {
184
+ path: 'biome.json',
185
+ content: JSON.stringify(biomeConfig, null, 2) + '\n',
186
+ },
187
+ {
188
+ path: 'turbo.json',
189
+ content: JSON.stringify(turboConfig, null, 2) + '\n',
190
+ },
191
+ ];
192
+ }