herta
Version:
Advanced mathematics framework for scientific, engineering, and financial applications
939 lines (841 loc) • 29.8 kB
JavaScript
/**
* Erudition Make Command
* Scaffolding tool to generate boilerplate for different components
*
* IMPORTANT: The createProject function COPIES ALL existing files and folders
* instead of generating new ones, preserving the current project structure.
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const chalk = require('chalk');
/**
* Generate component scaffolding based on type and name
* @param {Array} args - Command line arguments
*/
function make(args) {
const type = args[0]; // e.g., 'module', 'controller', 'project', etc.
const name = args[1]; // e.g., 'QuantumPhysics', 'UserController', 'MyMathApp'
if (!type || !name) {
console.log(chalk.red('Error: Both type and name are required'));
console.log(chalk.yellow(`Usage: herta erudition make <type> <name>`));
console.log(chalk.yellow(`Example: herta erudition make module QuantumPhysics`));
return;
}
// Convert to proper case formats
const pascalName = toPascalCase(name);
const camelName = toCamelCase(name);
const snakeName = toSnakeCase(name);
try {
switch (type.toLowerCase()) {
case 'project':
createProject(pascalName);
break;
case 'module':
createModule(pascalName);
break;
case 'controller':
createController(pascalName);
break;
case 'service':
createService(pascalName);
break;
case 'test':
createTest(pascalName);
break;
case 'api':
createApi(pascalName);
break;
case 'rest-controller':
createRestController(pascalName);
break;
case 'graphql':
createGraphQL(pascalName);
break;
default:
console.log(chalk.red(`Error: Unknown type '${type}'`));
displayMakeHelp();
}
} catch (error) {
console.error(chalk.red(`Error creating ${type}: ${error.message}`));
}
}
/**
* Create a new module file
* @param {string} name - Module name in PascalCase
*/
function createModule(name) {
const destDir = path.join(process.cwd(), 'src', 'advanced');
const fileName = `${toSnakeCase(name)}.js`;
const filePath = path.join(destDir, fileName);
// Make sure the destination directory exists
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
// Check if file already exists
if (fs.existsSync(filePath)) {
console.log(chalk.red(`Error: Module '${fileName}' already exists in ${destDir}`));
return;
}
const fileContent = generateModuleContent(name);
fs.writeFileSync(filePath, fileContent);
console.log(chalk.green(`✓ Module created successfully!`));
console.log(chalk.cyan(` File: ${filePath}`));
console.log(chalk.yellow(`\nNext steps:`));
console.log(` 1. Import your module in the main index.js file:`);
console.log(chalk.dim(` const ${toCamelCase(name)} = require('./advanced/${toSnakeCase(name)}');`));
console.log(` 2. Register it in your exports:`);
console.log(chalk.dim(` module.exports = { ..., ${toCamelCase(name)} };`));
}
/**
* Create a new controller file
* @param {string} name - Controller name in PascalCase
*/
function createController(name) {
// Ensure the name ends with "Controller"
const controllerName = name.endsWith('Controller') ? name : `${name}Controller`;
const destDir = path.join(process.cwd(), 'src', 'controllers');
const fileName = `${toSnakeCase(controllerName)}.js`;
const filePath = path.join(destDir, fileName);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
if (fs.existsSync(filePath)) {
console.log(chalk.red(`Error: Controller '${fileName}' already exists in ${destDir}`));
return;
}
const fileContent = generateControllerContent(controllerName);
fs.writeFileSync(filePath, fileContent);
console.log(chalk.green(`✓ Controller created successfully!`));
console.log(chalk.cyan(` File: ${filePath}`));
}
/**
* Create a new service file
* @param {string} name - Service name in PascalCase
*/
function createService(name) {
// Ensure the name ends with "Service"
const serviceName = name.endsWith('Service') ? name : `${name}Service`;
const destDir = path.join(process.cwd(), 'src', 'services');
const fileName = `${toSnakeCase(serviceName)}.js`;
const filePath = path.join(destDir, fileName);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
if (fs.existsSync(filePath)) {
console.log(chalk.red(`Error: Service '${fileName}' already exists in ${destDir}`));
return;
}
const fileContent = generateServiceContent(serviceName);
fs.writeFileSync(filePath, fileContent);
console.log(chalk.green(`✓ Service created successfully!`));
console.log(chalk.cyan(` File: ${filePath}`));
}
/**
* Create a new test file
* @param {string} name - Test name in PascalCase
*/
function createTest(name) {
const destDir = path.join(process.cwd(), 'test');
const fileName = `${toSnakeCase(name)}.spec.js`;
const filePath = path.join(destDir, fileName);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
if (fs.existsSync(filePath)) {
console.log(chalk.red(`Error: Test '${fileName}' already exists in ${destDir}`));
return;
}
const fileContent = generateTestContent(name);
fs.writeFileSync(filePath, fileContent);
console.log(chalk.green(`✓ Test created successfully!`));
console.log(chalk.cyan(` File: ${filePath}`));
}
/**
* Create a new API file
* @param {string} name - API name in PascalCase
*/
function createApi(name) {
const destDir = path.join(process.cwd(), 'src', 'api');
const fileName = `${toSnakeCase(name)}.js`;
const filePath = path.join(destDir, fileName);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
if (fs.existsSync(filePath)) {
console.log(chalk.red(`Error: API '${fileName}' already exists in ${destDir}`));
return;
}
const fileContent = generateApiContent(name);
fs.writeFileSync(filePath, fileContent);
console.log(chalk.green(`✓ API created successfully!`));
console.log(chalk.cyan(` File: ${filePath}`));
}
/**
* Create a new REST controller file
* @param {string} name - REST controller name in PascalCase
*/
function createRestController(name) {
// Ensure the name ends with "Controller"
const controllerName = name.endsWith('Controller') ? name : `${name}Controller`;
const destDir = path.join(process.cwd(), 'src', 'controllers');
const fileName = `${toSnakeCase(controllerName)}.js`;
const filePath = path.join(destDir, fileName);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
if (fs.existsSync(filePath)) {
console.log(chalk.red(`Error: REST Controller '${fileName}' already exists in ${destDir}`));
return;
}
const fileContent = generateRestControllerContent(controllerName);
fs.writeFileSync(filePath, fileContent);
console.log(chalk.green(`✓ REST Controller created successfully!`));
console.log(chalk.cyan(` File: ${filePath}`));
}
/**
* Create a new GraphQL schema and resolver file
* @param {string} name - GraphQL schema name in PascalCase
*/
function createGraphQL(name) {
const schemaDestDir = path.join(process.cwd(), 'src', 'api', 'graphql', 'schemas');
const resolverDestDir = path.join(process.cwd(), 'src', 'api', 'graphql', 'resolvers');
const schemaFileName = `${toSnakeCase(name)}.graphql.js`;
const resolverFileName = `${toSnakeCase(name)}.resolver.js`;
const schemaFilePath = path.join(schemaDestDir, schemaFileName);
const resolverFilePath = path.join(resolverDestDir, resolverFileName);
// Make sure the destination directories exist
if (!fs.existsSync(schemaDestDir)) {
fs.mkdirSync(schemaDestDir, { recursive: true });
}
if (!fs.existsSync(resolverDestDir)) {
fs.mkdirSync(resolverDestDir, { recursive: true });
}
// Check if files already exist
if (fs.existsSync(schemaFilePath)) {
console.log(chalk.red(`Error: GraphQL Schema '${schemaFileName}' already exists in ${schemaDestDir}`));
return;
}
if (fs.existsSync(resolverFilePath)) {
console.log(chalk.red(`Error: GraphQL Resolver '${resolverFileName}' already exists in ${resolverDestDir}`));
return;
}
const schemaContent = generateGraphQLSchemaContent(name);
const resolverContent = generateGraphQLResolverContent(name);
fs.writeFileSync(schemaFilePath, schemaContent);
fs.writeFileSync(resolverFilePath, resolverContent);
console.log(chalk.green(`✓ GraphQL Schema and Resolver created successfully!`));
console.log(chalk.cyan(` Schema: ${schemaFilePath}`));
console.log(chalk.cyan(` Resolver: ${resolverFilePath}`));
}
/**
* Display help for make command
*/
function displayMakeHelp() {
console.log(`
${chalk.bold.cyan('HERTA.JS MAKE COMMAND')}
${chalk.dim('Generate component scaffolding')}
${chalk.bold('Usage:')}
npx herta erudition make <type> <name>
${chalk.bold('Types:')}
${chalk.yellow('project')} Create a new project by copying ALL existing files
${chalk.yellow('module')} Create a new module
${chalk.yellow('controller')} Create a new controller
${chalk.yellow('service')} Create a new service
${chalk.yellow('api')} Create a new API endpoint
${chalk.yellow('rest-controller')} Create a RESTful controller
${chalk.yellow('graphql')} Create GraphQL schema and resolver
${chalk.yellow('test')} Create a test suite
${chalk.bold('Examples:')}
npx herta erudition make project MyMathApp
npx herta erudition make module QuantumPhysics
npx herta erudition make controller UserController
`);
}
/**
* Create a new Herta.js project by copying ALL existing files
* @param {string} name - Project name in PascalCase
* @param {string} [targetPath] - Project path (optional)
*/
function createProject(name, targetPath) {
const kebabName = toKebabCase(name);
const projectPath = targetPath ? `${targetPath}/${kebabName}` : path.join(process.cwd(), kebabName);
// Find the project root directory (where package.json is located)
let currentPath = __dirname; // Start from the directory of this script
while (currentPath !== '/' && !fs.existsSync(path.join(currentPath, 'package.json'))) {
currentPath = path.dirname(currentPath);
}
// If we couldn't find package.json, try the current working directory as a fallback
if (currentPath === '/' && !fs.existsSync(path.join(currentPath, 'package.json'))) {
currentPath = process.cwd();
console.log(chalk.yellow(`Could not find package.json in parent directories, using current directory: ${currentPath}`));
}
if (fs.existsSync(projectPath)) {
console.log(chalk.red(`Error: Directory ${kebabName} already exists`));
return;
}
console.log(chalk.cyan(`Creating project by copying ALL existing files: ${chalk.bold(kebabName)}...`));
// Create project directory
fs.mkdirSync(projectPath, { recursive: true });
// List of directories to copy
const dirsToCreate = [
'src',
'test',
'docs',
'bin',
'commands',
'examples',
'scripts',
'templates',
'public',
'dist'
];
// Create each directory
dirsToCreate.forEach(dir => {
const targetDir = path.join(projectPath, dir);
fs.mkdirSync(targetDir, { recursive: true });
console.log(chalk.green(`Created directory: ${dir}`));
});
// Copy all directories recursively
console.log(chalk.cyan('Copying all files and directories...'));
dirsToCreate.forEach(dir => {
const sourceDir = path.join(currentPath, dir);
const targetDir = path.join(projectPath, dir);
if (fs.existsSync(sourceDir)) {
try {
console.log(chalk.green(`Copying directory: ${dir}`));
// First remove the target directory
execSync(`rm -rf "${targetDir}"`, { stdio: 'pipe' });
// Then copy the entire source directory with its contents
execSync(`cp -R "${sourceDir}" "${path.dirname(targetDir)}/"`, { stdio: 'pipe' });
console.log(chalk.green(`✓ Successfully copied all files in ${dir}`));
} catch (error) {
console.log(chalk.red(`Error copying directory ${dir}: ${error.message}`));
}
}
});
// Copy important root files
const rootFiles = [
'README.md',
'CHANGELOG.md',
'LICENSE',
'webpack.config.js',
'webpack.cli.config.js',
'webpack.api.config.js',
'.gitignore',
'.npmrc',
'.eslintrc.js',
'swaggerDef.js',
'jest.config.js',
'server.js',
'index.js',
'setup.js', // Ensure setup.js is copied
'tsconfig.json', // For TypeScript projects
'.babelrc', // Babel configuration if present
'.prettierrc', // Code formatting config
'.editorconfig' // Editor configuration
];
// First, display which files we're going to copy
console.log(chalk.cyan('\nCopying root files...'));
// Critical files that MUST be copied
const criticalRootFiles = ['server.js', 'index.js', 'setup.js', 'package.json'];
// Copy each file, with special handling for critical files
rootFiles.forEach(file => {
const sourceFile = path.join(currentPath, file);
const targetFile = path.join(projectPath, file);
if (fs.existsSync(sourceFile)) {
try {
// Make a direct bit-by-bit copy of the file
const fileContent = fs.readFileSync(sourceFile);
fs.writeFileSync(targetFile, fileContent);
if (criticalRootFiles.includes(file)) {
console.log(chalk.green(`✓ Successfully copied critical file: ${file}`));
} else {
console.log(chalk.green(`Copied file: ${file}`));
}
} catch (error) {
console.log(chalk.red(`Error copying ${file}: ${error.message}`));
// For critical files, attempt an additional copy method
if (criticalRootFiles.includes(file)) {
try {
console.log(chalk.yellow(`Attempting alternative copy method for ${file}...`));
execSync(`cp "${sourceFile}" "${targetFile}"`, { stdio: 'pipe' });
console.log(chalk.green(`✓ Successfully copied ${file} using cp command`));
} catch (altError) {
console.log(chalk.red(`Failed to copy critical file ${file} using alternative method: ${altError.message}`));
}
}
}
} else if (criticalRootFiles.includes(file)) {
//console.log(chalk.red(`Critical file ${file} not found in source directory!`));
}
});
// Special handling for package.json - make a direct copy first, then update only the name
const packageJsonSource = path.join(currentPath, 'package.json');
const packageJsonTarget = path.join(projectPath, 'package.json');
if (fs.existsSync(packageJsonSource)) {
try {
// First make a direct copy to preserve ALL contents
fs.copyFileSync(packageJsonSource, packageJsonTarget);
console.log(chalk.green('✓ Copied package.json'));
// Then update only the minimal required fields
const packageJson = JSON.parse(fs.readFileSync(packageJsonTarget, 'utf8'));
packageJson.name = kebabName;
packageJson.description = `${name} - Built with Herta.js framework`;
// Write it back with just those changes, preserving EVERYTHING else
fs.writeFileSync(packageJsonTarget, JSON.stringify(packageJson, null, 2));
console.log(chalk.green('✓ Updated package.json name while preserving all scripts and other settings'));
} catch (error) {
console.log(chalk.red(`Error updating package.json: ${error.message}`));
return;
}
} else {
console.log(chalk.red('Error: Could not find package.json in the source directory'));
return;
}
// Verify critical files were copied successfully
const criticalPaths = [
path.join(projectPath, 'package.json'),
path.join(projectPath, 'server.js'),
path.join(projectPath, 'index.js'),
path.join(projectPath, 'setup.js')
];
// Check for important src files (like autodiff)
const srcFiles = fs.readdirSync(path.join(currentPath, 'src'));
console.log(chalk.cyan('\nVerifying critical source files...'));
const missingFiles = [];
criticalPaths.forEach(filePath => {
if (!fs.existsSync(filePath)) {
const fileName = path.basename(filePath);
missingFiles.push(fileName);
//console.log(chalk.red(`Warning: ${fileName} was not copied!`));
}
});
// Specifically check if src files exist in the target
srcFiles.forEach(srcFile => {
const sourceFile = path.join(currentPath, 'src', srcFile);
const targetFile = path.join(projectPath, 'src', srcFile);
// Only check files, not directories
if (fs.existsSync(sourceFile) && fs.statSync(sourceFile).isFile()) {
if (!fs.existsSync(targetFile)) {
missingFiles.push(`src/${srcFile}`);
//console.log(chalk.red(`Warning: src/${srcFile} was not copied!`));
} else {
console.log(chalk.green(`✓ Verified src/${srcFile}`));
}
}
});
// If we're missing important files, attempt to copy them manually using multiple methods
if (missingFiles.length > 0) {
console.log(chalk.yellow('\nAttempting to manually copy missing files...'));
missingFiles.forEach(fileName => {
try {
const dirName = path.dirname(fileName);
const sourceFile = path.join(currentPath, fileName);
const targetFile = path.join(projectPath, fileName);
// Ensure the target directory exists
if (dirName !== '.') {
fs.mkdirSync(path.join(projectPath, dirName), { recursive: true });
}
if (fs.existsSync(sourceFile)) {
// Try multiple copy methods for maximum reliability
try {
// Method 1: Direct read/write
const content = fs.readFileSync(sourceFile);
fs.writeFileSync(targetFile, content);
console.log(chalk.green(`✓ Successfully copied ${fileName} using read/write method`));
} catch (copyError) {
// Method 2: Use copyFileSync
try {
fs.copyFileSync(sourceFile, targetFile);
console.log(chalk.green(`✓ Successfully copied ${fileName} using copyFile method`));
} catch (copyError2) {
// Method 3: Use shell cp command
try {
execSync(`cp "${sourceFile}" "${targetFile}"`, { stdio: 'pipe' });
console.log(chalk.green(`✓ Successfully copied ${fileName} using cp command`));
} catch (cpError) {
throw new Error(`All copy methods failed for ${fileName}`);
}
}
}
// Verify the file was actually copied and has content
if (fs.existsSync(targetFile) && fs.statSync(targetFile).size > 0) {
console.log(chalk.green(`✓ Verified ${fileName} was successfully copied`));
} else {
console.log(chalk.red(`Warning: ${fileName} was copied but may be empty or incomplete!`));
}
} else {
//console.log(chalk.red(`Source file ${fileName} does not exist!`));
}
} catch (error) {
console.log(chalk.red(`Error copying ${fileName}: ${error.message}`));
}
});
}
console.log(chalk.green('\n✓ Successfully copied all project files and directories'));
console.log(chalk.yellow(`\nInstalling dependencies...`));
try {
execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
console.log(chalk.green('✓ Dependencies installed successfully!'));
} catch (error) {
console.log(chalk.red(`Error installing dependencies: ${error.message}`));
console.log(chalk.yellow('You may need to run npm install manually in the project directory.'));
}
console.log(chalk.green(`\n✓ Project ${chalk.bold(name)} created successfully at ${projectPath}!`));
console.log(chalk.cyan('\nTo get started:'));
console.log(chalk.yellow(` cd ${kebabName}`));
console.log(chalk.yellow(' npm install'));
console.log(chalk.yellow(' npm start'));
}
// Utility functions for case conversion
/**
* Convert string to PascalCase
* @param {string} str - String to convert
* @returns {string} PascalCase string
*/
function toPascalCase(str) {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, letter => letter.toUpperCase())
.replace(/\s+|-|_/g, '');
}
/**
* Convert string to camelCase
* @param {string} str - String to convert
* @returns {string} camelCase string
*/
function toCamelCase(str) {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => index === 0 ? letter.toLowerCase() : letter.toUpperCase())
.replace(/\s+|-|_/g, '');
}
/**
* Convert string to snake_case
* @param {string} str - String to convert
* @returns {string} snake_case string
*/
function toSnakeCase(str) {
return str
.replace(/([a-z])([A-Z])/g, '$1_$2')
.replace(/[\s-]+/g, '_')
.toLowerCase();
}
/**
* Convert string to kebab-case
* @param {string} str - String to convert
* @returns {string} kebab-case string
*/
function toKebabCase(str) {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase();
}
/**
* Template generator functions (implementation will be added as needed)
*/
function generateModuleContent(name) {
// Using array join method to avoid syntax highlighting issues with comments in template strings
return [
`/**`,
` * ${name} Module`,
` * Advanced mathematical operations for Herta.js`,
` */`,
``,
`// Module implementation`,
`const ${toCamelCase(name)} = {`,
` // Add your methods here`,
` `,
` /**`,
` * Example method`,
` * @param {number} x - First parameter`,
` * @param {number} y - Second parameter`,
` * @returns {number} - Result`,
` */`,
` calculate(x, y) {`,
` return x * y;`,
` }`,
`};`,
``,
`module.exports = ${toCamelCase(name)};`
].join('\n');
}
function generateControllerContent(name) {
// Using array join method to avoid syntax highlighting issues with comments in template strings
return [
`/**`,
` * ${name}`,
` * Controller for handling application logic`,
` */`,
``,
`class ${name} {`,
` /**`,
` * Constructor`,
` */`,
` constructor() {`,
` // Initialize controller`,
` }`,
` `,
` /**`,
` * Example method`,
` * @param {Object} req - Request object`,
` * @param {Object} res - Response object`,
` */`,
` async handleRequest(req, res) {`,
` try {`,
` // Implementation`,
` return { success: true, data: 'Response data' };`,
` } catch (error) {`,
` return { success: false, error: error.message };`,
` }`,
` }`,
`}`,
``,
`module.exports = new ${name}();`
].join('\n');
}
function generateServiceContent(name) {
// Implementation will be similar to controller content
return [
`/**`,
` * ${name}`,
` * Service for business logic`,
` */`,
``,
`class ${name} {`,
` /**`,
` * Constructor`,
` */`,
` constructor() {`,
` // Initialize service`,
` }`,
` `,
` /**`,
` * Example method`,
` * @param {Object} data - Input data`,
` * @returns {Object} - Result`,
` */`,
` async process(data) {`,
` try {`,
` // Implementation`,
` return { success: true, result: 'Processed data' };`,
` } catch (error) {`,
` return { success: false, error: error.message };`,
` }`,
` }`,
`}`,
``,
`module.exports = new ${name}();`
].join('\n');
}
function generateTestContent(name) {
return [
`/**`,
` * Test Suite for ${name}`,
` */`,
``,
`const assert = require('assert');`,
`// Import module to test`,
`// const ${toCamelCase(name)} = require('../path/to/${toSnakeCase(name)}');`,
``,
`describe('${name} Tests', () => {`,
` before(() => {`,
` // Setup test environment`,
` });`,
``,
` after(() => {`,
` // Clean up test environment`,
` });`,
``,
` it('should pass a basic test', () => {`,
` // Test implementation`,
` assert.strictEqual(true, true);`,
` });`,
``,
` it('should handle error conditions', () => {`,
` // Test error handling`,
` assert.throws(() => {`,
` throw new Error('Test error');`,
` }, /Test error/);`,
` });`,
`});`
].join('\n');
}
function generateApiContent(name) {
return [
`/**`,
` * ${name} API`,
` * RESTful API endpoints`,
` */`,
``,
`const express = require('express');`,
`const router = express.Router();`,
``,
`/**`,
` * @swagger`,
` * /api/${toKebabCase(name)}:`,
` * get:`,
` * summary: Get data`,
` * description: Retrieve data`,
` * responses:`,
` * 200:`,
` * description: Successful operation`,
` */`,
`router.get('/', async (req, res) => {`,
` try {`,
` // Implementation`,
` res.json({ success: true, data: 'Response data' });`,
` } catch (error) {`,
` res.status(500).json({ success: false, error: error.message });`,
` }`,
`});`,
``,
`/**`,
` * @swagger`,
` * /api/${toKebabCase(name)}:`,
` * post:`,
` * summary: Create new data`,
` * description: Create new data entry`,
` * responses:`,
` * 200:`,
` * description: Successful operation`,
` */`,
`router.post('/', async (req, res) => {`,
` try {`,
` // Implementation`,
` res.json({ success: true, data: 'Data created successfully' });`,
` } catch (error) {`,
` res.status(500).json({ success: false, error: error.message });`,
` }`,
`});`,
``,
`module.exports = router;`
].join('\n');
}
function generateRestControllerContent(name) {
return [
`/**`,
` * ${name}`,
` * REST controller for API endpoints`,
` */`,
``,
`const express = require('express');`,
`const router = express.Router();`,
``,
`/**`,
` * @swagger`,
` * /api/${toKebabCase(name.replace('Controller', ''))}:`,
` * get:`,
` * summary: Get all items`,
` * description: Retrieves all items`,
` * responses:`,
` * 200:`,
` * description: Successful operation`,
` */`,
`router.get('/', async (req, res) => {`,
` try {`,
` // Implementation for GET all`,
` res.json({ success: true, data: [] });`,
` } catch (error) {`,
` res.status(500).json({ success: false, error: error.message });`,
` }`,
`});`,
``,
`/**`,
` * @swagger`,
` * /api/${toKebabCase(name.replace('Controller', ''))}/:id:`,
` * get:`,
` * summary: Get item by ID`,
` * description: Retrieves a specific item by ID`,
` * parameters:`,
` * - in: path`,
` * name: id`,
` * required: true`,
` * schema:`,
` * type: string`,
` * responses:`,
` * 200:`,
` * description: Successful operation`,
` * 404:`,
` * description: Item not found`,
` */`,
`router.get('/:id', async (req, res) => {`,
` try {`,
` const { id } = req.params;`,
` // Implementation for GET by ID`,
` res.json({ success: true, data: { id } });`,
` } catch (error) {`,
` res.status(500).json({ success: false, error: error.message });`,
` }`,
`});`,
``,
`module.exports = router;`
].join('\n');
}
function generateGraphQLSchemaContent(name) {
return [
`/**`,
` * ${name} GraphQL Schema`,
` */`,
``,
`const { gql } = require('apollo-server-express');`,
``,
`const ${name}Schema = gql\``,
` type ${name} {`,
` id: ID!`,
` name: String!`,
` description: String`,
` createdAt: String!`,
` updatedAt: String!`,
` }`,
``,
` extend type Query {`,
` get${name}(id: ID!): ${name}`,
` getAll${name}s: [${name}!]!`,
` }`,
``,
` extend type Mutation {`,
` create${name}(name: String!, description: String): ${name}!`,
` update${name}(id: ID!, name: String, description: String): ${name}!`,
` delete${name}(id: ID!): Boolean!`,
` }`,
`\`;`,
``,
`module.exports = ${name}Schema;`
].join('\n');
}
function generateGraphQLResolverContent(name) {
return [
`/**`,
` * ${name} GraphQL Resolvers`,
` */`,
``,
`const ${name}Resolvers = {`,
` Query: {`,
` /**`,
` * Get ${name} by ID`,
` * @param {Object} _ - Parent resolver`,
` * @param {Object} args - Query arguments`,
` * @returns {Object} - ${name} object`,
` */`,
` async get${name}(_, { id }) {`,
` try {`,
` // Implementation`,
` return {`,
` id,`,
` name: 'Example',`,
` description: 'Example description',`,
` createdAt: new Date().toISOString(),`,
` updatedAt: new Date().toISOString()`,
` };`,
` } catch (error) {`,
` throw new Error(\`Failed to get ${name}: \${error.message}\`);`,
` }`,
` }`,
` }`,
`};`,
``,
`module.exports = ${name}Resolvers;`
].join('\n');
}
module.exports = make;