import { DMMF } from '@prisma/generator-helper'; import * as path from 'path'; import * as fs from 'fs/promises'; import { toKebabCase } from './utils/string-formatter'; interface GenerateModulesOptions { models: DMMF.Model[]; outputDir: string; } /** * Generate NestJS module for each model */ export async function generateModules(options: GenerateModulesOptions): Promise { const { models, outputDir } = options; // Generate individual module for each model for (const model of models) { await generateModelModule(model, outputDir); await generateModelIndexFile(model, outputDir); } // Generate index file for system-context module await generateSystemContextIndexFile(outputDir); // Generate root module that imports all model modules await generateRootModule(models, outputDir); } /** * Generate a NestJS module file for a specific model */ async function generateModelModule(model: DMMF.Model, outputDir: string): Promise { const modelName = model.name; const fileName = `${toKebabCase(modelName)}.module.ts`; const filePath = path.join(outputDir, toKebabCase(modelName), fileName); const controllerName = `${modelName}Controller`; const serviceName = `${modelName}Service`; let content = `import { Module } from '@nestjs/common';\n`; content += `import { ${controllerName} } from './${toKebabCase(modelName)}.controller';\n`; content += `import { ${serviceName} } from './${toKebabCase(modelName)}.service';\n`; content += `import { PrismaModule } from '../prisma';\n`; content += `import { SystemContextModule } from '../system-context';\n\n`; content += `@Module({\n`; content += ` controllers: [${controllerName}],\n`; content += ` providers: [${serviceName}],\n`; content += ` imports: [PrismaModule, SystemContextModule],\n`; content += ` exports: [${serviceName}],\n`; content += `})\n`; content += `export class ${modelName}Module {}\n`; try { await fs.access(filePath); // File exists, don't overwrite it } catch (error) { // File doesn't exist, create it await fs.writeFile(filePath, content); } } /** * Generate an index file for a model that exports all relevant components */ async function generateModelIndexFile(model: DMMF.Model, outputDir: string): Promise { const modelName = model.name; const indexPath = path.join(outputDir, toKebabCase(modelName), 'index.ts'); let content = ``; content += `export * from './${toKebabCase(modelName)}.controller';\n`; content += `export * from './${toKebabCase(modelName)}.service';\n`; content += `export * from './${toKebabCase(modelName)}.module';\n`; content += `export * from './dto';\n`; try { await fs.access(indexPath); // File exists, don't overwrite it } catch (error) { // File doesn't exist, create it await fs.writeFile(indexPath, content); } } /** * Generate an index file for the SystemContext module */ async function generateSystemContextIndexFile(outputDir: string): Promise { const fileName = 'index.ts'; const filePath = path.join(outputDir, 'system-context', fileName); let content = `// Export all components from SystemContext module `; content += `export * from './system-context.module';\n`; content += `export * from './system-context.service';\n`; await fs.writeFile(filePath, content); } /** * Generate a root module that imports all model modules */ async function generateRootModule(models: DMMF.Model[], outputDir: string): Promise { const fileName = 'app.module.ts'; const filePath = path.join(outputDir, fileName); let imports = ''; let modulesList = ''; for (const model of models) { const modelName = model.name; imports += `import { ${modelName}Module } from './${toKebabCase(modelName)}';\n`; modulesList += ` ${modelName}Module,\n`; } let content = `import { Module } from '@nestjs/common';\n`; content += `import { PrismaModule } from './prisma';\n`; content += `import { SystemContextModule } from './system-context';\n`; content += imports; content += `@Module({\n`; content += ` imports: [\n`; content += ` PrismaModule,\n`; content += ` SystemContextModule,\n`; content += modulesList; content += ` ],\n`; content += ` exports: [\n`; content += ` SystemContextModule,\n`; content += modulesList; content += ` ],\n`; content += `})\n`; content += `export class AppModule {}\n`; try { await fs.access(filePath); // File exists, don't overwrite it } catch (error) { // File doesn't exist, create it await fs.writeFile(filePath, content); } }