UNPKG

superuser-task-runner

Version:

A powerful task runner designed to manage complex development workflows across both monorepo and single-project configurations. Built as a more flexible alternative to Turborepo with enhanced customization capabilities, this tool focuses on unique deploym

178 lines (143 loc) 5.49 kB
#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const { loadEnvConfig } = require('./loadEnvConfig.js'); const colors = require('./colors.js'); const { ensureMethJsonExists, displayVersion } = require('./helpers.js'); // Function to display help function displayHelp() { console.log(`${colors.cyan}${colors.bright}STR ADD - Add commands to str.json${colors.reset}\n`); console.log(`${colors.bright}Usage:${colors.reset}`); console.log(` ${colors.green}Single Project:${colors.reset}`); console.log(` str-add <task-name> <command>`); console.log(` Example: str-add "test" "pnpm test"`); console.log(); console.log(` ${colors.green}Monorepo Project:${colors.reset}`); console.log(` str-add <task-name> <directory> <command>`); console.log(` Example: str-add "i:app" "apps/app" "pnpm i --filter app --prefer-offline --no-cache"`); console.log(); console.log(`${colors.bright}Options:${colors.reset}`); console.log(` -h, --help Show this help message`); console.log(` -v, --version Show version`); console.log(); console.log(`${colors.dim}The tool automatically detects single vs monorepo based on STR_CONFIG in .env${colors.reset}`); } // Function to add a task to str.json function addTask(taskName, directory, command) { const methJsonPath = ensureMethJsonExists(); try { // Read existing str.json const fileContent = fs.readFileSync(methJsonPath, 'utf-8'); const methData = JSON.parse(fileContent); // Ensure tasks object exists if (!methData.tasks) { methData.tasks = {}; } // Check if task already exists if (methData.tasks[taskName]) { console.log(`${colors.yellow}Task "${taskName}" already exists. Overwriting...${colors.reset}`); } // Create task object const taskObj = { command: command }; // Add directory if provided (monorepo style) if (directory) { taskObj.directory = directory; } // Add task to tasks object methData.tasks[taskName] = taskObj; // Write back to file with proper formatting fs.writeFileSync(methJsonPath, JSON.stringify(methData, null, 4), 'utf-8'); console.log(`${colors.green}${colors.bright}✓ Successfully added task "${taskName}"${colors.reset}`); // Display what was added console.log(`${colors.dim}Task details:${colors.reset}`); console.log(` Name: ${colors.cyan}${taskName}${colors.reset}`); if (directory) { console.log(` Directory: ${colors.cyan}${directory}${colors.reset}`); } console.log(` Command: ${colors.cyan}${command}${colors.reset}`); } catch (err) { console.error(`${colors.red}Failed to add task: ${err.message}${colors.reset}`); process.exit(1); } } // Function to validate task name function validateTaskName(taskName) { if (!taskName || taskName.trim() === '') { console.error(`${colors.red}Error: Task name cannot be empty${colors.reset}`); return false; } // Check for invalid characters const invalidChars = /[<>:"/\\|?*\x00-\x1f]/; if (invalidChars.test(taskName)) { console.error(`${colors.red}Error: Task name contains invalid characters${colors.reset}`); return false; } return true; } // Function to validate command function validateCommand(command) { if (!command || command.trim() === '') { console.error(`${colors.red}Error: Command cannot be empty${colors.reset}`); return false; } return true; } // Main function function main() { const args = process.argv.slice(2); // Handle help and version flags if (args.includes('-h') || args.includes('--help')) { displayHelp(); return; } if (args.includes('-v') || args.includes('--version')) { displayVersion(); return; } // Check if no arguments provided if (args.length === 0) { console.error(`${colors.red}Error: No arguments provided${colors.reset}\n`); displayHelp(); process.exit(1); } // Detect project type const methConfig = loadEnvConfig(); console.log(`${colors.dim}Detected project type: ${methConfig}${colors.reset}`); let taskName, directory, command; if (methConfig === 'monorepo') { // Monorepo: str-add <task-name> <directory> <command> if (args.length < 3) { console.error(`${colors.red}Error: Monorepo projects require 3 arguments: <task-name> <directory> <command>${colors.reset}\n`); displayHelp(); process.exit(1); } taskName = args[0]; directory = args[1]; command = args.slice(2).join(' '); // Join remaining args as command } else { // Single: str-add <task-name> <command> if (args.length < 2) { console.error(`${colors.red}Error: Single projects require 2 arguments: <task-name> <command>${colors.reset}\n`); displayHelp(); process.exit(1); } taskName = args[0]; directory = null; command = args.slice(1).join(' '); // Join remaining args as command } // Validate inputs if (!validateTaskName(taskName)) { process.exit(1); } if (!validateCommand(command)) { process.exit(1); } // Add the task addTask(taskName, directory, command); console.log(`\n${colors.green}${colors.bright}Task added successfully!${colors.reset}`); console.log(`${colors.dim}You can now run: ${colors.cyan}str ${taskName}${colors.reset} ${colors.dim}or use ${colors.cyan}str-ui${colors.reset} ${colors.dim}to see it in the interactive menu.${colors.reset}`); } // Run the main function main();