@saulpaulus17/node-module-generator 2.0.5 โ†’ 3.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 (65) hide show
  1. package/README.md +33 -13
  2. package/bin/cli.js +17 -6
  3. package/commands/dto.command.js +3 -3
  4. package/commands/module.command.js +2 -2
  5. package/commands/repository.command.js +6 -6
  6. package/commands/resource.command.js +3 -3
  7. package/commands/usecase.command.js +2 -2
  8. package/generator/dto.generator.js +28 -17
  9. package/generator/module.generator.js +57 -57
  10. package/generator/repository.generator.js +38 -29
  11. package/generator/resource.generator.js +56 -56
  12. package/generator/usecase.generator.js +34 -21
  13. package/package.json +11 -3
  14. package/templates/module/controller.test.ejs +1 -1
  15. package/templates/module/di.ejs +6 -6
  16. package/templates/module/route.ejs +2 -1
  17. package/templates/module/usecase.test.ejs +1 -1
  18. package/utils/case.util.js +24 -7
  19. package/utils/file.util.js +46 -0
  20. package/utils/logger.util.js +30 -0
  21. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  22. package/.github/ISSUE_TEMPLATE/custom.md +0 -10
  23. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  24. package/.github/workflows/ci.yml +0 -28
  25. package/.github/workflows/release.yml +0 -31
  26. package/DOCS_STEPS.md +0 -40
  27. package/release.yml +0 -0
  28. package/src/modules/Auth/Auth.module.js +0 -15
  29. package/src/modules/Auth/application/dtos/auth.dto.js +0 -10
  30. package/src/modules/Auth/application/usecases/AuthUseCase.js +0 -12
  31. package/src/modules/Auth/application/usecases/AuthUseCase.test.js +0 -30
  32. package/src/modules/Auth/domain/entities/Auth.js +0 -5
  33. package/src/modules/Auth/domain/repositories/AuthRepository.js +0 -9
  34. package/src/modules/Auth/infrastructure/repositories/PrismaAuthRepository.js +0 -15
  35. package/src/modules/Auth/interfaces/controllers/AuthController.js +0 -15
  36. package/src/modules/Auth/interfaces/controllers/AuthController.test.js +0 -49
  37. package/src/modules/Auth/interfaces/routes/auth.routes.js +0 -9
  38. package/src/modules/Auth/package.json +0 -3
  39. package/src/modules/order/application/usecases/create-order.usecase.js +0 -15
  40. package/src/modules/order/application/usecases/create-order.usecase.test.js +0 -26
  41. package/src/modules/order/domain/entities/order.entity.js +0 -8
  42. package/src/modules/order/domain/repositories/order.repository.interface.js +0 -11
  43. package/src/modules/order/infrastructure/repositories/order.repository.impl.js +0 -23
  44. package/src/modules/order/infrastructure/validation/create-order.schema.js +0 -7
  45. package/src/modules/order/interfaces/controllers/order.controller.js +0 -16
  46. package/src/modules/order/interfaces/controllers/order.controller.test.js +0 -46
  47. package/src/modules/order/interfaces/routes/order.routes.js +0 -9
  48. package/src/modules/order/order.module.js +0 -16
  49. package/src/modules/product/application/usecases/getProduct.usecase.js +0 -15
  50. package/src/modules/product/application/usecases/getProduct.usecase.test.js +0 -26
  51. package/src/modules/product/domain/entities/product.entity.js +0 -8
  52. package/src/modules/product/domain/repositories/product.repository.interface.js +0 -11
  53. package/src/modules/product/infrastructure/repositories/product.repository.impl.js +0 -23
  54. package/src/modules/product/infrastructure/validation/getProduct.schema.js +0 -7
  55. package/src/modules/product/product.module.js +0 -5
  56. package/src/modules/user/application/usecases/create-user.usecase.js +0 -15
  57. package/src/modules/user/application/usecases/create-user.usecase.test.js +0 -26
  58. package/src/modules/user/domain/entities/user.entity.js +0 -8
  59. package/src/modules/user/domain/repositories/user.repository.interface.js +0 -11
  60. package/src/modules/user/infrastructure/repositories/user.repository.impl.js +0 -23
  61. package/src/modules/user/infrastructure/validation/create-user.schema.js +0 -7
  62. package/src/modules/user/interfaces/controllers/user.controller.js +0 -16
  63. package/src/modules/user/interfaces/controllers/user.controller.test.js +0 -46
  64. package/src/modules/user/interfaces/routes/user.routes.js +0 -9
  65. package/src/modules/user/user.module.js +0 -16
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <img src="https://raw.githubusercontent.com/saul-paulus/node-module-generator/main/assets/banner.png" alt="Node Module Generator Banner" width="600" style="max-width: 100%;" />
2
+ <img src="./assets/banner.png" alt="Node Module Generator Banner" width="600" style="max-width: 100%;" />
3
3
  <h1>๐Ÿš€ Node Module Generator (NMG)</h1>
4
4
  <p><strong>The ultimate CLI companion for rapid, enterprise-grade Node.js scaffolding.</strong></p>
5
5
  <p>
@@ -49,7 +49,7 @@ graph TD
49
49
  - ๐Ÿ’Ž **Clean Architecture by Design**: Strict separation into Domain, Application, Infrastructure, and Interface layers.
50
50
  - ๐Ÿ’‰ **Native Dependency Injection**: Fully pre-configured for **Awilix**, providing seamless DI management.
51
51
  - ๐Ÿงช **Test-Ready Scaffolding**: Automatically generates **Jest** test suites for Controllers and Use Cases.
52
- - ๐Ÿš€ **Modern Tooling**: Native support for **ES Modules (ESM)**, **Prisma ORM**, and **Joi/Zod** DTO patterns.
52
+ - ๐Ÿš€ **Full ESM Support**: Native support for **ECMAScript Modules (ESM)** with consistent **kebab-case** file naming.
53
53
  - ๐Ÿค– **Granular Control**: Generate full modules or individual components (UseCases, Repos, DTOs) without disrupting existing code.
54
54
 
55
55
  ---
@@ -76,6 +76,25 @@ npx @saulpaulus17/node-module-generator <command> <name>
76
76
 
77
77
  ---
78
78
 
79
+ ## ๐Ÿ› ๏ธ Target Project Dependencies
80
+
81
+ To ensure the modules generated by NMG function correctly, your main project must have the following core dependencies installed:
82
+
83
+ ### Production Dependencies
84
+ ```bash
85
+ npm install express awilix @prisma/client
86
+ ```
87
+
88
+ ### Development Dependencies
89
+ ```bash
90
+ npm install --save-dev jest
91
+ ```
92
+
93
+ > [!TIP]
94
+ > These dependencies are essential because the generated code relies on Express for routing, Awilix for Dependency Injection, and Prisma for the data layer.
95
+
96
+ ---
97
+
79
98
  ## ๐Ÿš€ Detailed Usage
80
99
 
81
100
  ### 1. Generating a Full Module
@@ -108,25 +127,25 @@ Scaffolding a module (e.g., `nmg module Product`) produces the following industr
108
127
  ```text
109
128
  src/modules/Product/
110
129
  โ”œโ”€โ”€ application/
111
- โ”‚ โ”œโ”€โ”€ dtos/ # DTO schemas (e.g., product.dto.js)
130
+ โ”‚ โ”œโ”€โ”€ dtos/ # DTO schemas (e.g., product-dto.js)
112
131
  โ”‚ โ””โ”€โ”€ usecases/ # Business orchestration
113
- โ”‚ โ”œโ”€โ”€ ProductUseCase.js # Logic implementation
114
- โ”‚ โ””โ”€โ”€ ProductUseCase.test.js # Unit tests
132
+ โ”‚ โ”œโ”€โ”€ product-use-case.js # Logic implementation
133
+ โ”‚ โ””โ”€โ”€ product-use-case.test.js # Unit tests
115
134
  โ”œโ”€โ”€ domain/
116
135
  โ”‚ โ”œโ”€โ”€ entities/ # Business entity definitions
117
- โ”‚ โ”‚ โ””โ”€โ”€ Product.js
136
+ โ”‚ โ”‚ โ””โ”€โ”€ product-entity.js
118
137
  โ”‚ โ””โ”€โ”€ repositories/ # Repository Interface (Contracts)
119
- โ”‚ โ””โ”€โ”€ ProductRepository.js
138
+ โ”‚ โ””โ”€โ”€ product-repository.js
120
139
  โ”œโ”€โ”€ infrastructure/
121
140
  โ”‚ โ”œโ”€โ”€ repositories/ # Implementation (default: Prisma)
122
- โ”‚ โ”‚ โ””โ”€โ”€ PrismaProductRepository.js
141
+ โ”‚ โ”‚ โ””โ”€โ”€ prisma-product-repository.js
123
142
  โ”œโ”€โ”€ interfaces/
124
143
  โ”‚ โ”œโ”€โ”€ controllers/ # Express handlers
125
- โ”‚ โ”‚ โ”œโ”€โ”€ ProductController.js
126
- โ”‚ โ”‚ โ””โ”€โ”€ ProductController.test.js
144
+ โ”‚ โ”‚ โ”œโ”€โ”€ product-controller.js
145
+ โ”‚ โ”‚ โ””โ”€โ”€ product-controller.test.js
127
146
  โ”‚ โ””โ”€โ”€ routes/ # Express routes & method binding
128
- โ”‚ โ””โ”€โ”€ product.routes.js
129
- โ””โ”€โ”€ Product.module.js # Central Awilix Module Registration
147
+ โ”‚ โ””โ”€โ”€ product-routes.js
148
+ โ””โ”€โ”€ product.module.js # Central Awilix Module Registration
130
149
  ```
131
150
 
132
151
  ---
@@ -138,7 +157,8 @@ To finalize your new module integration, follow these standard steps:
138
157
  1. **DI Registration**: Open `src/container.js` and register any specific repository aliases or scoped usecases.
139
158
  2. **Route Mounting**: Mount the generated router in `src/app.js`:
140
159
  ```javascript
141
- app.use('/api/v1/product', container.resolve('productRoutes'));
160
+ import productRoutes from './modules/Product/interfaces/routes/product-routes.js';
161
+ app.use('/api/v1/product', productRoutes);
142
162
  ```
143
163
  3. **Detailed Implementation**: Build out the specific logic in the generated templates (which are already integrated via Awilix).
144
164
 
package/bin/cli.js CHANGED
@@ -1,14 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { Command } = require("commander");
3
+ import { Command } from "commander";
4
+ import moduleCommand from "../commands/module.command.js";
5
+ import usecaseCommand from "../commands/usecase.command.js";
6
+ import resourceCommand from "../commands/resource.command.js";
7
+ import repositoryCommand from "../commands/repository.command.js";
8
+ import dtoCommand from "../commands/dto.command.js";
9
+
4
10
  const program = new Command();
5
11
 
6
12
  program.name("nmg").version("1.0.0").description("Clean nodejs CLI");
7
13
 
8
- require("../commands/module.command")(program);
9
- require("../commands/usecase.command")(program);
10
- require("../commands/resource.command")(program);
11
- require("../commands/repository.command")(program);
12
- require("../commands/dto.command")(program);
14
+ process.on("unhandledRejection", (err) => {
15
+ console.error("โœ– FATAL ERROR: ", err.stack || err);
16
+ process.exit(1);
17
+ });
18
+
19
+ moduleCommand(program);
20
+ usecaseCommand(program);
21
+ resourceCommand(program);
22
+ repositoryCommand(program);
23
+ dtoCommand(program);
13
24
 
14
25
  program.parse();
@@ -1,9 +1,9 @@
1
- const generateDto = require("../generator/dto.generator");
1
+ import generateDto from "../generator/dto.generator.js";
2
2
 
3
- module.exports = (program) => {
3
+ export default (program) => {
4
4
  program
5
5
  .command("dto <name>")
6
- .description("Create a new DTO (validation schema)")
6
+ .description("Create a new DTO inside an existing module")
7
7
  .option("-m, --module <moduleName>", "Specify the target module")
8
8
  .action((name, options) => {
9
9
  if (!options.module) {
@@ -1,6 +1,6 @@
1
- const generateModule = require("../generator/module.generator");
1
+ import generateModule from "../generator/module.generator.js";
2
2
 
3
- module.exports = (program) => {
3
+ export default (program) => {
4
4
  program
5
5
  .command("module <name>")
6
6
  .description("Create a new module")
@@ -1,10 +1,10 @@
1
- const generateRepository = require("../generator/repository.generator");
1
+ import generateRepository from "../generator/repository.generator.js";
2
2
 
3
- module.exports = (program) => {
3
+ export default (program) => {
4
4
  program
5
- .command("repository <moduleName>")
6
- .description("Create domain and infrastructure repositories for a module")
7
- .action((moduleName) => {
8
- generateRepository(moduleName);
5
+ .command("repository <name>")
6
+ .description("Create a new repository inside an existing module")
7
+ .action((name) => {
8
+ generateRepository(name);
9
9
  });
10
10
  };
@@ -1,9 +1,9 @@
1
- const generateResource = require("../generator/resource.generator");
1
+ import generateResource from "../generator/resource.generator.js";
2
2
 
3
- module.exports = (program) => {
3
+ export default (program) => {
4
4
  program
5
5
  .command("resource <name>")
6
- .description("Create a new resource")
6
+ .description("Create a complete resource (CRUD)")
7
7
  .action((name) => {
8
8
  generateResource(name);
9
9
  });
@@ -1,6 +1,6 @@
1
- const generateUsecase = require("../generator/usecase.generator");
1
+ import generateUsecase from "../generator/usecase.generator.js";
2
2
 
3
- module.exports = (program) => {
3
+ export default (program) => {
4
4
  program
5
5
  .command("usecase <name>")
6
6
  .description("Create a new usecase inside an existing module")
@@ -1,21 +1,32 @@
1
- const path = require("path");
2
- const fs = require("fs-extra");
3
- const ejs = require("ejs");
4
- const { pascalCase, camelCase } = require("../utils/case.util");
1
+ import path from "path";
2
+ import { pascalCase, camelCase, kebabCase } from "../utils/case.util.js";
3
+ import FileUtil from "../utils/file.util.js";
4
+ import Logger from "../utils/logger.util.js";
5
5
 
6
- module.exports = async function (schemaName, moduleName) {
7
- const basePath = path.join(process.cwd(), "src/modules", moduleName);
8
- const dtoDir = path.join(basePath, "application/dtos");
9
- fs.ensureDirSync(dtoDir);
6
+ export default async function (schemaName, moduleName) {
7
+ try {
8
+ Logger.info(`Starting generation for DTO: ${schemaName} in module: ${moduleName}`);
9
+ const basePath = path.join(process.cwd(), "src/modules", moduleName);
10
+ const dtoDir = "application/dtos";
11
+
12
+ FileUtil.ensureDirectories(basePath, [dtoDir]);
10
13
 
11
- const templateData = {
12
- name: moduleName,
13
- className: pascalCase(schemaName),
14
- camelName: camelCase(moduleName),
15
- };
14
+ const templateData = {
15
+ name: moduleName,
16
+ className: pascalCase(schemaName),
17
+ camelName: camelCase(moduleName),
18
+ kebabName: kebabCase(schemaName),
19
+ };
16
20
 
17
- const templateContent = await ejs.renderFile(path.join(__dirname, "../templates/module/dto.ejs"), templateData);
18
- fs.writeFileSync(path.join(dtoDir, `${schemaName.toLowerCase()}.dto.js`), templateContent);
21
+ await FileUtil.renderAndWrite(
22
+ "module/dto.ejs",
23
+ templateData,
24
+ path.join(basePath, dtoDir, `${kebabCase(schemaName)}-dto.js`)
25
+ );
19
26
 
20
- console.log(`โœ” DTO ${schemaName} generated inside module ${moduleName} at application/dtos.`);
21
- };
27
+ Logger.success(`DTO ${schemaName} generated inside module ${moduleName} at application/dtos.`);
28
+ } catch (error) {
29
+ Logger.error(`Failed to generate DTO ${schemaName}`, error);
30
+ process.exit(1);
31
+ }
32
+ }
@@ -1,57 +1,57 @@
1
- const path = require("path");
2
- const fs = require("fs-extra");
3
- const ejs = require("ejs");
4
- const { pascalCase, camelCase } = require("../utils/case.util");
5
-
6
- module.exports = async function (name) {
7
- const basePath = path.join(process.cwd(), "src/modules", name);
8
-
9
- const dirs = [
10
- "domain/entities",
11
- "domain/repositories",
12
- "application/usecases",
13
- "application/dtos",
14
- "infrastructure/repositories",
15
- "interfaces/controllers",
16
- "interfaces/routes",
17
- ];
18
-
19
- // Create directories
20
- dirs.forEach((dir) => fs.ensureDirSync(path.join(basePath, dir)));
21
-
22
- // Generate scoped package.json for ESM support
23
- fs.writeJsonSync(path.join(basePath, "package.json"), { type: "module" }, { spaces: 2 });
24
-
25
- const templateData = {
26
- name,
27
- className: pascalCase(name),
28
- camelName: camelCase(name),
29
- useCaseClassName: `${pascalCase(name)}UseCase`,
30
- useCaseFileName: `${name.toLowerCase()}.usecase`,
31
- };
32
-
33
- const renderAndWrite = async (templateName, outputPath) => {
34
- const templateContent = await ejs.renderFile(
35
- path.join(__dirname, "../templates/module", templateName),
36
- templateData
37
- );
38
- fs.writeFileSync(path.join(basePath, outputPath), templateContent);
39
- };
40
-
41
- await renderAndWrite("controller.ejs", `interfaces/controllers/${pascalCase(name)}Controller.js`);
42
- await renderAndWrite("controller.test.ejs", `interfaces/controllers/${pascalCase(name)}Controller.test.js`);
43
- await renderAndWrite("route.ejs", `interfaces/routes/${name.toLowerCase()}.routes.js`);
44
-
45
- await renderAndWrite("usecase.ejs", `application/usecases/${pascalCase(name)}UseCase.js`);
46
- await renderAndWrite("usecase.test.ejs", `application/usecases/${pascalCase(name)}UseCase.test.js`);
47
-
48
- await renderAndWrite("entity.ejs", `domain/entities/${pascalCase(name)}.js`);
49
- await renderAndWrite("repository.interface.ejs", `domain/repositories/${pascalCase(name)}Repository.js`);
50
-
51
- await renderAndWrite("repository.impl.ejs", `infrastructure/repositories/Prisma${pascalCase(name)}Repository.js`);
52
- await renderAndWrite("dto.ejs", `application/dtos/${name.toLowerCase()}.dto.js`);
53
-
54
- await renderAndWrite("di.ejs", `${name}.module.js`);
55
-
56
- console.log(`โœ” Module ${name} directory structure, standard files, and tests created.`);
57
- };
1
+ import path from "path";
2
+ import { pascalCase, camelCase, kebabCase } from "../utils/case.util.js";
3
+ import FileUtil from "../utils/file.util.js";
4
+ import Logger from "../utils/logger.util.js";
5
+
6
+ export default async function (name) {
7
+ try {
8
+ Logger.info(`Starting generation for module: ${name}`);
9
+ const basePath = path.join(process.cwd(), "src/modules", name);
10
+
11
+ const dirs = [
12
+ "domain/entities",
13
+ "domain/repositories",
14
+ "application/usecases",
15
+ "application/dtos",
16
+ "infrastructure/repositories",
17
+ "interfaces/controllers",
18
+ "interfaces/routes",
19
+ ];
20
+
21
+ // Create directories
22
+ FileUtil.ensureDirectories(basePath, dirs);
23
+
24
+ const templateData = {
25
+ name,
26
+ className: pascalCase(name),
27
+ camelName: camelCase(name),
28
+ kebabName: kebabCase(name),
29
+ };
30
+
31
+ const filesToGenerate = [
32
+ { tpl: "module/controller.ejs", out: `interfaces/controllers/${kebabCase(name)}-controller.js` },
33
+ { tpl: "module/controller.test.ejs", out: `interfaces/controllers/${kebabCase(name)}-controller.test.js` },
34
+ { tpl: "module/route.ejs", out: `interfaces/routes/${kebabCase(name)}-routes.js` },
35
+ { tpl: "module/usecase.ejs", out: `application/usecases/${kebabCase(name)}-use-case.js` },
36
+ { tpl: "module/usecase.test.ejs", out: `application/usecases/${kebabCase(name)}-use-case.test.js` },
37
+ { tpl: "module/entity.ejs", out: `domain/entities/${kebabCase(name)}-entity.js` },
38
+ { tpl: "module/repository.interface.ejs", out: `domain/repositories/${kebabCase(name)}-repository.js` },
39
+ { tpl: "module/repository.impl.ejs", out: `infrastructure/repositories/prisma-${kebabCase(name)}-repository.js` },
40
+ { tpl: "module/dto.ejs", out: `application/dtos/${kebabCase(name)}-dto.js` },
41
+ { tpl: "module/di.ejs", out: `${kebabCase(name)}.module.js` }
42
+ ];
43
+
44
+ for (const file of filesToGenerate) {
45
+ await FileUtil.renderAndWrite(
46
+ file.tpl,
47
+ templateData,
48
+ path.join(basePath, file.out)
49
+ );
50
+ }
51
+
52
+ Logger.success(`Module ${name} generated successfully!`);
53
+ } catch (error) {
54
+ Logger.error(`Failed to generate module ${name}`, error);
55
+ process.exit(1);
56
+ }
57
+ }
@@ -1,36 +1,45 @@
1
- const path = require("path");
2
- const fs = require("fs-extra");
3
- const ejs = require("ejs");
4
- const { pascalCase, camelCase } = require("../utils/case.util");
1
+ import path from "path";
2
+ import { pascalCase, camelCase, kebabCase } from "../utils/case.util.js";
3
+ import FileUtil from "../utils/file.util.js";
4
+ import Logger from "../utils/logger.util.js";
5
5
 
6
- module.exports = async function (moduleName) {
7
- const basePath = path.join(process.cwd(), "src/modules", moduleName);
6
+ export default async function (moduleName) {
7
+ try {
8
+ Logger.info(`Starting repository pattern generation for module: ${moduleName}`);
9
+ const basePath = path.join(process.cwd(), "src/modules", moduleName);
8
10
 
9
- const entityDir = path.join(basePath, "domain/entities");
10
- const repoInterfaceDir = path.join(basePath, "domain/repositories");
11
- const repoImplDir = path.join(basePath, "infrastructure/repositories");
11
+ const dirs = [
12
+ "domain/entities",
13
+ "domain/repositories",
14
+ "infrastructure/repositories",
15
+ ];
12
16
 
13
- fs.ensureDirSync(entityDir);
14
- fs.ensureDirSync(repoInterfaceDir);
15
- fs.ensureDirSync(repoImplDir);
17
+ FileUtil.ensureDirectories(basePath, dirs);
16
18
 
17
- const templateData = {
18
- name: moduleName,
19
- className: pascalCase(moduleName),
20
- camelName: camelCase(moduleName),
21
- };
19
+ const templateData = {
20
+ name: moduleName,
21
+ className: pascalCase(moduleName),
22
+ camelName: camelCase(moduleName),
23
+ kebabName: kebabCase(moduleName),
24
+ };
22
25
 
23
- const renderAndWrite = async (templateName, outputPath) => {
24
- const templateContent = await ejs.renderFile(
25
- path.join(__dirname, "../templates/module", templateName),
26
- templateData
27
- );
28
- fs.writeFileSync(path.join(basePath, outputPath), templateContent);
29
- };
26
+ const filesToGenerate = [
27
+ { tpl: "module/entity.ejs", out: `domain/entities/${kebabCase(moduleName)}-entity.js` },
28
+ { tpl: "module/repository.interface.ejs", out: `domain/repositories/${kebabCase(moduleName)}-repository.js` },
29
+ { tpl: "module/repository.impl.ejs", out: `infrastructure/repositories/prisma-${kebabCase(moduleName)}-repository.js` }
30
+ ];
30
31
 
31
- await renderAndWrite("entity.ejs", `domain/entities/${pascalCase(moduleName)}.js`);
32
- await renderAndWrite("repository.interface.ejs", `domain/repositories/${pascalCase(moduleName)}Repository.js`);
33
- await renderAndWrite("repository.impl.ejs", `infrastructure/repositories/Prisma${pascalCase(moduleName)}Repository.js`);
32
+ for (const file of filesToGenerate) {
33
+ await FileUtil.renderAndWrite(
34
+ file.tpl,
35
+ templateData,
36
+ path.join(basePath, file.out)
37
+ );
38
+ }
34
39
 
35
- console.log(`โœ” Repository patterns for ${moduleName} generated successfully.`);
36
- };
40
+ Logger.success(`Repository patterns for ${moduleName} generated successfully.`);
41
+ } catch (error) {
42
+ Logger.error(`Failed to generate repository patterns for ${moduleName}`, error);
43
+ process.exit(1);
44
+ }
45
+ }
@@ -1,56 +1,56 @@
1
- const path = require("path");
2
- const fs = require("fs-extra");
3
- const ejs = require("ejs");
4
- const { pascalCase, camelCase } = require("../utils/case.util");
5
-
6
- module.exports = async function (name) {
7
- const basePath = path.join(process.cwd(), "src/modules", name);
8
-
9
- const dirs = [
10
- "domain/entities",
11
- "domain/repositories",
12
- "application/usecases",
13
- "application/dtos",
14
- "infrastructure/repositories",
15
- "interfaces/controllers",
16
- "interfaces/routes",
17
- ];
18
-
19
- dirs.forEach((dir) => fs.ensureDirSync(path.join(basePath, dir)));
20
-
21
- // Generate scoped package.json for ESM support
22
- fs.writeJsonSync(path.join(basePath, "package.json"), { type: "module" }, { spaces: 2 });
23
-
24
- const templateData = {
25
- name,
26
- className: pascalCase(name),
27
- camelName: camelCase(name),
28
- useCaseClassName: `${pascalCase(name)}UseCase`,
29
- useCaseFileName: `${name.toLowerCase()}.usecase`,
30
- };
31
-
32
- const renderAndWrite = async (templateName, outputPath) => {
33
- const templateContent = await ejs.renderFile(
34
- path.join(__dirname, "../templates/module", templateName),
35
- templateData
36
- );
37
- fs.writeFileSync(path.join(basePath, outputPath), templateContent);
38
- };
39
-
40
- await renderAndWrite("controller.ejs", `interfaces/controllers/${pascalCase(name)}Controller.js`);
41
- await renderAndWrite("controller.test.ejs", `interfaces/controllers/${pascalCase(name)}Controller.test.js`);
42
- await renderAndWrite("route.ejs", `interfaces/routes/${name.toLowerCase()}.routes.js`);
43
-
44
- await renderAndWrite("usecase.ejs", `application/usecases/${pascalCase(name)}UseCase.js`);
45
- await renderAndWrite("usecase.test.ejs", `application/usecases/${pascalCase(name)}UseCase.test.js`);
46
-
47
- await renderAndWrite("entity.ejs", `domain/entities/${pascalCase(name)}.js`);
48
- await renderAndWrite("repository.interface.ejs", `domain/repositories/${pascalCase(name)}Repository.js`);
49
-
50
- await renderAndWrite("repository.impl.ejs", `infrastructure/repositories/Prisma${pascalCase(name)}Repository.js`);
51
- await renderAndWrite("dto.ejs", `application/dtos/${name.toLowerCase()}.dto.js`);
52
-
53
- await renderAndWrite("di.ejs", `${name}.module.js`);
54
-
55
- console.log(`โœ” Resource ${name} generated successfully with Clean Architecture and Awilix DI!`);
56
- };
1
+ import path from "path";
2
+ import { pascalCase, camelCase, kebabCase } from "../utils/case.util.js";
3
+ import FileUtil from "../utils/file.util.js";
4
+ import Logger from "../utils/logger.util.js";
5
+
6
+ export default async function (name) {
7
+ try {
8
+ Logger.info(`Starting generation for resource: ${name}`);
9
+ const basePath = path.join(process.cwd(), "src/modules", name);
10
+
11
+ const dirs = [
12
+ "domain/entities",
13
+ "domain/repositories",
14
+ "application/usecases",
15
+ "application/dtos",
16
+ "infrastructure/repositories",
17
+ "interfaces/controllers",
18
+ "interfaces/routes",
19
+ ];
20
+
21
+ FileUtil.ensureDirectories(basePath, dirs);
22
+
23
+ const templateData = {
24
+ name,
25
+ className: pascalCase(name),
26
+ camelName: camelCase(name),
27
+ kebabName: kebabCase(name),
28
+ };
29
+
30
+ const filesToGenerate = [
31
+ { tpl: "module/controller.ejs", out: `interfaces/controllers/${kebabCase(name)}-controller.js` },
32
+ { tpl: "module/controller.test.ejs", out: `interfaces/controllers/${kebabCase(name)}-controller.test.js` },
33
+ { tpl: "module/route.ejs", out: `interfaces/routes/${kebabCase(name)}-routes.js` },
34
+ { tpl: "module/usecase.ejs", out: `application/usecases/${kebabCase(name)}-use-case.js` },
35
+ { tpl: "module/usecase.test.ejs", out: `application/usecases/${kebabCase(name)}-use-case.test.js` },
36
+ { tpl: "module/entity.ejs", out: `domain/entities/${kebabCase(name)}-entity.js` },
37
+ { tpl: "module/repository.interface.ejs", out: `domain/repositories/${kebabCase(name)}-repository.js` },
38
+ { tpl: "module/repository.impl.ejs", out: `infrastructure/repositories/prisma-${kebabCase(name)}-repository.js` },
39
+ { tpl: "module/dto.ejs", out: `application/dtos/${kebabCase(name)}-dto.js` },
40
+ { tpl: "module/di.ejs", out: `${kebabCase(name)}.module.js` }
41
+ ];
42
+
43
+ for (const file of filesToGenerate) {
44
+ await FileUtil.renderAndWrite(
45
+ file.tpl,
46
+ templateData,
47
+ path.join(basePath, file.out)
48
+ );
49
+ }
50
+
51
+ Logger.success(`Resource ${name} generated successfully with Clean Architecture and Awilix DI!`);
52
+ } catch (error) {
53
+ Logger.error(`Failed to generate resource ${name}`, error);
54
+ process.exit(1);
55
+ }
56
+ }
@@ -1,26 +1,39 @@
1
- const path = require("path");
2
- const fs = require("fs-extra");
3
- const ejs = require("ejs");
4
- const { pascalCase, camelCase } = require("../utils/case.util");
1
+ import path from "path";
2
+ import { pascalCase, camelCase, kebabCase } from "../utils/case.util.js";
3
+ import FileUtil from "../utils/file.util.js";
4
+ import Logger from "../utils/logger.util.js";
5
5
 
6
- module.exports = async function (useCaseName, moduleName) {
7
- const basePath = path.join(process.cwd(), "src/modules", moduleName);
8
- const ucDir = path.join(basePath, "application/usecases");
9
- fs.ensureDirSync(ucDir);
6
+ export default async function (useCaseName, moduleName) {
7
+ try {
8
+ Logger.info(`Starting usecase generation: ${useCaseName} in module: ${moduleName}`);
9
+ const basePath = path.join(process.cwd(), "src/modules", moduleName);
10
+ const ucDir = "application/usecases";
11
+
12
+ FileUtil.ensureDirectories(basePath, [ucDir]);
10
13
 
11
- const templateData = {
12
- name: moduleName,
13
- className: pascalCase(moduleName),
14
- camelName: camelCase(moduleName),
15
- useCaseClassName: `${pascalCase(useCaseName)}UseCase`,
16
- useCaseFileName: useCaseName,
17
- };
14
+ const templateData = {
15
+ name: moduleName,
16
+ className: pascalCase(useCaseName),
17
+ camelName: camelCase(moduleName),
18
+ kebabName: kebabCase(useCaseName),
19
+ moduleKebabName: kebabCase(moduleName),
20
+ };
18
21
 
19
- const templateContent = await ejs.renderFile(path.join(__dirname, "../templates/module/usecase.ejs"), templateData);
20
- fs.writeFileSync(path.join(ucDir, `${pascalCase(useCaseName)}UseCase.js`), templateContent);
22
+ await FileUtil.renderAndWrite(
23
+ "module/usecase.ejs",
24
+ templateData,
25
+ path.join(basePath, ucDir, `${kebabCase(useCaseName)}-use-case.js`)
26
+ );
21
27
 
22
- const testContent = await ejs.renderFile(path.join(__dirname, "../templates/module/usecase.test.ejs"), templateData);
23
- fs.writeFileSync(path.join(ucDir, `${pascalCase(useCaseName)}UseCase.test.js`), testContent);
28
+ await FileUtil.renderAndWrite(
29
+ "module/usecase.test.ejs",
30
+ templateData,
31
+ path.join(basePath, ucDir, `${kebabCase(useCaseName)}-use-case.test.js`)
32
+ );
24
33
 
25
- console.log(`โœ” Usecase ${useCaseName} generated inside module ${moduleName}.`);
26
- };
34
+ Logger.success(`Usecase ${useCaseName} generated inside module ${moduleName}.`);
35
+ } catch (error) {
36
+ Logger.error(`Failed to generate usecase ${useCaseName}`, error);
37
+ process.exit(1);
38
+ }
39
+ }