UNPKG

@re-shell/cli

Version:

Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja

473 lines (472 loc) 17.6 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 }; }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.InteractivePrompter = void 0; exports.createPrompter = createPrompter; exports.getGlobalPrompter = getGlobalPrompter; exports.setGlobalPrompter = setGlobalPrompter; const prompts_1 = __importDefault(require("prompts")); const chalk_1 = __importDefault(require("chalk")); const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); class InteractivePrompter { constructor(options = {}) { this.history = []; this.responseCache = new Map(); this.suggestions = new Map(); this.theme = options.theme || this.getDefaultTheme(); // Load suggestions this.loadSuggestions(); // Override prompts for theming this.setupPromptTheme(); } getDefaultTheme() { return { prefix: chalk_1.default.cyan('?'), suffix: chalk_1.default.gray(':'), separator: chalk_1.default.gray('›'), errorPrefix: chalk_1.default.red('✖'), successPrefix: chalk_1.default.green('✓'), warningPrefix: chalk_1.default.yellow('⚠'), infoPrefix: chalk_1.default.blue('ℹ') }; } setupPromptTheme() { prompts_1.default.override({ onCancel: () => { console.log(chalk_1.default.red('\n✖ Operation cancelled')); process.exit(1); } }); } loadSuggestions() { // Load framework suggestions this.suggestions.set('framework', [ { title: 'React', value: 'react', description: 'Popular library for building user interfaces' }, { title: 'Vue', value: 'vue', description: 'Progressive framework for building UIs' }, { title: 'Svelte', value: 'svelte', description: 'Compile-time optimized framework' }, { title: 'Angular', value: 'angular', description: 'Platform for building mobile and desktop apps' }, { title: 'Vanilla', value: 'vanilla', description: 'Plain JavaScript without frameworks' } ]); // Load package manager suggestions this.suggestions.set('packageManager', [ { title: 'pnpm', value: 'pnpm', description: 'Fast, disk space efficient package manager' }, { title: 'npm', value: 'npm', description: 'Default Node.js package manager' }, { title: 'yarn', value: 'yarn', description: 'Fast, reliable, and secure dependency management' }, { title: 'bun', value: 'bun', description: 'Incredibly fast JavaScript runtime and package manager' } ]); // Load template suggestions this.suggestions.set('template', [ { title: 'Basic', value: 'basic', description: 'Simple project structure' }, { title: 'E-commerce', value: 'ecommerce', description: 'Online store template' }, { title: 'Dashboard', value: 'dashboard', description: 'Analytics dashboard template' }, { title: 'SaaS', value: 'saas', description: 'Software as a Service template' }, { title: 'Blog', value: 'blog', description: 'Content management template' } ]); // Load common project names this.suggestions.set('projectName', [ { title: 'my-app', value: 'my-app', description: 'Generic application name' }, { title: 'frontend-app', value: 'frontend-app', description: 'Frontend application' }, { title: 'web-platform', value: 'web-platform', description: 'Web platform project' }, { title: 'micro-frontend', value: 'micro-frontend', description: 'Microfrontend application' } ]); } async prompt(config, options = {}) { const startTime = Date.now(); const configs = Array.isArray(config) ? config : [config]; // Handle non-interactive mode if (options.nonInteractive || process.env.CI) { return this.handleNonInteractive(configs, options); } // Prepare prompts with enhancements const enhancedConfigs = configs.map(cfg => this.enhancePromptConfig(cfg, options)); try { // Execute prompts const response = await (0, prompts_1.default)(enhancedConfigs, { onCancel: () => { console.log(chalk_1.default.red('\n✖ Operation cancelled')); process.exit(1); } }); // Record history this.recordHistory(configs, response, Date.now() - startTime); // Save responses if requested if (options.saveResponses) { await this.saveResponses(response, options.responseFile); } // Cache responses for (const [key, value] of Object.entries(response)) { this.responseCache.set(key, value); } return response; } catch (error) { console.error(chalk_1.default.red(`\n${this.theme.errorPrefix} Prompt error: ${error.message}`)); throw error; } } enhancePromptConfig(config, options) { const enhanced = { ...config, name: config.name, message: `${this.theme.prefix} ${config.message}${this.theme.suffix}` }; // Add choices with descriptions if (config.choices) { enhanced.choices = config.choices.map(choice => ({ ...choice, title: choice.description ? `${choice.title} ${chalk_1.default.gray('- ' + choice.description)}` : choice.title })); } // Enhanced validation if (config.validate) { enhanced.validate = async (value) => { if (options.skipValidation) return true; const result = await config.validate(value); if (typeof result === 'string') { return `${this.theme.errorPrefix} ${result}`; } return result; }; } // Enhanced autocomplete if (config.type === 'autocomplete') { enhanced.suggest = async (input) => { // Use custom suggest function if provided if (config.suggest) { return await config.suggest(input); } // Use built-in suggestions const suggestions = this.suggestions.get(config.name) || []; return suggestions.filter(suggestion => suggestion.title.toLowerCase().includes(input.toLowerCase()) || suggestion.value.toLowerCase().includes(input.toLowerCase())); }; enhanced.limit = config.limit || 10; } // Add hints and warnings if (config.hint) { enhanced.message += chalk_1.default.gray(` (${config.hint})`); } if (config.warn) { enhanced.message += chalk_1.default.yellow(` ⚠ ${config.warn}`); } // Default values from cache or options if (!enhanced.initial) { enhanced.initial = options.defaults?.[config.name] || this.responseCache.get(config.name) || config.initial; } return enhanced; } handleNonInteractive(configs, options) { const response = {}; for (const config of configs) { const defaultValue = options.defaults?.[config.name] || this.responseCache.get(config.name) || config.initial; if (defaultValue !== undefined) { response[config.name] = defaultValue; } else { throw new Error(`No default value provided for required prompt '${config.name}' in non-interactive mode`); } } return response; } recordHistory(configs, response, duration) { const historyEntry = { timestamp: new Date(), prompts: configs.map(config => ({ name: config.name, value: response[config.name], duration: duration / configs.length // Approximate per-prompt duration })) }; this.history.push(historyEntry); // Keep only last 50 entries if (this.history.length > 50) { this.history = this.history.slice(-50); } } async saveResponses(response, filename) { try { const saveFile = filename || path.join(process.cwd(), '.re-shell', 'prompt-responses.json'); const dir = path.dirname(saveFile); await fs.ensureDir(dir); let existingData = {}; if (await fs.pathExists(saveFile)) { existingData = await fs.readJson(saveFile); } const updatedData = { ...existingData, ...response, lastUpdated: new Date().toISOString() }; await fs.writeJson(saveFile, updatedData, { spaces: 2 }); } catch (error) { // Don't throw on save errors console.warn(chalk_1.default.yellow(`${this.theme.warningPrefix} Failed to save responses: ${error}`)); } } // Built-in prompt templates async promptProjectSetup() { return this.prompt([ { type: 'text', name: 'name', message: 'Project name', initial: 'my-app', validate: (value) => { if (!value.trim()) return 'Project name is required'; if (!/^[a-z0-9-_]+$/.test(value)) { return 'Project name must contain only lowercase letters, numbers, hyphens, and underscores'; } return true; }, hint: 'lowercase, no spaces' }, { type: 'autocomplete', name: 'framework', message: 'Choose framework', choices: this.suggestions.get('framework') }, { type: 'confirm', name: 'typescript', message: 'Use TypeScript', initial: true }, { type: 'select', name: 'packageManager', message: 'Package manager', choices: this.suggestions.get('packageManager'), initial: 0 }, { type: 'select', name: 'template', message: 'Project template', choices: this.suggestions.get('template') }, { type: 'confirm', name: 'installDependencies', message: 'Install dependencies now', initial: true } ]); } async promptMicrofrontendConfig() { return this.prompt([ { type: 'text', name: 'name', message: 'Microfrontend name', validate: (value) => { if (!value.trim()) return 'Name is required'; if (!/^[a-z0-9-]+$/.test(value)) { return 'Name must contain only lowercase letters, numbers, and hyphens'; } return true; } }, { type: 'autocomplete', name: 'framework', message: 'Framework', choices: this.suggestions.get('framework') }, { type: 'number', name: 'port', message: 'Development port', initial: 3001, min: 1000, max: 65535, validate: (value) => { if (value < 1000 || value > 65535) { return 'Port must be between 1000 and 65535'; } return true; } }, { type: 'list', name: 'exposed', message: 'Exposed modules (comma-separated)', initial: './App', separator: ',' }, { type: 'confirm', name: 'typescript', message: 'Use TypeScript', initial: true } ]); } async promptConfigurationUpdate() { return this.prompt([ { type: 'confirm', name: 'updateGlobal', message: 'Update global configuration', initial: false }, { type: 'confirm', name: 'updateProject', message: 'Update project configuration', initial: true }, { type: 'confirm', name: 'backupExisting', message: 'Backup existing configuration', initial: true } ]); } // Utility methods getCachedResponse(name) { return this.responseCache.get(name); } setCachedResponse(name, value) { this.responseCache.set(name, value); } clearCache() { this.responseCache.clear(); } getHistory() { return [...this.history]; } clearHistory() { this.history = []; } addSuggestion(category, suggestion) { const existing = this.suggestions.get(category) || []; existing.push(suggestion); this.suggestions.set(category, existing); } getSuggestions(category) { return this.suggestions.get(category) || []; } } exports.InteractivePrompter = InteractivePrompter; _a = InteractivePrompter; // Validation helpers InteractivePrompter.validators = { required: (message = 'This field is required') => (value) => { if (value === undefined || value === null || value === '') { return message; } return true; }, minLength: (min, message) => (value) => { if (value.length < min) { return message || `Must be at least ${min} characters`; } return true; }, maxLength: (max, message) => (value) => { if (value.length > max) { return message || `Must be no more than ${max} characters`; } return true; }, pattern: (pattern, message) => (value) => { if (!pattern.test(value)) { return message || 'Invalid format'; } return true; }, email: (message = 'Invalid email format') => (value) => { const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailPattern.test(value)) { return message; } return true; }, url: (message = 'Invalid URL format') => (value) => { try { new URL(value); return true; } catch { return message; } }, port: (message = 'Invalid port number') => (value) => { if (value < 1 || value > 65535 || !Number.isInteger(value)) { return message; } return true; }, combine: (...validators) => async (value) => { for (const validator of validators) { const result = await validator(value); if (result !== true) { return result; } } return true; } }; // Global instance let globalPrompter = null; function createPrompter(options) { return new InteractivePrompter(options); } function getGlobalPrompter() { if (!globalPrompter) { globalPrompter = new InteractivePrompter(); } return globalPrompter; } function setGlobalPrompter(prompter) { globalPrompter = prompter; }