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

1,225 lines (1,199 loc) 71.2 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.InteractiveDocsGenerator = void 0; exports.generateInteractiveDocs = generateInteractiveDocs; exports.createDocsTheme = createDocsTheme; const events_1 = require("events"); const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const fast_glob_1 = __importDefault(require("fast-glob")); class InteractiveDocsGenerator extends events_1.EventEmitter { constructor(projectPath, config = {}) { super(); this.projectPath = projectPath; this.config = { outputPath: path.join(projectPath, 'docs'), includeExamples: true, includeLiveDemo: true, includeTypeDefinitions: true, includeCodePlayground: true, generateStaticSite: true, autoRefresh: true, port: 3000, theme: this.getDefaultTheme(), ...config }; } async generateDocumentation() { this.emit('generation:start', { projectPath: this.projectPath }); const startTime = Date.now(); const result = { success: false, outputPath: this.config.outputPath, generatedFiles: [], assets: [], statistics: { totalPages: 0, totalCommands: 0, totalExamples: 0, totalGuides: 0, totalTypes: 0, generationTime: 0, assetSize: 0, codeBlocks: 0, interactiveElements: 0 }, errors: [], warnings: [] }; try { // Ensure output directory exists await fs.ensureDir(this.config.outputPath); // Generate API documentation const apiDocs = await this.generateAPIDocumentation(); // Generate static site if enabled if (this.config.generateStaticSite) { await this.generateStaticSite(apiDocs); } // Generate search index if (apiDocs.search.enabled) { result.searchIndex = await this.generateSearchIndex(apiDocs); } // Copy assets await this.copyAssets(); // Generate statistics result.statistics = this.calculateStatistics(apiDocs); result.statistics.generationTime = Date.now() - startTime; result.success = true; this.emit('generation:complete', result); } catch (error) { result.errors.push({ type: 'generation', message: error.message, severity: 'error' }); this.emit('generation:error', error); } return result; } async generateAPIDocumentation() { this.emit('api:generation:start'); const commands = await this.extractCommandDocumentation(); const types = await this.extractTypeDocumentation(); const examples = await this.generateExamples(); const guides = await this.generateGuides(); const apiDocs = { metadata: await this.generateMetadata(), commands, types, examples, guides, playground: this.generatePlaygroundConfig(), search: this.generateSearchConfig() }; // Save API documentation as JSON const apiDocsPath = path.join(this.config.outputPath, 'api-docs.json'); await fs.writeJson(apiDocsPath, apiDocs, { spaces: 2 }); this.emit('api:generation:complete', apiDocs); return apiDocs; } async extractCommandDocumentation() { const commands = []; try { // Find command files const commandFiles = await (0, fast_glob_1.default)('src/commands/**/*.ts', { cwd: this.projectPath, absolute: true }); for (const file of commandFiles) { const commandDoc = await this.parseCommandFile(file); if (commandDoc) { commands.push(commandDoc); } } // Add built-in commands documentation commands.push(...this.getBuiltInCommandDocs()); } catch (error) { this.emit('warning', { type: 'missing_documentation', message: 'Could not extract command documentation', file: 'commands' }); } return commands.sort((a, b) => a.name.localeCompare(b.name)); } async parseCommandFile(filePath) { try { const content = await fs.readFile(filePath, 'utf-8'); const commandName = path.basename(filePath, '.ts'); // Extract JSDoc comments and analyze code const documentation = this.extractJSDocFromFile(content); return { name: commandName, category: this.categorizeCommand(commandName), description: documentation.description || `${commandName} command`, synopsis: documentation.synopsis || `re-shell ${commandName} [options]`, usage: documentation.usage || [ { pattern: `re-shell ${commandName}`, description: `Execute ${commandName} command`, required: true } ], options: documentation.options || [], examples: documentation.examples || this.generateDefaultExamples(commandName), relatedCommands: documentation.relatedCommands || [], since: documentation.since || '1.0.0', deprecated: documentation.deprecated, tags: documentation.tags || [this.categorizeCommand(commandName)], complexity: documentation.complexity || 'beginner' }; } catch (error) { return null; } } extractJSDocFromFile(content) { // Simple JSDoc extraction - in real implementation would use a proper parser const jsdocRegex = /\/\*\*([\s\S]*?)\*\//g; const matches = content.match(jsdocRegex); if (!matches || matches.length === 0) { return {}; } // Parse first JSDoc block const jsdoc = matches[0]; const description = this.extractDescription(jsdoc); const examples = this.extractExamples(jsdoc); return { description, examples, synopsis: description ? `re-shell command - ${description}` : undefined, usage: examples.length > 0 ? examples.map(ex => ({ pattern: ex.code, description: ex.description, required: true })) : undefined }; } extractDescription(jsdoc) { const lines = jsdoc.split('\n'); const descriptionLines = lines .map(line => line.replace(/^\s*\*\s?/, '')) .filter(line => line && !line.startsWith('@')) .slice(1, -1); return descriptionLines.join(' ').trim(); } extractExamples(jsdoc) { const examples = []; const exampleRegex = /@example\s+([\s\S]*?)(?=@|\*\/)/g; let match; while ((match = exampleRegex.exec(jsdoc)) !== null) { const exampleContent = match[1] .split('\n') .map(line => line.replace(/^\s*\*\s?/, '')) .join('\n') .trim(); examples.push({ id: `example-${examples.length + 1}`, title: `Example ${examples.length + 1}`, description: 'Command usage example', code: exampleContent, language: 'bash', interactive: true, playgroundEnabled: true, difficulty: 'beginner', tags: ['example'], output: '# Command output would appear here' }); } return examples; } categorizeCommand(commandName) { const categories = { 'Project Management': ['init', 'create', 'new', 'setup'], 'Build & Deploy': ['build', 'deploy', 'serve', 'start'], 'Development': ['dev', 'watch', 'test', 'lint'], 'Workspace': ['add', 'remove', 'list', 'workspace'], 'Configuration': ['config', 'configure', 'settings'], 'Analysis': ['analyze', 'doctor', 'audit', 'profile'], 'Utilities': ['help', 'version', 'update', 'clean'] }; for (const [category, commands] of Object.entries(categories)) { if (commands.some(cmd => commandName.includes(cmd))) { return category; } } return 'General'; } generateDefaultExamples(commandName) { return [ { id: `${commandName}-basic`, title: `Basic ${commandName} usage`, description: `Simple example of using the ${commandName} command`, code: `re-shell ${commandName}`, language: 'bash', output: `# ${commandName} command executed successfully`, interactive: true, playgroundEnabled: true, difficulty: 'beginner', tags: ['basic', commandName] }, { id: `${commandName}-advanced`, title: `Advanced ${commandName} usage`, description: `Advanced example with options`, code: `re-shell ${commandName} --verbose --config custom.yaml`, language: 'bash', output: `# ${commandName} executed with custom configuration`, interactive: true, playgroundEnabled: true, difficulty: 'intermediate', tags: ['advanced', commandName] } ]; } getBuiltInCommandDocs() { return [ { name: 'init', category: 'Project Management', description: 'Initialize a new Re-Shell project with comprehensive setup', synopsis: 're-shell init [project-name] [options]', usage: [ { pattern: 're-shell init', description: 'Initialize project in current directory', required: false }, { pattern: 're-shell init <project-name>', description: 'Initialize project in new directory', required: false } ], options: [ { name: 'template', alias: 't', type: 'string', description: 'Project template to use', default: 'basic', required: false, choices: ['basic', 'ecommerce', 'dashboard', 'saas'], examples: ['--template ecommerce', '-t dashboard'], validation: [ { type: 'enum', value: ['basic', 'ecommerce', 'dashboard', 'saas'], message: 'Template must be one of: basic, ecommerce, dashboard, saas' } ] }, { name: 'package-manager', alias: 'pm', type: 'string', description: 'Package manager to use', default: 'npm', required: false, choices: ['npm', 'yarn', 'pnpm', 'bun'], examples: ['--package-manager yarn', '-pm pnpm'] }, { name: 'skip-install', type: 'boolean', description: 'Skip dependency installation', default: false, required: false, examples: ['--skip-install'] } ], examples: [ { id: 'init-basic', title: 'Basic project initialization', description: 'Create a new Re-Shell project with default settings', code: 're-shell init my-project', language: 'bash', output: `Creating new Re-Shell project 'my-project'... ✓ Project structure created ✓ Dependencies installed ✓ Configuration files generated ✓ Git repository initialized Project created successfully! cd my-project && re-shell dev`, interactive: true, playgroundEnabled: true, difficulty: 'beginner', tags: ['init', 'basic', 'getting-started'] }, { id: 'init-ecommerce', title: 'E-commerce project with custom template', description: 'Initialize an e-commerce project with specialized template', code: 're-shell init my-store --template ecommerce --package-manager yarn', language: 'bash', output: `Creating e-commerce project 'my-store'... ✓ E-commerce template applied ✓ Product catalog structure created ✓ Payment integration setup ✓ Yarn dependencies installed ✓ Development environment configured E-commerce project ready!`, interactive: true, playgroundEnabled: true, difficulty: 'intermediate', tags: ['init', 'ecommerce', 'template'] } ], relatedCommands: ['create', 'add', 'dev'], since: '1.0.0', tags: ['project', 'initialization', 'setup'], complexity: 'beginner' }, { name: 'build', category: 'Build & Deploy', description: 'Build the project for production with optimization', synopsis: 're-shell build [workspace] [options]', usage: [ { pattern: 're-shell build', description: 'Build all workspaces', required: false }, { pattern: 're-shell build <workspace>', description: 'Build specific workspace', required: false } ], options: [ { name: 'mode', alias: 'm', type: 'string', description: 'Build mode', default: 'production', required: false, choices: ['development', 'production', 'test'], examples: ['--mode production', '-m development'] }, { name: 'watch', alias: 'w', type: 'boolean', description: 'Watch for changes and rebuild', default: false, required: false, examples: ['--watch'] }, { name: 'analyze', type: 'boolean', description: 'Analyze bundle size', default: false, required: false, examples: ['--analyze'] } ], examples: [ { id: 'build-production', title: 'Production build', description: 'Build all workspaces for production deployment', code: 're-shell build --mode production', language: 'bash', output: `Building all workspaces for production... ✓ Frontend built (2.3MB) ✓ Backend built (1.8MB) ✓ Shared libraries built (0.5MB) ✓ Assets optimized ✓ Source maps generated Build completed in 45.2s`, interactive: true, playgroundEnabled: true, difficulty: 'beginner', tags: ['build', 'production'] } ], relatedCommands: ['dev', 'serve', 'deploy'], since: '1.0.0', tags: ['build', 'production', 'optimization'], complexity: 'beginner' } ]; } async extractTypeDocumentation() { const types = []; try { // Find TypeScript definition files const typeFiles = await (0, fast_glob_1.default)('src/**/*.ts', { cwd: this.projectPath, absolute: true }); for (const file of typeFiles) { const fileTypes = await this.parseTypeFile(file); types.push(...fileTypes); } } catch (error) { this.emit('warning', { type: 'missing_documentation', message: 'Could not extract type documentation' }); } return types; } async parseTypeFile(filePath) { try { const content = await fs.readFile(filePath, 'utf-8'); const types = []; // Extract interfaces const interfaceRegex = /export interface (\w+)\s*{([^}]*)}/g; let match; while ((match = interfaceRegex.exec(content)) !== null) { const [, name, body] = match; const properties = this.parseInterfaceProperties(body); types.push({ name, type: 'interface', description: `${name} interface definition`, definition: match[0], properties, examples: [ { title: `${name} usage example`, description: `Example of using ${name} interface`, code: this.generateTypeExample(name, properties), explanation: `This example shows how to create and use a ${name} object` } ], since: '1.0.0', module: path.relative(this.projectPath, filePath) }); } return types; } catch (error) { return []; } } parseInterfaceProperties(body) { const properties = []; const lines = body.split('\n'); for (const line of lines) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('*')) continue; const propertyMatch = trimmed.match(/(\w+)(\?)?\s*:\s*([^;]+);?/); if (propertyMatch) { const [, name, optional, type] = propertyMatch; properties.push({ name, type: type.trim(), description: `${name} property`, optional: !!optional, readonly: trimmed.includes('readonly'), examples: [`${name}: ${this.generatePropertyExample(type.trim())}`] }); } } return properties; } generatePropertyExample(type) { switch (type.toLowerCase()) { case 'string': return '"example"'; case 'number': return '42'; case 'boolean': return 'true'; case 'date': return 'new Date()'; default: if (type.includes('[]')) return '[]'; if (type.includes('Record')) return '{}'; return '{}'; } } generateTypeExample(name, properties) { const exampleProps = properties.slice(0, 3).map(prop => { return ` ${prop.name}: ${prop.examples[0]}`; }).join(',\n'); return `const example: ${name} = { ${exampleProps} };`; } async generateExamples() { return [ { id: 'getting-started', category: 'Quick Start', title: 'Getting Started with Re-Shell', description: 'Complete guide to setting up your first Re-Shell project', difficulty: 'beginner', estimatedTime: '10 minutes', prerequisites: ['Node.js 14+', 'Basic command line knowledge'], objectives: [ 'Create a new Re-Shell project', 'Understand the project structure', 'Run the development server', 'Make your first changes' ], steps: [ { stepNumber: 1, title: 'Install Re-Shell CLI', description: 'Install the Re-Shell CLI globally using npm', code: 'npm install -g @re-shell/cli', explanation: 'This installs the Re-Shell command line interface globally on your system', output: 'Successfully installed @re-shell/cli@latest', tips: ['Use sudo on Linux/Mac if you encounter permission errors'] }, { stepNumber: 2, title: 'Create New Project', description: 'Initialize a new Re-Shell project', code: 're-shell init my-first-app --template basic', explanation: 'Creates a new project directory with the basic template', output: 'Project created successfully! Navigate to my-first-app to get started.', notes: ['The basic template includes a simple microfrontend setup'] }, { stepNumber: 3, title: 'Start Development Server', description: 'Navigate to the project and start the development server', code: 'cd my-first-app && re-shell dev', explanation: 'Starts the development server with hot reloading', output: 'Development server running at http://localhost:3000', tips: ['The server will automatically reload when you make changes'] } ], fullCode: `# Complete setup process npm install -g @re-shell/cli re-shell init my-first-app --template basic cd my-first-app re-shell dev`, output: 'Project created and development server started successfully!', troubleshooting: [ { issue: 'Permission denied during global install', solution: 'Use sudo or configure npm to use a different directory', prevention: 'Set up npm to use a global directory in your home folder' } ], variations: [ { title: 'Using Yarn', description: 'Same setup but using Yarn package manager', changes: ['Use yarn instead of npm'], code: 're-shell init my-first-app --template basic --package-manager yarn' } ], relatedExamples: ['project-structure', 'adding-microfrontends'] }, { id: 'adding-microfrontends', category: 'Microfrontends', title: 'Adding Your First Microfrontend', description: 'Learn how to add and configure microfrontends in your Re-Shell project', difficulty: 'intermediate', estimatedTime: '15 minutes', prerequisites: ['Existing Re-Shell project', 'Basic React knowledge'], objectives: [ 'Add a new microfrontend to your project', 'Configure routing between microfrontends', 'Share data between components', 'Build and deploy the application' ], steps: [ { stepNumber: 1, title: 'Add New Microfrontend', description: 'Create a new microfrontend for user management', code: 're-shell add users --framework react --typescript', explanation: 'Generates a new microfrontend with React and TypeScript setup', output: 'Microfrontend "users" created successfully!' }, { stepNumber: 2, title: 'Configure Routing', description: 'Set up routing to the new microfrontend', code: `// In src/App.tsx import { Route } from 'react-router-dom'; import Users from 'users/Users'; <Route path="/users" component={Users} />`, explanation: 'Adds routing configuration for the users microfrontend' } ], fullCode: `re-shell add users --framework react --typescript # Update routing configuration # Test the new microfrontend re-shell build`, output: 'Microfrontend integrated successfully!', troubleshooting: [], variations: [], relatedExamples: ['getting-started', 'project-structure'] } ]; } async generateGuides() { return [ { id: 'project-architecture', title: 'Re-Shell Project Architecture', description: 'Understanding the architecture and design principles of Re-Shell projects', category: 'Architecture', difficulty: 'intermediate', estimatedTime: '20 minutes', lastUpdated: new Date(), sections: [ { id: 'overview', title: 'Architecture Overview', content: `Re-Shell follows a microfrontend architecture pattern that allows teams to develop, deploy, and scale frontend applications independently. Each microfrontend is a self-contained application that can be developed using different frameworks and technologies. ## Key Principles 1. **Independence**: Each microfrontend operates independently 2. **Technology Agnostic**: Use different frameworks for different parts 3. **Deployment Flexibility**: Deploy components separately 4. **Team Autonomy**: Teams can work independently on their features`, codeBlocks: [ { id: 'structure-example', language: 'text', code: `project/ ├── apps/ │ ├── shell/ # Main application shell │ ├── header/ # Header microfrontend │ ├── sidebar/ # Sidebar microfrontend │ └── dashboard/ # Dashboard microfrontend ├── packages/ │ ├── shared/ # Shared utilities │ └── types/ # Shared types └── tools/ # Build and dev tools`, caption: 'Typical Re-Shell project structure', interactive: false, runnable: false } ], images: [], videos: [], interactive: false } ], prerequisites: ['Basic React knowledge', 'Understanding of frontend build tools'], learningObjectives: [ 'Understand microfrontend architecture', 'Learn Re-Shell project structure', 'Master component communication patterns' ], nextSteps: [ 'Build your first microfrontend', 'Implement shared state management', 'Set up CI/CD pipeline' ], resources: [ { title: 'Microfrontends.org', url: 'https://microfrontends.org', description: 'Comprehensive guide to microfrontend architecture', type: 'external' } ] } ]; } async generateMetadata() { try { const packageJsonPath = path.join(this.projectPath, 'package.json'); const packageJson = await fs.readJson(packageJsonPath); return { title: packageJson.name || 'Re-Shell Documentation', version: packageJson.version || '1.0.0', description: packageJson.description || 'Interactive API documentation for Re-Shell CLI', lastUpdated: new Date(), contributors: [ { name: 'Re-Shell Team', role: 'Maintainer' } ], license: packageJson.license || 'MIT', repository: packageJson.repository?.url || '', homepage: packageJson.homepage || '' }; } catch { return { title: 'Re-Shell Documentation', version: '1.0.0', description: 'Interactive API documentation for Re-Shell CLI', lastUpdated: new Date(), contributors: [], license: 'MIT', repository: '', homepage: '' }; } } generatePlaygroundConfig() { return { enabled: this.config.includeCodePlayground || false, defaultCode: `// Welcome to the Re-Shell playground! // Try running some commands: re-shell init my-app --template basic re-shell add users --framework react re-shell build`, availableCommands: ['init', 'add', 'build', 'dev', 'serve', 'analyze'], environment: { type: 'browser', runtime: 'nodejs', dependencies: ['@re-shell/cli'], timeout: 30000, memoryLimit: 512 }, features: [ { name: 'syntax-highlighting', enabled: true }, { name: 'auto-completion', enabled: true }, { name: 'error-highlighting', enabled: true }, { name: 'live-output', enabled: true } ], templates: [ { id: 'basic-init', title: 'Basic Project Initialization', description: 'Create a new Re-Shell project with default settings', code: 're-shell init my-project --template basic', category: 'Getting Started', difficulty: 'beginner' }, { id: 'ecommerce-setup', title: 'E-commerce Project Setup', description: 'Set up an e-commerce project with specialized features', code: `re-shell init my-store --template ecommerce re-shell add products --framework react re-shell add cart --framework vue`, category: 'Templates', difficulty: 'intermediate' } ] }; } generateSearchConfig() { return { enabled: true, provider: 'local', indexFields: ['title', 'description', 'content', 'tags'], filters: [ { field: 'category', label: 'Category', type: 'category', options: [ { value: 'commands', label: 'Commands' }, { value: 'guides', label: 'Guides' }, { value: 'examples', label: 'Examples' }, { value: 'types', label: 'Types' } ] }, { field: 'difficulty', label: 'Difficulty', type: 'difficulty', options: [ { value: 'beginner', label: 'Beginner' }, { value: 'intermediate', label: 'Intermediate' }, { value: 'advanced', label: 'Advanced' } ] } ], suggestions: true, instantSearch: true }; } async generateStaticSite(apiDocs) { this.emit('static-site:generation:start'); // Generate HTML pages await this.generateHomePage(apiDocs); await this.generateCommandPages(apiDocs.commands); await this.generateExamplePages(apiDocs.examples); await this.generateGuidePages(apiDocs.guides); await this.generateTypePages(apiDocs.types); // Generate navigation and search await this.generateNavigation(apiDocs); await this.generateSearchPage(apiDocs); // Generate assets await this.generateStyles(); await this.generateScripts(); this.emit('static-site:generation:complete'); } async generateHomePage(apiDocs) { const html = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${apiDocs.metadata.title}</title> <link rel="stylesheet" href="assets/styles.css"> <link rel="icon" type="image/x-icon" href="assets/favicon.ico"> </head> <body> <div id="app"> <header class="header"> <div class="container"> <div class="header-content"> <h1 class="logo">${apiDocs.metadata.title}</h1> <nav class="nav"> <a href="#commands">Commands</a> <a href="#examples">Examples</a> <a href="#guides">Guides</a> <a href="#types">Types</a> <a href="#playground">Playground</a> </nav> </div> </div> </header> <main class="main"> <section class="hero"> <div class="container"> <h2>Interactive API Documentation</h2> <p>${apiDocs.metadata.description}</p> <div class="hero-actions"> <a href="#getting-started" class="btn btn-primary">Get Started</a> <a href="#playground" class="btn btn-secondary">Try Playground</a> </div> </div> </section> <section class="features"> <div class="container"> <div class="feature-grid"> <div class="feature-card"> <h3>📚 Comprehensive Commands</h3> <p>${apiDocs.commands.length} documented commands with examples</p> <a href="commands.html">Explore Commands</a> </div> <div class="feature-card"> <h3>🚀 Live Examples</h3> <p>${apiDocs.examples.length} interactive examples to try</p> <a href="examples.html">Browse Examples</a> </div> <div class="feature-card"> <h3>📖 Step-by-Step Guides</h3> <p>${apiDocs.guides.length} detailed guides for every use case</p> <a href="guides.html">Read Guides</a> </div> <div class="feature-card"> <h3>🔧 Type Definitions</h3> <p>${apiDocs.types.length} TypeScript interfaces and types</p> <a href="types.html">View Types</a> </div> </div> </div> </section> </main> <footer class="footer"> <div class="container"> <p>&copy; ${new Date().getFullYear()} ${apiDocs.metadata.title}. Licensed under ${apiDocs.metadata.license}.</p> </div> </footer> </div> <script src="assets/scripts.js"></script> </body> </html>`; await fs.writeFile(path.join(this.config.outputPath, 'index.html'), html); } async generateCommandPages(commands) { // Generate commands index page const commandsHtml = this.generateCommandsIndexHtml(commands); await fs.writeFile(path.join(this.config.outputPath, 'commands.html'), commandsHtml); // Generate individual command pages for (const command of commands) { const commandHtml = this.generateCommandPageHtml(command); await fs.writeFile(path.join(this.config.outputPath, 'commands', `${command.name}.html`), commandHtml); } } generateCommandsIndexHtml(commands) { const categories = this.groupCommandsByCategory(commands); const categoriesHtml = Object.entries(categories).map(([category, cmds]) => ` <section class="command-category"> <h3>${category}</h3> <div class="command-grid"> ${cmds.map(cmd => ` <div class="command-card"> <h4><a href="commands/${cmd.name}.html">${cmd.name}</a></h4> <p>${cmd.description}</p> <div class="command-meta"> <span class="complexity ${cmd.complexity}">${cmd.complexity}</span> ${cmd.deprecated ? '<span class="deprecated">Deprecated</span>' : ''} </div> </div> `).join('')} </div> </section> `).join(''); return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Commands - Re-Shell Documentation</title> <link rel="stylesheet" href="assets/styles.css"> </head> <body> <div id="app"> <header class="header"> <div class="container"> <div class="header-content"> <h1><a href="index.html">Re-Shell Docs</a></h1> <nav class="nav"> <a href="commands.html" class="active">Commands</a> <a href="examples.html">Examples</a> <a href="guides.html">Guides</a> </nav> </div> </div> </header> <main class="main"> <div class="container"> <div class="content"> <h2>Commands Reference</h2> <p>Complete reference for all Re-Shell CLI commands with examples and options.</p> <div class="search-box"> <input type="text" placeholder="Search commands..." id="command-search"> </div> ${categoriesHtml} </div> </div> </main> </div> <script src="assets/scripts.js"></script> </body> </html>`; } groupCommandsByCategory(commands) { const categories = {}; for (const command of commands) { if (!categories[command.category]) { categories[command.category] = []; } categories[command.category].push(command); } return categories; } generateCommandPageHtml(command) { const optionsHtml = command.options.map(option => ` <tr> <td><code>--${option.name}${option.alias ? `, -${option.alias}` : ''}</code></td> <td>${option.type}</td> <td>${option.description}</td> <td>${option.default || 'None'}</td> <td>${option.required ? 'Yes' : 'No'}</td> </tr> `).join(''); const examplesHtml = command.examples.map(example => ` <div class="example"> <h4>${example.title}</h4> <p>${example.description}</p> <div class="code-block"> <pre><code class="language-${example.language}">${example.code}</code></pre> ${example.interactive ? '<button class="run-example">Run Example</button>' : ''} </div> ${example.output ? ` <div class="output"> <h5>Output:</h5> <pre><code>${example.output}</code></pre> </div> ` : ''} </div> `).join(''); return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${command.name} - Re-Shell Documentation</title> <link rel="stylesheet" href="../assets/styles.css"> <link rel="stylesheet" href="../assets/prism.css"> </head> <body> <div id="app"> <header class="header"> <div class="container"> <div class="header-content"> <h1><a href="../index.html">Re-Shell Docs</a></h1> <nav class="nav"> <a href="../commands.html">Commands</a> <a href="../examples.html">Examples</a> <a href="../guides.html">Guides</a> </nav> </div> </div> </header> <main class="main"> <div class="container"> <div class="content"> <div class="breadcrumb"> <a href="../index.html">Home</a> > <a href="../commands.html">Commands</a> > ${command.name} </div> <h1>${command.name}</h1> <p class="lead">${command.description}</p> <div class="command-meta"> <span class="category">${command.category}</span> <span class="complexity ${command.complexity}">${command.complexity}</span> <span class="since">Since v${command.since}</span> </div> <section class="synopsis"> <h2>Synopsis</h2> <div class="code-block"> <pre><code>${command.synopsis}</code></pre> </div> </section> <section class="usage"> <h2>Usage</h2> ${command.usage.map(usage => ` <div class="usage-pattern"> <code>${usage.pattern}</code> <p>${usage.description}</p> </div> `).join('')} </section> <section class="options"> <h2>Options</h2> <table class="options-table"> <thead> <tr> <th>Option</th> <th>Type</th> <th>Description</th> <th>Default</th> <th>Required</th> </tr> </thead> <tbody> ${optionsHtml} </tbody> </table> </section> <section class="examples"> <h2>Examples</h2> ${examplesHtml} </section> ${command.relatedCommands.length > 0 ? ` <section class="related"> <h2>Related Commands</h2> <ul> ${command.relatedCommands.map(cmd => ` <li><a href="${cmd}.html">${cmd}</a></li> `).join('')} </ul> </section> ` : ''} </div> </div> </main> </div> <script src="../assets/scripts.js"></script> <script src="../assets/prism.js"></script> </body> </html>`; } async generateExamplePages(examples) { // Implementation for example pages const examplesHtml = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Examples - Re-Shell Documentation</title> <link rel="stylesheet" href="assets/styles.css"> </head> <body> <div id="app"> <main class="main"> <div class="container"> <h2>Interactive Examples</h2> <p>Learn by doing with our interactive examples.</p> ${examples.map(example => ` <div class="example-card"> <h3>${example.title}</h3> <p>${example.description}</p> <div class="example-meta"> <span class="difficulty ${example.difficulty}">${example.difficulty}</span> <span class="time">${example.estimatedTime}</span> </div> <a href="examples/${example.id}.html" class="btn">Try Example</a> </div> `).join('')} </div> </main> </div> </body> </html>`; await fs.writeFile(path.join(this.config.outputPath, 'examples.html'), examplesHtml); } async generateGuidePages(guides) { // Implementation for guide pages const guidesHtml = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Guides - Re-Shell Documentation</title> <link rel="stylesheet" href="assets/styles.css"> </head> <body> <div id="app"> <main class="main"> <div class="container"> <h2>Comprehensive Guides</h2> <p>Step-by-step guides to master Re-Shell.</p> ${guides.map(guide => ` <div class="guide-card"> <h3>${guide.title}</h3> <p>${guide.description}</p> <div class="guide-meta"> <span class="difficulty ${guide.difficulty}">${guide.difficulty}</span> <span class="time">${guide.estimatedTime}</span> </div> <a href="guides/${guide.id}.html" class="btn">Re