UNPKG

express-hale

Version:

šŸš€ Interactive Express.js scaffold CLI with comprehensive error handling, TypeScript/JavaScript, database integrations, Git Flow, and development tools

276 lines • 11.5 kB
#!/usr/bin/env node "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 }); const inquirer_1 = __importDefault(require("inquirer")); const chalk_1 = __importDefault(require("chalk")); const commander_1 = require("commander"); const ora_1 = __importDefault(require("ora")); const path_1 = __importDefault(require("path")); const fs_extra_1 = __importDefault(require("fs-extra")); const generator_1 = require("./generator"); const error_handler_1 = require("./error-handler"); const startup_banner_1 = require("./startup-banner"); // Get version from package.json const packageJson = __importStar(require("../package.json")); // Setup global error handling (0, error_handler_1.setupGlobalErrorHandlers)(); const program = new commander_1.Command(); const errorHandler = error_handler_1.ErrorHandler.getInstance(); const startupBanner = startup_banner_1.StartupBanner.getInstance(); program .name('express-hale') .description('Interactive Express.js scaffold CLI') .version(packageJson.version) .argument('[project-name]', 'Name of the project') .action(async (projectName) => { let projectPath; let spinner; try { // Display startup banner await startupBanner.displayStartupBanner({ name: 'express-hale', version: packageJson.version, environment: process.env.NODE_ENV || 'development', author: 'Gaowenhan', }); console.log(chalk_1.default.blue.bold('šŸš€ Welcome to Express Hale CLI')); console.log(chalk_1.default.gray('Create a modern Express.js application with your preferred stack\n')); // Get project name if not provided if (!projectName) { try { const namePrompt = await inquirer_1.default.prompt([ { type: 'input', name: 'projectName', message: 'Project name:', default: 'my-express-app', validate: (input) => { if (!input.trim()) { return 'Project name is required'; } if (!/^[a-zA-Z0-9-_]+$/.test(input)) { return 'Project name can only contain letters, numbers, hyphens, and underscores'; } return true; }, }, ]); projectName = namePrompt.projectName; } catch (promptError) { throw new error_handler_1.CLIError('Failed to get project name from user input', 'INPUT_ERROR', { operation: 'project-name-prompt', phase: 'initialization', timestamp: new Date(), }, promptError instanceof Error ? promptError : undefined); } } // Interactive configuration prompts let config; try { config = await inquirer_1.default.prompt([ { type: 'list', name: 'language', message: 'Select language:', choices: [ { name: 'TypeScript', value: 'typescript' }, { name: 'JavaScript', value: 'javascript' }, ], default: 'typescript', }, { type: 'checkbox', name: 'databases', message: 'Select databases (use space to select):', choices: [ { name: 'MySQL', value: 'mysql', checked: false }, { name: 'MongoDB', value: 'mongodb', checked: false }, { name: 'Redis', value: 'redis', checked: false }, ], }, { type: 'list', name: 'packageManager', message: 'Select package manager:', choices: [ { name: 'pnpm (ęŽØč)', value: 'pnpm' }, { name: 'npm', value: 'npm' }, { name: 'yarn', value: 'yarn' }, ], default: 'pnpm', }, { type: 'confirm', name: 'eslint', message: 'Add ESLint for code linting?', default: true, }, { type: 'confirm', name: 'prettier', message: 'Add Prettier for code formatting?', default: true, }, { type: 'list', name: 'testing', message: 'Select testing framework:', choices: [ { name: 'Jest', value: 'jest' }, { name: 'Mocha', value: 'mocha' }, { name: 'None', value: 'none' }, ], default: 'jest', }, { type: 'confirm', name: 'docker', message: 'Add Docker configuration?', default: false, }, { type: 'confirm', name: 'gitInit', message: 'Initialize git repository?', default: true, }, { type: 'confirm', name: 'gitFlow', message: 'Initialize Git Flow workflow?', default: false, when: (answers) => answers.gitInit, }, { type: 'confirm', name: 'errorHandling', message: 'Add advanced error handling middleware and utilities?', default: true, }, ]); } catch (configError) { throw new error_handler_1.CLIError('Failed to collect project configuration', 'CONFIG_ERROR', { operation: 'configuration-prompt', phase: 'initialization', timestamp: new Date(), projectName, }, configError instanceof Error ? configError : undefined); } projectPath = path_1.default.resolve(process.cwd(), projectName); // Setup error handler with project context errorHandler.setLogFile(projectPath); // Check if directory already exists if (await fs_extra_1.default.pathExists(projectPath)) { try { const { overwrite } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'overwrite', message: `Directory ${projectName} already exists. Overwrite?`, default: false, }, ]); if (!overwrite) { console.log(chalk_1.default.yellow('Operation cancelled.')); process.exit(0); } await fs_extra_1.default.remove(projectPath); } catch (overwriteError) { throw new error_handler_1.CLIError(`Failed to handle existing directory: ${projectPath}`, 'PROJECT_EXISTS', { operation: 'directory-cleanup', phase: 'initialization', timestamp: new Date(), projectName, projectPath, }, overwriteError instanceof Error ? overwriteError : undefined); } } // Generate project spinner = (0, ora_1.default)('Generating project...').start(); try { const generator = new generator_1.ProjectGenerator(projectName, projectPath, config, packageJson.version); await generator.generate(); spinner.succeed(chalk_1.default.green('Project generated successfully!')); console.log(chalk_1.default.blue('\nšŸ“ Next steps:')); console.log(` cd ${projectName}`); console.log(` ${config.packageManager} install`); if (config.language === 'typescript') { console.log(` ${config.packageManager} run build`); } console.log(` ${config.packageManager} run dev`); console.log(chalk_1.default.gray('\nHappy coding! šŸŽ‰')); } catch (generationError) { spinner?.fail(chalk_1.default.red('Failed to generate project')); throw new error_handler_1.CLIError('Project generation failed', 'GENERATION_ERROR', { operation: 'project-generation', phase: 'generation', timestamp: new Date(), projectName, projectPath, }, generationError instanceof Error ? generationError : undefined); } } catch (error) { // Stop spinner if it's running if (spinner && spinner.isSpinning) { spinner.fail(chalk_1.default.red('Process failed')); } // Cleanup on error if (projectPath) { await errorHandler.cleanup(projectPath); } // Handle the error await errorHandler.handleError(error instanceof Error ? error : new Error(String(error))); } }); // Handle process termination gracefully process.on('SIGINT', () => { startupBanner.displayShutdownMessage(); process.exit(0); }); process.on('SIGTERM', () => { startupBanner.displayShutdownMessage(); process.exit(0); }); program.parse(); //# sourceMappingURL=index.js.map