diff --git a/src/app.module.ts b/src/app.module.ts index adb178a..800d284 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -8,6 +8,7 @@ import { ModuleUpdaterService } from './services/module-updater.service'; import { AngularGeneratorService } from './services/angular-generator.service'; import { TemplateService } from './services/template.service'; import { GenericTableGeneratorService } from './services/generic-table-generator.service'; +import { FileSystemService } from './services/file-system.service'; @Module({ imports: [], @@ -19,7 +20,8 @@ import { GenericTableGeneratorService } from './services/generic-table-generator ModuleUpdaterService, AngularGeneratorService, TemplateService, - GenericTableGeneratorService + GenericTableGeneratorService, + FileSystemService ], }) export class AppModule {} diff --git a/src/commands/generate.command.ts b/src/commands/generate.command.ts index f355d77..142fb53 100644 --- a/src/commands/generate.command.ts +++ b/src/commands/generate.command.ts @@ -1,9 +1,14 @@ // src/commands/generate.command.ts -import { Command, CommandRunner } from 'nest-commander'; +import { Command, CommandRunner, Option } from 'nest-commander'; import { EntityGeneratorService } from '../services/entity-generator.service'; import { CrudGeneratorService } from '../services/crud-generator.service'; import { AngularGeneratorService } from '../services/angular-generator.service'; +interface GenerateCommandOptions { + force: boolean; +} + + @Command({ name: 'generate', description: 'Generate code for the dvbooking project', @@ -19,8 +24,9 @@ export class GenerateCommand extends CommandRunner { super(); } - async run(passedParams: string[]): Promise { + async run(passedParams: string[], options?: GenerateCommandOptions): Promise { const [type, name] = passedParams; + const force = options?.force || false; // Default force to false if (!type || !name) { console.error('Error: Missing required arguments: and .'); @@ -31,20 +37,21 @@ export class GenerateCommand extends CommandRunner { switch (type) { case 'entity': - await this.entityGeneratorService.generate(name); + await this.entityGeneratorService.generate(name, force); break; case 'crud': - await this.crudGeneratorService.generate(name); + //await this.crudGeneratorService.generate(name,force); break; - case 'angular': // <-- 3. Add new case - await this.angularGeneratorService.generate(name); + case 'angular': + // todo: implement + // await this.angularGeneratorService.generate(name,force); break; case 'all': console.log('--- Generating Entity ---'); - const columns = await this.entityGeneratorService.generate(name); + const columns = await this.entityGeneratorService.generate(name, force); if (!columns) { console.error('❌ Entity generation failed. Aborting subsequent steps.'); @@ -52,10 +59,10 @@ export class GenerateCommand extends CommandRunner { } console.log('\n--- Generating CRUD Module ---'); - await this.crudGeneratorService.generate(name, columns); + await this.crudGeneratorService.generate(name, columns, force); console.log('\n✨ All backend files generated successfully! ✨'); console.log('\n--- Generating Angular Files ---'); - await this.angularGeneratorService.generate(name,columns); + await this.angularGeneratorService.generate(name,columns, force); console.log('\n✨ All files generated successfully! ✨'); break; @@ -64,4 +71,14 @@ export class GenerateCommand extends CommandRunner { break; } } + + // NEW: Add the --force option + @Option({ + flags: '-f, --force', + description: 'Overwrite existing files.', + defaultValue: false, + }) + parseForce(): boolean { + return true; + } } \ No newline at end of file diff --git a/src/services/angular-generator.service.ts b/src/services/angular-generator.service.ts index ab843a3..3bc7d88 100644 --- a/src/services/angular-generator.service.ts +++ b/src/services/angular-generator.service.ts @@ -9,6 +9,7 @@ import { promises as fsPromises } from 'fs'; import { TableColumn } from 'typeorm'; import { GenericTableGeneratorService } from './generic-table-generator.service'; import { mapDbToTsType, toCamelCase, toKebabCase, toPascalCase, toSingular } from '../utils/naming.utils'; +import { FileSystemService } from './file-system.service'; // Interface for structured field metadata passed to templates interface FieldDefinition { @@ -34,9 +35,10 @@ export class AngularGeneratorService { private readonly templateService: TemplateService, private readonly moduleUpdaterService: ModuleUpdaterService, private readonly genericTableGeneratorService: GenericTableGeneratorService, + private readonly fileSystemService: FileSystemService, ) {} - public async generate(tableName: string, columns?: TableColumn[]): Promise { + public async generate(tableName: string, columns: TableColumn[], force: boolean): Promise { console.log(`Generating Angular module for table: ${tableName}...`); const names = this.getNamingConvention(tableName); @@ -69,40 +71,40 @@ export class AngularGeneratorService { const featureDir = path.join(adminRoot, 'src', 'app', 'features', names.plural); try { - await this.generateModel(names, featureDir); - await this.generateService(names, featureDir); - await this.generateFilterComponent(names, featureDir); - await this.generateListComponent(names, featureDir); - - // 3. New Generic Table View - const tableCompPath = await this.generateTableComponent(tableName, columns || [], names, featureDir); - - // 4. Details & Form Views - await this.generateDetailsComponent(names, featureDir); - await this.generateFormComponent(names, featureDir); + await this.generateModel(names, featureDir, force); + await this.generateService(names, featureDir, force); + await this.generateFilterComponent(names, featureDir, force); + await this.generateListComponent(names, featureDir, force); + const tableCompPath = await this.generateTableComponent(tableName, columns || [], names, featureDir,force); + await this.generateDetailsComponent(names, featureDir, force); + await this.generateFormComponent(names, featureDir, force); const listCompPath = path.join(featureDir, 'components', `${names.singular}-list`, `${names.singular}-list.component.ts`); const detailsCompPath = path.join(featureDir, 'components', `${names.singular}-details`, `${names.singular}-details.component.ts`); const formCompPath = path.join(featureDir, 'components', `${names.singular}-form`, `${names.singular}-form.component.ts`); - await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}FormComponent`, formCompPath, `${names.plural}/new`); - await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}FormComponent`, formCompPath, `${names.plural}/:id/edit`); - await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}DetailsComponent`, detailsCompPath, `${names.plural}/:id`); + // Define the auth object. The role is the kebab-cased singular name (e.g., 'event-type') + const auth = { role: 'admin' }; - await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}TableComponent`, tableCompPath, `${names.plural}/table`); - await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}ListComponent`, listCompPath, names.plural); + // Pass the auth object to each route registration call + await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}FormComponent`, formCompPath, `${names.plural}/new`, auth); + await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}FormComponent`, formCompPath, `${names.plural}/:id/edit`, auth); + await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}DetailsComponent`, detailsCompPath, `${names.plural}/:id`, auth); + await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}TableComponent`, tableCompPath, `${names.plural}/table`, auth); + await this.moduleUpdaterService.addRouteToAngularApp(`${names.pascal}ListComponent`, listCompPath, names.plural, auth); + // --- END OF FIX --- console.log(`✅ Angular files for "${tableName}" created successfully in: ${featureDir}`); - console.log('\n✨ app.routes.ts has been updated with full CRUD routes (List + Table)! ✨'); + console.log('\n✨ app.routes.ts has been updated with full, secured CRUD routes! ✨'); } catch (error) { console.error(`❌ An error occurred during Angular generation:`, error.message); } } -private async generateTableComponent(tableName: string, columns: TableColumn[], names: NamingConvention, featureDir: string): Promise { +private async generateTableComponent(tableName: string, columns: TableColumn[], names: NamingConvention, featureDir: string, force: boolean): Promise { // This method now correctly calls the renamed service - return this.genericTableGeneratorService.generate(tableName, columns, names, featureDir); + return this.genericTableGeneratorService.generate(tableName, columns, names, featureDir, force); } private getFormFieldHtml(field: FieldDefinition, isFilter: boolean = false): string { @@ -128,51 +130,51 @@ private async generateTableComponent(tableName: string, columns: TableColumn[], } // ... (All other generate... and naming methods are unchanged) - private async generateModel(names: NamingConvention, featureDir: string) { + private async generateModel(names: NamingConvention, featureDir: string, force: boolean) { const modelsDir = path.join(featureDir, 'models'); const content = this.templateService.render('angular/model.ts.tpl', names); const filePath = path.join(modelsDir, `${names.singular}.model.ts`); await fsPromises.mkdir(modelsDir, { recursive: true }); - fs.writeFileSync(filePath, content); + await this.fileSystemService.writeFile(filePath, content, force); } - private async generateService(names: NamingConvention, featureDir: string) { + private async generateService(names: NamingConvention, featureDir: string, force: boolean) { const servicesDir = path.join(featureDir, 'services'); const content = this.templateService.render('angular/service.ts.tpl', names); const filePath = path.join(servicesDir, `${names.singular}.service.ts`); await fsPromises.mkdir(servicesDir, { recursive: true }); - fs.writeFileSync(filePath, content); + await this.fileSystemService.writeFile(filePath, content, force); } - private async generateFilterComponent(names: NamingConvention, featureDir: string) { + private async generateFilterComponent(names: NamingConvention, featureDir: string, force: boolean) { const compDir = path.join(featureDir, 'components', `${names.singular}-filter`); const tsContent = this.templateService.render('angular/filter.component.ts.tpl', names); const htmlContent = this.templateService.render('angular/filter.component.html.tpl', names); await fsPromises.mkdir(compDir, { recursive: true }); - fs.writeFileSync(path.join(compDir, `${names.singular}-filter.component.ts`), tsContent); - fs.writeFileSync(path.join(compDir, `${names.singular}-filter.component.html`), htmlContent); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-filter.component.ts`), tsContent, force); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-filter.component.html`), htmlContent, force); } - private async generateListComponent(names: NamingConvention, featureDir: string) { + private async generateListComponent(names: NamingConvention, featureDir: string, force: boolean) { const compDir = path.join(featureDir, 'components', `${names.singular}-list`); const tsContent = this.templateService.render('angular/list.component.ts.tpl', names); const htmlContent = this.templateService.render('angular/list.component.html.tpl', names); await fsPromises.mkdir(compDir, { recursive: true }); - fs.writeFileSync(path.join(compDir, `${names.singular}-list.component.ts`), tsContent); - fs.writeFileSync(path.join(compDir, `${names.singular}-list.component.html`), htmlContent); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-list.component.ts`), tsContent, force); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-list.component.html`), htmlContent, force); } - private async generateDetailsComponent(names: NamingConvention, featureDir: string) { + private async generateDetailsComponent(names: NamingConvention, featureDir: string, force: boolean) { const compDir = path.join(featureDir, 'components', `${names.singular}-details`); const tsContent = this.templateService.render('angular/details.component.ts.tpl', names); const htmlContent = this.templateService.render('angular/details.component.html.tpl', names); await fsPromises.mkdir(compDir, { recursive: true }); - fs.writeFileSync(path.join(compDir, `${names.singular}-details.component.ts`), tsContent); - fs.writeFileSync(path.join(compDir, `${names.singular}-details.component.html`), htmlContent); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-details.component.ts`), tsContent, force); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-details.component.html`), htmlContent, force); } - private async generateFormComponent(names: NamingConvention, featureDir: string) { + private async generateFormComponent(names: NamingConvention, featureDir: string, force: boolean) { const compDir = path.join(featureDir, 'components', `${names.singular}-form`); const tsContent = this.templateService.render('angular/form.component.ts.tpl', names); const htmlContent = this.templateService.render('angular/form.component.html.tpl', names); await fsPromises.mkdir(compDir, { recursive: true }); - fs.writeFileSync(path.join(compDir, `${names.singular}-form.component.ts`), tsContent); - fs.writeFileSync(path.join(compDir, `${names.singular}-form.component.html`), htmlContent); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-form.component.ts`), tsContent, force); + await this.fileSystemService.writeFile(path.join(compDir, `${names.singular}-form.component.html`), htmlContent, force); } private getNamingConvention(tableName: string): NamingConvention { const singular = toSingular(tableName); diff --git a/src/services/crud-generator.service.ts b/src/services/crud-generator.service.ts index 06bbc26..336396e 100644 --- a/src/services/crud-generator.service.ts +++ b/src/services/crud-generator.service.ts @@ -5,9 +5,9 @@ import { ModuleUpdaterService } from './module-updater.service'; import { TemplateService } from './template.service'; import { TableColumn } from 'typeorm'; import * as path from 'path'; -import * as fs from 'fs'; import { promises as fsPromises } from 'fs'; import { toCamelCase, toKebabCase, toPascalCase, toSingular } from '../utils/naming.utils'; +import { FileSystemService } from './file-system.service'; interface NamingConvention { [key: string]: string; @@ -24,9 +24,10 @@ export class CrudGeneratorService { private readonly configService: ConfigService, private readonly moduleUpdaterService: ModuleUpdaterService, private readonly templateService: TemplateService, + private readonly fileSystemService: FileSystemService, ) {} - public async generate(tableName: string, columns?: TableColumn[]): Promise { + public async generate(tableName: string, columns: TableColumn[] , force: boolean): Promise { console.log(`Generating CRUD module for table: ${tableName}...`); const names = this.getNamingConvention(tableName, columns); const config = this.configService.get(); @@ -41,10 +42,10 @@ export class CrudGeneratorService { names['entityPathForModule'] = path.relative(moduleDir, entityFullPath).replace(/\\/g, '/').replace('.ts', ''); names['entityPathForDtos'] = path.relative(path.join(moduleDir, 'dto'), entityFullPath).replace(/\\/g, '/').replace('.ts', ''); - await this.generateModuleFile(names, moduleDir); - await this.generateControllerFile(names, moduleDir); - await this.generateServiceFile(names, moduleDir); - await this.generateDtoFiles(names, moduleDir); + await this.generateModuleFile(names, moduleDir, force); + await this.generateControllerFile(names, moduleDir, force); + await this.generateServiceFile(names, moduleDir, force); + await this.generateDtoFiles(names, moduleDir, force); const moduleFileName = `${names.plural}.module.ts`; const fullModulePath = path.join(moduleDir, moduleFileName); @@ -57,39 +58,39 @@ export class CrudGeneratorService { } } - private async generateModuleFile(names: NamingConvention, moduleDir: string) { + private async generateModuleFile(names: NamingConvention, moduleDir: string, force: boolean) { // Use the pre-calculated path const content = this.templateService.render('nestjs/module.ts.tpl', { ...names, entityPath: names['entityPathForModule'] }); const filePath = path.join(moduleDir, `${names.plural}.module.ts`); await fsPromises.mkdir(moduleDir, { recursive: true }); - fs.writeFileSync(filePath, content); + await this.fileSystemService.writeFile(filePath, content, force); } - private async generateControllerFile(names: NamingConvention, moduleDir: string) { + private async generateControllerFile(names: NamingConvention, moduleDir: string, force: boolean) { const content = this.templateService.render('nestjs/controller.ts.tpl', names); const filePath = path.join(moduleDir, `${names.plural}.controller.ts`); await fsPromises.mkdir(moduleDir, { recursive: true }); - fs.writeFileSync(filePath, content); + await this.fileSystemService.writeFile(filePath, content, force); } - private async generateServiceFile(names: NamingConvention, moduleDir: string) { + private async generateServiceFile(names: NamingConvention, moduleDir: string, force: boolean) { // Use the pre-calculated path const content = this.templateService.render('nestjs/service.ts.tpl', { ...names, entityPath: names['entityPathForModule'] }); const filePath = path.join(moduleDir, `${names.plural}.service.ts`); await fsPromises.mkdir(moduleDir, { recursive: true }); - fs.writeFileSync(filePath, content); + await this.fileSystemService.writeFile(filePath, content, force); } - private async generateDtoFiles(names: NamingConvention, moduleDir: string) { + private async generateDtoFiles(names: NamingConvention, moduleDir: string, force: boolean) { const dtoDir = path.join(moduleDir, 'dto'); await fsPromises.mkdir(dtoDir, { recursive: true }); // Use the pre-calculated path const dtoNames = { ...names, entityPath: names['entityPathForDtos'] }; - fs.writeFileSync(path.join(dtoDir, `create-${names.singular}.dto.ts`), this.templateService.render('nestjs/create-dto.ts.tpl', dtoNames)); - fs.writeFileSync(path.join(dtoDir, `update-${names.singular}.dto.ts`), this.templateService.render('nestjs/update-dto.ts.tpl', dtoNames)); - fs.writeFileSync(path.join(dtoDir, `query-${names.singular}.dto.ts`), this.templateService.render('nestjs/query-dto.ts.tpl', dtoNames)); + await this.fileSystemService.writeFile(path.join(dtoDir, `create-${names.singular}.dto.ts`), this.templateService.render('nestjs/create-dto.ts.tpl', dtoNames), force); + await this.fileSystemService.writeFile(path.join(dtoDir, `update-${names.singular}.dto.ts`), this.templateService.render('nestjs/update-dto.ts.tpl', dtoNames), force); + await this.fileSystemService.writeFile(path.join(dtoDir, `query-${names.singular}.dto.ts`), this.templateService.render('nestjs/query-dto.ts.tpl', dtoNames), force); } // --- NAMING HELPERS --- diff --git a/src/services/entity-generator.service.ts b/src/services/entity-generator.service.ts index 76ccbe8..3df957d 100644 --- a/src/services/entity-generator.service.ts +++ b/src/services/entity-generator.service.ts @@ -8,16 +8,18 @@ import * as path from 'path'; import * as fs from 'fs'; import { promises as fsPromises } from 'fs'; import { mapDbToTsType, toPascalCase, toSingular } from '../utils/naming.utils'; +import { FileSystemService } from './file-system.service'; @Injectable() export class EntityGeneratorService { constructor( private readonly configService: ConfigService, private readonly moduleUpdaterService: ModuleUpdaterService, - private readonly templateService: TemplateService, // <-- 2. INJECT TemplateService + private readonly templateService: TemplateService, + private readonly fileSystemService: FileSystemService, ) {} - public async generate(tableName: string): Promise { + public async generate(tableName: string, force: boolean): Promise { console.log(`Generating entity for table: ${tableName}...`); const config = this.configService.get(); @@ -68,7 +70,7 @@ export class EntityGeneratorService { const outputPath = path.join(entitiesDir, entityFileName); await fsPromises.mkdir(entitiesDir, { recursive: true }); - fs.writeFileSync(outputPath, entityContent); + await this.fileSystemService.writeFile(outputPath, entityContent, force); console.log(`✅ Entity created successfully at: ${outputPath}`); await this.moduleUpdaterService.addEntityToTypeOrm(className, outputPath); diff --git a/src/services/file-system.service.ts b/src/services/file-system.service.ts new file mode 100644 index 0000000..513a281 --- /dev/null +++ b/src/services/file-system.service.ts @@ -0,0 +1,41 @@ +// src/services/file-system.service.ts +import { Injectable } from '@nestjs/common'; +import * as fs from 'fs'; +import { promises as fsPromises } from 'fs'; +import * as path from 'path'; + +@Injectable() +export class FileSystemService { + + /** + * Writes content to a file, but only if the file does not already exist, + * or if the 'force' flag is set to true. + * + * @param filePath The full path to the file. + * @param content The content to write. + * @param force If true, overwrites the file even if it exists. + */ + public async writeFile(filePath: string, content: string, force: boolean): Promise { + if (!force && fs.existsSync(filePath)) { + console.warn(`⚠️ SKIPPED: File already exists at ${filePath}. Use --force to overwrite.`); + return; + } + + try { + // Ensure the directory exists before writing the file + const dir = path.dirname(filePath); + await fsPromises.mkdir(dir, { recursive: true }); + + fs.writeFileSync(filePath, content); + + if (force && fs.existsSync(filePath)) { + console.log(`✅ OVERWRITTEN: ${filePath}`); + } else { + console.log(`✅ CREATED: ${filePath}`); + } + + } catch (error) { + console.error(`❌ FAILED to write file at ${filePath}:`, error.message); + } + } +} \ No newline at end of file diff --git a/src/services/generic-table-generator.service.ts b/src/services/generic-table-generator.service.ts index 43f25bf..f15f45a 100644 --- a/src/services/generic-table-generator.service.ts +++ b/src/services/generic-table-generator.service.ts @@ -6,19 +6,22 @@ import * as path from 'path'; import * as fs from 'fs'; import { promises as fsPromises } from 'fs'; import { mapDbToTsType } from '../utils/naming.utils'; +import { FileSystemService } from './file-system.service'; interface FieldDefinition { name: string; tsType: string; } interface NamingConvention { [key: string]: string; /*...*/ } @Injectable() export class GenericTableGeneratorService { - constructor(private readonly templateService: TemplateService) {} + constructor(private readonly templateService: TemplateService, + private readonly fileSystemService: FileSystemService,) {} public async generate( tableName: string, columns: TableColumn[], names: NamingConvention, featureDir: string, + force: boolean ): Promise { console.log(`Generating Generic Table View for ${tableName}...`); @@ -34,21 +37,24 @@ export class GenericTableGeneratorService { await fsPromises.mkdir(compDir, { recursive: true }); // Generate Data Provider - fs.writeFileSync( + await this.fileSystemService.writeFile( path.join(compDir, `${names.singular}-data-provider.service.ts`), this.templateService.render('angular-generic/data-provider.service.ts.tpl', names), + force ); // Generate Table Component TS - fs.writeFileSync( + await this.fileSystemService.writeFile( path.join(compDir, `${names.singular}-table.component.ts`), this.templateService.render('angular-generic/table.component.ts.tpl', names), + force ); // Generate Table Component HTML - fs.writeFileSync( + await this.fileSystemService.writeFile( path.join(compDir, `${names.singular}-table.component.html`), this.templateService.render('angular-generic/table.component.html.tpl', names), + force ); return path.join(compDir, `${names.singular}-table.component.ts`); diff --git a/src/services/module-updater.service.ts b/src/services/module-updater.service.ts index 4b7d0ec..eb8bff5 100644 --- a/src/services/module-updater.service.ts +++ b/src/services/module-updater.service.ts @@ -115,6 +115,7 @@ export class ModuleUpdaterService { componentNameToAdd: string, componentPath: string, routeName: string, + auth?: { role: string } // NEW: Optional auth parameter ): Promise { const config = this.configService.get(); const adminRoot = path.resolve(process.cwd(), config.admin.path); @@ -126,37 +127,48 @@ export class ModuleUpdaterService { const project = new Project(); const sourceFile = project.addSourceFileAtPath(appRoutesPath); - const relativeComponentPath = path - .relative(path.dirname(appRoutesPath), componentPath) - .replace(/\\/g, '/') - .replace('.ts', ''); - - const existingImport = sourceFile.getImportDeclaration( - (d) => d.getModuleSpecifierValue() === `./${relativeComponentPath}`, - ); - - if (!existingImport) { - sourceFile.addImportDeclaration({ - namedImports: [componentNameToAdd], - moduleSpecifier: `./${relativeComponentPath}`, - }); + // 1. Add Component Import (unchanged) + const relativeComponentPath = path.relative(path.dirname(appRoutesPath), componentPath).replace(/\\/g, '/').replace('.ts', ''); + const existingCompImport = sourceFile.getImportDeclaration(d => d.getModuleSpecifierValue() === `./${relativeComponentPath}`); + if (!existingCompImport) { + sourceFile.addImportDeclaration({ namedImports: [componentNameToAdd], moduleSpecifier: `./${relativeComponentPath}` }); console.log(`Added import for component ${componentNameToAdd}.`); - } else { - console.log(`Import for component ${componentNameToAdd} already exists.`); } + // 2. Add AuthGuard Import if needed + if (auth) { + // NOTE: This assumes a specific path for your AuthGuard. Adjust if necessary. + const authGuardPath = './auth/auth.guard'; + const existingAuthImport = sourceFile.getImportDeclaration(d => d.getModuleSpecifierValue() === authGuardPath); + if (!existingAuthImport) { + sourceFile.addImportDeclaration({ namedImports: ['AuthGuard'], moduleSpecifier: authGuardPath }); + console.log('Added import for AuthGuard.'); + } + } + + // 3. Find routes array (unchanged) const routesDeclaration = sourceFile.getVariableDeclarationOrThrow('routes'); - const routesArray = routesDeclaration.getInitializerIfKindOrThrow( - SyntaxKind.ArrayLiteralExpression, - ); + const routesArray = routesDeclaration.getInitializerIfKindOrThrow(SyntaxKind.ArrayLiteralExpression); - const routeAlreadyExists = routesArray - .getElements() - .some((elem) => elem.getText().includes(`path: '${routeName}'`)); + // 4. Build the Route Object String + let routeObjectString = `{ path: '${routeName}', component: ${componentNameToAdd} }`; + if (auth) { + // If auth is requested, build a multi-line string for the route object + routeObjectString = `{ + path: '${routeName}', + component: ${componentNameToAdd}, + canActivate: [AuthGuard], + data: { + roles: ['${auth.role}'], + }, + }`; + } + // 5. Check existence and insert the route + const routeAlreadyExists = routesArray.getElements().some((elem) => elem.getText().includes(`path: '${routeName}'`)); if (!routeAlreadyExists) { - routesArray.insertElement(0, `{ path: '${routeName}', component: ${componentNameToAdd} }`); - console.log(`Added route for path '${routeName}' to the beginning of the routes array.`); + routesArray.insertElement(0, routeObjectString); + console.log(`Added route for path '${routeName}' with auth config.`); } else { console.log(`Route for path '${routeName}' already exists.`); }