myex-cli
Version:
Opinionated Express.js framework with CLI tools
109 lines (89 loc) • 4.13 kB
JavaScript
import path from 'path';
import fs from 'fs-extra';
import chalk from 'chalk';
import ora from 'ora';
import { generateModel } from './generate-model.js';
import { generateController } from './generate-controller.js';
import { generateService } from './generate-service.js';
import { generateRoute } from './generate-route.js';
import { pascalCase, camelCase, pluralize } from '../utils/string-utils.js';
/**
* Generate a complete feature (model, controller, service, route)
* @param {string} name - Feature name
* @param {Object} options - Command options
*/
export async function generateFeature(name, options) {
const spinner = ora(`Generating feature: ${chalk.blue(name)}`).start();
try {
// Check if we're in a MYX project (presence of src directory)
if (!fs.existsSync('src')) {
spinner.fail(chalk.red('Not in a MYX project. Please run this command from the root of your MYX project.'));
return;
}
// Generate model
spinner.text = `Generating model: ${chalk.blue(name)}`;
await generateModel(name, options);
// Generate service
spinner.text = `Generating service: ${chalk.blue(name)}`;
await generateService(name, { model: name });
// Generate controller
spinner.text = `Generating controller: ${chalk.blue(name)}`;
await generateController(name, { model: name });
// Generate route
spinner.text = `Generating route: ${chalk.blue(name)}`;
await generateRoute(name, { controller: name });
// Update routes index.js to include the new route
await updateRoutesIndex(name);
spinner.succeed(chalk.green(`Feature "${name}" generated successfully.`));
console.log('');
console.log(chalk.cyan('Generated files:'));
console.log(` ${chalk.cyan('Model:')} src/models/${name}.model.js`);
console.log(` ${chalk.cyan('Service:')} src/services/${name}.service.js`);
console.log(` ${chalk.cyan('Controller:')} src/controllers/${name}.controller.js`);
console.log(` ${chalk.cyan('Routes:')} src/routes/${name}.routes.js`);
console.log('');
console.log(chalk.cyan('API Endpoints:'));
const pluralName = pluralize(name);
console.log(` ${chalk.green('GET')} /api/${pluralName} - Get all ${pluralName}`);
console.log(` ${chalk.green('GET')} /api/${pluralName}/:id - Get ${name} by ID`);
console.log(` ${chalk.yellow('POST')} /api/${pluralName} - Create new ${name}`);
console.log(` ${chalk.blue('PUT')} /api/${pluralName}/:id - Update ${name}`);
console.log(` ${chalk.red('DELETE')} /api/${pluralName}/:id - Delete ${name}`);
console.log('');
} catch (error) {
spinner.fail(chalk.red(`Failed to generate feature: ${error.message}`));
}
}
/**
* Update the routes index.js file to include the new route
* @param {string} name - Feature name
*/
async function updateRoutesIndex(name) {
const indexPath = path.join('src', 'routes', 'index.js');
const pluralName = pluralize(name);
// Read existing file
let content = await fs.readFile(indexPath, 'utf8');
// Import statement to add
const importStatement = `import { ${name}Routes } from './${name}.routes.js';`;
// Check if import already exists
if (content.includes(importStatement)) {
return; // Already imported
}
// Add import statement after the last import
const lastImportIndex = content.lastIndexOf('import');
const lastImportEndIndex = content.indexOf(';', lastImportIndex) + 1;
content =
content.substring(0, lastImportEndIndex) +
'\\n' + importStatement +
content.substring(lastImportEndIndex);
// Add route registration line before the last bracket
const routeRegistration = ` app.use('/api/${pluralName}', ${name}Routes);`;
const lastClosingBracket = content.lastIndexOf('}');
content =
content.substring(0, lastClosingBracket) +
' // Register route for ' + name + '\\n' +
routeRegistration + '\\n' +
content.substring(lastClosingBracket);
// Write updated content back to file
await fs.writeFile(indexPath, content, 'utf8');
}