UNPKG

kira-crud

Version:

Intelligent CRUD Generator for Laravel and Angular

288 lines (247 loc) 10.8 kB
/** * Angular Routes Updater * Utilité pour mettre à jour automatiquement les fichiers de routing Angular */ const fs = require('fs').promises; const path = require('path'); const chalk = require('chalk'); const { pascalCase, camelCase, kebabCase, pluralize } = require('./string-utils'); /** * Met à jour les fichiers de routing Angular pour un nouveau composant * @param {Object} config - Configuration du modèle * @param {string} outputDir - Chemin du composant généré * @param {string} angularPath - Chemin du projet Angular (optionnel) * @returns {Promise<boolean>} - Succès de l'opération */ async function updateAngularRoutes(config, outputDir, angularPath = null) { try { const modelName = config.model.name; const kebabCaseName = kebabCase(modelName); const pascalCaseName = pascalCase(modelName); const pluralKebabCase = kebabCase(pluralize(modelName)); // Définir les chemins des fichiers à mettre à jour const basePath = angularPath || process.cwd(); // Utiliser le chemin absolu pour garantir que les fichiers sont trouvés const pathsFile = path.resolve(basePath, 'src/app/paths.ts'); const routesFile = path.resolve(basePath, 'src/app/app.routes.ts'); const sidebarFile = path.resolve(basePath, 'src/app/shared/components/sidebar/sidebar.component.ts'); // Vérifier si les fichiers existent const pathsExists = await fileExists(pathsFile); const routesExists = await fileExists(routesFile); const sidebarExists = await fileExists(sidebarFile); if (!pathsExists || !routesExists || !sidebarExists) { console.log(chalk.yellow('Certains fichiers de routing n\'ont pas été trouvés. Mise à jour manuelle requise.')); return false; } // Mettre à jour paths.ts await updatePathsFile(pathsFile, kebabCaseName, pascalCaseName); // Mettre à jour app.routes.ts await updateRoutesFile(routesFile, kebabCaseName, pascalCaseName, outputDir); // Mettre à jour sidebar.component.ts await updateSidebarFile(sidebarFile, config); console.log(chalk.green('Fichiers de routing Angular mis à jour avec succès')); return true; } catch (error) { console.error(chalk.red(`Erreur lors de la mise à jour des routes Angular: ${error.message}`)); return false; } } /** * Met à jour le fichier paths.ts * @param {string} filePath - Chemin du fichier paths.ts * @param {string} routeName - Nom de la route en kebab-case * @param {string} componentName - Nom du composant en PascalCase */ async function updatePathsFile(filePath, routeName, componentName) { let content = await fs.readFile(filePath, 'utf8'); // Convertir le routeName en constante pour l'enum const enumName = routeName.replace(/-/g, '_').toUpperCase(); // Vérifier si la route existe déjà if (content.includes(`${enumName} =`)) { console.log(chalk.yellow(`La route ${enumName} existe déjà dans paths.ts`)); return; } // Ajouter la route dans l'enum const updatedContent = content.replace( /export enum Paths {([^}]*)}/, `export enum Paths {$1 ${enumName} = '${routeName}',\n}` ); // Écrire le fichier mis à jour await fs.writeFile(filePath, updatedContent, 'utf8'); console.log(chalk.green(`✓ Ajout de ${enumName} à paths.ts`)); } /** * Met à jour le fichier app.routes.ts * @param {string} filePath - Chemin du fichier app.routes.ts * @param {string} routeName - Nom de la route en kebab-case * @param {string} componentName - Nom du composant en PascalCase * @param {string} componentPath - Chemin du composant */ async function updateRoutesFile(filePath, routeName, componentName, componentPath) { let content = await fs.readFile(filePath, 'utf8'); // Vérifier si l'import existe déjà if (content.includes(`import { ${componentName}Component }`)) { console.log(chalk.yellow(`L'import pour ${componentName}Component existe déjà dans app.routes.ts`)); return; } // Convertir le routeName en constante pour l'enum et en route standard const enumName = routeName.replace(/-/g, '_').toUpperCase(); const routePath = routeName; // Route en kebab-case pour l'URL // Déterminer le chemin relatif du composant const relativePath = path.relative( path.dirname(filePath), componentPath ).replace(/\\/g, '/'); // Déterminer le chemin d'importation relatif let importPath; try { // Essayer de construire un chemin relatif à partir du dossier du fichier de routes importPath = path.relative( path.dirname(filePath), componentPath ).replace(/\\/g, '/'); // Si le chemin ne commence pas par ./ ou ../, ajouter ./ if (!importPath.startsWith('.')) { importPath = './' + importPath; } } catch (error) { // Fallback : utiliser un chemin standard basé sur la convention importPath = `./pages/admin/settings/${routeName}/${routeName}.component`; } // Ajouter l'import en haut du fichier // S'assurer que le chemin d'importation contient bien le nom du composant if (!importPath.endsWith('.component')) { // Si le chemin ne se termine pas par '.component', ajouter '/<kebab-case>.component' importPath = importPath.replace(/\/?$/, `/${routeName}.component`); } let importStatement = `import { ${componentName}Component } from '${importPath}';`; // Plusieurs modèles d'import à rechercher const importPatterns = [ /import { Routes } from '@angular\/router';.*/, /import .* from '@angular\/router';.*/, /import .* from '.*/ ]; let updatedContent = content; let importInserted = false; for (const pattern of importPatterns) { if (pattern.test(content)) { updatedContent = content.replace( pattern, match => `${match}\n${importStatement}` ); importInserted = true; break; } } // Si aucun modèle ne correspond, ajouter au début du fichier if (!importInserted) { updatedContent = `${importStatement}\n\n${content}`; } // Ajouter la route dans le tableau de routes // D'abord vérifier si la route existe déjà if (content.includes(`path: Paths.${enumName}`)) { console.log(chalk.yellow(`La route pour Paths.${enumName} existe déjà dans app.routes.ts`)); // Écrire quand même le fichier pour conserver les importations await fs.writeFile(filePath, updatedContent, 'utf8'); return; } // Trouver l'endroit où insérer la route // Rechercher le tableau des routes et insérer juste avant le crochet fermant const routeInsertionPattern = /(\n\s*\]\s*;)/; if (routeInsertionPattern.test(updatedContent)) { updatedContent = updatedContent.replace( routeInsertionPattern, `,\n {\n path: Paths.${enumName},\n component: ${componentName}Component\n }\n];` ); } else { // Rechercher d'autres modèles possibles const routePatterns = [ /\/\/ Routes générées automatiquement seront ajoutées ici/, /\/\/ Auto-generated routes will be added here/, /export const routes: Routes = \[/ ]; let routeInserted = false; for (const pattern of routePatterns) { if (pattern.test(updatedContent)) { if (pattern === routePatterns[2]) { // Si c'est le modèle de déclaration de routes, ajouter après le crochet d'ouverture updatedContent = updatedContent.replace( pattern, `export const routes: Routes = [\n {\n path: Paths.${enumName},\n component: ${componentName}Component\n },` ); } else { // Pour les commentaires, remplacer le commentaire updatedContent = updatedContent.replace( pattern, `${pattern.source}\n {\n path: Paths.${enumName},\n component: ${componentName}Component\n },` ); } routeInserted = true; break; } } // Si toujours pas inséré, essayer d'autres modèles de tableaux de routes if (!routeInserted) { if (updatedContent.includes('const routes: Routes = []')) { updatedContent = updatedContent.replace( /const routes: Routes = \[\s*\]/, `const routes: Routes = [\n {\n path: Paths.${enumName},\n component: ${componentName}Component\n }\n]` ); } else if (updatedContent.includes('export const routes: Routes = []')) { updatedContent = updatedContent.replace( /export const routes: Routes = \[\s*\]/, `export const routes: Routes = [\n {\n path: Paths.${enumName},\n component: ${componentName}Component\n }\n]` ); } else { // Dernière tentative: créer le tableau de routes s'il n'existe pas updatedContent += `\n\nexport const routes: Routes = [\n {\n path: Paths.${enumName},\n component: ${componentName}Component\n }\n];\n`; } } } // Écrire le fichier mis à jour await fs.writeFile(filePath, updatedContent, 'utf8'); console.log(chalk.green(`✓ Ajout de la route pour ${componentName}Component à app.routes.ts`)); } /** * Met à jour le fichier sidebar.component.ts * @param {string} filePath - Chemin du fichier sidebar.component.ts * @param {Object} config - Configuration du modèle */ async function updateSidebarFile(filePath, config) { let content = await fs.readFile(filePath, 'utf8'); const modelName = config.model.name; const kebabCaseName = kebabCase(modelName); const enumName = kebabCaseName.replace(/-/g, '_').toUpperCase(); const displayName = config.model.displayName || modelName; const menuIcon = config.routes?.menuIcon || 'list'; const menuTitle = config.routes?.menuTitle || displayName; // Vérifier si le menu existe déjà if (content.includes(`link: this.paths.${enumName}`)) { console.log(chalk.yellow(`Le menu pour ${menuTitle} existe déjà dans sidebar.component.ts`)); return; } // Ajouter un élément au menu const updatedContent = content.replace( /this\.menuConfig = \[([\s\S]*?)\];/, `this.menuConfig = [$1 {\n label: '${menuTitle}',\n link: this.paths.${enumName},\n icon: '${menuIcon}',\n guarded: true,\n },\n ];` ); // Écrire le fichier mis à jour await fs.writeFile(filePath, updatedContent, 'utf8'); console.log(chalk.green(`✓ Ajout du menu pour ${menuTitle} à sidebar.component.ts`)); } /** * Vérifie si un fichier existe * @param {string} filePath - Chemin du fichier * @returns {Promise<boolean>} - Le fichier existe */ async function fileExists(filePath) { try { await fs.access(filePath); return true; } catch (error) { return false; } } module.exports = { updateAngularRoutes };