UNPKG

4bnode

Version:

A professional tool to generate a Node.js app by 4Brains Technologies

236 lines (209 loc) 7.35 kB
#!/usr/bin/env node import fs from "fs"; import path from "path"; import readline from "readline"; import chalk from "chalk"; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); function listRoutes() { const projectRoot = process.cwd(); const routesDir = path.join(projectRoot, "src", "routes"); if (!fs.existsSync(routesDir)) { console.error(chalk.red("No routes directory found in src/routes")); return []; } return fs.readdirSync(routesDir).filter((file) => file.endsWith(".js")); } function listModels() { const projectRoot = process.cwd(); const modelsDir = path.join(projectRoot, "src", "models"); if (!fs.existsSync(modelsDir)) { console.error(chalk.red("No models directory found in src/models")); return []; } return fs.readdirSync(modelsDir).filter((file) => file.endsWith(".js")); } function getModelSchema(modelName) { const projectRoot = process.cwd(); const modelFilePath = path.join( projectRoot, "src", "models", modelName + ".js" ); if (!fs.existsSync(modelFilePath)) { console.error(chalk.red(`Model file not found: ${modelFilePath}`)); return []; } const modelFileContent = fs.readFileSync(modelFilePath, "utf8"); const schemaRegex = /new mongoose\.Schema\s*\(\s*\{([\s\S]*?)\}\s*\)/m; const match = modelFileContent.match(schemaRegex); if (match) { try { const schemaContent = match[1]; const fieldRegex = /(\w+):\s*\{[\s\S]*?\}/g; const schemaKeys = ["_id"]; // Always include `_id` let fieldMatch; while ((fieldMatch = fieldRegex.exec(schemaContent)) !== null) { schemaKeys.push(fieldMatch[1]); } return schemaKeys; } catch (error) { console.error(chalk.red("Error parsing schema: "), error); return ["_id"]; } } else { console.error(chalk.red("Schema not found in model file.")); return ["_id"]; } } function addReadTemplateToRoute(routeFile, modelName, selectedField = null) { const projectRoot = process.cwd(); const routeFilePath = path.join(projectRoot, "src", "routes", routeFile); const pascalModelName = modelName.charAt(0).toUpperCase() + modelName.slice(1); const readTemplateImport = `import ${pascalModelName} from '../models/${modelName}.js';\n`; let readTemplateFunction; if (selectedField) { readTemplateFunction = ` // Fetch data based on ${selectedField} try { const documents = await ${pascalModelName}.find({ ${selectedField}: req.query.${selectedField} }); if (documents.length === 0) { return res.status(404).json({ message: "No matching documents found" }); } res.json({ data: documents }); } catch (err) { console.error(err); res.status(500).json({ message: "Server error" }); } `; } else { readTemplateFunction = ` // Fetch all data try { const documents = await ${pascalModelName}.find(); res.json({ data: documents }); } catch (err) { console.error(err); res.status(500).json({ message: "Server error" }); } `; } if (!fs.existsSync(routeFilePath)) { console.error( chalk.red(`The specified route file does not exist: ${routeFilePath}`) ); return; } let routeContent = fs.readFileSync(routeFilePath, "utf8"); if (!routeContent.includes(`import ${pascalModelName}`)) { routeContent = readTemplateImport + routeContent; } const lastCloseIndex = routeContent.lastIndexOf("});"); if (lastCloseIndex !== -1) { const updatedContent = [ routeContent.slice(0, lastCloseIndex), readTemplateFunction, routeContent.slice(lastCloseIndex), ].join("\n"); routeContent = updatedContent; } else { routeContent += `\n${readTemplateFunction}\n`; } fs.writeFileSync(routeFilePath, routeContent, "utf8"); console.log(chalk.green(`Read template added to ${routeFile}`)); } // Main Logic const routeFiles = listRoutes(); const modelFiles = listModels(); if (routeFiles.length === 0 || modelFiles.length === 0) { rl.close(); process.exit(0); } console.log(chalk.blue("Select the route file to modify:")); routeFiles.forEach((file, index) => { console.log(chalk.yellow(`${index + 1}. ${file}`)); }); rl.question( chalk.cyan("Enter the number of the route file: "), (routeAnswer) => { const routeIndex = parseInt(routeAnswer, 10) - 1; if (routeIndex >= 0 && routeIndex < routeFiles.length) { const selectedRoute = routeFiles[routeIndex]; console.log(chalk.blue("Select the model file to use:")); modelFiles.forEach((file, index) => { console.log(chalk.yellow(`${index + 1}. ${file}`)); }); rl.question( chalk.cyan("Enter the number of the model file: "), (modelAnswer) => { const modelIndex = parseInt(modelAnswer, 10) - 1; if (modelIndex >= 0 && modelIndex < modelFiles.length) { const selectedModel = path.basename(modelFiles[modelIndex], ".js"); const schemaFields = getModelSchema(selectedModel); console.log(chalk.green("Do you want to:")); console.log(chalk.green("1. Fetch all data")); console.log(chalk.green("2. Fetch data based on a specific field")); rl.question( chalk.cyan("Enter your choice (1 or 2): "), (choiceAnswer) => { if (choiceAnswer === "1") { addReadTemplateToRoute(selectedRoute, selectedModel); rl.close(); } else if (choiceAnswer === "2" && schemaFields.length > 0) { console.log( chalk.green( "Select a field to filter data by (_id is always available):" ) ); schemaFields.forEach((field, index) => { console.log(chalk.yellow(`${index + 1}. ${field}`)); }); rl.question( chalk.cyan("Enter the number of the field: "), (fieldAnswer) => { const fieldIndex = parseInt(fieldAnswer, 10) - 1; if (fieldIndex >= 0 && fieldIndex < schemaFields.length) { const selectedField = schemaFields[fieldIndex]; addReadTemplateToRoute( selectedRoute, selectedModel, selectedField ); } else { console.error( chalk.red( "Invalid selection. Please choose a valid field number." ) ); } rl.close(); } ); } else { console.error( chalk.red("Invalid choice. Please enter 1 or 2.") ); rl.close(); } } ); } else { console.error( chalk.red("Invalid selection. Please choose a valid number.") ); rl.close(); } } ); } else { console.error( chalk.red("Invalid selection. Please choose a valid number.") ); rl.close(); } } );