nodejs-structure-cli 1.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 (243) hide show
  1. package/README.md +32 -0
  2. package/bin/index.js +143 -0
  3. package/lib/generator.js +145 -0
  4. package/lib/modules/app-setup.js +479 -0
  5. package/lib/modules/caching-setup.js +76 -0
  6. package/lib/modules/config-files.js +151 -0
  7. package/lib/modules/database-setup.js +116 -0
  8. package/lib/modules/kafka-setup.js +249 -0
  9. package/lib/modules/project-setup.js +32 -0
  10. package/lib/prompts.js +128 -0
  11. package/package.json +66 -0
  12. package/templates/clean-architecture/js/src/domain/models/User.js.ejs +11 -0
  13. package/templates/clean-architecture/js/src/errors/ApiError.js +14 -0
  14. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -0
  15. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -0
  16. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -0
  17. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -0
  18. package/templates/clean-architecture/js/src/index.js.ejs +56 -0
  19. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -0
  20. package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -0
  21. package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -0
  22. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +88 -0
  23. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -0
  24. package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -0
  25. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +93 -0
  26. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -0
  27. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +190 -0
  28. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -0
  29. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -0
  30. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -0
  31. package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -0
  32. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -0
  33. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -0
  34. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -0
  35. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -0
  36. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -0
  37. package/templates/clean-architecture/js/src/interfaces/routes/api.js.ejs +17 -0
  38. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -0
  39. package/templates/clean-architecture/js/src/usecases/CreateUser.js.ejs +14 -0
  40. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -0
  41. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  42. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  43. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -0
  44. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -0
  45. package/templates/clean-architecture/js/src/usecases/UpdateUser.js.ejs +11 -0
  46. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  47. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  48. package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -0
  49. package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -0
  50. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -0
  51. package/templates/clean-architecture/ts/src/domain/user.ts.ejs +9 -0
  52. package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -0
  53. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -0
  54. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -0
  55. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -0
  56. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -0
  57. package/templates/clean-architecture/ts/src/index.ts.ejs +144 -0
  58. package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -0
  59. package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -0
  60. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -0
  61. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +125 -0
  62. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -0
  63. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +208 -0
  64. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -0
  65. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -0
  66. package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -0
  67. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -0
  68. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -0
  69. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -0
  70. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -0
  71. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -0
  72. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -0
  73. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts.ejs +18 -0
  74. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -0
  75. package/templates/clean-architecture/ts/src/usecases/createUser.ts.ejs +11 -0
  76. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  77. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  78. package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -0
  79. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -0
  80. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  81. package/templates/clean-architecture/ts/src/usecases/updateUser.ts.ejs +10 -0
  82. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  83. package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -0
  84. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -0
  85. package/templates/common/.cursorrules.ejs +60 -0
  86. package/templates/common/.dockerignore +12 -0
  87. package/templates/common/.env.example.ejs +60 -0
  88. package/templates/common/.gitattributes +46 -0
  89. package/templates/common/.gitlab-ci.yml.ejs +86 -0
  90. package/templates/common/.lintstagedrc +6 -0
  91. package/templates/common/.prettierrc +7 -0
  92. package/templates/common/.snyk.ejs +45 -0
  93. package/templates/common/Dockerfile +73 -0
  94. package/templates/common/Jenkinsfile.ejs +87 -0
  95. package/templates/common/README.md.ejs +148 -0
  96. package/templates/common/_github/workflows/ci.yml.ejs +46 -0
  97. package/templates/common/_github/workflows/security.yml.ejs +36 -0
  98. package/templates/common/_gitignore +5 -0
  99. package/templates/common/_husky/pre-commit +4 -0
  100. package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -0
  101. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  102. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -0
  103. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  104. package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -0
  105. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  106. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -0
  107. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  108. package/templates/common/caching/js/memoryCache.js.ejs +60 -0
  109. package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -0
  110. package/templates/common/caching/js/redisClient.js.ejs +75 -0
  111. package/templates/common/caching/js/redisClient.spec.js.ejs +147 -0
  112. package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -0
  113. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -0
  114. package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -0
  115. package/templates/common/caching/ts/redisClient.ts.ejs +89 -0
  116. package/templates/common/database/js/database.js.ejs +19 -0
  117. package/templates/common/database/js/database.spec.js.ejs +56 -0
  118. package/templates/common/database/js/models/User.js.ejs +91 -0
  119. package/templates/common/database/js/models/User.js.mongoose.ejs +35 -0
  120. package/templates/common/database/js/models/User.spec.js.ejs +94 -0
  121. package/templates/common/database/js/mongoose.js.ejs +33 -0
  122. package/templates/common/database/js/mongoose.spec.js.ejs +43 -0
  123. package/templates/common/database/ts/database.spec.ts.ejs +56 -0
  124. package/templates/common/database/ts/database.ts.ejs +21 -0
  125. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -0
  126. package/templates/common/database/ts/models/User.ts.ejs +102 -0
  127. package/templates/common/database/ts/models/User.ts.mongoose.ejs +34 -0
  128. package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -0
  129. package/templates/common/database/ts/mongoose.ts.ejs +28 -0
  130. package/templates/common/docker-compose.yml.ejs +159 -0
  131. package/templates/common/ecosystem.config.js.ejs +40 -0
  132. package/templates/common/eslint.config.mjs.ejs +77 -0
  133. package/templates/common/health/js/healthRoute.js.ejs +50 -0
  134. package/templates/common/health/js/healthRoute.spec.js.ejs +70 -0
  135. package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -0
  136. package/templates/common/health/ts/healthRoute.ts.ejs +49 -0
  137. package/templates/common/jest.config.js.ejs +32 -0
  138. package/templates/common/jest.e2e.config.js.ejs +8 -0
  139. package/templates/common/kafka/js/config/kafka.js +9 -0
  140. package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -0
  141. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -0
  142. package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -0
  143. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -0
  144. package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -0
  145. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -0
  146. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -0
  147. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -0
  148. package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -0
  149. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  150. package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -0
  151. package/templates/common/kafka/ts/config/kafka.ts +7 -0
  152. package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -0
  153. package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -0
  154. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -0
  155. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -0
  156. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -0
  157. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -0
  158. package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -0
  159. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -0
  160. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  161. package/templates/common/migrate-mongo-config.js.ejs +31 -0
  162. package/templates/common/migrations/init.js.ejs +23 -0
  163. package/templates/common/package.json.ejs +137 -0
  164. package/templates/common/prompts/add-feature.md.ejs +26 -0
  165. package/templates/common/prompts/project-context.md.ejs +43 -0
  166. package/templates/common/prompts/troubleshoot.md.ejs +28 -0
  167. package/templates/common/public/css/style.css +147 -0
  168. package/templates/common/scripts/run-e2e.js.ejs +63 -0
  169. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -0
  170. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -0
  171. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -0
  172. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -0
  173. package/templates/common/sonar-project.properties.ejs +27 -0
  174. package/templates/common/src/config/auth.js.ejs +19 -0
  175. package/templates/common/src/config/auth.ts.ejs +19 -0
  176. package/templates/common/src/controllers/authController.js.ejs +101 -0
  177. package/templates/common/src/controllers/authController.ts.ejs +101 -0
  178. package/templates/common/src/middleware/auth.js.ejs +20 -0
  179. package/templates/common/src/middleware/auth.ts.ejs +25 -0
  180. package/templates/common/src/middleware/upload.js.ejs +31 -0
  181. package/templates/common/src/middleware/upload.ts.ejs +32 -0
  182. package/templates/common/src/routes/authRoutes.js.ejs +20 -0
  183. package/templates/common/src/routes/authRoutes.ts.ejs +20 -0
  184. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -0
  185. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -0
  186. package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -0
  187. package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -0
  188. package/templates/common/swagger.yml.ejs +118 -0
  189. package/templates/common/tsconfig.json +23 -0
  190. package/templates/common/views/ejs/index.ejs +55 -0
  191. package/templates/common/views/pug/index.pug +40 -0
  192. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -0
  193. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -0
  194. package/templates/mvc/js/src/config/env.js.ejs +46 -0
  195. package/templates/mvc/js/src/config/swagger.js.ejs +6 -0
  196. package/templates/mvc/js/src/controllers/userController.js.ejs +288 -0
  197. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -0
  198. package/templates/mvc/js/src/errors/ApiError.js +14 -0
  199. package/templates/mvc/js/src/errors/BadRequestError.js +11 -0
  200. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -0
  201. package/templates/mvc/js/src/errors/NotFoundError.js +11 -0
  202. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -0
  203. package/templates/mvc/js/src/graphql/context.js.ejs +7 -0
  204. package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -0
  205. package/templates/mvc/js/src/graphql/index.js.ejs +5 -0
  206. package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -0
  207. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -0
  208. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -0
  209. package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -0
  210. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -0
  211. package/templates/mvc/js/src/index.js.ejs +141 -0
  212. package/templates/mvc/js/src/routes/api.js.ejs +15 -0
  213. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -0
  214. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  215. package/templates/mvc/js/src/utils/errorMiddleware.js +29 -0
  216. package/templates/mvc/js/src/utils/httpCodes.js +9 -0
  217. package/templates/mvc/js/src/utils/logger.js +40 -0
  218. package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -0
  219. package/templates/mvc/ts/src/config/env.ts.ejs +45 -0
  220. package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -0
  221. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -0
  222. package/templates/mvc/ts/src/controllers/userController.ts.ejs +292 -0
  223. package/templates/mvc/ts/src/errors/ApiError.ts +15 -0
  224. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -0
  225. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -0
  226. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -0
  227. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -0
  228. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -0
  229. package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -0
  230. package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -0
  231. package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -0
  232. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -0
  233. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -0
  234. package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -0
  235. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -0
  236. package/templates/mvc/ts/src/index.ts.ejs +157 -0
  237. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -0
  238. package/templates/mvc/ts/src/routes/api.ts.ejs +17 -0
  239. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  240. package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -0
  241. package/templates/mvc/ts/src/utils/httpCodes.ts +7 -0
  242. package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -0
  243. package/templates/mvc/ts/src/utils/logger.ts +36 -0
@@ -0,0 +1,151 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import ejs from 'ejs';
4
+
5
+ export const renderPackageJson = async (templatesDir, targetDir, config) => {
6
+ const packageJsonPath = path.join(targetDir, 'package.json');
7
+ const packageTemplate = await fs.readFile(path.join(templatesDir, 'common', 'package.json.ejs'), 'utf-8');
8
+ const packageContent = ejs.render(packageTemplate, { ...config });
9
+ await fs.writeFile(packageJsonPath, packageContent);
10
+ };
11
+
12
+ export const renderDockerCompose = async (templatesDir, targetDir, config) => {
13
+ const dockerComposePath = path.join(targetDir, 'docker-compose.yml');
14
+ const dockerTemplate = await fs.readFile(path.join(templatesDir, 'common', 'docker-compose.yml.ejs'), 'utf-8');
15
+ const dockerContent = ejs.render(dockerTemplate, { ...config });
16
+ await fs.writeFile(dockerComposePath, dockerContent);
17
+ };
18
+
19
+ export const renderReadme = async (templatesDir, targetDir, config) => {
20
+ const readmePath = path.join(targetDir, 'README.md');
21
+ const readmeTemplate = await fs.readFile(path.join(templatesDir, 'common', 'README.md.ejs'), 'utf-8');
22
+ const readmeContent = ejs.render(readmeTemplate, { ...config });
23
+ await fs.writeFile(readmePath, readmeContent);
24
+ };
25
+
26
+ export const renderDockerfile = async (templatesDir, targetDir, config) => {
27
+ const dockerfileTemplate = await fs.readFile(path.join(templatesDir, 'common', 'Dockerfile'), 'utf-8');
28
+ const dockerfileContent = ejs.render(dockerfileTemplate, { ...config });
29
+ await fs.writeFile(path.join(targetDir, 'Dockerfile'), dockerfileContent);
30
+ };
31
+
32
+ export const renderPm2Config = async (templatesDir, targetDir, config) => {
33
+ const pm2ConfigPath = path.join(targetDir, 'ecosystem.config.js');
34
+ const pm2Template = await fs.readFile(path.join(templatesDir, 'common', 'ecosystem.config.js.ejs'), 'utf-8');
35
+ const pm2Content = ejs.render(pm2Template, { ...config });
36
+ await fs.writeFile(pm2ConfigPath, pm2Content);
37
+ };
38
+
39
+ export const renderProfessionalConfig = async (templatesDir, targetDir, config) => {
40
+ const eslintTemplate = await fs.readFile(path.join(templatesDir, 'common', 'eslint.config.mjs.ejs'), 'utf-8');
41
+ const eslintContent = ejs.render(eslintTemplate, { ...config });
42
+ await fs.writeFile(path.join(targetDir, 'eslint.config.mjs'), eslintContent);
43
+
44
+ await fs.copy(path.join(templatesDir, 'common', '.prettierrc'), path.join(targetDir, '.prettierrc'));
45
+ await fs.copy(path.join(templatesDir, 'common', '.lintstagedrc'), path.join(targetDir, '.lintstagedrc'));
46
+
47
+ const jestTemplate = await fs.readFile(path.join(templatesDir, 'common', 'jest.config.js.ejs'), 'utf-8');
48
+ const jestContent = ejs.render(jestTemplate, { ...config });
49
+ await fs.writeFile(path.join(targetDir, 'jest.config.js'), jestContent);
50
+
51
+ // E2E Config
52
+ const jestE2eTemplate = await fs.readFile(path.join(templatesDir, 'common', 'jest.e2e.config.js.ejs'), 'utf-8');
53
+ const jestE2eContent = ejs.render(jestE2eTemplate, { ...config });
54
+ await fs.writeFile(path.join(targetDir, 'jest.e2e.config.js'), jestE2eContent);
55
+
56
+ // 1. Setup Husky pre-commit (Always for Professional Standard)
57
+ const huskyDir = path.join(targetDir, '.husky');
58
+ await fs.ensureDir(huskyDir);
59
+ await fs.copy(path.join(templatesDir, 'common', '_husky', 'pre-commit'), path.join(huskyDir, 'pre-commit'));
60
+
61
+ // 2. Enterprise Security Hardening (Optional)
62
+ if (config.includeSecurity) {
63
+ await fs.copy(path.join(templatesDir, 'common', 'SECURITY.md'), path.join(targetDir, 'SECURITY.md'));
64
+
65
+ const sonarTemplate = await fs.readFile(path.join(templatesDir, 'common', 'sonar-project.properties.ejs'), 'utf-8');
66
+ const sonarContent = ejs.render(sonarTemplate, { ...config });
67
+ await fs.writeFile(path.join(targetDir, 'sonar-project.properties'), sonarContent);
68
+
69
+ const snykTemplate = await fs.readFile(path.join(templatesDir, 'common', '.snyk.ejs'), 'utf-8');
70
+ const snykContent = ejs.render(snykTemplate, { ...config });
71
+ await fs.writeFile(path.join(targetDir, '.snyk'), snykContent);
72
+ }
73
+ };
74
+
75
+ export const renderAiNativeFiles = async (templatesDir, targetDir, config) => {
76
+ // 1. .cursorrules
77
+ const cursorRulesPath = path.join(targetDir, '.cursorrules');
78
+ const cursorRulesTemplate = await fs.readFile(path.join(templatesDir, 'common', '.cursorrules.ejs'), 'utf-8');
79
+ const cursorRulesContent = ejs.render(cursorRulesTemplate, { ...config });
80
+ await fs.writeFile(cursorRulesPath, cursorRulesContent);
81
+
82
+ // 2. prompts/
83
+ const promptsDirTarget = path.join(targetDir, 'prompts');
84
+ await fs.ensureDir(promptsDirTarget);
85
+
86
+ const promptsSourceDir = path.join(templatesDir, 'common', 'prompts');
87
+ const promptFiles = await fs.readdir(promptsSourceDir);
88
+
89
+ for (const file of promptFiles) {
90
+ if (file.endsWith('.ejs')) {
91
+ const templatePath = path.join(promptsSourceDir, file);
92
+ const targetFilePath = path.join(promptsDirTarget, file.replace('.ejs', ''));
93
+ const templateContent = await fs.readFile(templatePath, 'utf-8');
94
+ const renderedContent = ejs.render(templateContent, { ...config });
95
+ await fs.writeFile(targetFilePath, renderedContent);
96
+ }
97
+ }
98
+ };
99
+
100
+ export const setupCiCd = async (templatesDir, targetDir, config) => {
101
+ const { ciProvider, includeSecurity } = config;
102
+ if (ciProvider === 'GitHub Actions') {
103
+ const workflowsDir = path.join(targetDir, '.github/workflows');
104
+ await fs.ensureDir(workflowsDir);
105
+
106
+ const ciTemplate = await fs.readFile(path.join(templatesDir, 'common', '_github/workflows/ci.yml.ejs'), 'utf-8');
107
+ const ciContent = ejs.render(ciTemplate, { ...config });
108
+ await fs.writeFile(path.join(workflowsDir, 'ci.yml'), ciContent);
109
+
110
+ if (includeSecurity) {
111
+ const securityTemplate = await fs.readFile(path.join(templatesDir, 'common', '_github/workflows/security.yml.ejs'), 'utf-8');
112
+ const securityContent = ejs.render(securityTemplate, { ...config });
113
+ await fs.writeFile(path.join(workflowsDir, 'security.yml'), securityContent);
114
+ }
115
+ } else if (ciProvider === 'Jenkins') {
116
+ const jenkinsTemplate = await fs.readFile(path.join(templatesDir, 'common', 'Jenkinsfile.ejs'), 'utf-8');
117
+ const jenkinsContent = ejs.render(jenkinsTemplate, { ...config });
118
+ await fs.writeFile(path.join(targetDir, 'Jenkinsfile'), jenkinsContent);
119
+ } else if (ciProvider === 'GitLab CI') {
120
+ const gitlabTemplate = await fs.readFile(path.join(templatesDir, 'common', '.gitlab-ci.yml.ejs'), 'utf-8');
121
+ const gitlabContent = ejs.render(gitlabTemplate, { ...config });
122
+ await fs.writeFile(path.join(targetDir, '.gitlab-ci.yml'), gitlabContent);
123
+ }
124
+ };
125
+
126
+ export const renderTestSample = async (templatesDir, targetDir, config) => {
127
+ await fs.ensureDir(path.join(targetDir, 'tests'));
128
+ if (config.language === 'TypeScript') {
129
+ const testsTsConfig = {
130
+ "extends": "../tsconfig.json",
131
+ "compilerOptions": {
132
+ "types": ["jest", "node"],
133
+ "rootDir": "..",
134
+ "noEmit": true
135
+ },
136
+ "include": ["**/*.ts", "../src/**/*.ts"]
137
+ };
138
+ await fs.writeFile(path.join(targetDir, 'tests', 'tsconfig.json'), JSON.stringify(testsTsConfig, null, 4));
139
+ }
140
+ };
141
+
142
+ export const renderEnvExample = async (templatesDir, targetDir, config) => {
143
+ const envExamplePath = path.join(targetDir, '.env.example');
144
+ const envPath = path.join(targetDir, '.env');
145
+ const envTemplate = await fs.readFile(path.join(templatesDir, 'common', '.env.example.ejs'), 'utf-8');
146
+
147
+ const envContent = ejs.render(envTemplate, { ...config });
148
+
149
+ await fs.writeFile(envExamplePath, envContent);
150
+ await fs.writeFile(envPath, envContent);
151
+ };
@@ -0,0 +1,116 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import ejs from 'ejs';
4
+
5
+ export const setupDatabase = async (templatesDir, targetDir, config) => {
6
+ const { database, dbName, language, architecture } = config;
7
+ const langExt = language === 'TypeScript' ? 'ts' : 'js';
8
+
9
+ // 1. Migrations
10
+ if (database === 'MongoDB') {
11
+ // Copy migrate-mongo config
12
+ const migrateConfigTemplate = await fs.readFile(path.join(templatesDir, 'common', 'migrate-mongo-config.js.ejs'), 'utf-8');
13
+ const migrateConfigContent = ejs.render(migrateConfigTemplate, { ...config });
14
+ await fs.writeFile(path.join(targetDir, 'migrate-mongo-config.js'), migrateConfigContent);
15
+
16
+ // Setup migrations directory
17
+ await fs.ensureDir(path.join(targetDir, 'migrations'));
18
+
19
+ // Create initial migration file with timestamp
20
+ const timestamp = new Date().toISOString().replace(/[-T:.Z]/g, '').slice(0, 14); // YYYYMMDDHHMMSS
21
+ const migrationTemplate = await fs.readFile(path.join(templatesDir, 'common', 'migrations', 'init.js.ejs'), 'utf-8');
22
+ await fs.writeFile(path.join(targetDir, 'migrations', `${timestamp}-initial-setup.js`), migrationTemplate);
23
+
24
+ } else if (database !== 'None') {
25
+ // Flyway for SQL
26
+ await fs.ensureDir(path.join(targetDir, 'flyway/sql'));
27
+ const dbType = database === 'PostgreSQL' ? 'postgres' : 'mysql';
28
+ const sourceDir = path.join(templatesDir, 'db', dbType);
29
+
30
+ const files = await fs.readdir(sourceDir);
31
+ for (const file of files) {
32
+ if (file.endsWith('.ejs')) {
33
+ const template = await fs.readFile(path.join(sourceDir, file), 'utf-8');
34
+ const content = ejs.render(template, { ...config });
35
+ const targetFileName = file.replace('.ejs', '');
36
+ await fs.writeFile(path.join(targetDir, 'flyway/sql', targetFileName), content);
37
+ } else {
38
+ await fs.copy(path.join(sourceDir, file), path.join(targetDir, 'flyway/sql', file));
39
+ }
40
+ }
41
+ }
42
+
43
+ // 2. Database Config
44
+ if (database !== 'None') {
45
+ const dbConfigFileName = language === 'TypeScript' ? (database === 'MongoDB' ? 'mongoose.ts' : 'database.ts') : (database === 'MongoDB' ? 'mongoose.js' : 'database.js');
46
+ const dbConfigTemplateSource = path.join(templatesDir, 'common', 'database', langExt, `${dbConfigFileName}.ejs`);
47
+
48
+ let dbConfigTarget;
49
+
50
+ if (architecture === 'MVC') {
51
+ await fs.ensureDir(path.join(targetDir, 'src/config'));
52
+ dbConfigTarget = path.join(targetDir, 'src/config', database === 'MongoDB' ? (language === 'TypeScript' ? 'database.ts' : 'database.js') : dbConfigFileName);
53
+ } else {
54
+ // Clean Architecture
55
+ await fs.ensureDir(path.join(targetDir, 'src/infrastructure/database'));
56
+ dbConfigTarget = path.join(targetDir, 'src/infrastructure/database', language === 'TypeScript' ? 'database.ts' : 'database.js');
57
+ }
58
+
59
+ if (await fs.pathExists(dbConfigTemplateSource)) {
60
+ const dbTemplate = await fs.readFile(dbConfigTemplateSource, 'utf-8');
61
+ const dbContent = ejs.render(dbTemplate, { ...config });
62
+ await fs.writeFile(dbConfigTarget, dbContent);
63
+
64
+ // Render Spec
65
+ const specTemplateName = dbConfigFileName.replace(`.${langExt}`, `.spec.${langExt}.ejs`);
66
+ const specTemplateSource = path.join(templatesDir, 'common', 'database', langExt, specTemplateName);
67
+ if (await fs.pathExists(specTemplateSource)) {
68
+ const specTemplate = await fs.readFile(specTemplateSource, 'utf-8');
69
+ const specContent = ejs.render(specTemplate, { ...config });
70
+ const specTarget = dbConfigTarget.replace(`${path.sep}src${path.sep}`, `${path.sep}tests${path.sep}unit${path.sep}`).replace(`.${langExt}`, `.spec.${langExt}`);
71
+ await fs.ensureDir(path.dirname(specTarget));
72
+ await fs.writeFile(specTarget, specContent);
73
+ }
74
+ }
75
+ } else if (architecture === 'MVC') {
76
+ // Even if DB is None, MVC needs src/config for other things (like swagger or general config)
77
+ await fs.ensureDir(path.join(targetDir, 'src/config'));
78
+ }
79
+
80
+ // 3. Models / Entities
81
+ await generateModels(templatesDir, targetDir, config);
82
+ };
83
+
84
+ export const generateModels = async (templatesDir, targetDir, config) => {
85
+ const { database, language, architecture } = config;
86
+ const langExt = language === 'TypeScript' ? 'ts' : 'js';
87
+ const modelFileName = language === 'TypeScript' ? 'User.ts' : 'User.js';
88
+
89
+ const sourceModelName = database === 'MongoDB' ? `${modelFileName}.mongoose.ejs` : `${modelFileName}.ejs`;
90
+ const modelTemplateSource = path.join(templatesDir, 'common', 'database', langExt, 'models', sourceModelName);
91
+ let modelTarget;
92
+
93
+ if (architecture === 'MVC') {
94
+ await fs.ensureDir(path.join(targetDir, 'src/models'));
95
+ modelTarget = path.join(targetDir, 'src/models', modelFileName);
96
+ } else {
97
+ await fs.ensureDir(path.join(targetDir, 'src/infrastructure/database/models'));
98
+ modelTarget = path.join(targetDir, 'src/infrastructure/database/models', modelFileName);
99
+ }
100
+
101
+ if (await fs.pathExists(modelTemplateSource)) {
102
+ const modelTemplate = await fs.readFile(modelTemplateSource, 'utf-8');
103
+ const modelContent = ejs.render(modelTemplate, { ...config });
104
+ await fs.writeFile(modelTarget, modelContent);
105
+
106
+ // Render Spec
107
+ const modelSpecTemplateSource = path.join(templatesDir, 'common', 'database', langExt, 'models', `User.spec.${langExt}.ejs`);
108
+ if (await fs.pathExists(modelSpecTemplateSource)) {
109
+ const modelSpecTemplate = await fs.readFile(modelSpecTemplateSource, 'utf-8');
110
+ const modelSpecContent = ejs.render(modelSpecTemplate, { ...config });
111
+ const modelSpecTarget = modelTarget.replace(`${path.sep}src${path.sep}`, `${path.sep}tests${path.sep}unit${path.sep}`).replace(`.${langExt}`, `.spec.${langExt}`);
112
+ await fs.ensureDir(path.dirname(modelSpecTarget));
113
+ await fs.writeFile(modelSpecTarget, modelSpecContent);
114
+ }
115
+ }
116
+ };
@@ -0,0 +1,249 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import ejs from 'ejs';
4
+
5
+ export const setupKafka = async (templatesDir, targetDir, config) => {
6
+ const { communication, architecture, language } = config;
7
+ if (communication !== 'Kafka') return;
8
+
9
+ const langExt = language === 'TypeScript' ? 'ts' : 'js';
10
+ const kafkaSource = path.join(templatesDir, 'common', 'kafka', langExt);
11
+
12
+ // 1. Copy necessary directories individually (to avoid orphaned templates in src)
13
+ if (await fs.pathExists(path.join(kafkaSource, 'services'))) {
14
+ await fs.copy(path.join(kafkaSource, 'services'), path.join(targetDir, 'src/services'));
15
+ }
16
+ if (await fs.pathExists(path.join(kafkaSource, 'config'))) {
17
+ await fs.copy(path.join(kafkaSource, 'config'), path.join(targetDir, 'src/config'));
18
+ }
19
+
20
+ // Render Kafka Service with dynamic logger path
21
+ const kafkaServiceFileName = `kafkaService.${langExt}`;
22
+ const kafkaServiceTemplate = path.join(targetDir, 'src', 'services', `${kafkaServiceFileName}.ejs`);
23
+ // Render Kafka Service Spec
24
+ const kafkaSpecFileName = `kafkaService.spec.${langExt}`;
25
+ const kafkaSpecTemplate = path.join(targetDir, 'src', 'services', `${kafkaSpecFileName}.ejs`);
26
+
27
+ if (await fs.pathExists(kafkaServiceTemplate)) {
28
+ let serviceLoggerPath, serviceConfigPath;
29
+ if (language === 'TypeScript') {
30
+ serviceLoggerPath = architecture === 'Clean Architecture' ? '@/infrastructure/log/logger' : '@/utils/logger';
31
+ serviceConfigPath = architecture === 'Clean Architecture' ? '@/infrastructure/config/kafka' : '@/config/kafka';
32
+ } else {
33
+ serviceLoggerPath = architecture === 'Clean Architecture' ? '../../infrastructure/log/logger' : '../utils/logger';
34
+ serviceConfigPath = architecture === 'Clean Architecture' ? '../../infrastructure/config/kafka' : '../config/kafka';
35
+ }
36
+
37
+ const content = ejs.render(await fs.readFile(kafkaServiceTemplate, 'utf-8'), { ...config, loggerPath: serviceLoggerPath, configPath: serviceConfigPath });
38
+ await fs.writeFile(path.join(targetDir, 'src', 'services', kafkaServiceFileName), content);
39
+ await fs.remove(kafkaServiceTemplate);
40
+ }
41
+
42
+ if (await fs.pathExists(kafkaSpecTemplate)) {
43
+ let specLoggerPath, specConfigPath, specServicePath;
44
+ if (language === 'TypeScript') {
45
+ specLoggerPath = architecture === 'Clean Architecture' ? '@/infrastructure/log/logger' : '@/utils/logger';
46
+ specConfigPath = architecture === 'Clean Architecture' ? '@/infrastructure/config/kafka' : '@/config/kafka';
47
+ specServicePath = architecture === 'Clean Architecture' ? '@/infrastructure/messaging/kafkaClient' : '@/services/kafkaService';
48
+ } else {
49
+ specLoggerPath = architecture === 'Clean Architecture' ? '../../infrastructure/log/logger' : '../utils/logger';
50
+ specConfigPath = architecture === 'Clean Architecture' ? '../../infrastructure/config/kafka' : '../config/kafka';
51
+ specServicePath = architecture === 'Clean Architecture' ? '../../infrastructure/messaging/kafkaClient' : '../services/kafkaService';
52
+ }
53
+
54
+ const specContent = ejs.render(await fs.readFile(kafkaSpecTemplate, 'utf-8'), { ...config, loggerPath: specLoggerPath, configPath: specConfigPath, servicePath: specServicePath });
55
+ await fs.writeFile(path.join(targetDir, 'src', 'services', kafkaSpecFileName), specContent);
56
+ await fs.remove(kafkaSpecTemplate);
57
+ }
58
+
59
+ // Render Kafka Config Spec
60
+ const kafkaConfigSpecFileName = `kafka.spec.${langExt}`;
61
+ const kafkaConfigSpecTemplate = path.join(templatesDir, 'common', 'kafka', langExt, 'config', `${kafkaConfigSpecFileName}.ejs`);
62
+ if (await fs.pathExists(kafkaConfigSpecTemplate)) {
63
+ const specContent = ejs.render(await fs.readFile(kafkaConfigSpecTemplate, 'utf-8'), { ...config });
64
+ let specTarget;
65
+ if (architecture === 'MVC') {
66
+ specTarget = path.join(targetDir, 'tests', 'unit', 'config', kafkaConfigSpecFileName);
67
+ } else {
68
+ specTarget = path.join(targetDir, 'tests', 'unit', 'infrastructure', 'config', kafkaConfigSpecFileName);
69
+ }
70
+ await fs.ensureDir(path.dirname(specTarget));
71
+ await fs.writeFile(specTarget, specContent);
72
+
73
+ const targetSpecTemplate = path.join(targetDir, 'src', 'config', `${kafkaConfigSpecFileName}.ejs`);
74
+ if (await fs.pathExists(targetSpecTemplate)) {
75
+ await fs.remove(targetSpecTemplate);
76
+ }
77
+ }
78
+
79
+ if (architecture === 'Clean Architecture') {
80
+ // Clean Architecture Restructuring
81
+ await fs.ensureDir(path.join(targetDir, 'src/infrastructure/messaging'));
82
+ await fs.ensureDir(path.join(targetDir, 'tests/unit/infrastructure/messaging'));
83
+ await fs.ensureDir(path.join(targetDir, 'src/infrastructure/config'));
84
+
85
+ const serviceExt = language === 'TypeScript' ? 'ts' : 'js';
86
+
87
+ await fs.move(
88
+ path.join(targetDir, `src/services/kafkaService.${serviceExt}`),
89
+ path.join(targetDir, `src/infrastructure/messaging/kafkaClient.${serviceExt}`),
90
+ { overwrite: true }
91
+ );
92
+
93
+ if (await fs.pathExists(path.join(targetDir, `src/services/kafkaService.spec.${serviceExt}`))) {
94
+ await fs.move(
95
+ path.join(targetDir, `src/services/kafkaService.spec.${serviceExt}`),
96
+ path.join(targetDir, `tests/unit/infrastructure/messaging/kafkaClient.spec.${serviceExt}`),
97
+ { overwrite: true }
98
+ );
99
+ }
100
+
101
+ if (await fs.pathExists(path.join(targetDir, `src/config/kafka.${serviceExt}`))) {
102
+ await fs.move(
103
+ path.join(targetDir, `src/config/kafka.${serviceExt}`),
104
+ path.join(targetDir, `src/infrastructure/config/kafka.${serviceExt}`),
105
+ { overwrite: true }
106
+ );
107
+ }
108
+
109
+ await fs.remove(path.join(targetDir, 'src/services'));
110
+
111
+ // Messaging Infrastructure Enhancement
112
+ const messagingDir = path.join(targetDir, 'src/interfaces/messaging');
113
+ await fs.ensureDir(path.join(messagingDir, 'consumers/instances'));
114
+ await fs.ensureDir(path.join(messagingDir, 'schemas'));
115
+
116
+ const loggerPath = language === 'TypeScript' ? '@/infrastructure/log/logger' : '../../../../infrastructure/log/logger';
117
+ const errorMessagesPath = language === 'TypeScript' ? '@/utils/errorMessages' : '../../../../utils/errorMessages';
118
+ const userEventSchemaPath = language === 'TypeScript' ? '@/messaging/schemas/userEventSchema' : '../../schemas/userEventSchema';
119
+ const messagingTemplates = [
120
+ { src: 'baseConsumer', subDir: 'messaging', dest: 'interfaces/messaging/baseConsumer' },
121
+ { src: 'userEventSchema', subDir: 'messaging', dest: 'interfaces/messaging/schemas/userEventSchema' },
122
+ { src: 'welcomeEmailConsumer', subDir: 'messaging', dest: 'interfaces/messaging/consumers/instances/welcomeEmailConsumer' },
123
+ { src: 'kafkaEvents', subDir: 'utils', dest: 'utils/kafkaEvents' }
124
+ ];
125
+
126
+ for (const t of messagingTemplates) {
127
+ const templateSubDir = t.subDir || 'messaging';
128
+ const templateSource = path.join(templatesDir, 'common', 'kafka', langExt, templateSubDir, `${t.src}.${langExt}.ejs`);
129
+ if (await fs.pathExists(templateSource)) {
130
+ // Calculate dynamic relative paths for JS
131
+ let dynamicLoggerPath = loggerPath;
132
+ let dynamicErrorMessagesPath = errorMessagesPath;
133
+ let dynamicUserEventSchemaPath = userEventSchemaPath;
134
+ let dynamicKafkaEventsPath = language === 'TypeScript' ? '@/utils/kafkaEvents' : '../../utils/kafkaEvents';
135
+ let dynamicBaseConsumerPath = language === 'TypeScript' ? '@/interfaces/messaging/baseConsumer' : '../../baseConsumer';
136
+
137
+ if (language === 'JavaScript') {
138
+ const destDir = path.dirname(path.join('src', t.dest));
139
+ dynamicLoggerPath = path.relative(destDir, 'src/infrastructure/log/logger').replace(/\\/g, '/');
140
+ dynamicErrorMessagesPath = path.relative(destDir, 'src/utils/errorMessages').replace(/\\/g, '/');
141
+ dynamicUserEventSchemaPath = path.relative(destDir, 'src/interfaces/messaging/schemas/userEventSchema').replace(/\\/g, '/');
142
+ dynamicKafkaEventsPath = path.relative(destDir, 'src/utils/kafkaEvents').replace(/\\/g, '/');
143
+ dynamicBaseConsumerPath = path.relative(destDir, 'src/interfaces/messaging/baseConsumer').replace(/\\/g, '/');
144
+ }
145
+
146
+ const content = ejs.render(await fs.readFile(templateSource, 'utf-8'), {
147
+ ...config,
148
+ loggerPath: dynamicLoggerPath,
149
+ errorMessagesPath: dynamicErrorMessagesPath,
150
+ userEventSchemaPath: dynamicUserEventSchemaPath,
151
+ kafkaEventsPath: dynamicKafkaEventsPath,
152
+ baseConsumerPath: dynamicBaseConsumerPath
153
+ });
154
+ const destPath = path.join(targetDir, 'src', `${t.dest}.${langExt}`);
155
+ await fs.ensureDir(path.dirname(destPath));
156
+ await fs.writeFile(destPath, content);
157
+ }
158
+
159
+ // Render Specs for messaging components
160
+ const specTemplateSource = path.join(templatesDir, 'common', 'kafka', langExt, 'messaging', `${t.src}.spec.${langExt}.ejs`);
161
+ if (await fs.pathExists(specTemplateSource)) {
162
+ const specContent = ejs.render(await fs.readFile(specTemplateSource, 'utf-8'), { ...config, loggerPath });
163
+ const specDest = path.join(targetDir, 'tests', 'unit', `${t.dest}.spec.${langExt}`);
164
+ await fs.ensureDir(path.dirname(specDest));
165
+ await fs.writeFile(specDest, specContent);
166
+ }
167
+ }
168
+
169
+ } else if (architecture === 'MVC') {
170
+ const serviceExt = language === 'TypeScript' ? 'ts' : 'js';
171
+
172
+ const messagingDir = path.join(targetDir, 'src/messaging');
173
+ await fs.ensureDir(path.join(messagingDir, 'consumers/instances'));
174
+ await fs.ensureDir(path.join(messagingDir, 'schemas'));
175
+
176
+ const loggerPath = language === 'TypeScript' ? '@/utils/logger' : '../../../utils/logger';
177
+ const errorMessagesPath = language === 'TypeScript' ? '@/utils/errorMessages' : '../../../utils/errorMessages';
178
+ const userEventSchemaPath = language === 'TypeScript' ? '@/messaging/schemas/userEventSchema' : '../../schemas/userEventSchema';
179
+ const messagingTemplates = [
180
+ { src: 'baseConsumer', subDir: 'messaging', dest: 'messaging/baseConsumer' },
181
+ { src: 'userEventSchema', subDir: 'messaging', dest: 'messaging/schemas/userEventSchema' },
182
+ { src: 'welcomeEmailConsumer', subDir: 'messaging', dest: 'messaging/consumers/instances/welcomeEmailConsumer' },
183
+ { src: 'kafkaEvents', subDir: 'utils', dest: 'utils/kafkaEvents' }
184
+ ];
185
+
186
+ for (const t of messagingTemplates) {
187
+ const templateSubDir = t.subDir || 'messaging';
188
+ const templateSource = path.join(templatesDir, 'common', 'kafka', langExt, templateSubDir, `${t.src}.${langExt}.ejs`);
189
+ if (await fs.pathExists(templateSource)) {
190
+ // Calculate dynamic relative paths for JS
191
+ let dynamicLoggerPath = loggerPath;
192
+ let dynamicErrorMessagesPath = errorMessagesPath;
193
+ let dynamicUserEventSchemaPath = userEventSchemaPath;
194
+ let dynamicKafkaEventsPath = language === 'TypeScript' ? '@/utils/kafkaEvents' : '../../utils/kafkaEvents';
195
+ let dynamicBaseConsumerPath = language === 'TypeScript' ? '@/messaging/baseConsumer' : '../../baseConsumer';
196
+
197
+ if (language === 'JavaScript') {
198
+ const destDir = path.dirname(path.join('src', t.dest));
199
+ dynamicLoggerPath = path.relative(destDir, 'src/utils/logger').replace(/\\/g, '/');
200
+ dynamicErrorMessagesPath = path.relative(destDir, 'src/utils/errorMessages').replace(/\\/g, '/');
201
+ dynamicUserEventSchemaPath = path.relative(destDir, 'src/messaging/schemas/userEventSchema').replace(/\\/g, '/');
202
+ dynamicKafkaEventsPath = path.relative(destDir, 'src/utils/kafkaEvents').replace(/\\/g, '/');
203
+ dynamicBaseConsumerPath = path.relative(destDir, 'src/messaging/baseConsumer').replace(/\\/g, '/');
204
+ }
205
+
206
+ const content = ejs.render(await fs.readFile(templateSource, 'utf-8'), {
207
+ ...config,
208
+ loggerPath: dynamicLoggerPath,
209
+ errorMessagesPath: dynamicErrorMessagesPath,
210
+ userEventSchemaPath: dynamicUserEventSchemaPath,
211
+ kafkaEventsPath: dynamicKafkaEventsPath,
212
+ baseConsumerPath: dynamicBaseConsumerPath
213
+ });
214
+ const destPath = path.join(targetDir, 'src', `${t.dest}.${langExt}`);
215
+ await fs.ensureDir(path.dirname(destPath));
216
+ await fs.writeFile(destPath, content);
217
+ }
218
+
219
+ // Render Specs for messaging components
220
+ const specTemplateSource = path.join(templatesDir, 'common', 'kafka', langExt, 'messaging', `${t.src}.spec.${langExt}.ejs`);
221
+ if (await fs.pathExists(specTemplateSource)) {
222
+ const specContent = ejs.render(await fs.readFile(specTemplateSource, 'utf-8'), { ...config, loggerPath });
223
+ const specDest = path.join(targetDir, 'tests', 'unit', `${t.dest}.spec.${langExt}`);
224
+ await fs.ensureDir(path.dirname(specDest));
225
+ await fs.writeFile(specDest, specContent);
226
+ }
227
+ }
228
+
229
+ if (await fs.pathExists(path.join(targetDir, `src/services/kafkaService.spec.${serviceExt}`))) {
230
+ await fs.ensureDir(path.join(targetDir, 'tests/unit/services'));
231
+ await fs.move(
232
+ path.join(targetDir, `src/services/kafkaService.spec.${serviceExt}`),
233
+ path.join(targetDir, `tests/unit/services/kafkaService.spec.${serviceExt}`),
234
+ { overwrite: true }
235
+ );
236
+ }
237
+
238
+ }
239
+ };
240
+
241
+ export const setupViews = async (templatesDir, targetDir, config) => {
242
+ const { architecture, viewEngine } = config;
243
+ if (architecture === 'MVC' && viewEngine && viewEngine !== 'None') {
244
+ const publicDir = path.join(templatesDir, 'common', 'public');
245
+ if (await fs.pathExists(publicDir)) {
246
+ await fs.copy(publicDir, path.join(targetDir, 'public'));
247
+ }
248
+ }
249
+ };
@@ -0,0 +1,32 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ export const setupProjectDirectory = async (targetDir, projectName) => {
5
+ if (await fs.pathExists(targetDir)) {
6
+ throw new Error(`Directory ${projectName} already exists.`);
7
+ }
8
+ await fs.ensureDir(targetDir);
9
+ };
10
+
11
+ export const copyBaseStructure = async (templatesDir, targetDir, architecture, language) => {
12
+ const structureMap = {
13
+ 'MVC': 'mvc',
14
+ 'Clean Architecture': 'clean-architecture'
15
+ };
16
+ const archTemplate = structureMap[architecture];
17
+ const langExt = language === 'TypeScript' ? 'ts' : 'js';
18
+ const templatePath = path.join(templatesDir, archTemplate, langExt);
19
+
20
+ await fs.copy(templatePath, targetDir);
21
+ return { archTemplate, langExt, templatePath };
22
+ };
23
+
24
+ export const copyCommonFiles = async (templatesDir, targetDir, language) => {
25
+ await fs.copy(path.join(templatesDir, 'common', '_gitignore'), path.join(targetDir, '.gitignore'));
26
+ await fs.copy(path.join(templatesDir, 'common', '.dockerignore'), path.join(targetDir, '.dockerignore'));
27
+ await fs.copy(path.join(templatesDir, 'common', '.gitattributes'), path.join(targetDir, '.gitattributes'));
28
+
29
+ if (language === 'TypeScript') {
30
+ await fs.copy(path.join(templatesDir, 'common', 'tsconfig.json'), path.join(targetDir, 'tsconfig.json'));
31
+ }
32
+ };