UNPKG

cl-generate

Version:

A cross-platform CLI tool to generate NestJS clean architecture modules

1,490 lines (1,332 loc) 71.2 kB
#!/usr/bin/env node const fs = require("fs").promises; const path = require("path"); const createDir = require("../shares/createDir"); const createFile = require("../shares/createFile"); // Colors for output const COLORS = { GREEN: "\x1b[32m", YELLOW: "\x1b[33m", RED: "\x1b[31m", NC: "\x1b[0m", }; class ModuleGenerator { constructor(moduleNameLower, moduleNamePascal, moduleNameCapitalized) { this.moduleNameLower = moduleNameLower; this.moduleNamePascal = moduleNamePascal; this.moduleNameCapitalized = moduleNameCapitalized; this.rootDir = "src"; this.domainDir = path.join(this.rootDir, "domain"); this.infraDir = path.join(this.rootDir, "infrastructure"); this.useCasesDir = path.join(this.rootDir, "usecases"); this.modelName = `${this.moduleNamePascal}Model`; this.dtoName = `${this.moduleNamePascal}Dto`; this.entityName = `${this.moduleNamePascal}Entity`; this.entityFilePath = `@infrastructure/entities/${this.moduleNameLower}.entity`; this.repositoryName = `${this.moduleNamePascal}Repo`; this.repositoryImplName = `${this.moduleNamePascal}RepoImpl`; this.repositoryInterfaceName = `${this.moduleNamePascal}Interface`; this.useCaseName = `${this.moduleNamePascal}Usecase`; this.controllerName = `${this.moduleNamePascal}Controller`; this.serviceName = `${this.moduleNamePascal}Service`; this.moduleNameUpper = this.moduleNameLower.replace("-", "_").toUpperCase(); this.createModelName = `Create${this.moduleNamePascal}Model`; this.createValidationName = `Create${this.moduleNamePascal}Validation`; this.createActionName = `Create${this.moduleNamePascal}Action`; this.createRepositoryName = `Create${this.moduleNamePascal}Repository`; this.createRepositoryImplName = `Create${this.moduleNamePascal}RepositoryImpl`; this.createRepositoryInterfaceName = `Create${this.moduleNamePascal}RepositoryInterface`; this.createFunctionName = `Create${this.moduleNamePascal}`; this.responseModelName = `Response${this.moduleNamePascal}Model`; this.updateModelName = `Update${this.moduleNamePascal}Model`; this.updateValidationName = `Update${this.moduleNamePascal}Validation`; this.updateActionName = `Update${this.moduleNamePascal}Action`; this.updateRepositoryName = `Update${this.moduleNamePascal}Repository`; this.updateRepositoryImplName = `Update${this.moduleNamePascal}RepositoryImpl`; this.updateRepositoryInterfaceName = `Update${this.moduleNamePascal}RepositoryInterface`; this.updateFunctionName = `Update${this.moduleNamePascal}`; this.deleteModelName = `Delete${this.moduleNamePascal}Model`; this.deleteValidationName = `Delete${this.moduleNamePascal}Validation`; this.deleteActionName = `Delete${this.moduleNamePascal}Action`; this.deleteRepositoryName = `Delete${this.moduleNamePascal}Repository`; this.deleteRepositoryImplName = `Delete${this.moduleNamePascal}RepositoryImpl`; this.deleteRepositoryInterfaceName = `Delete${this.moduleNamePascal}RepositoryInterface`; this.deleteFunctionName = `Delete${this.moduleNamePascal}`; this.loadAllModelName = `LoadAll${this.moduleNamePascal}Model`; this.loadAllValidationName = `LoadAll${this.moduleNamePascal}Validation`; this.loadAllActionName = `LoadAll${this.moduleNamePascal}Action`; this.loadAllRepositoryName = `LoadAll${this.moduleNamePascal}Repository`; this.loadAllRepositoryImplName = `LoadAll${this.moduleNamePascal}RepositoryImpl`; this.loadAllRepositoryInterfaceName = `LoadAll${this.moduleNamePascal}RepositoryInterface`; this.loadAllFunctionName = `LoadAll${this.moduleNamePascal}`; this.loadByIdModelName = `Load${this.moduleNamePascal}ByIdModel`; this.loadByIdValidationName = `Load${this.moduleNamePascal}ByIdValidation`; this.loadByIdActionName = `Load${this.moduleNamePascal}ByIdAction`; this.loadByIdRepositoryName = `Load${this.moduleNamePascal}ByIdRepository`; this.loadByIdRepositoryImplName = `Load${this.moduleNamePascal}ByIdRepositoryImpl`; this.loadByIdRepositoryInterfaceName = `Load${this.moduleNamePascal}ByIdRepositoryInterface`; this.loadByIdFunctionName = `Load${this.moduleNamePascal}ById`; this.createUseCaseName = `Create${this.moduleNamePascal}Usecase`; this.updateUseCaseName = `Update${this.moduleNamePascal}Usecase`; this.deleteUseCaseName = `Delete${this.moduleNamePascal}Usecase`; this.loadAllUseCaseName = `LoadAll${this.moduleNamePascal}Usecase`; this.loadByIdUseCaseName = `Load${this.moduleNamePascal}ByIdUsecase`; this.moduleUsecaseProxyName = `${this.moduleNamePascal}UsecaseProxy`; this.createPostUseCaseProxyName = `POST_CREATE_${this.moduleNameUpper}_USECASE_PROXY`; this.updatePostUseCaseProxyName = `POST_UPDATE_${this.moduleNameUpper}_USECASE_PROXY`; this.deletePostUseCaseProxyName = `POST_DELETE_${this.moduleNameUpper}_USECASE_PROXY`; this.loadAllPostUseCaseProxyName = `POST_LOAD_ALL_${this.moduleNameUpper}_USECASE_PROXY`; this.loadByIdPostUseCaseProxyName = `POST_LOAD_BY_ID_${this.moduleNameUpper}_USECASE_PROXY`; this.createPostUsecaseProxyValue = `create${this.moduleNamePascal}UsecaseProxy`; this.updatePostUsecaseProxyValue = `update${this.moduleNamePascal}UsecaseProxy`; this.deletePostUsecaseProxyValue = `delete${this.moduleNamePascal}UsecaseProxy`; this.loadAllPostUsecaseProxyValue = `loadAll${this.moduleNamePascal}UsecaseProxy`; this.loadByIdPostUsecaseProxyValue = `load${this.moduleNamePascal}ByIdUsecaseProxy`; } async setupDirectories() { const dirs = [ path.join(this.domainDir, "dtos"), // path.join(this.domainDir, "repositories"), path.join(this.domainDir, "models"), path.join(this.infraDir, "controllers", this.moduleNameLower), path.join(this.infraDir, "entities"), path.join(this.infraDir, "repositories", this.moduleNameLower), // this.useCasesDir, ]; await Promise.all(dirs.map((dir) => createDir(dir))); } async setupSubDirectories() { const dirs = [ { path: path.join( this.infraDir, "repositories", this.moduleNameLower, `create${this.moduleNamePascal}` ), action: this.getCreateActionContent(), validation: this.getCreateValidationContent(), name: `create${this.moduleNamePascal}`, }, { path: path.join( this.infraDir, "repositories", this.moduleNameLower, `update${this.moduleNamePascal}` ), action: this.getUpdateActionContent(), validation: this.getUpdateValidationContent(), name: `update${this.moduleNamePascal}`, }, { path: path.join( this.infraDir, "repositories", this.moduleNameLower, `delete${this.moduleNamePascal}` ), action: this.getDeleteActionContent(), validation: this.getDeleteValidationContent(), name: `delete${this.moduleNamePascal}`, }, { path: path.join( this.infraDir, "repositories", this.moduleNameLower, `loadAll${this.moduleNamePascal}` ), action: this.getLoadAllActionContent(), validation: this.getLoadAllValidationContent(), name: `loadAll${this.moduleNamePascal}`, }, { path: path.join( this.infraDir, "repositories", this.moduleNameLower, `load${this.moduleNamePascal}ById` ), action: this.getLoadByIdActionContent(), validation: this.getLoadByIdValidationContent(), name: `load${this.moduleNamePascal}ById`, }, ]; await Promise.all(dirs.map((dir) => createDir(dir.path))); await Promise.all( dirs.map((dir) => { createFile( `${path.join(dir.path, `${dir.name}.action.ts`)}`, dir.action ); createFile( `${path.join(dir.path, `${dir.name}.validation.ts`)}`, dir.validation ); }) ); } async generateFiles() { const files = [ { path: path.join( this.domainDir, "dtos", `${this.moduleNameLower}.dto.ts` ), content: this.getDtoContent(), }, { path: path.join( this.domainDir, "repositories", `${this.moduleNameLower}.interface.ts` ), content: this.getRepositoryInterfaceContent(), }, { path: path.join( this.domainDir, "models", `${this.moduleNameLower}.model.ts` ), content: this.getModelContent(), }, { path: path.join( this.infraDir, "controllers", this.moduleNameLower, `${this.moduleNameLower}.controller.ts` ), content: this.getControllerContent(), }, { path: path.join( this.infraDir, "entities", `${this.moduleNameLower}.entity.ts` ), content: this.getEntityContent(), }, { path: path.join( this.infraDir, "repositories", this.moduleNameLower, `${this.moduleNameLower}.repository.ts` ), content: this.getRepositoryImplContent(), }, { path: path.join(this.useCasesDir, `${this.moduleNameLower}.usecase.ts`), content: this.getUsecaseContent(), }, { path: path.join( this.infraDir, "usecases-proxy", `${this.moduleNameLower}.usecase.proxy.ts` ), content: this.getUsecaseProxyContent(), }, // { // path: path.join( // this.infraDir, // "repositories", // this.moduleNameLower, // `${this.moduleNameLower}.module.ts` // ), // content: this.getModuleContent(), // }, // { // path: path.join( // this.infraDir, // "repositories", // `repositories.module.ts` // ), // content: this.getRepoModuleContent(), // }, ]; await Promise.all(files.map((file) => createFile(file.path, file.content))); } converted() { return this.moduleNameLower.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase() ); } async updateAppModule() { const appModulePath = path.join(this.rootDir, "app.module.ts"); const importLine = `import { ${this.moduleNamePascal}Module } from './infrastructure/repositories/${this.moduleNameLower}/${this.moduleNameLower}.module';`; const moduleEntry = `${this.moduleNamePascal}Module`; try { let content = await fs.readFile(appModulePath, "utf8").catch(() => ""); if (!content) { content = this.getDefaultAppModuleContent(importLine, moduleEntry); await createFile(appModulePath, content); return; } if (!content.includes(moduleEntry)) { const lines = content.split("\n"); const importIndex = lines.findIndex((line) => line.startsWith("import { Module }") ); lines.splice(importIndex + 1, 0, importLine); const importsIndex = lines.findIndex((line) => line.includes("imports: [") ); if (importsIndex !== -1) { const importLine = lines[importsIndex]; lines[importsIndex] = importLine.includes("[],") ? ` imports: [${moduleEntry}],` : importLine.replace("imports: [", `imports: [${moduleEntry}, `); } await fs.writeFile(appModulePath, lines.join("\n"), "utf8"); console.log(`${COLORS.GREEN}✔ Updated ${appModulePath}${COLORS.NC}`); } else { console.log( `${COLORS.YELLOW}⚠ Module already in ${appModulePath}${COLORS.NC}` ); } } catch (error) { throw new Error(`Failed to update app.module.ts: ${error.message}`); } } async updateRepoModule() { const repoModulePath = path.join( this.infraDir, "repositories", `repositories.module.ts` ); const importLine = `import { ${this.repositoryImplName} } from './${this.moduleNameLower}/${this.moduleNameLower}.repository';`; const importEntityLine = `import { ${this.entityName} } from '@infrastructure/entities/${this.moduleNameLower}.entity';`; const typeOrmImportLine = `import { TypeOrmModule } from '@nestjs/typeorm';`; try { let content = await fs.readFile(repoModulePath, "utf8").catch(() => ""); if (!content) { content = this.getRepoModuleContent(); await createFile(repoModulePath, content); console.log(`${COLORS.GREEN}✔ Created ${repoModulePath}${COLORS.NC}`); return; } // Skip if repository is already imported if (content.includes(importLine)) { console.log( `${COLORS.YELLOW}⚠ Repository already in ${repoModulePath}${COLORS.NC}` ); return; } const lines = content.split("\n"); // Add import statements const importIndex = lines.findIndex((line) => line.startsWith("import { Module }") ); if (importIndex === -1) { throw new Error("Could not find Module import statement"); } // Make sure TypeOrmModule is imported if (!content.includes("TypeOrmModule")) { lines.splice( importIndex + 1, 0, typeOrmImportLine, importLine, importEntityLine ); } else { lines.splice(importIndex + 1, 0, importLine, importEntityLine); } // Update imports array - specifically focusing on TypeOrmModule.forFeature const importsIndex = lines.findIndex((line) => line.includes("imports: [") ); if (importsIndex !== -1) { // Find TypeOrmModule.forFeature or add it const typeOrmFeatureIndex = lines.findIndex((line) => line.includes("TypeOrmModule.forFeature([") ); if (typeOrmFeatureIndex !== -1) { // TypeOrmModule.forFeature exists, update it to include the new entity if (!lines[typeOrmFeatureIndex].includes(this.entityName)) { lines[typeOrmFeatureIndex] = lines[typeOrmFeatureIndex].replace( "TypeOrmModule.forFeature([", `TypeOrmModule.forFeature([${this.entityName}, ` ); } } else { // TypeOrmModule.forFeature doesn't exist, add it to imports const importLine = lines[importsIndex]; if (importLine.includes("[],")) { lines[ importsIndex ] = ` imports: [TypeOrmModule.forFeature([${this.entityName}])],`; } else { lines[importsIndex] = importLine.replace( "imports: [", `imports: [TypeOrmModule.forFeature([${this.entityName}]), ` ); } } } else { throw new Error("Could not find imports array in module"); } // Update providers array const providersIndex = lines.findIndex((line) => line.includes("providers: [") ); if (providersIndex !== -1) { const providerLine = lines[providersIndex]; if (providerLine.includes("[],")) { lines[providersIndex] = ` providers: [${this.repositoryImplName}],`; } else if (!providerLine.includes(this.repositoryImplName)) { lines[providersIndex] = providerLine.replace( "providers: [", `providers: [${this.repositoryImplName}, ` ); } } // Update exports array const exportsIndex = lines.findIndex((line) => line.includes("exports: [") ); if (exportsIndex !== -1) { const exportLine = lines[exportsIndex]; if (exportLine.includes("[],")) { lines[exportsIndex] = ` exports: [${this.repositoryImplName}],`; } else if (!exportLine.includes(this.repositoryImplName)) { lines[exportsIndex] = exportLine.replace( "exports: [", `exports: [${this.repositoryImplName}, ` ); } } await fs.writeFile(repoModulePath, lines.join("\n"), "utf8"); console.log(`${COLORS.GREEN}✔ Updated ${repoModulePath}${COLORS.NC}`); } catch (error) { console.error( `${COLORS.RED}Error updating repositories.module.ts: ${error.message}${COLORS.NC}` ); throw new Error( `Failed to update repositories.module.ts: ${error.message}` ); } } async updateUseCaseProxyModule() { const useCaseProxyModulePath = path.join( this.infraDir, "usecases-proxy", "usecases-proxy.module.ts" ); const importLine = `import { ${this.moduleUsecaseProxyName} } from './${this.moduleNameLower}.usecase.proxy';`; const proxyProviderLine = `...new ${this.moduleUsecaseProxyName}().providers()`; // Creating array of static constant definitions const staticConstantDefs = [ `static ${this.createPostUseCaseProxyName} = '${this.createPostUsecaseProxyValue}';`, `static ${this.updatePostUseCaseProxyName} = '${this.updatePostUsecaseProxyValue}';`, `static ${this.deletePostUseCaseProxyName} = '${this.deletePostUsecaseProxyValue}';`, `static ${this.loadAllPostUseCaseProxyName} = '${this.loadAllPostUsecaseProxyValue}';`, `static ${this.loadByIdPostUseCaseProxyName} = '${this.loadByIdPostUsecaseProxyValue}';`, ]; // Creating array of export lines const exportLines = [ `UsecasesProxyModule.${this.createPostUseCaseProxyName},`, `UsecasesProxyModule.${this.updatePostUseCaseProxyName},`, `UsecasesProxyModule.${this.deletePostUseCaseProxyName},`, `UsecasesProxyModule.${this.loadAllPostUseCaseProxyName},`, `UsecasesProxyModule.${this.loadByIdPostUseCaseProxyName},`, ]; try { let content = await fs .readFile(useCaseProxyModulePath, "utf8") .catch((error) => { throw new Error( `usecase-proxy.module.ts not found: ${error.message}` ); }); let modified = false; // Check if usecase is already imported if (content.includes(importLine)) { // Check if all constants are already defined const allConstantsExist = staticConstantDefs.every((constant) => content.includes(constant.split(" = ")[0]) ); if (allConstantsExist) { console.log( `${COLORS.YELLOW}⚠ Usecase already in usecase-proxy.module.ts${COLORS.NC}` ); return; } } // Add import at the top, after the first import statement const firstImportEndIndex = content.indexOf( "\n", content.indexOf("import") ); content = content.substring(0, firstImportEndIndex + 1) + importLine + "\n" + content.substring(firstImportEndIndex + 1); modified = true; // Add static constants before the register method // Find the appropriate location - before static register() const registerIndex = content.indexOf("static register()"); if (registerIndex === -1) { throw new Error( "Could not find register method in usecase-proxy.module.ts" ); } // Add comment section and constants let insertText = ""; // Check if there's already a section for this module type const sectionComment = `// ${this.moduleNameLower}`; if (!content.includes(sectionComment)) { insertText = ` ${sectionComment}\n`; } // Add each constant definition for (const constDef of staticConstantDefs) { if (!content.includes(constDef.split(" = ")[0])) { insertText += ` ${constDef}\n`; } } if (insertText) { insertText += "\n"; // Find the last line before register method let insertPosition = content.lastIndexOf("\n", registerIndex); if (content.substring(insertPosition - 1, insertPosition) === "\n") { // Already has a blank line insertPosition = content.lastIndexOf("\n", insertPosition - 1); } content = content.substring(0, insertPosition + 1) + insertText + content.substring(insertPosition + 1); modified = true; } // Add provider to the providers array if (!content.includes(proxyProviderLine)) { const providersStart = content.indexOf( "providers: [", content.indexOf("static register()") ); if (providersStart === -1) { throw new Error("Could not find providers array in register method"); } const providersClosingBracket = content.indexOf("]", providersStart); const lastProvider = content.lastIndexOf(",", providersClosingBracket); if (lastProvider > providersStart) { // There are existing providers content = content.substring(0, lastProvider + 1) + "\n " + proxyProviderLine + "," + content.substring(lastProvider + 1); } else { // Empty providers array or only one provider without comma const openingBracket = content.indexOf("[", providersStart); content = content.substring(0, openingBracket + 1) + "\n " + proxyProviderLine + ",\n " + content.substring(openingBracket + 1); } modified = true; } // Add exports to the exports array const exportsStart = content.indexOf( "exports: [", content.indexOf("static register()") ); if (exportsStart === -1) { throw new Error("Could not find exports array in register method"); } // Add comment for export section if it doesn't exist const exportSectionComment = `// export ${this.moduleNameLower}`; let exportsToAdd = ""; if (!content.includes(exportSectionComment)) { exportsToAdd += `\n ${exportSectionComment}`; } // Add each export line that doesn't already exist for (const exportLine of exportLines) { if (!content.includes(exportLine.split(",")[0])) { exportsToAdd += `\n ${exportLine}`; } } if (exportsToAdd) { // Add at the end before closing bracket const exportsEndIndex = content.indexOf("]", exportsStart); content = content.substring(0, exportsEndIndex) + exportsToAdd + content.substring(exportsEndIndex); modified = true; } if (modified) { await fs.writeFile(useCaseProxyModulePath, content, "utf8"); console.log( `${COLORS.GREEN}✔ Updated usecase-proxy.module.ts${COLORS.NC}` ); } } catch (error) { console.error( `${COLORS.RED}Error updating usecase-proxy.module.ts: ${error.message}${COLORS.NC}` ); throw new Error( `Failed to update usecase-proxy.module.ts: ${error.message}` ); } } async updateControllerModule() { const controllerModulePath = path.join( this.infraDir, "controllers", "controllers.module.ts" ); const importLine = `import { ${this.controllerName} } from './${this.moduleNameLower}/${this.moduleNameLower}.controller';`; try { // Read the current content of the module file const fileBuffer = await fs.readFile(controllerModulePath); let moduleContent = fileBuffer.toString("utf8"); // Check if this controller is already imported if (!moduleContent.includes(importLine)) { // Split content into parts const importSection = moduleContent.substring( 0, moduleContent.indexOf("@Module") ); const moduleSection = moduleContent.substring( moduleContent.indexOf("@Module") ); // Add new import line if not already there const updatedImports = importSection.trim() + "\n" + importLine + "\n\n"; // Find controllers section const controllersStartIndex = moduleSection.indexOf("controllers:"); const controllersEndIndex = moduleSection.indexOf( "]", controllersStartIndex ); // Extract controller names from current array const controllersArrayContent = moduleSection .substring( moduleSection.indexOf("[", controllersStartIndex) + 1, controllersEndIndex ) .trim(); // Build new controllers array let newControllersArray; if (!controllersArrayContent) { // Empty array case newControllersArray = `[${this.controllerName}]`; } else if (!controllersArrayContent.includes(this.controllerName)) { // Add to existing array const controllers = controllersArrayContent .split(",") .map((c) => c.trim()) .filter((c) => c); // Remove empty entries controllers.push(this.controllerName); newControllersArray = `[${controllers.join(", ")}]`; } else { // Controller already in array newControllersArray = `[${controllersArrayContent}]`; } // Build the start of the module section const moduleStart = moduleSection.substring(0, controllersStartIndex); // Build the end of the module section const moduleEnd = moduleSection.substring(controllersEndIndex + 1); // Combine everything const newModuleContent = updatedImports + moduleStart + `controllers: ${newControllersArray}` + moduleEnd; // Write the updated content back to the file await fs.writeFile(controllerModulePath, newModuleContent); console.log( `Successfully added ${this.controllerName} to controllers.module.ts` ); } else { console.log( `${this.controllerName} is already in controllers.module.ts` ); } } catch (error) { console.error("Error updating controllers.module.ts:", error); throw error; } } async updateEntityModule(entityName, entityFilePath) { const typeOrmModulePath = path.join( this.infraDir, "config", "typeorm", "typeorm.module.ts" ); const importLine = `import { ${entityName} } from '${entityFilePath}';`; try { // Read the current content of the module file const fileBuffer = await fs.readFile(typeOrmModulePath); let moduleContent = fileBuffer.toString("utf8"); // Check if this entity is already imported if (!moduleContent.includes(importLine)) { // Split content into parts const importSection = moduleContent.substring( 0, moduleContent.indexOf("export const getTypeOrmModuleOptions") ); const restOfFile = moduleContent.substring( moduleContent.indexOf("export const getTypeOrmModuleOptions") ); // Add new import line if not already there const updatedImports = importSection.trim() + "\n" + importLine + "\n\n"; // Find entities array in getTypeOrmModuleOptions const entitiesStartIndex = restOfFile.indexOf("entities:"); const entitiesEndIndex = restOfFile.indexOf("]", entitiesStartIndex); // Extract entity names from current array const entitiesArrayContent = restOfFile .substring( restOfFile.indexOf("[", entitiesStartIndex) + 1, entitiesEndIndex ) .trim(); // Build new entities array let newEntitiesArray; if (!entitiesArrayContent) { // Empty array case newEntitiesArray = `[${entityName}]`; } else if (!entitiesArrayContent.includes(entityName)) { // Add to existing array const entities = entitiesArrayContent .split(",") .map((e) => e.trim()) .filter((e) => e); // Remove empty entries entities.push(entityName); newEntitiesArray = `[${entities.join(", ")}]`; } else { // Entity already in array newEntitiesArray = `[${entitiesArrayContent}]`; } // Build the start of the function const functionStart = restOfFile.substring(0, entitiesStartIndex); // Build the end of the function const functionEnd = restOfFile.substring(entitiesEndIndex + 1); // Combine everything const newModuleContent = updatedImports + functionStart + `entities: ${newEntitiesArray}` + functionEnd; // Write the updated content back to the file await fs.writeFile(typeOrmModulePath, newModuleContent); console.log( `Successfully added ${entityName} to typeorm.module.ts entities` ); } else { console.log(`${entityName} is already in typeorm.module.ts`); } } catch (error) { console.error("Error updating typeorm.module.ts:", error); throw error; } } async execute() { try { console.log( `${COLORS.YELLOW}Generating resource: ${this.moduleNameLower}${COLORS.NC}` ); await this.setupDirectories(); await this.generateFiles(); await this.setupSubDirectories(); await this.updateRepoModule(); await this.updateUseCaseProxyModule(); // await this.updateAppModule(); await this.updateControllerModule(); await this.updateEntityModule(this.entityName, this.entityFilePath); console.log( `${COLORS.GREEN}✔ Resource generation completed successfully${COLORS.NC}` ); } catch (error) { console.error(`${COLORS.RED}❌ Error:${COLORS.NC} ${error.message}`); process.exit(1); } } getUsecaseProxyContent() { return ` import { LoggerService } from '@infrastructure/logger/logger.service'; import { UseCaseProxy } from './usecases-proxy'; import { UsecasesProxyModule } from './usecases-proxy.module'; import { ${this.repositoryImplName} } from './../repositories/${ this.moduleNameLower }/${this.moduleNameLower}.repository'; import { ${this.createUseCaseName}, ${this.updateUseCaseName}, ${this.deleteUseCaseName}, ${this.loadAllUseCaseName}, ${this.loadByIdUseCaseName} } from '@usecases/${this.moduleNameLower}.usecase'; export class ${this.moduleUsecaseProxyName} { constructor(){} providers() { return [ { inject:[LoggerService, ${this.repositoryImplName}], provide: UsecasesProxyModule.${this.createPostUseCaseProxyName}, useFactory: (logger: LoggerService, ${this.converted()}: ${ this.repositoryImplName }) => { return new UseCaseProxy(new ${ this.createUseCaseName }(logger, ${this.converted()})); } }, { inject: [LoggerService, ${this.repositoryImplName}], provide: UsecasesProxyModule.${this.updatePostUseCaseProxyName}, useFactory: (logger: LoggerService, ${this.converted()}: ${ this.repositoryImplName }) => { return new UseCaseProxy(new ${ this.updateUseCaseName }(logger, ${this.converted()})); } }, { inject: [LoggerService, ${this.repositoryImplName}], provide: UsecasesProxyModule.${this.deletePostUseCaseProxyName}, useFactory: (logger: LoggerService, ${this.converted()}: ${ this.repositoryImplName }) => { return new UseCaseProxy(new ${ this.deleteUseCaseName }(logger, ${this.converted()})); } }, { inject: [LoggerService, ${this.repositoryImplName}], provide: UsecasesProxyModule.${this.loadAllPostUseCaseProxyName}, useFactory: (logger: LoggerService, ${this.converted()}: ${ this.repositoryImplName }) => { return new UseCaseProxy(new ${ this.loadAllUseCaseName }(logger, ${this.converted()})); } }, { inject: [LoggerService, ${this.repositoryImplName}], provide: UsecasesProxyModule.${this.loadByIdPostUseCaseProxyName}, useFactory: (logger: LoggerService, ${this.converted()}: ${ this.repositoryImplName }) => { return new UseCaseProxy(new ${ this.loadByIdUseCaseName }(logger, ${this.converted()})); } } ] } } `; } getCreateActionContent() { return ` /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ import { ${this.createModelName} } from '@domain/models/${this.moduleNameLower}.model'; import { ${this.entityName} } from '@infrastructure/entities/${this.moduleNameLower}.entity'; import { QueryRunner } from 'typeorm'; export class ${this.createActionName} extends ${this.createModelName} { constructor(private readonly session: QueryRunner) { super(); } public Init(params: ${this.createModelName}): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.InitParams(params); await this.${this.createFunctionName}(); const response = { name: this.name, }; resolve(response); } catch (error) { reject(new Error(error)); } }); } private InitParams(params: ${this.createModelName}): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { // system // this.backendKey = params.backendKey; // this.platform = params.platform; this.name = params.name; resolve('InitParams completed'); } catch (error) { console.log('ERROR InitParams', error?.message); reject(new Error(error?.message)); } }); } private ${this.createFunctionName}(): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { const model: ${this.createModelName} = { name: this.name, isActive: true, createdAt: new Date(), updatedAt: new Date(), }; await this.session.manager.insert(${this.entityName}, model); resolve("${this.moduleNamePascal} created successfully"); } catch (error) { console.log('ERROR Create', error?.message); reject(new Error(error?.message)); } }); } } `; } getCreateValidationContent() { return ` /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ import { ${this.createModelName} } from '@domain/models/${ this.moduleNameLower }.model'; import { ${this.entityName} } from '@infrastructure/entities/${ this.moduleNameLower }.entity'; import { Repository } from 'typeorm'; export class ${this.createValidationName} extends ${this.createModelName} { constructor(private readonly ${this.converted()}Repository: Repository<${ this.entityName }>) { super(); } public Init(params: ${this.createModelName}): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.InitParams(params); await this.ValidateParams(); const response = {}; resolve(response); } catch (error) { reject(error instanceof Error ? error : new Error(String(error))); } }); } private InitParams(params: ${this.createModelName}): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { this.name = params.name; resolve('InitParams completed'); } catch (error) { console.log('ERROR InitParams', error?.message); reject(new Error(error?.message || 'Unknown error')); } }); } private ValidateParams(): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { if (!this.name) { throw new Error('Invalid params'); } resolve('ValidateParams completed'); } catch (error) { console.log('ERROR ValidateParams', error?.message); reject(new Error(error?.message || 'Unknown error')); } }); } } `; } getUpdateActionContent() { return ` /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable prettier/prettier */ import { ${this.updateModelName} } from '@domain/models/${this.moduleNameLower}.model'; import { ${this.entityName} } from '@infrastructure/entities/${this.moduleNameLower}.entity'; import { QueryRunner } from 'typeorm'; export class ${this.updateActionName} extends ${this.updateModelName} { constructor(private readonly session: QueryRunner) { super(); } public Init(params: ${this.updateModelName}): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.InitParams(params); await this.${this.updateFunctionName}(); const response = { name: this.name, }; resolve(response); } catch (error) { reject(error instanceof Error ? error : new Error(error)); } }); } private InitParams(params: ${this.updateModelName}): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { // system // this.backendKey = params.backendKey; // this.platform = params.platform; this.name = params.name; this._id = params._id; this.isActive = params.isActive; this.createdAt = params.createdAt; this.updatedAt = params.updatedAt; resolve('InitParams completed'); } catch (error) { console.log('ERROR InitParams', error?.message); reject(error?.message); } }); } private ${this.updateFunctionName}(): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { const condition = { _id: this._id, }; const model: ${this.updateModelName} = { _id: this._id, name: this.name, isActive: this.isActive, createdAt: this.createdAt, updatedAt: this.updatedAt, }; await this.session.manager.update(${this.entityName}, condition, model); resolve("${this.moduleNamePascal} updated successfully"); } catch (error) { console.log('ERROR Update', error?.message); reject(error instanceof Error ? error : new Error(error?.message)); } }); } } `; } getUpdateValidationContent() { return ` /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ import { ${this.updateModelName} } from '@domain/models/${ this.moduleNameLower }.model'; import { ${this.entityName} } from '@infrastructure/entities/${ this.moduleNameLower }.entity'; import { Repository } from 'typeorm'; export class ${this.updateValidationName} extends ${this.updateModelName} { constructor(private readonly ${this.converted()}Repository: Repository<${ this.entityName }>) { super(); } public Init(params: ${this.updateModelName}): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.InitParams(params); await this.ValidateParams(); const response = {}; resolve(response); } catch (error) { reject(error instanceof Error ? error : new Error(String(error))); } }); } private InitParams(params: ${this.updateModelName}): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { this.name = params.name; this._id = params._id; this.isActive = params.isActive; this.createdAt = params.createdAt; this.updatedAt = params.updatedAt; resolve('InitParams completed'); } catch (error) { console.log('ERROR InitParams', error?.message); reject(new Error(error?.message)); } }); } private ValidateParams(): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { if (!this.name) { throw new Error('Invalid params'); } resolve('ValidateParams completed'); } catch (error) { console.log('ERROR ValidateParams', error?.message); reject(new Error(error?.message)); } }); } } `; } getDeleteActionContent() { return ` /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable prettier/prettier */ import { ${this.deleteModelName} } from '@domain/models/${this.moduleNameLower}.model'; import { ${this.entityName} } from '@infrastructure/entities/${this.moduleNameLower}.entity'; import { QueryRunner } from 'typeorm'; export class ${this.deleteActionName} extends ${this.deleteModelName} { constructor(private readonly session: QueryRunner) { super(); } public Init(params: ${this.deleteModelName}): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.InitParams(params); await this.${this.deleteFunctionName}(); const response = { _id: this._id, }; resolve(response); } catch (error) { reject(error instanceof Error ? error : new Error(error)); } } ); } private InitParams(params: ${this.deleteModelName}): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { this._id = params._id; resolve('InitParams completed'); } catch (error) { console.log('ERROR InitParams', error?.message); reject(error?.message); } }); } private ${this.deleteFunctionName}(): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { const condition = { _id: this._id, }; await this.session.manager.delete(${this.entityName}, condition); resolve("${this.moduleNamePascal} deleted successfully"); } catch (error) { console.log('ERROR Delete', error?.message); reject(error instanceof Error ? error : new Error(error?.message)); } }); } } `; } getDeleteValidationContent() { return ` /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable prettier/prettier */ import { ${this.deleteModelName} } from '@domain/models/${ this.moduleNameLower }.model'; import { ${this.entityName} } from '@infrastructure/entities/${ this.moduleNameLower }.entity'; import { Repository } from 'typeorm'; export class ${this.deleteValidationName} extends ${this.deleteModelName} { constructor(private readonly ${this.converted()}Repository: Repository<${ this.entityName }>) { super(); } public Init(params: ${this.deleteModelName}): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.InitParams(params); await this.ValidateParams(); const response = {}; resolve(response); } catch (error) { reject(error instanceof Error ? error : new Error(String(error))); } }); } private InitParams(params: ${this.deleteModelName}): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { this._id = params._id; resolve('InitParams completed'); } catch (error) { console.log('ERROR InitParams', error?.message); reject(error?.message); } }); } private ValidateParams(): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { if (!this._id) { throw new Error('Invalid params'); } resolve('ValidateParams completed'); } catch (error) { console.log('ERROR ValidateParams', error?.message); reject(error?.message); } }); } } `; } getLoadAllActionContent() { return ` /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable prettier/prettier */ import { ${this.loadAllModelName}, ${this.responseModelName} } from '@domain/models/${this.moduleNameLower}.model'; import { ${this.entityName} } from '@infrastructure/entities/${this.moduleNameLower}.entity'; import { QueryRunner } from 'typeorm'; export class ${this.loadAllActionName} extends ${this.loadAllModelName} { constructor(private readonly session: QueryRunner) { super(); } public Init(): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.${this.loadAllFunctionName}(); const response = { name: this.name, }; resolve(response); } catch (error) { reject(new Error(error)); } }); } private ${this.loadAllFunctionName}(): Promise<${this.responseModelName}[]> { return new Promise<${this.responseModelName}[]>(async (resolve, reject) => { try { const entities = await this.session.manager.find(${this.entityName}); const result: ${this.responseModelName}[] = entities.map((entity) => ({ _id: entity._id, name: entity.name, isActive: entity.isActive, createdAt: entity.createdAt, updatedAt: entity.updatedAt, })); resolve(result); } catch (error) { console.log('ERROR LoadAll', error?.message); reject(new Error(error?.message)); } }); } } `; } getLoadAllValidationContent() { return ` /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable prettier/prettier */ import { ${this.loadAllModelName} } from '@domain/models/${ this.moduleNameLower }.model'; import { ${this.entityName} } from '@infrastructure/entities/${ this.moduleNameLower }.entity'; import { Repository } from 'typeorm'; export class ${this.loadAllValidationName} extends ${this.loadAllModelName} { constructor(private readonly ${this.converted()}Repository: Repository<${ this.entityName }>) { super(); } public Init(params: ${this.loadAllModelName}): Promise<any> { return new Promise<any>(async (resolve, reject) => { try { await this.InitParams(params); await this.ValidateParams(); const response = {}; resolve(response); } catch (error) { reject(error instanceof Error ? error : new Error(String(error))); } }); } private InitParams(params: ${this.loadAllModelName}): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { this.name = params.name; resolve('InitParams completed'); } catch (error) { console.log('ERROR InitParams', error?.message); reject(error?.message); } }); } private ValidateParams(): Promise<string> { return new Promise<string>(async (resolve, reject) => { try { if (!this.name) { throw new Error('Invalid params'); } resolve('ValidateParams completed'); } catch (error) { console.log('ERROR ValidateParams', error?.message); reject(error?.message); } }); } } `; } getLoadByIdActionContent() { return ` /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable no-async-promise-executor */ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable prettier/