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.
- package/README.md +32 -0
- package/bin/index.js +143 -0
- package/lib/generator.js +145 -0
- package/lib/modules/app-setup.js +479 -0
- package/lib/modules/caching-setup.js +76 -0
- package/lib/modules/config-files.js +151 -0
- package/lib/modules/database-setup.js +116 -0
- package/lib/modules/kafka-setup.js +249 -0
- package/lib/modules/project-setup.js +32 -0
- package/lib/prompts.js +128 -0
- package/package.json +66 -0
- package/templates/clean-architecture/js/src/domain/models/User.js.ejs +11 -0
- package/templates/clean-architecture/js/src/errors/ApiError.js +14 -0
- package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -0
- package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -0
- package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -0
- package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -0
- package/templates/clean-architecture/js/src/index.js.ejs +56 -0
- package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -0
- package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -0
- package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -0
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +88 -0
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -0
- package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -0
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +93 -0
- package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -0
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +190 -0
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -0
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -0
- package/templates/clean-architecture/js/src/interfaces/routes/api.js.ejs +17 -0
- package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -0
- package/templates/clean-architecture/js/src/usecases/CreateUser.js.ejs +14 -0
- package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -0
- package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
- package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -0
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -0
- package/templates/clean-architecture/js/src/usecases/UpdateUser.js.ejs +11 -0
- package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
- package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
- package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -0
- package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -0
- package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -0
- package/templates/clean-architecture/ts/src/domain/user.ts.ejs +9 -0
- package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -0
- package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -0
- package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -0
- package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -0
- package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -0
- package/templates/clean-architecture/ts/src/index.ts.ejs +144 -0
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -0
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -0
- package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -0
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +125 -0
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -0
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +208 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -0
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -0
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -0
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts.ejs +18 -0
- package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -0
- package/templates/clean-architecture/ts/src/usecases/createUser.ts.ejs +11 -0
- package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
- package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -0
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -0
- package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
- package/templates/clean-architecture/ts/src/usecases/updateUser.ts.ejs +10 -0
- package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
- package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -0
- package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -0
- package/templates/common/.cursorrules.ejs +60 -0
- package/templates/common/.dockerignore +12 -0
- package/templates/common/.env.example.ejs +60 -0
- package/templates/common/.gitattributes +46 -0
- package/templates/common/.gitlab-ci.yml.ejs +86 -0
- package/templates/common/.lintstagedrc +6 -0
- package/templates/common/.prettierrc +7 -0
- package/templates/common/.snyk.ejs +45 -0
- package/templates/common/Dockerfile +73 -0
- package/templates/common/Jenkinsfile.ejs +87 -0
- package/templates/common/README.md.ejs +148 -0
- package/templates/common/_github/workflows/ci.yml.ejs +46 -0
- package/templates/common/_github/workflows/security.yml.ejs +36 -0
- package/templates/common/_gitignore +5 -0
- package/templates/common/_husky/pre-commit +4 -0
- package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -0
- package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
- package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -0
- package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
- package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -0
- package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
- package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -0
- package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
- package/templates/common/caching/js/memoryCache.js.ejs +60 -0
- package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -0
- package/templates/common/caching/js/redisClient.js.ejs +75 -0
- package/templates/common/caching/js/redisClient.spec.js.ejs +147 -0
- package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -0
- package/templates/common/caching/ts/memoryCache.ts.ejs +73 -0
- package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -0
- package/templates/common/caching/ts/redisClient.ts.ejs +89 -0
- package/templates/common/database/js/database.js.ejs +19 -0
- package/templates/common/database/js/database.spec.js.ejs +56 -0
- package/templates/common/database/js/models/User.js.ejs +91 -0
- package/templates/common/database/js/models/User.js.mongoose.ejs +35 -0
- package/templates/common/database/js/models/User.spec.js.ejs +94 -0
- package/templates/common/database/js/mongoose.js.ejs +33 -0
- package/templates/common/database/js/mongoose.spec.js.ejs +43 -0
- package/templates/common/database/ts/database.spec.ts.ejs +56 -0
- package/templates/common/database/ts/database.ts.ejs +21 -0
- package/templates/common/database/ts/models/User.spec.ts.ejs +100 -0
- package/templates/common/database/ts/models/User.ts.ejs +102 -0
- package/templates/common/database/ts/models/User.ts.mongoose.ejs +34 -0
- package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -0
- package/templates/common/database/ts/mongoose.ts.ejs +28 -0
- package/templates/common/docker-compose.yml.ejs +159 -0
- package/templates/common/ecosystem.config.js.ejs +40 -0
- package/templates/common/eslint.config.mjs.ejs +77 -0
- package/templates/common/health/js/healthRoute.js.ejs +50 -0
- package/templates/common/health/js/healthRoute.spec.js.ejs +70 -0
- package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -0
- package/templates/common/health/ts/healthRoute.ts.ejs +49 -0
- package/templates/common/jest.config.js.ejs +32 -0
- package/templates/common/jest.e2e.config.js.ejs +8 -0
- package/templates/common/kafka/js/config/kafka.js +9 -0
- package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -0
- package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -0
- package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -0
- package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -0
- package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -0
- package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -0
- package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -0
- package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -0
- package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -0
- package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
- package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -0
- package/templates/common/kafka/ts/config/kafka.ts +7 -0
- package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -0
- package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -0
- package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -0
- package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -0
- package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -0
- package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -0
- package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -0
- package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -0
- package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
- package/templates/common/migrate-mongo-config.js.ejs +31 -0
- package/templates/common/migrations/init.js.ejs +23 -0
- package/templates/common/package.json.ejs +137 -0
- package/templates/common/prompts/add-feature.md.ejs +26 -0
- package/templates/common/prompts/project-context.md.ejs +43 -0
- package/templates/common/prompts/troubleshoot.md.ejs +28 -0
- package/templates/common/public/css/style.css +147 -0
- package/templates/common/scripts/run-e2e.js.ejs +63 -0
- package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -0
- package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -0
- package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -0
- package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -0
- package/templates/common/sonar-project.properties.ejs +27 -0
- package/templates/common/src/config/auth.js.ejs +19 -0
- package/templates/common/src/config/auth.ts.ejs +19 -0
- package/templates/common/src/controllers/authController.js.ejs +101 -0
- package/templates/common/src/controllers/authController.ts.ejs +101 -0
- package/templates/common/src/middleware/auth.js.ejs +20 -0
- package/templates/common/src/middleware/auth.ts.ejs +25 -0
- package/templates/common/src/middleware/upload.js.ejs +31 -0
- package/templates/common/src/middleware/upload.ts.ejs +32 -0
- package/templates/common/src/routes/authRoutes.js.ejs +20 -0
- package/templates/common/src/routes/authRoutes.ts.ejs +20 -0
- package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -0
- package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -0
- package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -0
- package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -0
- package/templates/common/swagger.yml.ejs +118 -0
- package/templates/common/tsconfig.json +23 -0
- package/templates/common/views/ejs/index.ejs +55 -0
- package/templates/common/views/pug/index.pug +40 -0
- package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -0
- package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -0
- package/templates/mvc/js/src/config/env.js.ejs +46 -0
- package/templates/mvc/js/src/config/swagger.js.ejs +6 -0
- package/templates/mvc/js/src/controllers/userController.js.ejs +288 -0
- package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -0
- package/templates/mvc/js/src/errors/ApiError.js +14 -0
- package/templates/mvc/js/src/errors/BadRequestError.js +11 -0
- package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -0
- package/templates/mvc/js/src/errors/NotFoundError.js +11 -0
- package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -0
- package/templates/mvc/js/src/graphql/context.js.ejs +7 -0
- package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -0
- package/templates/mvc/js/src/graphql/index.js.ejs +5 -0
- package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -0
- package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -0
- package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -0
- package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -0
- package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -0
- package/templates/mvc/js/src/index.js.ejs +141 -0
- package/templates/mvc/js/src/routes/api.js.ejs +15 -0
- package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -0
- package/templates/mvc/js/src/utils/errorMessages.js +14 -0
- package/templates/mvc/js/src/utils/errorMiddleware.js +29 -0
- package/templates/mvc/js/src/utils/httpCodes.js +9 -0
- package/templates/mvc/js/src/utils/logger.js +40 -0
- package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -0
- package/templates/mvc/ts/src/config/env.ts.ejs +45 -0
- package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -0
- package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -0
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +292 -0
- package/templates/mvc/ts/src/errors/ApiError.ts +15 -0
- package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -0
- package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -0
- package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -0
- package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -0
- package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -0
- package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -0
- package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -0
- package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -0
- package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -0
- package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -0
- package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -0
- package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -0
- package/templates/mvc/ts/src/index.ts.ejs +157 -0
- package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -0
- package/templates/mvc/ts/src/routes/api.ts.ejs +17 -0
- package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
- package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -0
- package/templates/mvc/ts/src/utils/httpCodes.ts +7 -0
- package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -0
- package/templates/mvc/ts/src/utils/logger.ts +36 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import ejs from 'ejs';
|
|
4
|
+
|
|
5
|
+
export const renderIndexFile = async (templatePath, targetDir, config) => {
|
|
6
|
+
const { communication, viewEngine, database, architecture, projectName, language, caching } = config;
|
|
7
|
+
const indexFileName = language === 'TypeScript' ? 'index.ts' : 'index.js';
|
|
8
|
+
const indexPath = path.join(targetDir, 'src', indexFileName);
|
|
9
|
+
const indexTemplateSource = path.join(templatePath, 'src', `${indexFileName}.ejs`);
|
|
10
|
+
|
|
11
|
+
if (await fs.pathExists(indexTemplateSource)) {
|
|
12
|
+
const indexTemplate = await fs.readFile(indexTemplateSource, 'utf-8');
|
|
13
|
+
const indexContent = ejs.render(indexTemplate, { ...config });
|
|
14
|
+
await fs.writeFile(indexPath, indexContent);
|
|
15
|
+
await fs.remove(path.join(targetDir, 'src', `${indexFileName}.ejs`));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const renderEnvConfig = async (templatePath, targetDir, config) => {
|
|
20
|
+
const { language, architecture, database, caching, communication } = config;
|
|
21
|
+
const envExt = language === 'TypeScript' ? 'ts' : 'js';
|
|
22
|
+
|
|
23
|
+
let configDir = path.join(targetDir, 'src', 'config');
|
|
24
|
+
if (architecture === 'Clean Architecture' && language === 'JavaScript') {
|
|
25
|
+
configDir = path.join(targetDir, 'src', 'infrastructure', 'config');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const envTemplatePath = path.join(configDir, `env.${envExt}.ejs`);
|
|
29
|
+
const envDestPath = path.join(configDir, `env.${envExt}`);
|
|
30
|
+
|
|
31
|
+
if (await fs.pathExists(envTemplatePath)) {
|
|
32
|
+
const envTemplate = await fs.readFile(envTemplatePath, 'utf-8');
|
|
33
|
+
const envContent = ejs.render(envTemplate, { ...config });
|
|
34
|
+
await fs.writeFile(envDestPath, envContent);
|
|
35
|
+
await fs.remove(envTemplatePath);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const renderErrorMiddleware = async (templatePath, targetDir, config) => {
|
|
40
|
+
const { language, architecture } = config;
|
|
41
|
+
const errName = language === 'TypeScript' ? 'errorMiddleware.ts' : 'errorMiddleware.js';
|
|
42
|
+
const errTemplateName = `${errName}.ejs`;
|
|
43
|
+
|
|
44
|
+
if (architecture === 'MVC') {
|
|
45
|
+
// MVC: render from target's src/utils/ (the .ejs copy put there by copyBaseStructure)
|
|
46
|
+
const ejsCopy = path.join(targetDir, 'src/utils', errTemplateName);
|
|
47
|
+
const dest = path.join(targetDir, 'src/utils', errName);
|
|
48
|
+
if (await fs.pathExists(ejsCopy)) {
|
|
49
|
+
await fs.writeFile(dest, await fs.readFile(ejsCopy, 'utf-8'));
|
|
50
|
+
await fs.remove(ejsCopy);
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
// Clean Architecture: render from target's src/utils/ (the .ejs copy put there by copyBaseStructure)
|
|
54
|
+
const utilsEjsCopy = path.join(targetDir, 'src/utils', errTemplateName);
|
|
55
|
+
const utilsDest = path.join(targetDir, 'src/utils', errName);
|
|
56
|
+
await fs.ensureDir(path.join(targetDir, 'src/utils'));
|
|
57
|
+
if (await fs.pathExists(utilsEjsCopy)) {
|
|
58
|
+
await fs.writeFile(utilsDest, await fs.readFile(utilsEjsCopy, 'utf-8'));
|
|
59
|
+
await fs.remove(utilsEjsCopy);
|
|
60
|
+
}
|
|
61
|
+
// Also render the middleware version if present (NOT removing from template)
|
|
62
|
+
const mwDir = path.join(targetDir, 'src/infrastructure/webserver/middleware');
|
|
63
|
+
const mwEjsCopy = path.join(mwDir, errTemplateName);
|
|
64
|
+
const mwDest = path.join(mwDir, errName);
|
|
65
|
+
if (await fs.pathExists(mwEjsCopy)) {
|
|
66
|
+
await fs.ensureDir(mwDir);
|
|
67
|
+
await fs.writeFile(mwDest, await fs.readFile(mwEjsCopy, 'utf-8'));
|
|
68
|
+
await fs.remove(mwEjsCopy);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Render errorMiddleware spec template
|
|
73
|
+
const specExt = language === 'TypeScript' ? 'ts' : 'js';
|
|
74
|
+
const specTemplatePath = path.join(templatePath, '../../common/src/utils', `errorMiddleware.spec.${specExt}.ejs`);
|
|
75
|
+
if (await fs.pathExists(specTemplatePath)) {
|
|
76
|
+
const testUtilsDir = path.join(targetDir, 'tests', 'unit', 'utils');
|
|
77
|
+
await fs.ensureDir(testUtilsDir);
|
|
78
|
+
const specContent = ejs.render(await fs.readFile(specTemplatePath, 'utf-8'), config);
|
|
79
|
+
await fs.writeFile(path.join(testUtilsDir, `errorMiddleware.spec.${specExt}`), specContent);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const renderDynamicComponents = async (templatePath, targetDir, config) => {
|
|
84
|
+
const { architecture, language, database, caching } = config;
|
|
85
|
+
|
|
86
|
+
// MVC Controller
|
|
87
|
+
if (architecture === 'MVC') {
|
|
88
|
+
const userControllerName = language === 'TypeScript' ? 'userController.ts' : 'userController.js';
|
|
89
|
+
const userControllerSpecName = language === 'TypeScript' ? 'userController.spec.ts' : 'userController.spec.js';
|
|
90
|
+
|
|
91
|
+
const userControllerPath = path.join(targetDir, 'src/controllers', userControllerName);
|
|
92
|
+
const userControllerSpecPath = path.join(targetDir, 'tests/unit/controllers', userControllerSpecName);
|
|
93
|
+
|
|
94
|
+
const userControllerTemplate = path.join(templatePath, 'src/controllers', `${userControllerName}.ejs`);
|
|
95
|
+
const userControllerSpecTemplate = path.join(templatePath, 'src/controllers', `${userControllerSpecName}.ejs`);
|
|
96
|
+
|
|
97
|
+
if (await fs.pathExists(userControllerTemplate)) {
|
|
98
|
+
const content = ejs.render(await fs.readFile(userControllerTemplate, 'utf-8'), { ...config });
|
|
99
|
+
await fs.writeFile(userControllerPath, content);
|
|
100
|
+
await fs.remove(path.join(targetDir, 'src/controllers', `${userControllerName}.ejs`));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (await fs.pathExists(userControllerSpecTemplate)) {
|
|
104
|
+
await fs.ensureDir(path.join(targetDir, 'tests/unit/controllers'));
|
|
105
|
+
const content = ejs.render(await fs.readFile(userControllerSpecTemplate, 'utf-8'), { ...config });
|
|
106
|
+
await fs.writeFile(userControllerSpecPath, content);
|
|
107
|
+
await fs.remove(path.join(targetDir, 'src/controllers', `${userControllerSpecName}.ejs`));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Clean Architecture Repo
|
|
111
|
+
else if (architecture === 'Clean Architecture') {
|
|
112
|
+
const repoName = language === 'TypeScript' ? 'UserRepository.ts' : 'UserRepository.js';
|
|
113
|
+
const repoSpecName = language === 'TypeScript' ? 'UserRepository.spec.ts' : 'UserRepository.spec.js';
|
|
114
|
+
|
|
115
|
+
const repoPath = path.join(targetDir, 'src/infrastructure/repositories', repoName);
|
|
116
|
+
const repoSpecPath = path.join(targetDir, 'tests/unit/infrastructure/repositories', repoSpecName);
|
|
117
|
+
|
|
118
|
+
const repoTemplate = path.join(templatePath, 'src/infrastructure/repositories', `${repoName}.ejs`);
|
|
119
|
+
const repoSpecTemplate = path.join(templatePath, 'src/infrastructure/repositories', `${repoSpecName}.ejs`);
|
|
120
|
+
|
|
121
|
+
if (await fs.pathExists(repoTemplate)) {
|
|
122
|
+
const content = ejs.render(await fs.readFile(repoTemplate, 'utf-8'), { ...config });
|
|
123
|
+
await fs.writeFile(repoPath, content);
|
|
124
|
+
await fs.remove(path.join(targetDir, 'src/infrastructure/repositories', `${repoName}.ejs`));
|
|
125
|
+
}
|
|
126
|
+
if (await fs.pathExists(repoSpecTemplate)) {
|
|
127
|
+
await fs.ensureDir(path.join(targetDir, 'tests/unit/infrastructure/repositories'));
|
|
128
|
+
const content = ejs.render(await fs.readFile(repoSpecTemplate, 'utf-8'), { ...config });
|
|
129
|
+
await fs.writeFile(repoSpecPath, content);
|
|
130
|
+
await fs.remove(path.join(targetDir, 'src/infrastructure/repositories', `${repoSpecName}.ejs`));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const controllerName = language === 'TypeScript' ? 'userController.ts' : 'userController.js';
|
|
134
|
+
const controllerSpecName = language === 'TypeScript' ? 'userController.spec.ts' : 'userController.spec.js';
|
|
135
|
+
|
|
136
|
+
const controllerPath = path.join(targetDir, 'src/interfaces/controllers', controllerName);
|
|
137
|
+
const controllerSpecPath = path.join(targetDir, 'tests/unit/interfaces/controllers', controllerSpecName);
|
|
138
|
+
|
|
139
|
+
const controllerTemplate = path.join(templatePath, 'src/interfaces/controllers', `${controllerName}.ejs`);
|
|
140
|
+
const controllerSpecTemplate = path.join(templatePath, 'src/interfaces/controllers', `${controllerSpecName}.ejs`);
|
|
141
|
+
|
|
142
|
+
if (await fs.pathExists(controllerTemplate)) {
|
|
143
|
+
const content = ejs.render(await fs.readFile(controllerTemplate, 'utf-8'), { ...config });
|
|
144
|
+
await fs.writeFile(controllerPath, content);
|
|
145
|
+
await fs.remove(path.join(targetDir, 'src/interfaces/controllers', `${controllerName}.ejs`));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (await fs.pathExists(controllerSpecTemplate)) {
|
|
149
|
+
await fs.ensureDir(path.join(targetDir, 'tests/unit/interfaces/controllers'));
|
|
150
|
+
const content = ejs.render(await fs.readFile(controllerSpecTemplate, 'utf-8'), { ...config });
|
|
151
|
+
await fs.writeFile(controllerSpecPath, content);
|
|
152
|
+
await fs.remove(path.join(targetDir, 'src/interfaces/controllers', `${controllerSpecName}.ejs`));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Render Server (Clean Arch JS only)
|
|
156
|
+
if (architecture === 'Clean Architecture' && language === 'JavaScript') {
|
|
157
|
+
const serverName = 'server.js';
|
|
158
|
+
const serverPath = path.join(targetDir, 'src/infrastructure/webserver', serverName);
|
|
159
|
+
const serverTemplate = path.join(templatePath, 'src/infrastructure/webserver', `${serverName}.ejs`);
|
|
160
|
+
|
|
161
|
+
if (await fs.pathExists(serverTemplate)) {
|
|
162
|
+
const content = ejs.render(await fs.readFile(serverTemplate, 'utf-8'), { ...config });
|
|
163
|
+
await fs.writeFile(serverPath, content);
|
|
164
|
+
await fs.remove(path.join(targetDir, 'src/infrastructure/webserver', `${serverName}.ejs`));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Cleanup REST routes if neither REST APIs nor Kafka is selected
|
|
169
|
+
if (config.communication !== 'REST APIs' && config.communication !== 'Kafka') {
|
|
170
|
+
if (architecture === 'MVC') {
|
|
171
|
+
await fs.remove(path.join(targetDir, 'src/routes'));
|
|
172
|
+
} else if (architecture === 'Clean Architecture') {
|
|
173
|
+
await fs.remove(path.join(targetDir, 'src/interfaces/routes'));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Advanced Health Check Route Modularization
|
|
178
|
+
const healthExt = language === 'TypeScript' ? 'ts' : 'js';
|
|
179
|
+
const healthTemplatePath = path.join(templatePath, '../../common/health', healthExt, `healthRoute.${healthExt}.ejs`);
|
|
180
|
+
|
|
181
|
+
if (await fs.pathExists(healthTemplatePath)) {
|
|
182
|
+
let routeDestDir = path.join(targetDir, 'src', 'routes');
|
|
183
|
+
if (architecture === 'Clean Architecture') {
|
|
184
|
+
routeDestDir = path.join(targetDir, 'src', 'interfaces', 'routes');
|
|
185
|
+
}
|
|
186
|
+
await fs.ensureDir(routeDestDir);
|
|
187
|
+
|
|
188
|
+
const healthRouteContent = ejs.render(await fs.readFile(healthTemplatePath, 'utf-8'), { ...config });
|
|
189
|
+
await fs.writeFile(path.join(routeDestDir, `healthRoute.${healthExt}`), healthRouteContent);
|
|
190
|
+
|
|
191
|
+
// Render health route spec template
|
|
192
|
+
const healthSpecTemplatePath = path.join(templatePath, '../../common/health', healthExt, `healthRoute.spec.${healthExt}.ejs`);
|
|
193
|
+
if (await fs.pathExists(healthSpecTemplatePath)) {
|
|
194
|
+
let testRouteDestDir = path.join(targetDir, 'tests', 'unit', 'routes');
|
|
195
|
+
if (architecture === 'Clean Architecture') {
|
|
196
|
+
testRouteDestDir = path.join(targetDir, 'tests', 'unit', 'interfaces', 'routes');
|
|
197
|
+
}
|
|
198
|
+
await fs.ensureDir(testRouteDestDir);
|
|
199
|
+
const specContent = ejs.render(await fs.readFile(healthSpecTemplatePath, 'utf-8'), config);
|
|
200
|
+
await fs.writeFile(path.join(testRouteDestDir, `healthRoute.spec.${healthExt}`), specContent);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Advanced Graceful Shutdown Modularization
|
|
205
|
+
const shutdownExt = language === 'TypeScript' ? 'ts' : 'js';
|
|
206
|
+
const shutdownTemplatePath = path.join(templatePath, '../../common/shutdown', shutdownExt, `gracefulShutdown.${shutdownExt}.ejs`);
|
|
207
|
+
|
|
208
|
+
if (await fs.pathExists(shutdownTemplatePath)) {
|
|
209
|
+
let utilsDestDir = path.join(targetDir, 'src', 'utils');
|
|
210
|
+
await fs.ensureDir(utilsDestDir);
|
|
211
|
+
|
|
212
|
+
const shutdownContent = ejs.render(await fs.readFile(shutdownTemplatePath, 'utf-8'), { ...config });
|
|
213
|
+
await fs.writeFile(path.join(utilsDestDir, `gracefulShutdown.${shutdownExt}`), shutdownContent);
|
|
214
|
+
|
|
215
|
+
// Render graceful shutdown spec template
|
|
216
|
+
const shutdownSpecTemplatePath = path.join(templatePath, '../../common/shutdown', shutdownExt, `gracefulShutdown.spec.${shutdownExt}.ejs`);
|
|
217
|
+
if (await fs.pathExists(shutdownSpecTemplatePath)) {
|
|
218
|
+
const testUtilsDestDir = path.join(targetDir, 'tests', 'unit', 'utils');
|
|
219
|
+
await fs.ensureDir(testUtilsDestDir);
|
|
220
|
+
const specContent = ejs.render(await fs.readFile(shutdownSpecTemplatePath, 'utf-8'), config);
|
|
221
|
+
await fs.writeFile(path.join(testUtilsDestDir, `gracefulShutdown.spec.${shutdownExt}`), specContent);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Advanced E2E Testing Generation
|
|
226
|
+
const e2eExt = language === 'TypeScript' ? 'ts' : 'js';
|
|
227
|
+
const e2eTemplatePath = path.join(templatePath, '../../common/src/tests/e2e', `e2e.users.test.${e2eExt}.ejs`);
|
|
228
|
+
|
|
229
|
+
if (await fs.pathExists(e2eTemplatePath)) {
|
|
230
|
+
let e2eDestDir = path.join(targetDir, 'tests', 'e2e');
|
|
231
|
+
await fs.ensureDir(e2eDestDir);
|
|
232
|
+
|
|
233
|
+
const e2eContent = ejs.render(await fs.readFile(e2eTemplatePath, 'utf-8'), { ...config });
|
|
234
|
+
await fs.writeFile(path.join(e2eDestDir, `e2e.users.test.${e2eExt}`), e2eContent);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// E2E Test Orchestrator Generation
|
|
238
|
+
const e2eOrchestratorTemplatePath = path.join(templatePath, '../../common/scripts', 'run-e2e.js.ejs');
|
|
239
|
+
if (await fs.pathExists(e2eOrchestratorTemplatePath)) {
|
|
240
|
+
let scriptsDestDir = path.join(targetDir, 'scripts');
|
|
241
|
+
await fs.ensureDir(scriptsDestDir);
|
|
242
|
+
|
|
243
|
+
const orchestratorContent = ejs.render(await fs.readFile(e2eOrchestratorTemplatePath, 'utf-8'), { ...config });
|
|
244
|
+
await fs.writeFile(path.join(scriptsDestDir, 'run-e2e.js'), orchestratorContent);
|
|
245
|
+
|
|
246
|
+
// Cleanup the raw ejs copy in target
|
|
247
|
+
if (await fs.pathExists(path.join(scriptsDestDir, 'run-e2e.js.ejs'))) {
|
|
248
|
+
await fs.remove(path.join(scriptsDestDir, 'run-e2e.js.ejs'));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// GraphQL Setup
|
|
253
|
+
if (config.communication === 'GraphQL') {
|
|
254
|
+
const ext = language === 'TypeScript' ? 'ts' : 'js';
|
|
255
|
+
let graphqlInternalPath = architecture === 'MVC' ? 'src/graphql' : 'src/interfaces/graphql';
|
|
256
|
+
|
|
257
|
+
const sourceGraphqDir = path.join(templatePath, graphqlInternalPath);
|
|
258
|
+
const targetGraphqlDir = path.join(targetDir, graphqlInternalPath);
|
|
259
|
+
|
|
260
|
+
if (await fs.pathExists(sourceGraphqDir)) {
|
|
261
|
+
// Read and render all .ejs files in the directory recursively
|
|
262
|
+
const renderEjsDir = async (src, dest) => {
|
|
263
|
+
await fs.ensureDir(dest);
|
|
264
|
+
const items = await fs.readdir(src);
|
|
265
|
+
for (let item of items) {
|
|
266
|
+
const srcPath = path.join(src, item);
|
|
267
|
+
const destPath = path.join(dest, item);
|
|
268
|
+
const stat = await fs.stat(srcPath);
|
|
269
|
+
|
|
270
|
+
if (stat.isDirectory()) {
|
|
271
|
+
await renderEjsDir(srcPath, destPath);
|
|
272
|
+
} else if (item.endsWith('.ejs')) {
|
|
273
|
+
const content = ejs.render(await fs.readFile(srcPath, 'utf-8'), { language, architecture, database, caching });
|
|
274
|
+
// Remove .ejs extension
|
|
275
|
+
const finalDestPath = destPath.slice(0, -4);
|
|
276
|
+
await fs.writeFile(finalDestPath, content);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
await renderEjsDir(sourceGraphqDir, targetGraphqlDir);
|
|
282
|
+
// After successful generation, remove the raw template folder in the target dir (since copyBaseStructure copies EVERYTHING)
|
|
283
|
+
await fs.remove(path.join(targetDir, graphqlInternalPath)); // remove the raw dir
|
|
284
|
+
await renderEjsDir(sourceGraphqDir, targetGraphqlDir); // render them into place
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
// Cleanup GraphQL template dirs if REST or Kafka is selected
|
|
288
|
+
let graphqlInternalPath = architecture === 'MVC' ? 'src/graphql' : 'src/interfaces/graphql';
|
|
289
|
+
await fs.remove(path.join(targetDir, graphqlInternalPath));
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export const renderSwaggerConfig = async (templatesDir, targetDir, config) => {
|
|
294
|
+
const { communication, projectName, architecture, language } = config;
|
|
295
|
+
|
|
296
|
+
// Check for Swagger config template (typically in src/config/swagger.ts.ejs)
|
|
297
|
+
const swaggerTsTemplate = path.join(targetDir, 'src', 'config', 'swagger.ts.ejs');
|
|
298
|
+
// MVC JS uses swagger.js.ejs in src/config/
|
|
299
|
+
const swaggerJsTemplate = path.join(targetDir, 'src', 'config', 'swagger.js.ejs');
|
|
300
|
+
// Clean Arch JS uses swagger.js.ejs in src/infrastructure/webserver/
|
|
301
|
+
const swaggerJsCleanTemplate = path.join(targetDir, 'src', 'infrastructure', 'webserver', 'swagger.js.ejs');
|
|
302
|
+
|
|
303
|
+
// Ensure config directory exists
|
|
304
|
+
let configDir = path.join(targetDir, 'src', 'config');
|
|
305
|
+
if (architecture === 'Clean Architecture' && language === 'JavaScript') {
|
|
306
|
+
configDir = path.join(targetDir, 'src', 'infrastructure', 'webserver');
|
|
307
|
+
}
|
|
308
|
+
await fs.ensureDir(configDir);
|
|
309
|
+
|
|
310
|
+
if (communication === 'REST APIs' || communication === 'Kafka') {
|
|
311
|
+
const swaggerYmlTemplateSource = path.join(templatesDir, 'common', 'swagger.yml.ejs');
|
|
312
|
+
if (await fs.pathExists(swaggerYmlTemplateSource)) {
|
|
313
|
+
const ymlContent = ejs.render(await fs.readFile(swaggerYmlTemplateSource, 'utf-8'), { projectName });
|
|
314
|
+
await fs.writeFile(path.join(configDir, 'swagger.yml'), ymlContent);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (await fs.pathExists(swaggerTsTemplate)) {
|
|
318
|
+
const content = ejs.render(await fs.readFile(swaggerTsTemplate, 'utf-8'), { communication });
|
|
319
|
+
await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.ts'), content);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// MVC JS: render swagger.js.ejs → swagger.js
|
|
323
|
+
if (await fs.pathExists(swaggerJsTemplate)) {
|
|
324
|
+
const content = await fs.readFile(swaggerJsTemplate, 'utf-8');
|
|
325
|
+
await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.js'), content);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Clean Arch JS: render swagger.js.ejs → swagger.js in webserver/
|
|
329
|
+
if (await fs.pathExists(swaggerJsCleanTemplate)) {
|
|
330
|
+
const content = await fs.readFile(swaggerJsCleanTemplate, 'utf-8');
|
|
331
|
+
await fs.writeFile(path.join(targetDir, 'src', 'infrastructure', 'webserver', 'swagger.js'), content);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Always remove the .ejs template after processing (or if non-REST, just delete it)
|
|
336
|
+
if (await fs.pathExists(swaggerTsTemplate)) await fs.remove(swaggerTsTemplate);
|
|
337
|
+
if (await fs.pathExists(swaggerJsTemplate)) await fs.remove(swaggerJsTemplate);
|
|
338
|
+
if (await fs.pathExists(swaggerJsCleanTemplate)) await fs.remove(swaggerJsCleanTemplate);
|
|
339
|
+
|
|
340
|
+
// Also cleanup yml template if not REST APIs since copyBaseStructure copies it earlier
|
|
341
|
+
const swaggerYmlDestPath = path.join(targetDir, 'src', 'config', 'swagger.yml.ejs');
|
|
342
|
+
if (await fs.pathExists(swaggerYmlDestPath)) {
|
|
343
|
+
await fs.remove(swaggerYmlDestPath);
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
export const setupViews = async (templatesDir, targetDir, config) => {
|
|
348
|
+
const { architecture, viewEngine } = config;
|
|
349
|
+
if (architecture === 'MVC' && viewEngine && viewEngine !== 'None') {
|
|
350
|
+
const viewsSource = path.join(templatesDir, 'common', 'views', viewEngine.toLowerCase());
|
|
351
|
+
if (await fs.pathExists(viewsSource)) {
|
|
352
|
+
await fs.copy(viewsSource, path.join(targetDir, 'src/views'));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
export const processAllTests = async (targetDir, config) => {
|
|
358
|
+
const srcDir = path.join(targetDir, 'src');
|
|
359
|
+
const testsDir = path.join(targetDir, 'tests');
|
|
360
|
+
|
|
361
|
+
const processDir = async (currentDir) => {
|
|
362
|
+
if (!(await fs.pathExists(currentDir))) return;
|
|
363
|
+
const items = await fs.readdir(currentDir);
|
|
364
|
+
for (const item of items) {
|
|
365
|
+
|
|
366
|
+
const itemPath = path.join(currentDir, item);
|
|
367
|
+
const stat = await fs.stat(itemPath);
|
|
368
|
+
if (stat.isDirectory()) {
|
|
369
|
+
await processDir(itemPath);
|
|
370
|
+
} else if (itemPath.endsWith('.spec.ts') ||
|
|
371
|
+
itemPath.endsWith('.spec.js') ||
|
|
372
|
+
itemPath.endsWith('.test.ts') ||
|
|
373
|
+
itemPath.endsWith('.test.js') ||
|
|
374
|
+
itemPath.endsWith('.spec.ts.ejs') ||
|
|
375
|
+
itemPath.endsWith('.spec.js.ejs') ||
|
|
376
|
+
itemPath.endsWith('.test.ts.ejs') ||
|
|
377
|
+
itemPath.endsWith('.test.js.ejs')) {
|
|
378
|
+
const relativePath = path.relative(srcDir, itemPath);
|
|
379
|
+
|
|
380
|
+
const cleanRelativePath = relativePath.replace(/\.ejs$/, '');
|
|
381
|
+
|
|
382
|
+
// Exclude e2e if it accidentally falls here, as it's processed separately
|
|
383
|
+
if (cleanRelativePath.includes('e2e')) {
|
|
384
|
+
await fs.remove(itemPath);
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const targetTestPath = path.join(testsDir, 'unit', cleanRelativePath);
|
|
389
|
+
|
|
390
|
+
await fs.ensureDir(path.dirname(targetTestPath));
|
|
391
|
+
|
|
392
|
+
const template = await fs.readFile(itemPath, 'utf-8');
|
|
393
|
+
const content = ejs.render(template, config);
|
|
394
|
+
|
|
395
|
+
await fs.writeFile(targetTestPath, content);
|
|
396
|
+
await fs.remove(itemPath);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
await processDir(srcDir);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
export const renderAuthAndUploadComponents = async (templatesDir, targetDir, config) => {
|
|
405
|
+
const { architecture, language, auth, includeMulter, googleLogin } = config;
|
|
406
|
+
const ext = language === 'TypeScript' ? 'ts' : 'js';
|
|
407
|
+
const commonSrcDir = path.join(templatesDir, 'common', 'src');
|
|
408
|
+
|
|
409
|
+
// 1. Render Middleware
|
|
410
|
+
let middlewareDestDir = path.join(targetDir, 'src', 'middleware');
|
|
411
|
+
if (architecture === 'Clean Architecture') {
|
|
412
|
+
middlewareDestDir = path.join(targetDir, 'src', 'infrastructure', 'webserver', 'middleware');
|
|
413
|
+
}
|
|
414
|
+
await fs.ensureDir(middlewareDestDir);
|
|
415
|
+
|
|
416
|
+
// Multer
|
|
417
|
+
if (includeMulter) {
|
|
418
|
+
const uploadTemplate = path.join(commonSrcDir, 'middleware', `upload.${ext}.ejs`);
|
|
419
|
+
if (await fs.pathExists(uploadTemplate)) {
|
|
420
|
+
const content = ejs.render(await fs.readFile(uploadTemplate, 'utf-8'), { ...config });
|
|
421
|
+
await fs.writeFile(path.join(middlewareDestDir, `upload.${ext}`), content);
|
|
422
|
+
}
|
|
423
|
+
// Ensure uploads directory exists
|
|
424
|
+
await fs.ensureDir(path.join(targetDir, 'uploads'));
|
|
425
|
+
// Add .gitkeep to uploads
|
|
426
|
+
await fs.writeFile(path.join(targetDir, 'uploads', '.gitkeep'), '');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Auth Middleware
|
|
430
|
+
if (auth && auth !== 'None') {
|
|
431
|
+
const authTemplate = path.join(commonSrcDir, 'middleware', `auth.${ext}.ejs`);
|
|
432
|
+
if (await fs.pathExists(authTemplate)) {
|
|
433
|
+
const content = ejs.render(await fs.readFile(authTemplate, 'utf-8'), { ...config });
|
|
434
|
+
await fs.writeFile(path.join(middlewareDestDir, `auth.${ext}`), content);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// 2. Render Auth Controller & Routes
|
|
439
|
+
if (auth && auth !== 'None') {
|
|
440
|
+
let authControllerDestDir = path.join(targetDir, 'src', 'controllers');
|
|
441
|
+
let authRoutesDestDir = path.join(targetDir, 'src', 'routes');
|
|
442
|
+
|
|
443
|
+
if (architecture === 'Clean Architecture') {
|
|
444
|
+
authControllerDestDir = path.join(targetDir, 'src', 'interfaces', 'controllers');
|
|
445
|
+
authRoutesDestDir = path.join(targetDir, 'src', 'interfaces', 'routes');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
await fs.ensureDir(authControllerDestDir);
|
|
449
|
+
await fs.ensureDir(authRoutesDestDir);
|
|
450
|
+
|
|
451
|
+
// Controller
|
|
452
|
+
const controllerTemplate = path.join(commonSrcDir, 'controllers', `authController.${ext}.ejs`);
|
|
453
|
+
if (await fs.pathExists(controllerTemplate)) {
|
|
454
|
+
const content = ejs.render(await fs.readFile(controllerTemplate, 'utf-8'), { ...config });
|
|
455
|
+
await fs.writeFile(path.join(authControllerDestDir, `authController.${ext}`), content);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Routes
|
|
459
|
+
const routesTemplate = path.join(commonSrcDir, 'routes', `authRoutes.${ext}.ejs`);
|
|
460
|
+
if (await fs.pathExists(routesTemplate)) {
|
|
461
|
+
const content = ejs.render(await fs.readFile(routesTemplate, 'utf-8'), { ...config });
|
|
462
|
+
await fs.writeFile(path.join(authRoutesDestDir, `authRoutes.${ext}`), content);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// 3. Better-Auth Config
|
|
466
|
+
if (auth === 'Better-Auth') {
|
|
467
|
+
let configDestDir = path.join(targetDir, 'src', 'config');
|
|
468
|
+
if (architecture === 'Clean Architecture' && language === 'JavaScript') {
|
|
469
|
+
configDestDir = path.join(targetDir, 'src', 'infrastructure', 'config');
|
|
470
|
+
}
|
|
471
|
+
await fs.ensureDir(configDestDir);
|
|
472
|
+
const authConfigTemplate = path.join(commonSrcDir, 'config', `auth.${ext}.ejs`);
|
|
473
|
+
if (await fs.pathExists(authConfigTemplate)) {
|
|
474
|
+
const content = ejs.render(await fs.readFile(authConfigTemplate, 'utf-8'), { ...config });
|
|
475
|
+
await fs.writeFile(path.join(configDestDir, `auth.${ext}`), content);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import ejs from 'ejs';
|
|
4
|
+
|
|
5
|
+
export const setupCaching = async (templatesDir, targetDir, config) => {
|
|
6
|
+
const { caching, language, architecture } = config;
|
|
7
|
+
if (!caching || caching === 'None') return;
|
|
8
|
+
|
|
9
|
+
if (caching === 'Redis' || caching === 'Memory Cache') {
|
|
10
|
+
const langExt = language === 'TypeScript' ? 'ts' : 'js';
|
|
11
|
+
const clientObj = caching === 'Redis'
|
|
12
|
+
? (language === 'TypeScript' ? 'redisClient.ts' : 'redisClient.js')
|
|
13
|
+
: (language === 'TypeScript' ? 'memoryCache.ts' : 'memoryCache.js');
|
|
14
|
+
const cacheSource = path.join(templatesDir, 'common', 'caching', langExt, `${clientObj}.ejs`);
|
|
15
|
+
|
|
16
|
+
let cacheTarget;
|
|
17
|
+
let loggerPath;
|
|
18
|
+
|
|
19
|
+
if (architecture === 'MVC') {
|
|
20
|
+
await fs.ensureDir(path.join(targetDir, 'src/config'));
|
|
21
|
+
cacheTarget = path.join(targetDir, 'src/config', clientObj);
|
|
22
|
+
loggerPath = language === 'TypeScript' ? '@/utils/logger' : '../utils/logger';
|
|
23
|
+
} else {
|
|
24
|
+
// Clean Architecture
|
|
25
|
+
await fs.ensureDir(path.join(targetDir, 'src/infrastructure/caching'));
|
|
26
|
+
cacheTarget = path.join(targetDir, 'src/infrastructure/caching', clientObj);
|
|
27
|
+
loggerPath = language === 'TypeScript' ? '@/infrastructure/log/logger' : '../log/logger';
|
|
28
|
+
|
|
29
|
+
// Overwrite UseCases with Caching Enabled
|
|
30
|
+
const useCases = language === 'TypeScript'
|
|
31
|
+
? [
|
|
32
|
+
{ name: 'getAllUsers.ts', src: 'getAllUsers.ts.ejs' },
|
|
33
|
+
{ name: 'createUser.ts', src: 'createUser.ts.ejs' },
|
|
34
|
+
{ name: 'updateUser.ts', src: 'updateUser.ts.ejs' },
|
|
35
|
+
{ name: 'deleteUser.ts', src: 'deleteUser.ts.ejs' }
|
|
36
|
+
]
|
|
37
|
+
: [
|
|
38
|
+
{ name: 'GetAllUsers.js', src: 'GetAllUsers.js.ejs' },
|
|
39
|
+
{ name: 'CreateUser.js', src: 'CreateUser.js.ejs' },
|
|
40
|
+
{ name: 'UpdateUser.js', src: 'UpdateUser.js.ejs' },
|
|
41
|
+
{ name: 'DeleteUser.js', src: 'DeleteUser.js.ejs' }
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const useCaseTargetDir = path.join(targetDir, 'src/usecases');
|
|
45
|
+
await fs.ensureDir(useCaseTargetDir);
|
|
46
|
+
|
|
47
|
+
for (const uc of useCases) {
|
|
48
|
+
const useCaseSource = path.join(templatesDir, 'common', 'caching', 'clean', langExt, uc.src);
|
|
49
|
+
if (await fs.pathExists(useCaseSource)) {
|
|
50
|
+
const ucContent = await fs.readFile(useCaseSource, 'utf-8');
|
|
51
|
+
const renderedUc = ejs.render(ucContent, { caching });
|
|
52
|
+
await fs.writeFile(path.join(useCaseTargetDir, uc.name), renderedUc);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (await fs.pathExists(cacheSource)) {
|
|
58
|
+
const cacheTemplate = await fs.readFile(cacheSource, 'utf-8');
|
|
59
|
+
const content = ejs.render(cacheTemplate, { loggerPath });
|
|
60
|
+
await fs.writeFile(cacheTarget, content);
|
|
61
|
+
|
|
62
|
+
// Render Spec if exists
|
|
63
|
+
const specTemplateName = clientObj.replace(`.${langExt}`, `.spec.${langExt}.ejs`);
|
|
64
|
+
const specTemplateSource = path.join(templatesDir, 'common', 'caching', langExt, specTemplateName);
|
|
65
|
+
if (await fs.pathExists(specTemplateSource)) {
|
|
66
|
+
const specTemplate = await fs.readFile(specTemplateSource, 'utf-8');
|
|
67
|
+
const specLoggerPath = architecture === 'Clean Architecture' ? '@/infrastructure/log/logger' : '@/utils/logger';
|
|
68
|
+
const specRedisPath = architecture === 'Clean Architecture' ? '@/infrastructure/caching/redisClient' : '@/config/redisClient';
|
|
69
|
+
const specContent = ejs.render(specTemplate, { ...config, loggerPath: specLoggerPath, redisClientPath: specRedisPath });
|
|
70
|
+
const specTarget = cacheTarget.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
|
+
}
|
|
76
|
+
};
|