ddd-backend-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 +140 -0
- package/dist/generators/module/baseModel.js +25 -0
- package/dist/generators/module/containerRegistry.js +33 -0
- package/dist/generators/module/createOpenApiBase.js +44 -0
- package/dist/generators/module/fileCreator.js +19 -0
- package/dist/generators/module/generateModule.js +43 -0
- package/dist/generators/module/openApiRegistry.js +26 -0
- package/dist/generators/module/routeRegistry.js +21 -0
- package/dist/generators/module/structure.js +32 -0
- package/dist/generators/module/types.js +2 -0
- package/dist/index.js +39 -0
- package/dist/initializer/createBaseStructure.js +11 -0
- package/dist/initializer/createGitIgnore.js +15 -0
- package/dist/initializer/createMainFile.js +36 -0
- package/dist/initializer/createPackageJson.js +20 -0
- package/dist/initializer/createTsConfig.js +29 -0
- package/dist/initializer/initProject.js +30 -0
- package/dist/initializer/installDependencies.js +14 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<h1 align="left">Backend CLI Automation</h1>
|
|
2
|
+
<img src="https://i.ibb.co/0VfX0r3F/backend-Automation.png" alt="backend Automation" border="0">
|
|
3
|
+
|
|
4
|
+
###
|
|
5
|
+
|
|
6
|
+
<p align="left">CLI para generar automáticamente la estructura base de un módulo CRUD en un proyecto Backend usando Node.js + TypeScript + Express + EJS templates.<br><br>Este proyecto te permite crear tu propio template de Backend y personalizarlo usando solo comandos, sin necesidad de escribir todo el código repetitivo cada vez.</p>
|
|
7
|
+
|
|
8
|
+
Documentación paso a paso en mi Notion, para que puedas replicar la lógica y adaptarlo a tu manera: https://www.notion.so/oscarmolina/Automatizacion-Backend-3037c9c9fb1780f5bb06db3a9fb9ef83?source=copy_link
|
|
9
|
+
|
|
10
|
+
###
|
|
11
|
+
|
|
12
|
+
<h2 align="left">Repositorio del CLI</h2>
|
|
13
|
+
|
|
14
|
+
###
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
#clonar el proyecto
|
|
18
|
+
git clone https://github.com/oscarMolina1523/BackendAutomation
|
|
19
|
+
|
|
20
|
+
#navegar dentro de la carpeta
|
|
21
|
+
cd backend-cli
|
|
22
|
+
|
|
23
|
+
#instalar dependencias
|
|
24
|
+
npm install
|
|
25
|
+
|
|
26
|
+
#hacer build del proyecto
|
|
27
|
+
npm run build
|
|
28
|
+
|
|
29
|
+
#crear link de direccion en la pc
|
|
30
|
+
npm link
|
|
31
|
+
```
|
|
32
|
+
###
|
|
33
|
+
|
|
34
|
+
<h2 align="left">Estructura del Proyecto CLI</h2>
|
|
35
|
+
|
|
36
|
+
###
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
backend-cli/
|
|
40
|
+
│
|
|
41
|
+
├── src/
|
|
42
|
+
│ ├── index.ts <-----ejcuta todos los procesos
|
|
43
|
+
│ ├── initializer/
|
|
44
|
+
│ │ ├── createBaseStructure.ts
|
|
45
|
+
│ │ ├── createGitIgnore.ts
|
|
46
|
+
│ │ ├── createPackageJson.ts
|
|
47
|
+
│ │ ├── createTsConfig.ts
|
|
48
|
+
│ │ ├── initProject.ts <---ejecuta el flujo
|
|
49
|
+
│ │ └── installDependencies.ts
|
|
50
|
+
│ ├── generators/
|
|
51
|
+
│ │ ├──modules/
|
|
52
|
+
│ │ ├── baseModel.ts
|
|
53
|
+
│ │ ├── containerRegistry.ts
|
|
54
|
+
│ │ ├── createOpenApiBase.ts
|
|
55
|
+
│ │ ├── fileCreator.ts
|
|
56
|
+
│ │ ├── generateModule.ts <---ejecuta el flujo de trabajo
|
|
57
|
+
│ │ ├── routeRegistry.ts
|
|
58
|
+
│ │ ├── structure.ts
|
|
59
|
+
│ │ ├── types.ts
|
|
60
|
+
│ │ └── openApiRegistry.ts
|
|
61
|
+
├── templates/
|
|
62
|
+
│ ├── controller.ejs
|
|
63
|
+
│ ├── dto.ejs
|
|
64
|
+
│ ├── entity.ejs
|
|
65
|
+
│ ├── path.ejs
|
|
66
|
+
│ ├── service.interface.ejs
|
|
67
|
+
│ ├── service.impl.ejs
|
|
68
|
+
│ ├── repository.interface.ejs
|
|
69
|
+
│ ├── repository.impl.ejs
|
|
70
|
+
│ ├── routes.ejs
|
|
71
|
+
│ └── schema.ejs
|
|
72
|
+
│
|
|
73
|
+
├── dist/ ← Se genera automáticamente con npm run build
|
|
74
|
+
├── package.json
|
|
75
|
+
├── tsconfig.json
|
|
76
|
+
```
|
|
77
|
+
###
|
|
78
|
+
|
|
79
|
+
<h2 align="left">¿Cómo funciona el CLI?</h2>
|
|
80
|
+
|
|
81
|
+
Este CLI utiliza:
|
|
82
|
+
Commander → Para manejar comandos en consola,
|
|
83
|
+
EJS → Para generar archivos dinámicamente usando templates,
|
|
84
|
+
fs-extra → Para manipulación de archivos,
|
|
85
|
+
TypeScript → Para tipado y compilación.
|
|
86
|
+
|
|
87
|
+
Para usarlo , debes haber ejecutado los comandos mencionados anteriormente y estar seguros
|
|
88
|
+
de que esta funcionando el CLI (no es necesario qeu el proyecto CLI este corriendo, con haber ejecutado sus comandos es suficiente),
|
|
89
|
+
debes ubicarte en el espacio sobre el que trabajaras, en mi caso el Escritorio(Desktop) y ejecutar los comandos a continuación.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
|
|
94
|
+
#para iniciar el proyecto nuevo y crear una base usa el siguiente comando
|
|
95
|
+
|
|
96
|
+
mycli init test-api
|
|
97
|
+
|
|
98
|
+
#donde init es el comando de inicializacion y test-api el nombre del proyecto,
|
|
99
|
+
# una vez creado debemos entrar en el proyecto con el comando:
|
|
100
|
+
|
|
101
|
+
cd test-api
|
|
102
|
+
|
|
103
|
+
#luego ejecutaremos el siguiente comando que se encargara de crearnos la estructura
|
|
104
|
+
# de carpetas y archivos de manera automatizada
|
|
105
|
+
|
|
106
|
+
mycli generate Product name:string price:number
|
|
107
|
+
|
|
108
|
+
#El CLI:
|
|
109
|
+
#Crea una carpeta src/product
|
|
110
|
+
#Genera automáticamente:
|
|
111
|
+
#Controller
|
|
112
|
+
#Service (interface + implementación)
|
|
113
|
+
#Repository (interface + implementación)
|
|
114
|
+
#Routes
|
|
115
|
+
#Swagger schema
|
|
116
|
+
#Inserta dinámicamente los campos en el template de Swagger
|
|
117
|
+
```
|
|
118
|
+
###
|
|
119
|
+
<h2 align="left">¿Donde ver la documentaciónde los endpoints?</h2>
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
#en tu navegador de preferencia luego de asegurarte de que tu backend este corriendo
|
|
123
|
+
#debes escribir la siguiente ruta
|
|
124
|
+
|
|
125
|
+
http:localhost:3000
|
|
126
|
+
|
|
127
|
+
#tambien podrás ver la documentación y probar cada endpoint
|
|
128
|
+
#desde Scalar en la web usando la siguiente ruta
|
|
129
|
+
|
|
130
|
+
http:localhost:3000/api-docs
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
<h2 align="left">✨ Autor</h2>
|
|
135
|
+
|
|
136
|
+
###
|
|
137
|
+
|
|
138
|
+
<p align="left">Desarrollador Oscar Molina<br>💼 Desarrollador Web<br>GitHub: @oscarMolina1523<br>linkedin: https://www.linkedin.com/in/oscar-molina-916195309</p>
|
|
139
|
+
|
|
140
|
+
###
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ensureBaseModel = ensureBaseModel;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
//this create the base model file if it does not exist to be extended by other models
|
|
10
|
+
async function ensureBaseModel(domainPath) {
|
|
11
|
+
const baseModelPath = path_1.default.join(domainPath, "entities", "base.model.ts");
|
|
12
|
+
if (await fs_extra_1.default.pathExists(baseModelPath)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const content = `
|
|
16
|
+
export default abstract class BaseModel {
|
|
17
|
+
id: string;
|
|
18
|
+
|
|
19
|
+
constructor(id: string) {
|
|
20
|
+
this.id = id;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
await fs_extra_1.default.writeFile(baseModelPath, content.trim());
|
|
25
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerModuleInContainer = registerModuleInContainer;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
//this register every module's dependencies in the dependency container
|
|
10
|
+
async function registerModuleInContainer(webApiPath, name, moduleName) {
|
|
11
|
+
const registryPath = path_1.default.join(webApiPath, "container", "dependencyContainer.ts");
|
|
12
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(registryPath));
|
|
13
|
+
if (!(await fs_extra_1.default.pathExists(registryPath))) {
|
|
14
|
+
await fs_extra_1.default.writeFile(registryPath, `import { container } from "tsyringe";
|
|
15
|
+
// AUTO-GENERATED MODULE REGISTRATIONS
|
|
16
|
+
`);
|
|
17
|
+
}
|
|
18
|
+
let content = await fs_extra_1.default.readFile(registryPath, "utf-8");
|
|
19
|
+
if (content.includes(`${name}Service`))
|
|
20
|
+
return;
|
|
21
|
+
const importBlock = `import { I${name}Repository } from "./../../Domain/repositories/${moduleName}Repository.interface";
|
|
22
|
+
import { ${name}Repository } from "./../../Infrastructure/repositories/${moduleName}.repository";
|
|
23
|
+
import { I${name}Service } from "./../../Application/interfaces/${moduleName}.service.interface";
|
|
24
|
+
import { ${name}Service } from "./../../Application/services/${moduleName}.service";
|
|
25
|
+
import { ${name}Controller } from "./../controllers/${moduleName}.controller";`;
|
|
26
|
+
const registerBlock = `// ${name}
|
|
27
|
+
container.register<I${name}Repository>("I${name}Repository", { useClass: ${name}Repository });
|
|
28
|
+
container.register<I${name}Service>("I${name}Service", { useClass: ${name}Service });
|
|
29
|
+
container.register<${name}Controller>("${name}Controller", { useClass: ${name}Controller });`;
|
|
30
|
+
content = content.replace('import { container } from "tsyringe";', `import { container } from "tsyringe";\n${importBlock}`);
|
|
31
|
+
content = content.replace("// AUTO-GENERATED MODULE REGISTRATIONS", `// AUTO-GENERATED MODULE REGISTRATIONS\n${registerBlock}`);
|
|
32
|
+
await fs_extra_1.default.writeFile(registryPath, content);
|
|
33
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createOpenApiBase = createOpenApiBase;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function createOpenApiBase() {
|
|
10
|
+
const docsPath = path_1.default.join("src", "WebApi", "docs");
|
|
11
|
+
await fs_extra_1.default.ensureDir(docsPath);
|
|
12
|
+
const openApiPath = path_1.default.join(docsPath, "openapi.ts");
|
|
13
|
+
if (await fs_extra_1.default.pathExists(openApiPath)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const content = `
|
|
17
|
+
export const OpenApiSpecification = {
|
|
18
|
+
openapi: "3.0.0",
|
|
19
|
+
info: {
|
|
20
|
+
title: "My API",
|
|
21
|
+
version: "1.0.0",
|
|
22
|
+
description: "Auto-generated API documentation"
|
|
23
|
+
},
|
|
24
|
+
servers: [
|
|
25
|
+
{
|
|
26
|
+
url: "http://localhost:3000",
|
|
27
|
+
description: "Local server"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
paths: {},
|
|
31
|
+
components: {
|
|
32
|
+
securitySchemes: {
|
|
33
|
+
BearerAuth: {
|
|
34
|
+
type: "http",
|
|
35
|
+
scheme: "bearer",
|
|
36
|
+
bearerFormat: "JWT"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
schemas: {}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
`;
|
|
43
|
+
await fs_extra_1.default.writeFile(openApiPath, content.trim());
|
|
44
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createFile = createFile;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const ejs_1 = __importDefault(require("ejs"));
|
|
10
|
+
async function createFile(template, destination, data) {
|
|
11
|
+
const templatePath = path_1.default.resolve(__dirname, "../../../templates", template);
|
|
12
|
+
if (await fs_extra_1.default.pathExists(destination)) {
|
|
13
|
+
console.log(`Skipped: ${destination}`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const content = (await ejs_1.default.renderFile(templatePath, data));
|
|
17
|
+
await fs_extra_1.default.writeFile(destination, content);
|
|
18
|
+
console.log(`Created: ${destination}`);
|
|
19
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateModule = generateModule;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const structure_1 = require("./structure");
|
|
9
|
+
const baseModel_1 = require("./baseModel");
|
|
10
|
+
const fileCreator_1 = require("./fileCreator");
|
|
11
|
+
const containerRegistry_1 = require("./containerRegistry");
|
|
12
|
+
const routeRegistry_1 = require("./routeRegistry");
|
|
13
|
+
const openApiRegistry_1 = require("./openApiRegistry");
|
|
14
|
+
const createOpenApiBase_1 = require("./createOpenApiBase");
|
|
15
|
+
async function generateModule(name, fields) {
|
|
16
|
+
const moduleName = name.toLowerCase();
|
|
17
|
+
const parsedFields = fields.map((f) => {
|
|
18
|
+
const [fieldName, type] = f.split(":");
|
|
19
|
+
return { fieldName, type };
|
|
20
|
+
});
|
|
21
|
+
const rootPath = path_1.default.join(process.cwd(), "src");
|
|
22
|
+
const { webApiPath, applicationPath, domainPath, infrastructurePath, } = await (0, structure_1.createModuleStructure)(rootPath);
|
|
23
|
+
await (0, baseModel_1.ensureBaseModel)(domainPath);
|
|
24
|
+
// WebApi
|
|
25
|
+
await (0, fileCreator_1.createFile)("controller.ejs", path_1.default.join(webApiPath, "controllers", `${moduleName}.controller.ts`), { name, moduleName, fields: parsedFields });
|
|
26
|
+
await (0, fileCreator_1.createFile)("routes.ejs", path_1.default.join(webApiPath, "routes", `${moduleName}.routes.ts`), { name, fields: parsedFields });
|
|
27
|
+
await (0, fileCreator_1.createFile)("path.ejs", path_1.default.join(webApiPath, "docs", "paths", `${moduleName}.path.ts`), { name, moduleName, fields: parsedFields });
|
|
28
|
+
await (0, fileCreator_1.createFile)("schema.ejs", path_1.default.join(webApiPath, "docs", "schemas", `${moduleName}.schema.ts`), { name, moduleName, fields: parsedFields });
|
|
29
|
+
// Application
|
|
30
|
+
await (0, fileCreator_1.createFile)("dto.ejs", path_1.default.join(applicationPath, "dtos", `${moduleName}.dto.ts`), { name, fields: parsedFields });
|
|
31
|
+
await (0, fileCreator_1.createFile)("service.interface.ejs", path_1.default.join(applicationPath, "interfaces", `${moduleName}.service.interface.ts`), { name, moduleName });
|
|
32
|
+
await (0, fileCreator_1.createFile)("service.impl.ejs", path_1.default.join(applicationPath, "services", `${moduleName}.service.ts`), { name, moduleName });
|
|
33
|
+
// Domain
|
|
34
|
+
await (0, fileCreator_1.createFile)("entity.ejs", path_1.default.join(domainPath, "entities", `${moduleName}.ts`), { name, fields: parsedFields });
|
|
35
|
+
await (0, fileCreator_1.createFile)("repository.interface.ejs", path_1.default.join(domainPath, "repositories", `${moduleName}Repository.interface.ts`), { name, moduleName });
|
|
36
|
+
// Infrastructure
|
|
37
|
+
await (0, fileCreator_1.createFile)("repository.impl.ejs", path_1.default.join(infrastructurePath, "repositories", `${moduleName}.repository.ts`), { name, moduleName });
|
|
38
|
+
await (0, containerRegistry_1.registerModuleInContainer)(webApiPath, name, moduleName);
|
|
39
|
+
(0, routeRegistry_1.registerRouteInMain)(moduleName);
|
|
40
|
+
await (0, createOpenApiBase_1.createOpenApiBase)();
|
|
41
|
+
await (0, openApiRegistry_1.registerOpenApi)(webApiPath, name, moduleName);
|
|
42
|
+
console.log(`Module ${name} created successfully ✔`);
|
|
43
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerOpenApi = registerOpenApi;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
//this is to register the generated open api paths and schemas in the main openapi file
|
|
10
|
+
async function registerOpenApi(webApiPath, name, moduleName) {
|
|
11
|
+
const openApiPath = path_1.default.join(webApiPath, "docs", "openapi.ts");
|
|
12
|
+
if (!(await fs_extra_1.default.pathExists(openApiPath)))
|
|
13
|
+
return;
|
|
14
|
+
let content = await fs_extra_1.default.readFile(openApiPath, "utf-8");
|
|
15
|
+
const importPaths = `import { ${name}Paths } from "./paths/${moduleName}.path";`;
|
|
16
|
+
const importSchemas = `import { ${name}Schemas } from "./schemas/${moduleName}.schema";`;
|
|
17
|
+
if (!content.includes(importPaths))
|
|
18
|
+
content = importPaths + "\n" + content;
|
|
19
|
+
if (!content.includes(importSchemas))
|
|
20
|
+
content = importSchemas + "\n" + content;
|
|
21
|
+
if (!content.includes(`...${name}Paths`))
|
|
22
|
+
content = content.replace("paths: {", `paths: {\n ...${name}Paths,`);
|
|
23
|
+
if (!content.includes(`...${name}Schemas`))
|
|
24
|
+
content = content.replace("schemas: {", `schemas: {\n ...${name}Schemas,`);
|
|
25
|
+
await fs_extra_1.default.writeFile(openApiPath, content);
|
|
26
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerRouteInMain = registerRouteInMain;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
//this register every module's routes in the main application file
|
|
9
|
+
function registerRouteInMain(moduleName) {
|
|
10
|
+
const mainPath = "src/main.ts";
|
|
11
|
+
let content = fs_1.default.readFileSync(mainPath, "utf-8");
|
|
12
|
+
const importLine = `import ${moduleName}Routes from "./WebApi/routes/${moduleName}.routes";`;
|
|
13
|
+
const useLine = `app.use("/${moduleName}", ${moduleName}Routes);`;
|
|
14
|
+
if (!content.includes(importLine)) {
|
|
15
|
+
content = content.replace('import express from "express";', `import express from "express";\n${importLine}`);
|
|
16
|
+
}
|
|
17
|
+
if (!content.includes(useLine)) {
|
|
18
|
+
content = content.replace("app.use(express.json());", `app.use(express.json());\n${useLine}`);
|
|
19
|
+
}
|
|
20
|
+
fs_1.default.writeFileSync(mainPath, content);
|
|
21
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createModuleStructure = createModuleStructure;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
//this only creates the folder structure for a module
|
|
10
|
+
async function createModuleStructure(rootPath) {
|
|
11
|
+
//Base folders
|
|
12
|
+
const webApiPath = path_1.default.join(rootPath, "WebApi");
|
|
13
|
+
const applicationPath = path_1.default.join(rootPath, "Application");
|
|
14
|
+
const domainPath = path_1.default.join(rootPath, "Domain");
|
|
15
|
+
const infrastructurePath = path_1.default.join(rootPath, "Infrastructure");
|
|
16
|
+
//subfolders of WebApi
|
|
17
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(webApiPath, "controllers"));
|
|
18
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(webApiPath, "routes"));
|
|
19
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(webApiPath, "docs"));
|
|
20
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(webApiPath, "docs", "paths"));
|
|
21
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(webApiPath, "docs", "schemas"));
|
|
22
|
+
//subfolders of Application
|
|
23
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(applicationPath, "dtos"));
|
|
24
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(applicationPath, "interfaces"));
|
|
25
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(applicationPath, "services"));
|
|
26
|
+
//subfolders of Domain
|
|
27
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(domainPath, "entities"));
|
|
28
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(domainPath, "repositories"));
|
|
29
|
+
//subfolders of Infrastructure
|
|
30
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(infrastructurePath, "repositories"));
|
|
31
|
+
return { webApiPath, applicationPath, domainPath, infrastructurePath };
|
|
32
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const initProject_1 = require("./initializer/initProject");
|
|
6
|
+
const generateModule_1 = require("./generators/module/generateModule");
|
|
7
|
+
const program = new commander_1.Command();
|
|
8
|
+
program
|
|
9
|
+
.name("ddd-backend-cli")
|
|
10
|
+
.version("1.0.0");
|
|
11
|
+
// ==============================
|
|
12
|
+
// INIT PROJECT
|
|
13
|
+
// ==============================
|
|
14
|
+
program
|
|
15
|
+
.command("init <projectName>")
|
|
16
|
+
.description("Initialize a new TypeScript layered project")
|
|
17
|
+
.action(async (projectName) => {
|
|
18
|
+
try {
|
|
19
|
+
await (0, initProject_1.initProject)(projectName);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error("Error initializing project:", error);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
// ==============================
|
|
26
|
+
// GENERATE MODULE
|
|
27
|
+
// ==============================
|
|
28
|
+
program
|
|
29
|
+
.command("generate-model <name> [fields...]")
|
|
30
|
+
.description("Generate CRUD module")
|
|
31
|
+
.action(async (name, fields) => {
|
|
32
|
+
try {
|
|
33
|
+
await (0, generateModule_1.generateModule)(name, fields || []);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error("Error generating module:", error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createBaseStructure = createBaseStructure;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
async function createBaseStructure() {
|
|
9
|
+
//create src folder
|
|
10
|
+
await fs_extra_1.default.ensureDir("src");
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createGitignore = createGitignore;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
async function createGitignore() {
|
|
9
|
+
const content = `
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
.env
|
|
13
|
+
`;
|
|
14
|
+
await fs_extra_1.default.writeFile(".gitignore", content.trim());
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createMainFile = createMainFile;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
async function createMainFile() {
|
|
9
|
+
const content = `
|
|
10
|
+
import "reflect-metadata";
|
|
11
|
+
import "./WebApi/container/dependencyContainer";
|
|
12
|
+
import express from "express";
|
|
13
|
+
import { OpenApiSpecification } from "./WebApi/docs/openapi";
|
|
14
|
+
import { apiReference } from "@scalar/express-api-reference";
|
|
15
|
+
|
|
16
|
+
const app = express();
|
|
17
|
+
const PORT = process.env.PORT || 3000;
|
|
18
|
+
|
|
19
|
+
app.use(express.urlencoded({ extended: false }));
|
|
20
|
+
app.use(express.json());
|
|
21
|
+
|
|
22
|
+
app.use(
|
|
23
|
+
"/api-docs",
|
|
24
|
+
apiReference({
|
|
25
|
+
spec: {
|
|
26
|
+
content: OpenApiSpecification,
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
app.listen(PORT, () => {
|
|
32
|
+
console.log(\`Server running on port \${PORT}\`);
|
|
33
|
+
});
|
|
34
|
+
`;
|
|
35
|
+
await fs_extra_1.default.writeFile("src/main.ts", content.trim());
|
|
36
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createPackageJson = createPackageJson;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
async function createPackageJson(projectName) {
|
|
9
|
+
const packageJson = {
|
|
10
|
+
name: projectName,
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
main: "dist/main.js",
|
|
13
|
+
scripts: {
|
|
14
|
+
build: "tsc",
|
|
15
|
+
start: "node dist/main.js",
|
|
16
|
+
dev: "ts-node-dev --respawn src/main.ts",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
await fs_extra_1.default.writeJson("package.json", packageJson, { spaces: 2 });
|
|
20
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createTsConfig = createTsConfig;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
async function createTsConfig() {
|
|
9
|
+
const tsconfig = {
|
|
10
|
+
compilerOptions: {
|
|
11
|
+
rootDir: "./src",
|
|
12
|
+
outDir: "./dist",
|
|
13
|
+
module: "Commonjs",
|
|
14
|
+
target: "ES2020",
|
|
15
|
+
lib: ["ES2020"],
|
|
16
|
+
types: ["node"],
|
|
17
|
+
sourceMap: true,
|
|
18
|
+
declaration: true,
|
|
19
|
+
strict: true,
|
|
20
|
+
esModuleInterop: true,
|
|
21
|
+
skipLibCheck: true,
|
|
22
|
+
experimentalDecorators: true,
|
|
23
|
+
emitDecoratorMetadata: true,
|
|
24
|
+
},
|
|
25
|
+
include: ["src"],
|
|
26
|
+
exclude: ["node_modules", "dist"],
|
|
27
|
+
};
|
|
28
|
+
await fs_extra_1.default.writeJson("tsconfig.json", tsconfig, { spaces: 2 });
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initProject = initProject;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const createPackageJson_1 = require("./createPackageJson");
|
|
10
|
+
const createTsConfig_1 = require("./createTsConfig");
|
|
11
|
+
const createGitIgnore_1 = require("./createGitIgnore");
|
|
12
|
+
const createBaseStructure_1 = require("./createBaseStructure");
|
|
13
|
+
const createMainFile_1 = require("./createMainFile");
|
|
14
|
+
const installDependencies_1 = require("./installDependencies");
|
|
15
|
+
async function initProject(projectName) {
|
|
16
|
+
const rootPath = path_1.default.join(process.cwd(), projectName);
|
|
17
|
+
if (await fs_extra_1.default.pathExists(rootPath)) {
|
|
18
|
+
console.log("Project already exists");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
await fs_extra_1.default.ensureDir(rootPath);
|
|
22
|
+
process.chdir(rootPath);
|
|
23
|
+
await (0, createPackageJson_1.createPackageJson)(projectName);
|
|
24
|
+
await (0, createTsConfig_1.createTsConfig)();
|
|
25
|
+
await (0, createGitIgnore_1.createGitignore)();
|
|
26
|
+
await (0, createBaseStructure_1.createBaseStructure)();
|
|
27
|
+
await (0, createMainFile_1.createMainFile)();
|
|
28
|
+
await (0, installDependencies_1.installDependencies)();
|
|
29
|
+
console.log("Project initialized successfully ✔");
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.installDependencies = installDependencies;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
async function installDependencies() {
|
|
6
|
+
console.log("Installing dependencies...");
|
|
7
|
+
try {
|
|
8
|
+
(0, child_process_1.execSync)("npm install express tsyringe reflect-metadata @scalar/express-api-reference", { stdio: "inherit" });
|
|
9
|
+
(0, child_process_1.execSync)("npm install -D typescript ts-node-dev @types/node @types/express", { stdio: "inherit" });
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
console.error("Dependency installation failed");
|
|
13
|
+
}
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ddd-backend-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI para generar proyectos backend con DDD",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ddd-backend-cli": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"cli",
|
|
14
|
+
"ddd",
|
|
15
|
+
"backend",
|
|
16
|
+
"generator"
|
|
17
|
+
],
|
|
18
|
+
"author": "Oscar Molina",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"dev": "tsc -w"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"commander": "^14.0.3",
|
|
26
|
+
"ejs": "^3.1.10",
|
|
27
|
+
"fs-extra": "^11.3.3"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/ejs": "^3.1.5",
|
|
31
|
+
"@types/fs-extra": "^11.0.4",
|
|
32
|
+
"@types/node": "^20.11.30",
|
|
33
|
+
"typescript": "^5.3.3"
|
|
34
|
+
}
|
|
35
|
+
}
|