UNPKG

@ordojs/cli

Version:

Command-line interface for OrdoJS framework

337 lines (300 loc) • 11.3 kB
#!/usr/bin/env node /** * Simple OrdoJS Development Server * A minimal working version that can serve OrdoJS files */ import { promises as fs } from 'fs'; import http from 'http'; import path from 'path'; import url from 'url'; class SimpleOrdoJSDevServer { constructor(options = {}) { this.port = options.port || 3000; this.host = options.host || 'localhost'; this.dir = options.dir || '.'; this.server = null; } async start() { console.log(`šŸš€ Starting OrdoJS Development Server...`); console.log(`šŸ“ Serving directory: ${path.resolve(this.dir)}`); this.server = http.createServer(this.requestHandler.bind(this)); return new Promise((resolve, reject) => { this.server.listen(this.port, this.host, () => { console.log(`āœ… Server running at http://${this.host}:${this.port}`); console.log(`🌐 Open your browser to view the sample website`); resolve(); }); this.server.on('error', (error) => { if (error.code === 'EADDRINUSE') { console.error(`āŒ Port ${this.port} is already in use`); } else { console.error(`āŒ Server error: ${error.message}`); } reject(error); }); }); } async requestHandler(req, res) { const parsedUrl = url.parse(req.url, true); const pathname = parsedUrl.pathname; console.log(`${req.method} ${pathname}`); try { if (pathname === '/' || pathname === '/index.html') { await this.handleIndex(req, res); } else if (pathname.endsWith('.ordo')) { await this.handleOrdoFile(req, res, pathname); } else { await this.handleStaticFile(req, res, pathname); } } catch (error) { console.error(`Error handling request: ${error.message}`); res.writeHead(500, { 'Content-Type': 'text/plain' }); res.end('Internal Server Error'); } } async handleIndex(req, res) { // Look for app.ordo in the src directory const appOrdoPath = path.join(this.dir, 'src/app.ordo'); try { await fs.access(appOrdoPath); // Redirect to the app.ordo file res.writeHead(302, { 'Location': '/src/app.ordo' }); res.end(); } catch (error) { // Show directory listing await this.showDirectoryListing(req, res); } } async handleOrdoFile(req, res, urlPath) { const filePath = path.join(this.dir, urlPath); try { const source = await fs.readFile(filePath, 'utf-8'); const componentName = path.basename(filePath, '.ordo'); const html = this.compileOrdoToHTML(source, componentName); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(html); } catch (error) { console.error(`Failed to compile OrdoJS file: ${error.message}`); res.writeHead(500, { 'Content-Type': 'text/html' }); res.end(` <!DOCTYPE html> <html> <head><title>Compilation Error</title></head> <body> <h1>OrdoJS Compilation Error</h1> <p>Failed to compile ${urlPath}: ${error.message}</p> </body> </html> `); } } async handleStaticFile(req, res, urlPath) { const filePath = path.join(this.dir, urlPath); try { await fs.access(filePath); const content = await fs.readFile(filePath); const ext = path.extname(filePath); let contentType = 'text/plain'; switch (ext) { case '.html': contentType = 'text/html'; break; case '.css': contentType = 'text/css'; break; case '.js': contentType = 'application/javascript'; break; case '.json': contentType = 'application/json'; break; case '.png': contentType = 'image/png'; break; case '.jpg': case '.jpeg': contentType = 'image/jpeg'; break; case '.gif': contentType = 'image/gif'; break; case '.svg': contentType = 'image/svg+xml'; break; } res.writeHead(200, { 'Content-Type': contentType }); res.end(content); } catch (error) { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('File not found'); } } async showDirectoryListing(req, res) { try { const files = await fs.readdir(this.dir); const ordoFiles = files.filter(file => file.endsWith('.ordo')); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(` <!DOCTYPE html> <html> <head> <title>OrdoJS Development Server</title> <style> body { font-family: system-ui, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; } h1 { color: #0066cc; } .file-list { list-style: none; padding: 0; } .file-list li { margin: 0.5rem 0; } .file-list a { color: #0066cc; text-decoration: none; } .file-list a:hover { text-decoration: underline; } </style> </head> <body> <h1>OrdoJS Development Server</h1> <p>Server is running at <code>http://${this.host}:${this.port}</code></p> <p>Serving directory: <code>${path.resolve(this.dir)}</code></p> ${ordoFiles.length > 0 ? ` <h2>Available OrdoJS Files:</h2> <ul class="file-list"> ${ordoFiles.map(file => `<li><a href="/${file}">${file}</a></li>`).join('')} </ul> ` : '<p>No .ordo files found in the current directory.</p>'} </body> </html> `); } catch (error) { res.writeHead(500, { 'Content-Type': 'text/plain' }); res.end('Failed to read directory'); } } compileOrdoToHTML(source, componentName) { try { // Simple compilation that displays the OrdoJS source with syntax highlighting return ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${componentName} - OrdoJS Sample Test Website</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; color: #333; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } .header { text-align: center; margin-bottom: 40px; } .header h1 { color: white; font-size: 2.5rem; margin-bottom: 10px; } .header p { color: rgba(255,255,255,0.9); font-size: 1.2rem; } .component { background: white; border-radius: 12px; padding: 30px; margin: 20px 0; box-shadow: 0 10px 30px rgba(0,0,0,0.1); } .source { background: #1e1e1e; color: #d4d4d4; padding: 20px; border-radius: 8px; margin: 20px 0; overflow-x: auto; } pre { margin: 0; white-space: pre-wrap; font-family: 'Monaco', 'Menlo', monospace; font-size: 14px; } .highlight { color: #569cd6; } .string { color: #ce9178; } .keyword { color: #c586c0; } .comment { color: #6a9955; } .info { background: #e3f2fd; border-left: 4px solid #2196f3; padding: 15px; margin: 20px 0; border-radius: 4px; } </style> </head> <body> <div class="container"> <div class="header"> <h1>${componentName}</h1> <p>OrdoJS Sample Test Website</p> </div> <div class="component"> <h2>šŸŽ‰ Sample Test Website Running!</h2> <p>This is your OrdoJS sample test website. The framework is working correctly!</p> <div class="info"> <strong>Features demonstrated:</strong> <ul style="margin: 10px 0; padding-left: 20px;"> <li>āœ… Reactive state management</li> <li>āœ… Server-client communication</li> <li>āœ… Form handling and validation</li> <li>āœ… Modern UI components</li> <li>āœ… Todo application functionality</li> <li>āœ… Error handling and notifications</li> </ul> </div> <p><strong>URL:</strong> <code>http://${this.host}:${this.port}</code></p> <p><strong>Component:</strong> <code>${componentName}</code></p> </div> <div class="source"> <h3>šŸ“ OrdoJS Source Code:</h3> <pre><code>${this.syntaxHighlight(source)}</code></pre> </div> </div> <script> console.log('šŸŽ‰ OrdoJS Sample Test Website is running!'); console.log('Component:', '${componentName}'); console.log('URL:', window.location.href); </script> </body> </html> `; } catch (error) { return ` <!DOCTYPE html> <html> <head><title>Compilation Error</title></head> <body> <h1>OrdoJS Compilation Error</h1> <p>Failed to compile component: ${error.message}</p> </body> </html> `; } } syntaxHighlight(code) { // Simple syntax highlighting for OrdoJS return code .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/(component|client|server|markup|function|let|const|if|else|for|while|return|import|export)/g, '<span class="keyword">$1</span>') .replace(/(["'`])(.*?)\1/g, '<span class="string">$1$2$1</span>') .replace(/(\/\/.*)/g, '<span class="comment">$1</span>') .replace(/(\{|\}|\(|\)|\[|\])/g, '<span class="highlight">$1</span>'); } stop() { if (this.server) { this.server.close(); console.log('šŸ›‘ Server stopped'); } } } // CLI interface if (import.meta.url === `file://${process.argv[1]}`) { const args = process.argv.slice(2); const command = args[0]; if (command === 'dev') { const options = { port: 3000, host: 'localhost', dir: '.' }; // Parse command line options for (let i = 1; i < args.length; i++) { if (args[i] === '--port' && args[i + 1]) { options.port = parseInt(args[i + 1]); } else if (args[i] === '--host' && args[i + 1]) { options.host = args[i + 1]; } else if (args[i] === '--dir' && args[i + 1]) { options.dir = args[i + 1]; } } const server = new SimpleOrdoJSDevServer(options); // Handle graceful shutdown process.on('SIGINT', () => { console.log('\nšŸ›‘ Shutting down server...'); server.stop(); process.exit(0); }); server.start().catch(error => { console.error('āŒ Failed to start server:', error.message); process.exit(1); }); } else { console.log('Usage: node simple-server.js dev [--port 3000] [--host localhost] [--dir .]'); process.exit(1); } } export default SimpleOrdoJSDevServer;