UNPKG

@burgan-tech/vnext-template

Version:

vNext template package with domain-based workflow components and schema validation

244 lines (209 loc) 6.94 kB
#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const readline = require('readline'); // Load configuration from vnext.config.json function loadConfig() { try { return JSON.parse(fs.readFileSync('vnext.config.json', 'utf8')); } catch (error) { return null; } } // Get paths configuration with defaults function getPathsConfig() { const config = loadConfig(); const defaults = { componentsRoot: '{domainName}', schemas: 'Schemas', workflows: 'Workflows', tasks: 'Tasks', views: 'Views', functions: 'Functions', extensions: 'Extensions' }; if (config && config.paths) { return { ...defaults, ...config.paths }; } return defaults; } // Check if already set up (componentsRoot directory exists with vnext structure) function isAlreadySetup() { const pathsConfig = getPathsConfig(); const componentsRoot = pathsConfig.componentsRoot; // Check if componentsRoot directory exists and contains vnext structure if (componentsRoot && fs.existsSync(componentsRoot)) { const schemasPath = path.join(componentsRoot, pathsConfig.schemas); const workflowsPath = path.join(componentsRoot, pathsConfig.workflows); const tasksPath = path.join(componentsRoot, pathsConfig.tasks); if (fs.existsSync(schemasPath) || fs.existsSync(workflowsPath) || fs.existsSync(tasksPath)) { return true; } } return false; } // Validate domain name function validateDomainName(domainName) { if (!domainName) { console.error('❌ Domain name cannot be empty'); return false; } // Validate domain name format (alphanumeric, hyphens, underscores) if (!/^[a-zA-Z0-9_-]+$/.test(domainName)) { console.error('❌ Domain name can only contain letters, numbers, hyphens, and underscores'); return false; } return true; } // Prompt for domain name function promptDomainName() { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); return new Promise((resolve) => { rl.question('Enter your domain name (e.g., "user-management", "order-processing"): ', (answer) => { rl.close(); const domainName = answer.trim(); if (!validateDomainName(domainName)) { process.exit(1); } resolve(domainName); }); }); } // Get domain name from command line arguments, environment variable, or prompt async function getDomainName() { // Check for command line argument const args = process.argv.slice(2); if (args.length > 0) { const domainName = args[0].trim(); if (validateDomainName(domainName)) { return domainName; } else { process.exit(1); } } // Check for environment variable (for npm install usage) if (process.env.DOMAIN_NAME) { const domainName = process.env.DOMAIN_NAME.trim(); if (validateDomainName(domainName)) { return domainName; } else { console.error(`❌ Invalid domain name in DOMAIN_NAME environment variable: ${domainName}`); process.exit(1); } } // Otherwise prompt for it return await promptDomainName(); } // Replace {domainName} in a file function replaceInFile(filePath, domainName) { try { let content = fs.readFileSync(filePath, 'utf8'); const originalContent = content; content = content.replace(/\{domainName\}/g, domainName); if (content !== originalContent) { fs.writeFileSync(filePath, content, 'utf8'); return true; } return false; } catch (error) { console.warn(`⚠️ Warning: Could not process ${filePath}: ${error.message}`); return false; } } // Replace {domainName} in all files recursively function replaceInDirectory(dirPath, domainName, processedFiles = new Set()) { if (!fs.existsSync(dirPath)) { return; } const entries = fs.readdirSync(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); const relativePath = path.relative('.', fullPath); // Skip node_modules, .git, and other common directories if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist' || entry.name === '.github' || entry.name.startsWith('.')) { continue; } if (entry.isDirectory()) { replaceInDirectory(fullPath, domainName, processedFiles); } else if (entry.isFile()) { // Process text files const ext = path.extname(entry.name).toLowerCase(); if (['.json', '.js', '.md', '.sh', '.txt', '.yml', '.yaml'].includes(ext) || entry.name === '.gitignore' || entry.name === '.gitattributes') { if (!processedFiles.has(relativePath)) { if (replaceInFile(fullPath, domainName)) { processedFiles.add(relativePath); } } } } } } // Rename {domainName} directory function renameDomainDirectory(domainName) { const templateDir = '{domainName}'; const targetDir = domainName; if (fs.existsSync(templateDir)) { if (fs.existsSync(targetDir)) { console.error(`❌ Error: Directory ${targetDir} already exists`); process.exit(1); } fs.renameSync(templateDir, targetDir); console.log(` ✓ Renamed ${templateDir}/ to ${targetDir}/`); return true; } return false; } // Check if running in node_modules (installed as dependency) function isInstalledAsDependency() { const cwd = process.cwd(); return cwd.includes('node_modules'); } // Main setup function async function setup() { // Skip if installed as a dependency if (isInstalledAsDependency()) { return; } // Check if already set up first if (isAlreadySetup()) { return; } // Check if {domainName} directory exists (template not yet configured) if (!fs.existsSync('{domainName}')) { console.log('⚠️ Template directory {domainName} not found'); console.log(' This might already be a configured project.\n'); return; } console.log('🚀 vNext Template Setup'); console.log('=======================\n'); // Get domain name from command line or prompt const domainName = await getDomainName(); console.log(`\n📝 Setting up domain: ${domainName}\n`); // Replace in all files console.log('🔄 Replacing {domainName} in files...'); const processedFiles = new Set(); replaceInDirectory('.', domainName, processedFiles); console.log(` ✓ Processed ${processedFiles.size} file(s)`); // Rename directory console.log('\n📁 Renaming domain directory...'); renameDomainDirectory(domainName); console.log('\n✅ Setup complete!'); console.log(`\nYour domain "${domainName}" is now configured.`); console.log('You can start adding your schemas, workflows, tasks, and other components.\n'); } // Run setup setup().catch((error) => { console.error('❌ Setup failed:', error.message); process.exit(1); });