kira-crud
Version:
Intelligent CRUD Generator for Laravel and Angular
288 lines (247 loc) • 10.8 kB
JavaScript
/**
* 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
};