@ordojs/cli
Version:
Command-line interface for OrdoJS framework
337 lines (300 loc) ⢠11.3 kB
JavaScript
#!/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(`
<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(`
<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 `
<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 `
<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, '<')
.replace(/>/g, '>')
.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;