UNPKG

@diagramers/cli

Version:

Diagramers CLI - Command-line tools for managing Diagramers projects

263 lines 15.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extendCommand = extendCommand; const project_extender_1 = require("../services/project-extender"); const table_generator_1 = require("../services/table-generator"); const relation_generator_1 = require("../services/relation-generator"); const chalk_1 = __importDefault(require("chalk")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); function extendCommand(program) { program .command('extend') .description(`Extend project with additional features and modules\n\nSupported usages:\n\n --module <module> [--crud] [--fields field1,field2] Generate new module with optional CRUD and fields\n --table <module:table> --fields field1,field2 Generate new table in a module\n --endpoint <module:endpoint> [--method GET|POST|...] Generate new endpoint for a module\n --relation <module:table1-table2[:type]> Generate relation between tables (type: one-to-one, one-to-many, many-to-many)\n --feature <feature> Add a feature (auth, email, etc.)\n\nExamples:\n diagramers extend --module products --crud\n diagramers extend --module users --fields email,username,role --crud\n diagramers extend --table products:categories --fields name,description,slug\n diagramers extend --endpoint products:search --method GET\n diagramers extend --relation products:category-product:one-to-many\n diagramers extend --feature auth\n`) .option('-f, --feature <feature>', 'Feature to add (auth, email, socket, etc.)') .option('-m, --module <module>', 'Generate new module with full CRUD operations') .option('-e, --endpoint <module:endpoint>', 'Generate new endpoint for existing module (format: module:endpoint)') .option('-t, --table <table>', 'Generate database table/collection with seeding') .option('-r, --relation <relation>', 'Generate database relations') .option('-l, --list', 'List available features and templates') .option('--crud', 'Generate full CRUD operations for module') .option('--fields <fields>', 'Comma-separated list of fields for module/table') .option('--type <type>', 'Database type (mongodb, mysql, postgres)') .option('--method <method>', 'HTTP method for endpoint (GET, POST, PUT, DELETE)', 'GET') .option('--path <path>', 'Custom path for endpoint (defaults to endpoint name)') .option('--description <description>', 'Description for the endpoint') .option('--force', 'Force generation even if conflicts exist') .option('--no-routes', 'Skip route generation for modules') .option('--no-database', 'Skip database setup for modules') .action(async (options) => { try { // Validate we're in a diagramers API project if (!isDiagramersApiProject()) { console.error(chalk_1.default.red('❌ This command must be run from a diagramers API project')); console.log(chalk_1.default.yellow('💡 Navigate to your API project directory or run: diagramers init api <project-name>')); process.exit(1); } if (options.list) { const extender = new project_extender_1.ProjectExtender(); await extender.listFeatures(); return; } const extender = new project_extender_1.ProjectExtender(); // Generate new endpoint for existing module if (options.endpoint) { const [moduleName, endpointName] = options.endpoint.split(':'); if (!moduleName || !endpointName) { console.error(chalk_1.default.red('❌ Endpoint format should be module:endpoint (e.g., product:search)')); process.exit(1); } // Validate module exists if (!fs.existsSync(path.join(process.cwd(), 'src/modules', moduleName))) { console.error(chalk_1.default.red(`❌ Module '${moduleName}' does not exist`)); console.log(chalk_1.default.yellow(`💡 Create it first with: diagramers extend --module ${moduleName}`)); process.exit(1); } console.log(chalk_1.default.blue(`🔧 Generating endpoint '${endpointName}' for module '${moduleName}'`)); console.log(chalk_1.default.gray(` Method: ${options.method}`)); if (options.path) { console.log(chalk_1.default.gray(` Path: ${options.path}`)); } if (options.description) { console.log(chalk_1.default.gray(` Description: ${options.description}`)); } await extender.generateEndpoint(moduleName, endpointName, { method: options.method, path: options.path, description: options.description }); console.log(chalk_1.default.green(`✅ Endpoint '${endpointName}' generated successfully!`)); console.log(chalk_1.default.blue(`🔗 Available at: /api/${moduleName}/${options.path || endpointName}`)); return; } // Generate new module if (options.module) { console.log(chalk_1.default.blue(`🔧 Generating module: ${options.module}`)); if (options.crud) { console.log(chalk_1.default.gray(` CRUD: Enabled`)); } if (options.fields) { console.log(chalk_1.default.gray(` Fields: ${options.fields}`)); } if (options.type) { console.log(chalk_1.default.gray(` Database type: ${options.type}`)); } if (options.routes === false) { console.log(chalk_1.default.gray(` Routes: Disabled`)); } if (options.database === false) { console.log(chalk_1.default.gray(` Database: Disabled`)); } await extender.generateModule(options.module, { crud: options.crud, fields: options.fields?.split(','), type: options.type || 'mongodb', generateRoutes: options.routes !== false, generateDatabase: options.database !== false }); console.log(chalk_1.default.green(`✅ Module ${options.module} generated successfully!`)); console.log(chalk_1.default.blue(`📁 Location: src/modules/${options.module}/`)); if (options.routes !== false) { console.log(chalk_1.default.blue(`🔗 Routes: /api/${options.module}s`)); } return; } // Generate database table if (options.table) { // Parse table format: module:table or just table (assume same name for module) const tableParts = options.table.split(':'); let moduleName; let tableName; if (tableParts.length === 2) { moduleName = tableParts[0]; tableName = tableParts[1]; } else { // If no module specified, use table name as module name moduleName = options.table; tableName = options.table; } // Validate module exists if (!fs.existsSync(path.join(process.cwd(), 'src/modules', moduleName))) { console.error(chalk_1.default.red(`❌ Module '${moduleName}' does not exist`)); console.log(chalk_1.default.yellow(`💡 Create it first with: diagramers extend --module ${moduleName}`)); process.exit(1); } console.log(chalk_1.default.blue(`🗄️ Generating table: ${tableName} in module: ${moduleName}`)); console.log(chalk_1.default.gray(` Database type: ${options.type || 'mongodb'}`)); if (options.fields) { console.log(chalk_1.default.gray(` Fields: ${options.fields}`)); } await (0, table_generator_1.generateTable)(moduleName, tableName, { fields: options.fields?.split(','), type: options.type || 'mongodb', force: options.force }); console.log(chalk_1.default.green(`✅ Table ${tableName} generated successfully!`)); console.log(chalk_1.default.blue(`📁 Location: src/modules/${moduleName}/entities/${tableName}.entity.ts`)); console.log(chalk_1.default.blue(`📁 Location: src/modules/${moduleName}/schemas/${tableName}.schema.ts`)); return; } // Generate database relations if (options.relation) { console.log(chalk_1.default.blue(`🔗 Generating relations for: ${options.relation}`)); // Parse relation parameters (format: module:table1-table2 or module:table1-table2:type) const relationParts = options.relation.split(':'); let moduleName; let tablesAndType; if (relationParts.length >= 2) { moduleName = relationParts[0]; tablesAndType = relationParts.slice(1).join(':'); } else { console.error(chalk_1.default.red('❌ Relation format should be module:table1-table2 or module:table1-table2:type')); console.error(chalk_1.default.red(' Examples: products:product-category, users:user-profile:one-to-one')); process.exit(1); } // Validate module exists if (!fs.existsSync(path.join(process.cwd(), 'src/modules', moduleName))) { console.error(chalk_1.default.red(`❌ Module '${moduleName}' does not exist`)); console.log(chalk_1.default.yellow(`💡 Create it first with: diagramers extend --module ${moduleName}`)); process.exit(1); } // Parse tables and relation type const typeIndex = tablesAndType.lastIndexOf(':'); let tables; let relationType; if (typeIndex > 0 && ['one-to-one', 'one-to-many', 'many-to-many'].includes(tablesAndType.substring(typeIndex + 1))) { tables = tablesAndType.substring(0, typeIndex); relationType = tablesAndType.substring(typeIndex + 1); } else { tables = tablesAndType; relationType = 'one-to-many'; // Default to one-to-many } const tableNames = tables.split('-'); if (tableNames.length !== 2) { console.error(chalk_1.default.red('❌ Tables should be separated by a dash (-)')); console.error(chalk_1.default.red(' Examples: product-category, user-profile')); process.exit(1); } const [table1, table2] = tableNames; console.log(chalk_1.default.gray(` Module: ${moduleName}`)); console.log(chalk_1.default.gray(` Tables: ${table1}${table2}`)); console.log(chalk_1.default.gray(` Type: ${relationType}`)); // Import and call the relation generator await (0, relation_generator_1.generateRelation)(moduleName, table1, table2, relationType); console.log(chalk_1.default.green(`✅ Relations ${options.relation} generated successfully!`)); console.log(chalk_1.default.blue(`🔗 ${table1}${table2} (${relationType}) in module ${moduleName}`)); return; } // Add feature (legacy support) if (options.feature) { console.log(chalk_1.default.blue(`🔧 Adding feature: ${options.feature}`)); await extender.addFeature(options.feature); console.log(chalk_1.default.green(`✅ Feature ${options.feature} added successfully!`)); return; } console.log(chalk_1.default.red('❌ Please specify what to generate: --module, --table, --relation, or --feature')); console.log(chalk_1.default.yellow('💡 Use --list to see available options')); console.log(chalk_1.default.gray('💡 Examples:')); console.log(chalk_1.default.gray(' diagramers extend --module products --crud')); console.log(chalk_1.default.gray(' diagramers extend --table products:categories --fields name,description')); console.log(chalk_1.default.gray(' diagramers extend --endpoint products:search --method GET')); process.exit(1); } catch (error) { console.error(chalk_1.default.red(`❌ Failed to extend project: ${error.message}`)); if (error.code === 'MODULE_NOT_FOUND') { console.log(chalk_1.default.yellow('💡 Create the module first with: diagramers extend --module <module-name>')); } else if (error.code === 'TABLE_ALREADY_EXISTS') { console.log(chalk_1.default.yellow('💡 Use --force to override existing table or choose a different name')); } else if (error.code === 'INVALID_FIELD_FORMAT') { console.log(chalk_1.default.yellow('💡 Field format should be: fieldName,fieldName2,fieldName3')); } process.exit(1); } }); } // Helper function to validate diagramers API project function isDiagramersApiProject() { const currentDir = process.cwd(); const requiredDirs = ['src/modules', 'src/core', 'src/shared']; return requiredDirs.every(dir => fs.existsSync(path.join(currentDir, dir))); } //# sourceMappingURL=extend.js.map