kira-crud
Version:
Intelligent CRUD Generator for Laravel and Angular
240 lines (205 loc) • 6.7 kB
JavaScript
#!/usr/bin/env node
/**
* Custom Generator CLI
* Generates Angular components following the project structure
*/
const chalk = require('chalk');
const ora = require('ora');
const figlet = require('figlet');
const boxen = require('boxen');
const path = require('path');
const fs = require('fs').promises;
const inquirer = require('inquirer');
const { program } = require('commander');
const gradient = require('gradient-string');
const yaml = require('js-yaml');
const AngularCustomGenerator = require('./generators/angular-custom-generator');
const { validateConfigFile, displayValidationResults } = require('./utils/config-validator');
// Constants for styling
const titleGradient = gradient(['#4285F4', '#34A853']);
/**
* Display the banner
*/
function displayBanner() {
console.log(
titleGradient.multiline(
figlet.textSync('Kira Custom', {
font: 'Small',
horizontalLayout: 'default'
})
)
);
console.log(
boxen(
`${chalk.bold('KIRA Custom Generator')} ${chalk.dim('v1.0.0')}\n` +
`Generate Angular components that match your project structure`,
{
padding: 1,
margin: { top: 1, bottom: 1 },
borderStyle: 'round',
borderColor: 'green'
}
)
);
}
/**
* Find configuration files in a directory
* @param {string} directory - Directory to search
* @returns {Promise<Array>} - List of configuration files
*/
async function findConfigFiles(directory) {
try {
const files = await fs.readdir(directory);
return files.filter(file =>
file.endsWith('.yml') || file.endsWith('.yaml') || file.endsWith('.json')
);
} catch (error) {
console.error(chalk.red(`Error reading directory: ${error.message}`));
return [];
}
}
/**
* Generate custom components from a configuration file
* @param {string} configPath - Path to the configuration file
* @param {Object} options - Generation options
*/
async function generateFromConfig(configPath, options) {
const spinner = ora('Loading configuration...').start();
try {
// Validate configuration
const validationResult = await validateConfigFile(configPath);
if (!validationResult.valid) {
spinner.fail('Configuration validation failed');
displayValidationResults(validationResult);
return;
}
spinner.succeed('Configuration validated successfully');
// Create generator
const generator = new AngularCustomGenerator({
outputPath: options.output || 'front/src/app/pages/admin/settings',
verbose: options.verbose
});
// Load configuration
await generator.loadConfig(configPath);
await generator.initialize();
// Execute generation
spinner.text = 'Generating components...';
spinner.start();
const success = await generator.execute();
if (success) {
spinner.succeed('Components generated successfully');
// Display summary
const summary = generator.transaction.getSummary();
console.log(boxen(
`${chalk.green.bold('✓')} Generated ${chalk.cyan(generator.config.model.name)} components\n\n` +
`${chalk.bold('Files created/modified:')} ${summary.operationsByType.write || 0}\n` +
`${chalk.bold('Directories created:')} ${summary.operationsByType.mkdir || 0}\n\n` +
`${chalk.gray('Output directory:')} ${path.join(options.output || 'front/src/app/pages/admin/settings', generator.modelData.kebabCase)}`,
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'green'
}
));
} else {
spinner.fail('Generation failed');
}
} catch (error) {
spinner.fail('Generation failed');
console.error(chalk.red(`\nError: ${error.message}`));
}
}
/**
* Run the generator in interactive mode
*/
async function runInteractive() {
displayBanner();
// Find configuration files
// Chercher d'abord dans le répertoire du module (fonctionne avec npm global)
// puis dans le répertoire du projet courant
const globalExamplesDir = path.join(__dirname, 'examples');
const localExamplesDir = path.join(process.cwd(), 'examples');
let configFiles = await findConfigFiles(globalExamplesDir);
// Si aucun fichier trouvé dans le répertoire global, essayer le répertoire local
if (configFiles.length === 0) {
configFiles = await findConfigFiles(localExamplesDir);
}
if (configFiles.length === 0) {
console.log(chalk.yellow('No configuration files found in examples directory.'));
return;
}
// Déterminer le bon répertoire source pour les fichiers de configuration
// Cela permet de gérer aussi bien les installations globales que locales
let usedExamplesDir;
try {
await fs.access(path.join(globalExamplesDir, configFiles[0]));
usedExamplesDir = globalExamplesDir;
} catch (error) {
usedExamplesDir = localExamplesDir;
}
const { configFile } = await inquirer.prompt({
type: 'list',
name: 'configFile',
message: 'Select a configuration file:',
choices: configFiles.map(file => ({
name: file,
value: path.join(usedExamplesDir, file)
}))
});
const { outputPath } = await inquirer.prompt({
type: 'input',
name: 'outputPath',
message: 'Output directory for components:',
default: 'front/src/app/pages/admin/settings'
});
const { verbose } = await inquirer.prompt({
type: 'confirm',
name: 'verbose',
message: 'Enable verbose output?',
default: false
});
await generateFromConfig(configFile, {
output: outputPath,
verbose
});
}
/**
* Command line interface setup
*/
program
.version('1.0.0')
.description('KIRA Custom Generator')
.option('-c, --config <path>', 'Path to configuration file')
.option('-o, --output <path>', 'Output directory for components')
.option('-v, --verbose', 'Enable verbose output')
.option('-i, --interactive', 'Run in interactive mode');
program.parse(process.argv);
/**
* Main application entry point
*/
async function main() {
const options = program.opts();
// Default to interactive mode if no config provided
if (!options.config && !options.interactive) {
options.interactive = true;
}
try {
if (options.interactive) {
await runInteractive();
} else if (options.config) {
displayBanner();
await generateFromConfig(options.config, options);
}
} catch (error) {
console.error(chalk.red(`\nAn error occurred: ${error.message}\n`));
process.exit(1);
}
}
// Run the application
if (require.main === module) {
main();
}
module.exports = {
generateFromConfig
};