nodejs-quickstart-structure 1.18.0 → 1.19.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 (113) hide show
  1. package/CHANGELOG.md +17 -4
  2. package/README.md +2 -1
  3. package/bin/index.js +93 -92
  4. package/lib/generator.js +1 -1
  5. package/lib/modules/caching-setup.js +76 -73
  6. package/lib/modules/config-files.js +4 -0
  7. package/lib/modules/kafka-setup.js +249 -191
  8. package/lib/modules/project-setup.js +1 -0
  9. package/package.json +13 -2
  10. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  11. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  12. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  13. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  14. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  15. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  16. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +1 -1
  17. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  18. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  19. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  20. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  21. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  22. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  23. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  24. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  25. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  26. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  27. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  28. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  29. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  30. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  31. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  32. package/templates/clean-architecture/ts/src/index.ts.ejs +1 -1
  33. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  34. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  35. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  36. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  37. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  38. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  39. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  40. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  41. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  42. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  43. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  44. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  45. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  46. package/templates/common/.gitattributes +46 -0
  47. package/templates/common/.snyk.ejs +45 -0
  48. package/templates/common/Dockerfile +17 -9
  49. package/templates/common/README.md.ejs +295 -263
  50. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  51. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  52. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  53. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  54. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  55. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  56. package/templates/common/database/js/models/User.js.ejs +79 -53
  57. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  58. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  59. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  60. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  61. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  62. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  63. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  64. package/templates/common/jest.e2e.config.js.ejs +8 -8
  65. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  66. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  67. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  68. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  69. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  70. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  71. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  72. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  73. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  74. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  75. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  76. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  77. package/templates/common/package.json.ejs +10 -2
  78. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  79. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  80. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  81. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  82. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  83. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  84. package/templates/common/swagger.yml.ejs +118 -66
  85. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  86. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  87. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  88. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  89. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  90. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  91. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  92. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  93. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  94. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  95. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  96. package/templates/mvc/js/src/index.js.ejs +1 -1
  97. package/templates/mvc/js/src/routes/api.js +10 -8
  98. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  99. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  100. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  101. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  102. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  103. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  104. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  105. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  106. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  107. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  108. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  109. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  110. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  111. package/templates/mvc/ts/src/routes/api.ts +12 -10
  112. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  113. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
package/CHANGELOG.md CHANGED
@@ -1,9 +1,22 @@
1
- # Changelog
1
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2
2
 
3
- All notable changes to this project will be documented in this file.
3
+ ## [1.19.0] - 2026-03-28
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+ ### Added
6
+ - **Security Hardening**: Added `SECURITY.md` file to the project.
7
+ - **Git Attributes**: Added `.gitattributes` file to the project.
8
+ - **Contributing Guide**: Added `CONTRIBUTING.md` file to the project.
9
+
10
+ ## [1.18.1] - 2026-03-27
11
+
12
+ ### Fixed
13
+ - **Template Security Hardening**: Resolved 29 vulnerabilities in `package.json.ejs` by upgrading `Apollo Server`, `Jest`, and `ESLint`.
14
+ - **Apollo Server 5 Compatibility**: Migrated GraphQL integration to use `@as-integrations/express4`, resolving breaking changes in the latest Apollo release.
15
+ - **Surgical Security Overrides**: Implemented targeted `overrides` for `brace-expansion`, `jake`, and `micromatch`. Removed global `glob/minimatch` overrides to maintain compatibility with Jest's internal APIs while preserving a "Zero-Vulnerability" status.
16
+ - **E2E Validated**: Verified the entire "Secure-by-Default" ecosystem via Windows E2E tests, achieving 100% pass rate.
17
+ - **Enterprise Standards**: Synchronized all generator templates with the latest secure dependency standards across MVC and Clean Architecture.
18
+ ### Changed
19
+ - **Readme**: Standardize Generated Project README.
7
20
 
8
21
  ## [1.18.0] - 2026-03-25
9
22
 
package/README.md CHANGED
@@ -20,7 +20,7 @@ A powerful CLI tool to scaffold production-ready Node.js microservices with buil
20
20
  - [⚙️ Configuration Options](#-configuration-options)
21
21
  - [🏗️ Generated Project Structure](#-generated-project-structure)
22
22
  - [📖 Documentation](#-documentation)
23
- - [🗺️ Roadmap & Support](#️-roadmap--support)
23
+ - [🗺️ Support & Roadmap](#️-roadmap--support)
24
24
 
25
25
  ---
26
26
 
@@ -53,6 +53,7 @@ nodejs-quickstart init
53
53
  - **Communication Patterns**: Supports **REST**, **GraphQL** (Apollo), and **Kafka** (Event-driven).
54
54
  - **Multi-layer Caching**: Integrated **Redis** or built-in **Memory Cache**.
55
55
  - **AI-Native Optimized**: specifically designed for **Cursor** and AI agents, including built-in `.cursorrules` and Agent Skill prompts. 🚀
56
+ - **Next Gen Web UI**: (Coming Soon) A modern, browser-based project selector featuring real-time virtualization — set for release in v2.0.0!
56
57
 
57
58
  ---
58
59
 
package/bin/index.js CHANGED
@@ -1,92 +1,93 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from 'commander';
4
- import chalk from 'chalk';
5
- import { getProjectDetails } from '../lib/prompts.js';
6
- import { generateProject } from '../lib/generator.js';
7
- import { readFileSync } from 'fs';
8
- import { join, dirname } from 'path';
9
- import { fileURLToPath } from 'url';
10
-
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
- const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
13
-
14
- const program = new Command();
15
-
16
- program
17
- .name('nodejs-quickstart')
18
- .description('🚀 CLI to scaffold production-ready Node.js microservices.\n\nGenerates projects with:\n- MVC or Clean Architecture\n- REST or Kafka\n- MySQL, PostgreSQL, or MongoDB\n- Docker, Flyway & Mongoose support')
19
- .version(pkg.version, '-v, --version', 'Output the current version')
20
- .addHelpText('after', `\n${chalk.yellow('Example:')}\n $ nodejs-quickstart init ${chalk.gray('# Start the interactive setup')}\n`);
21
-
22
- program
23
- .command('init')
24
- .description('Initialize a new Node.js project')
25
- .option('-n, --project-name <name>', 'Project name')
26
- .option('-l, --language <language>', 'Language (JavaScript, TypeScript)')
27
- .option('-a, --architecture <architecture>', 'Architecture (MVC, Clean Architecture)')
28
- .option('--view-engine <view>', 'View Engine (None, EJS, Pug) - MVC only')
29
- .option('-d, --database <database>', 'Database (MySQL, PostgreSQL)')
30
- .option('--db-name <name>', 'Database name')
31
- .option('-c, --communication <communication>', 'Communication (REST APIs, GraphQL, Kafka)')
32
- .option('--ci-provider <provider>', 'CI/CD Provider (None, GitHub Actions, Jenkins, GitLab CI)')
33
- .option('--include-security', 'Include Enterprise Security Hardening')
34
- .option('--caching <type>', 'Caching Layer (None/Redis)')
35
- .action(async (options) => {
36
- // Fix for Commander camelCase conversion
37
- if (options.ciProvider) {
38
- options.ciProvider = options.ciProvider;
39
- }
40
-
41
- console.log(chalk.blue('Welcome to the Node.js Quickstart Generator!'));
42
-
43
- try {
44
- const answers = await getProjectDetails(options);
45
- console.log(chalk.green('\nConfiguration received:'));
46
- console.log(JSON.stringify(answers, null, 2));
47
-
48
- console.log(chalk.yellow('\nGenerating project...'));
49
- await generateProject(answers);
50
-
51
- console.log(chalk.green('\n✔ Project generated successfully!'));
52
-
53
- console.log(chalk.magenta('\n🚀 Project is AI-Ready!'));
54
- console.log(chalk.magenta('-----------------------------------------'));
55
- console.log(chalk.magenta('🤖 We detected you are using AI tools.'));
56
- console.log(chalk.magenta(`📍 Use Cursor? We've configured '.cursorrules' for you.`));
57
- console.log(chalk.magenta(`📍 Use ChatGPT/Gemini? Check the 'prompts/' folder for Agent Skills.`));
58
- console.log(chalk.magenta('-----------------------------------------'));
59
-
60
- let manualStartInstructions = `\n${chalk.yellow('Development:')}\n cd ${answers.projectName}\n npm install`;
61
-
62
- const needsInfrastructure = answers.database !== 'None' || answers.caching === 'Redis' || answers.communication === 'Kafka';
63
-
64
- if (needsInfrastructure) {
65
- let servicesToStart = '';
66
- if (answers.database === 'MongoDB') servicesToStart += ' db';
67
- else if (answers.database !== 'None') servicesToStart += ' db flyway';
68
- if (answers.caching === 'Redis') servicesToStart += ' redis';
69
- if (answers.communication === 'Kafka') servicesToStart += ' kafka';
70
-
71
- manualStartInstructions += `\n docker-compose up -d${servicesToStart} # Start infrastructure first\n npm run dev`;
72
- } else {
73
- manualStartInstructions += `\n npm run dev`;
74
- }
75
-
76
- console.log(chalk.cyan(`\nNext steps:\n cd ${answers.projectName}\n npm install\n docker-compose up\n-----------------------${manualStartInstructions}\n\n${chalk.yellow('Production (PM2):')}\n npm run build\n npm run deploy\n npx pm2 logs`));
77
-
78
- } catch (error) {
79
- if (error.name === 'ExitPromptError') {
80
- console.log(chalk.yellow('\n\n👋 Goodbye! Setup cancelled.'));
81
- process.exit(0);
82
- }
83
- console.error(chalk.red('Error generating project:'), error);
84
- process.exit(1);
85
- }
86
- });
87
-
88
- program.parse(process.argv);
89
-
90
- if (!process.argv.slice(2).length) {
91
- program.outputHelp();
92
- }
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { getProjectDetails } from '../lib/prompts.js';
6
+ import { generateProject } from '../lib/generator.js';
7
+ import { readFileSync } from 'fs';
8
+ import { join, dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
13
+
14
+ const program = new Command();
15
+
16
+ program
17
+ .name('nodejs-quickstart')
18
+ .description('🚀 CLI to scaffold production-ready Node.js microservices.\n\nGenerates projects with:\n- MVC or Clean Architecture\n- REST or Kafka\n- MySQL, PostgreSQL, or MongoDB\n- Docker, Flyway & Mongoose support')
19
+ .version(pkg.version, '-v, --version', 'Output the current version')
20
+ .addHelpText('after', `\n${chalk.yellow('Example:')}\n $ nodejs-quickstart init ${chalk.gray('# Start the interactive setup')}\n`);
21
+
22
+ program
23
+ .command('init')
24
+ .description('Initialize a new Node.js project')
25
+ .option('-n, --project-name <name>', 'Project name')
26
+ .option('-l, --language <language>', 'Language (JavaScript, TypeScript)')
27
+ .option('-a, --architecture <architecture>', 'Architecture (MVC, Clean Architecture)')
28
+ .option('--view-engine <view>', 'View Engine (None, EJS, Pug) - MVC only')
29
+ .option('-d, --database <database>', 'Database (MySQL, PostgreSQL)')
30
+ .option('--db-name <name>', 'Database name')
31
+ .option('-c, --communication <communication>', 'Communication (REST APIs, GraphQL, Kafka)')
32
+ .option('--ci-provider <provider>', 'CI/CD Provider (None, GitHub Actions, Jenkins, GitLab CI)')
33
+ .option('--include-security', 'Include Enterprise Security Hardening')
34
+ .option('--caching <type>', 'Caching Layer (None/Redis)')
35
+ .action(async (options) => {
36
+ // Fix for Commander camelCase conversion
37
+ if (options.ciProvider) {
38
+ options.ciProvider = options.ciProvider;
39
+ }
40
+
41
+ console.log(chalk.blue('Welcome to the Node.js Quickstart Generator!'));
42
+
43
+ try {
44
+ const answers = await getProjectDetails(options);
45
+ console.log(chalk.blue(`\n🚀 Preparing to generate ${chalk.bold(answers.projectName)} (${answers.architecture})...`));
46
+
47
+ console.log(chalk.yellow('\nGenerating project files...'));
48
+ await generateProject(answers);
49
+
50
+ console.log(chalk.green('\n✔ Project generated successfully!'));
51
+
52
+ console.log(chalk.magenta('\n🚀 Project is AI-Ready!'));
53
+ console.log(chalk.magenta('-----------------------------------------'));
54
+ console.log(chalk.magenta('🤖 We detected you are using AI tools.'));
55
+ console.log(chalk.magenta(`📍 Use Cursor? We've configured '.cursorrules' for you.`));
56
+ console.log(chalk.magenta(`📍 Use ChatGPT/Gemini? Check the 'prompts/' folder for Agent Skills.`));
57
+ console.log(chalk.magenta('-----------------------------------------'));
58
+
59
+ let manualStartInstructions = `\n${chalk.yellow('Development:')}\n cd ${answers.projectName}\n npm install`;
60
+
61
+ const needsInfrastructure = answers.database !== 'None' || answers.caching === 'Redis' || answers.communication === 'Kafka';
62
+
63
+ if (needsInfrastructure) {
64
+ let servicesToStart = '';
65
+ if (answers.database === 'MongoDB') servicesToStart += ' db';
66
+ else if (answers.database !== 'None') servicesToStart += ' db flyway';
67
+ if (answers.caching === 'Redis') servicesToStart += ' redis';
68
+ if (answers.communication === 'Kafka') servicesToStart += ' kafka';
69
+
70
+ manualStartInstructions += `\n docker-compose up -d${servicesToStart} # Start infrastructure first\n npm run dev`;
71
+ } else {
72
+ manualStartInstructions += `\n npm run dev`;
73
+ }
74
+
75
+ console.log(chalk.cyan(`\nNext steps:\n cd ${answers.projectName}\n npm install\n docker-compose up\n-----------------------${manualStartInstructions}\n\n${chalk.yellow('Production (PM2):')}\n npm run build\n npm run deploy\n npx pm2 logs`));
76
+
77
+ console.log(chalk.yellow(`\n⭐ If this tool saved you 5 minutes, please give us a star on GitHub: ${chalk.underline('https://github.com/paudang/nodejs-quickstart-structure')}`));
78
+
79
+ } catch (error) {
80
+ if (error.name === 'ExitPromptError') {
81
+ console.log(chalk.yellow('\n\n👋 Goodbye! Setup cancelled.'));
82
+ process.exit(0);
83
+ }
84
+ console.error(chalk.red('Error generating project:'), error);
85
+ process.exit(1);
86
+ }
87
+ });
88
+
89
+ program.parse(process.argv);
90
+
91
+ if (!process.argv.slice(2).length) {
92
+ program.outputHelp();
93
+ }
package/lib/generator.js CHANGED
@@ -132,7 +132,7 @@ export const generateProject = async (config) => {
132
132
  2. git init
133
133
  3. npm install
134
134
  4. npm run prepare (To setup Husky hooks)
135
- 5. docker-compose up -d (To start DB/Infrastructure)
135
+ 5. docker-compose up -d${config.database !== 'None' ? ' db' : ''}${config.caching === 'Redis' ? ' redis' : ''}${config.communication === 'Kafka' ? ' kafka' : ''} (To start DB/Infrastructure)
136
136
  6. npm run dev (To start development server)
137
137
  7. npm test (To run tests)
138
138
  `);
@@ -1,73 +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 UseCase with Caching Enabled
30
- const useCaseName = language === 'TypeScript' ? 'getAllUsers.ts' : 'GetAllUsers.js';
31
- const useCaseSource = path.join(templatesDir, 'common', 'caching', 'clean', langExt, `${useCaseName}.ejs`);
32
-
33
- // Both TS and JS templates use 'usecases' directory
34
- const useCaseTargetDir = path.join(targetDir, 'src/usecases');
35
- await fs.ensureDir(useCaseTargetDir);
36
-
37
- if (await fs.pathExists(useCaseSource)) {
38
- const ucContent = await fs.readFile(useCaseSource, 'utf-8');
39
- const renderedUc = ejs.render(ucContent, { caching });
40
- await fs.writeFile(path.join(useCaseTargetDir, useCaseName), renderedUc);
41
- }
42
-
43
- // Also Overwrite CreateUser with Caching (Invalidation) Enabled
44
- const createUserParams = language === 'TypeScript' ? { name: 'createUser.ts', src: 'createUser.ts.ejs' } : { name: 'CreateUser.js', src: 'CreateUser.js.ejs' };
45
- const createUserSource = path.join(templatesDir, 'common', 'caching', 'clean', langExt, createUserParams.src);
46
-
47
- if (await fs.pathExists(createUserSource)) {
48
- const createUserContent = await fs.readFile(createUserSource, 'utf-8');
49
- const renderedCreateUser = ejs.render(createUserContent, { caching });
50
- await fs.writeFile(path.join(useCaseTargetDir, createUserParams.name), renderedCreateUser);
51
- }
52
- }
53
-
54
- if (await fs.pathExists(cacheSource)) {
55
- const cacheTemplate = await fs.readFile(cacheSource, 'utf-8');
56
- const content = ejs.render(cacheTemplate, { loggerPath });
57
- await fs.writeFile(cacheTarget, content);
58
-
59
- // Render Spec if exists
60
- const specTemplateName = clientObj.replace(`.${langExt}`, `.spec.${langExt}.ejs`);
61
- const specTemplateSource = path.join(templatesDir, 'common', 'caching', langExt, specTemplateName);
62
- if (await fs.pathExists(specTemplateSource)) {
63
- const specTemplate = await fs.readFile(specTemplateSource, 'utf-8');
64
- const specLoggerPath = architecture === 'Clean Architecture' ? '@/infrastructure/log/logger' : '@/utils/logger';
65
- const specRedisPath = architecture === 'Clean Architecture' ? '@/infrastructure/caching/redisClient' : '@/config/redisClient';
66
- const specContent = ejs.render(specTemplate, { ...config, loggerPath: specLoggerPath, redisClientPath: specRedisPath });
67
- const specTarget = cacheTarget.replace(`${path.sep}src${path.sep}`, `${path.sep}tests${path.sep}unit${path.sep}`).replace(`.${langExt}`, `.spec.${langExt}`);
68
- await fs.ensureDir(path.dirname(specTarget));
69
- await fs.writeFile(specTarget, specContent);
70
- }
71
- }
72
- }
73
- };
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
+ };
@@ -65,6 +65,10 @@ export const renderProfessionalConfig = async (templatesDir, targetDir, config)
65
65
  const sonarTemplate = await fs.readFile(path.join(templatesDir, 'common', 'sonar-project.properties.ejs'), 'utf-8');
66
66
  const sonarContent = ejs.render(sonarTemplate, { ...config });
67
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);
68
72
  }
69
73
  };
70
74