UNPKG

ruch

Version:

Revolutionary React TypeScript CLI with hexagonal architecture & AI-powered development assistance. Create maintainable, scalable applications with domain-driven design and integrated AI tooling.

243 lines (219 loc) 7.52 kB
#!/usr/bin/env bun import { Command } from 'commander'; import fs from 'fs-extra'; import type { DomainGenerationOptions } from './templates/domains'; import { ConfigProvider, ConsoleLogger, DefaultPathUtils, DomainFactory, } from './services'; import { createDomain } from './commands/create'; import { deleteDomain } from './commands/delete'; import { listDomains } from './commands/list'; import { createHttpClient } from './commands/http-client'; import { initServiceContext, generateServiceContext, updateServiceContext } from './commands/context'; import { initMsw, generateMswHandlers, generateMswMocks, updateMsw, updateMswDomain } from './commands/msw'; import { createVisualizeCommand } from './commands/visualize'; import { generateAiGuide } from './commands/guide-ai'; import { generateDomainFiles } from './templates/domains'; // Initialize services const config = ConfigProvider.getConfig(); const logger = new ConsoleLogger(); const pathUtils = new DefaultPathUtils(config); const domainFactory = new DomainFactory({ logger, pathUtils, generateDomainFiles, }); const program = new Command(); program .name('ruch') .description('Revolutionary React TypeScript CLI with hexagonal architecture & AI-powered development assistance') .version('1.1.3'); // Create command program .command('create') .description('Create a new domain with its hexagonal structure') .argument('<domain>', 'Name of the domain to create') .option('--with-ui', 'Include UI folder with React components', true) .option('--without-ui', 'Exclude UI folder') .option('--with-store', 'Include store folder with Zustand', true) .option('--without-store', 'Exclude store folder') .option('--with-queries', 'Include queries folder with React Query', true) .option('--without-queries', 'Exclude queries folder') .option('--with-api', 'Include API folder with Axios', true) .option('--without-api', 'Exclude API folder') .action(async (domainName: string, options) => { try { const domainOptions: DomainGenerationOptions = { withUi: options.withoutUi ? false : options.withUi, withStore: options.withoutStore ? false : options.withStore, withQueries: options.withoutQueries ? false : options.withQueries, withApi: options.withoutApi ? false : options.withApi, }; await domainFactory.createDomain(domainName, domainOptions); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); // Delete command program .command('delete') .description('Delete an existing domain') .argument('<domain>', 'Name of the domain to delete') .option('-f, --force', 'Force deletion without asking for confirmation', false) .action(async (domainName: string, options) => { try { await deleteDomain(domainName, options.force, fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); // List command program .command('list') .description('List all existing domains') .action(async () => { try { await listDomains(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); // Context command with subcommands const contextCommand = program .command('context') .description('Manage React service context for dependency injection'); contextCommand .command('init') .description('Initialize empty service context') .action(async () => { try { await initServiceContext(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); contextCommand .command('generate') .description('Generate service context with all existing domains') .action(async () => { try { await generateServiceContext(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); contextCommand .command('update') .description('Update service context with missing domains') .action(async () => { try { await updateServiceContext(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); // HTTP Client command program .command('http-client') .description('Generate a default HTTP client configuration') .action(async () => { try { await createHttpClient(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); // Guide AI command program .command('guide-ai') .description('Generate AI-friendly documentation and configuration for the project architecture') .option('--tools <tools>', 'Integrate with specific AI tools (cursor, copilot, windsurf, juni)', '') .action(async (options: { tools?: string }) => { try { const tools = options.tools ? options.tools.split(',').map((t: string) => t.trim()) : []; await generateAiGuide(logger, tools); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); // MSW command with subcommands const mswCommand = program .command('msw') .description('Manage Mock Service Worker (MSW) configuration and handlers'); mswCommand .command('init') .description('Initialize MSW configuration in the project') .action(async () => { try { await initMsw(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); mswCommand .command('handlers') .description('Generate MSW handlers for all domains') .action(async () => { try { await generateMswHandlers(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); mswCommand .command('mocks') .description('Generate mock data for all domains') .action(async () => { try { await generateMswMocks(fs, logger); } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); mswCommand .command('update') .description('Update MSW configuration with missing handlers or for a specific domain') .argument('[domain]', 'Specific domain to update (optional)') .action(async (domain?: string) => { try { if (domain) { await updateMswDomain(domain, fs, logger); } else { await updateMsw(fs, logger); } } catch (error) { logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } }); // Add visualize command program.addCommand(createVisualizeCommand()); // Display help if no command is provided if (process.argv.length <= 2) { program.help(); } // Global error handling process.on('uncaughtException', (error) => { logger.error(`Unhandled error: ${error.message}`); process.exit(1); }); process.on('unhandledRejection', (reason) => { logger.error(`Unhandled rejection: ${reason}`); process.exit(1); }); // Start the program program.parse();