UNPKG

initrajs

Version:

⚡ InitraJS - JavaScript CLI Toolkit | Lightning-fast scaffolding for React, Next.js, Node.js with TypeScript | The future of JavaScript development | 10x faster than create-react-app | Ultimate developer productivity tool

308 lines (285 loc) 10.3 kB
import fs from 'fs-extra'; import path from 'path'; import chalk from 'chalk'; const validateName = (name) => /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name); const detectFramework = () => { const cwd = process.cwd(); const packagePath = path.join(cwd, 'package.json'); if (fs.existsSync(packagePath)) { const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8')); if (pkg.dependencies?.next || pkg.devDependencies?.next) return 'next'; if (pkg.dependencies?.react || pkg.devDependencies?.react) return 'react'; if (pkg.dependencies?.express || pkg.devDependencies?.express) return 'node'; } return 'react'; }; const getAPIRouteTemplate = (routeName, method, isTypeScript, framework) => { const methodUpper = method.toUpperCase(); if (framework === 'next') { // Next.js API Route const typeImport = isTypeScript ? "import { NextRequest, NextResponse } from 'next/server';\n\n" : ''; const paramTypes = isTypeScript ? ': NextRequest' : ''; const responseType = isTypeScript ? ': Promise<NextResponse>' : ''; return `${typeImport}export async function ${methodUpper}(request${paramTypes})${responseType} { try { // Handle ${methodUpper} request for ${routeName} ${methodUpper === 'GET' ? ` // Example: Fetch data const data = { message: '${routeName} data fetched successfully', timestamp: new Date().toISOString() }; return NextResponse.json(data);` : methodUpper === 'POST' ? ` const body = await request.json(); // Example: Process the data const result = { message: '${routeName} created successfully', data: body, id: Math.random().toString(36).substr(2, 9) }; return NextResponse.json(result, { status: 201 });` : methodUpper === 'PUT' ? ` const body = await request.json(); // Example: Update data const result = { message: '${routeName} updated successfully', data: body, timestamp: new Date().toISOString() }; return NextResponse.json(result);` : ` // Example: Delete data const result = { message: '${routeName} deleted successfully', timestamp: new Date().toISOString() }; return NextResponse.json(result);`} } catch (error) { console.error('Error in ${routeName} ${methodUpper}:', error); return NextResponse.json( { error: 'Internal Server Error' }, { status: 500 } ); } }`; } else { // Express.js API Route const typeImport = isTypeScript ? "import { Request, Response } from 'express';\n\n" : ''; const paramTypes = isTypeScript ? ': Request, res: Response' : ''; return `${typeImport}export const ${method.toLowerCase()}${routeName.charAt(0).toUpperCase() + routeName.slice(1)} = (req${paramTypes}) => { try { ${methodUpper === 'GET' ? ` // Example: Fetch data const data = { message: '${routeName} data fetched successfully', timestamp: new Date().toISOString() }; res.json(data);` : methodUpper === 'POST' ? ` const body = req.body; // Example: Process the data const result = { message: '${routeName} created successfully', data: body, id: Math.random().toString(36).substr(2, 9) }; res.status(201).json(result);` : methodUpper === 'PUT' ? ` const body = req.body; // Example: Update data const result = { message: '${routeName} updated successfully', data: body, timestamp: new Date().toISOString() }; res.json(result);` : ` // Example: Delete data const result = { message: '${routeName} deleted successfully', timestamp: new Date().toISOString() }; res.json(result);`} } catch (error) { console.error('Error in ${routeName} ${methodUpper}:', error); res.status(500).json({ error: 'Internal Server Error' }); } };`; } }; const getPageRouteTemplate = (routeName, isTypeScript, framework) => { const componentName = routeName.charAt(0).toUpperCase() + routeName.slice(1); if (framework === 'next') { // Next.js Page Component const typeImport = isTypeScript ? "import { Metadata } from 'next';\n" : ''; const metadataExport = isTypeScript ? ` export const metadata: Metadata = { title: '${componentName}', description: '${componentName} page description', };\n` : ''; return `${typeImport}import styles from './${routeName}.module.css'; ${metadataExport} export default function ${componentName}Page() { return ( <div className={styles.container}> <h1 className={styles.title}>${componentName}</h1> <p className={styles.description}> Welcome to the ${componentName} page. </p> <div className={styles.content}> {/* Your page content goes here */} <div className={styles.card}> <h2>Getting Started</h2> <p>Edit this page to add your content.</p> </div> </div> </div> ); }`; } else { // React Page Component return `import React from 'react'; import styles from './${routeName}.module.css'; const ${componentName}Page${isTypeScript ? ': React.FC' : ''} = () => { return ( <div className={styles.container}> <h1 className={styles.title}>${componentName}</h1> <p className={styles.description}> Welcome to the ${componentName} page. </p> <div className={styles.content}> {/* Your page content goes here */} <div className={styles.card}> <h2>Getting Started</h2> <p>Edit this page to add your content.</p> </div> </div> </div> ); }; export default ${componentName}Page;`; } }; const getPageCSSTemplate = (routeName) => { return `.container { min-height: 100vh; padding: 2rem; background-color: #f5f5f5; } .title { font-size: 2.5rem; font-weight: bold; color: #333; text-align: center; margin-bottom: 1rem; } .description { font-size: 1.2rem; color: #666; text-align: center; margin-bottom: 2rem; } .content { max-width: 800px; margin: 0 auto; } .card { background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); margin-bottom: 1rem; } .card h2 { color: #333; margin-bottom: 1rem; } .card p { color: #666; line-height: 1.6; }`; }; export const generateRoute = async (name, options) => { try { // Validate route name if (!validateName(name)) { console.error(chalk.red('❌ Invalid route name. Use only letters, numbers, hyphens and underscores. Must start with a letter.')); return; } // Determine language preference const isTypeScript = options.typescript || (!options.javascript && true); const isAPI = options.api || false; const method = options.method?.toUpperCase() || 'GET'; // Validate HTTP method for API routes if (isAPI && !['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)) { console.error(chalk.red('❌ Invalid HTTP method. Use GET, POST, PUT, DELETE, or PATCH.')); return; } // Detect framework const framework = detectFramework(); // Determine route directory based on framework and type let routeDir; let fileName; const fileExt = isTypeScript ? 'ts' : 'js'; if (framework === 'next') { if (isAPI) { // Next.js API routes go in app/api/ routeDir = path.join(process.cwd(), 'src', 'app', 'api', options.path || '', name); fileName = 'route'; } else { // Next.js pages go in app/ routeDir = path.join(process.cwd(), 'src', 'app', options.path || '', name); fileName = 'page'; } } else { // React/Node routes const baseDir = isAPI ? 'routes' : 'pages'; routeDir = path.join(process.cwd(), 'src', baseDir, options.path || ''); fileName = name; } // Create directory await fs.ensureDir(routeDir); // Generate route content let routeContent; let cssContent = null; if (isAPI) { routeContent = getAPIRouteTemplate(name, method, isTypeScript, framework); } else { routeContent = getPageRouteTemplate(name, isTypeScript, framework); cssContent = getPageCSSTemplate(name); } // Write route file const routeFile = path.join(routeDir, `${fileName}.${isAPI ? fileExt : (isTypeScript ? 'tsx' : 'jsx')}`); await fs.writeFile(routeFile, routeContent); // Write CSS file for page routes if (cssContent) { const cssFile = path.join(routeDir, `${name}.module.css`); await fs.writeFile(cssFile, cssContent); } // Success message console.log(chalk.green(`✅ ${framework} ${isAPI ? 'API' : 'page'} route created successfully!`)); console.log(chalk.blue(`📁 Location: ${path.relative(process.cwd(), routeDir)}`)); console.log(chalk.blue(`📄 Files created:`)); console.log(chalk.blue(` - ${fileName}.${isAPI ? fileExt : (isTypeScript ? 'tsx' : 'jsx')}`)); if (cssContent) { console.log(chalk.blue(` - ${name}.module.css`)); } if (isAPI) { console.log(chalk.yellow(`🌐 HTTP Method: ${method}`)); console.log(chalk.yellow(`🔗 URL: /api/${options.path ? options.path + '/' : ''}${name}`)); } else { console.log(chalk.yellow(`🔗 URL: /${options.path ? options.path + '/' : ''}${name}`)); } } catch (error) { console.error(chalk.red('❌ Route generation failed')); if (error instanceof Error) { console.error(chalk.red(error.message)); } process.exit(1); } };