UNPKG

scaffold-scripts

Version:

Simple CLI tool for managing and running your own scripts. Add any script, run it anywhere.

324 lines 16.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AdvancedScriptConverter = void 0; class AdvancedScriptConverter { /** * Generate all platform versions of a script */ generateVersions(originalScript, scriptType, originalPlatform) { const versions = { original: originalScript }; // Generate platform-specific versions based on script type switch (scriptType.type) { case 'shell': versions.unix = originalScript; // Keep as-is for Unix versions.windows = this.convertShellToPowerShell(originalScript); versions.crossPlatform = this.generateCrossPlatformScript(originalScript, 'shell'); break; case 'powershell': versions.windows = originalScript; // Keep as-is for Windows versions.unix = this.convertPowerShellToShell(originalScript); versions.crossPlatform = this.generateCrossPlatformScript(originalScript, 'powershell'); break; case 'python': case 'nodejs': // Interpreter-based scripts work on all platforms with minor adjustments versions.unix = this.adjustForUnix(originalScript, scriptType.type); versions.windows = this.adjustForWindows(originalScript, scriptType.type); versions.crossPlatform = this.generateCrossPlatformScript(originalScript, scriptType.type); break; case 'batch': versions.windows = originalScript; // Keep as-is for Windows versions.unix = this.convertBatchToShell(originalScript); versions.crossPlatform = this.generateCrossPlatformScript(originalScript, 'batch'); break; default: // For mixed or unknown types, try to generate cross-platform version versions.crossPlatform = this.generateCrossPlatformScript(originalScript, 'mixed'); break; } return versions; } /** * Convert Shell script to PowerShell */ convertShellToPowerShell(script) { return script // Directory operations .replace(/mkdir -p\s+([^\\s&|;]+)/g, 'New-Item -ItemType Directory -Force -Path "$1"') .replace(/mkdir\s+([^\\s&|;]+)/g, 'New-Item -ItemType Directory -Force -Path "$1"') .replace(/rmdir\s+([^\\s&|;]+)/g, 'Remove-Item -Recurse -Force -Path "$1"') .replace(/rm -rf\s+([^\\s&|;]+)/g, 'Remove-Item -Recurse -Force -Path "$1"') .replace(/rm\s+([^\\s&|;]+)/g, 'Remove-Item -Path "$1"') // File operations .replace(/touch\s+([^\\s&|;]+)/g, 'New-Item -ItemType File -Force -Path "$1"') .replace(/cp\s+([^\\s&|;]+)\s+([^\\s&|;]+)/g, 'Copy-Item -Path "$1" -Destination "$2"') .replace(/mv\s+([^\\s&|;]+)\s+([^\\s&|;]+)/g, 'Move-Item -Path "$1" -Destination "$2"') // Output and text operations .replace(/echo\s+"([^"]+)"/g, 'Write-Output "$1"') .replace(/echo\s+'([^']+)'/g, "Write-Output '$1'") .replace(/echo\s+([^\\s&|;]+)/g, 'Write-Output $1') .replace(/cat\s+([^\\s&|;]+)/g, 'Get-Content -Path "$1"') // Listing and finding .replace(/ls\s+([^\\s&|;]+)/g, 'Get-ChildItem -Path "$1"') .replace(/ls$/g, 'Get-ChildItem') .replace(/find\s+([^\\s&|;]+)\s+-name\s+"([^"]+)"/g, 'Get-ChildItem -Path "$1" -Name "$2" -Recurse') .replace(/grep\s+([^\\s&|;]+)\s+([^\\s&|;]+)/g, 'Select-String -Pattern "$1" -Path "$2"') // Environment and system .replace(/export\s+([A-Z_]+)=([^\\s&|;]+)/g, '$env:$1="$2"') .replace(/\$([A-Z_]+)/g, '$env:$1') .replace(/which\s+([^\\s&|;]+)/g, 'Get-Command "$1"') .replace(/whoami/g, '$env:USERNAME') .replace(/pwd/g, 'Get-Location') // Path separators .replace(/\//g, '\\\\') // Control flow - handle complex patterns first, then simple ones .replace(/(.+?)\s+&&\s+(.+?)\s+\|\|\s+(.+)/g, (match, first, second, third) => { // Handle: cmd1 && cmd2 || cmd3 return `${first.trim()}; if ($?) { ${second.trim()} } else { ${third.trim()} }`; }) .replace(/(.+?)\s+&&\s+(.+)/g, (match, first, second) => { // Handle: cmd1 && cmd2 return `${first.trim()}; if ($?) { ${second.trim()} }`; }) .replace(/(.+?)\s+\|\|\s+(.+)/g, (match, first, second) => { // Handle: cmd1 || cmd2 return `${first.trim()}; if (-not $?) { ${second.trim()} }`; }); } /** * Convert PowerShell script to Shell */ convertPowerShellToShell(script) { let converted = script; // Handle PowerShell arrays first converted = this.convertPowerShellArrays(converted); // Handle PowerShell conditionals and try/catch blocks converted = this.convertPowerShellControlFlow(converted); // Standard PowerShell command conversions converted = converted // Directory operations with better parameter handling .replace(/New-Item\s+-ItemType\s+Directory\s+-Force\s+-Path\s+"?([^"\\s]+)"?(?:\s+\|\s+Out-Null)?/gi, 'mkdir -p "$1"') .replace(/New-Item\s+-ItemType\s+Directory\s+-Path\s+"?([^"\\s]+)"?(?:\s+\|\s+Out-Null)?/gi, 'mkdir -p "$1"') .replace(/Remove-Item\s+-Recurse\s+-Force\s+-Path\s+"?([^"\\s]+)"?/gi, 'rm -rf "$1"') .replace(/Remove-Item\s+-Path\s+"?([^"\\s]+)"?/gi, 'rm "$1"') // File operations with parameter variations .replace(/New-Item\s+-ItemType\s+File\s+-Force\s+-Path\s+"?([^"\\s]+)"?(?:\s+\|\s+Out-Null)?/gi, 'touch "$1"') .replace(/Copy-Item\s+-Path\s+"?([^"\\s]+)"?\s+-Destination\s+"?([^"\\s]+)"?/gi, 'cp "$1" "$2"') .replace(/Move-Item\s+-Path\s+"?([^"\\s]+)"?\s+-Destination\s+"?([^"\\s]+)"?/gi, 'mv "$1" "$2"') // Output operations with color parameters .replace(/Write-Host\s+"([^"]+)"\s+-ForegroundColor\s+\w+/gi, 'echo "$1"') .replace(/Write-Host\s+'([^']+)'\s+-ForegroundColor\s+\w+/gi, "echo '$1'") .replace(/Write-Host\s+"([^"]+)"\s+-NoNewline\s+-ForegroundColor\s+\w+/gi, 'printf "$1"') .replace(/Write-Output\s+"([^"]+)"/gi, 'echo "$1"') .replace(/Write-Output\s+'([^']+)'/gi, "echo '$1'") .replace(/Write-Output\s+([^\\s;]+)/gi, 'echo $1') .replace(/Write-Host\s+"([^"]+)"/gi, 'echo "$1"') .replace(/Write-Host\s+'([^']+)'/gi, "echo '$1'") .replace(/Write-Host\s+([^\\s;]+)/gi, 'echo $1') .replace(/Get-Content\s+-Path\s+"?([^"\\s]+)"?/gi, 'cat "$1"') // Listing and finding with better parameter handling .replace(/Get-ChildItem\s+-Path\s+"?([^"\\s]+)"?\s+-Recurse\s+-Force/gi, 'find "$1" -type f') .replace(/Get-ChildItem\s+-Path\s+"?([^"\\s]+)"?/gi, 'ls "$1"') .replace(/Get-ChildItem(?:\s+|$)/gi, 'ls') .replace(/Select-String\s+-Pattern\s+"?([^"\\s]+)"?\s+-Path\s+"?([^"\\s]+)"?/gi, 'grep "$1" "$2"') // Environment and system with better variable handling .replace(/\$env:([A-Z_]+)\s*=\s*"([^"]+)"/gi, 'export $1="$2"') .replace(/\$env:([A-Z_]+)/gi, '$$$1') .replace(/Get-Command\s+"?([^"\\s]+)"?/gi, 'which "$1"') .replace(/\$env:USERNAME/gi, '$(whoami)') .replace(/Get-Location/gi, 'pwd') // PowerShell-specific variable syntax .replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*Get-Location/gi, '$1=$(pwd)') .replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*Read-Host/gi, 'read -p "Enter value: " $1') // PowerShell Set-Location to cd .replace(/Set-Location\s+"?([^"\\s]+)"?/gi, 'cd "$1"') .replace(/Set-Location\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/gi, 'cd "$$1"') // PowerShell Test-Path to file test .replace(/Test-Path\s+"?([^"\\s]+)"?/gi, '[ -e "$1" ]') .replace(/-not\s+\(Test-Path\s+"?([^"\\s]+)"?\)/gi, '[ ! -e "$1" ]') // Path separators .replace(/\\\\/gi, '/'); return converted; } /** * Convert PowerShell arrays to shell arrays */ convertPowerShellArrays(script) { // Convert PowerShell array syntax @('item1', 'item2') to shell array return script.replace(/@\(\s*([^)]+)\s*\)/g, (match, items) => { // Split items and clean them up const itemList = items.split(',').map((item) => item.trim()); return '(' + itemList.join(' ') + ')'; }); } /** * Convert PowerShell control flow to shell equivalents */ convertPowerShellControlFlow(script) { let converted = script; // Convert PowerShell if statements converted = converted.replace(/if\s*\(\s*([^)]+)\s*\)\s*\{/gi, 'if [ $1 ]; then'); // Convert PowerShell try/catch blocks converted = converted.replace(/try\s*\{/gi, '# try block - error handling in shell:'); converted = converted.replace(/\}\s*catch\s*\{/gi, '# catch block:'); converted = converted.replace(/catch\s*\{([^}]+)\}/gi, '# error handler: $1'); // Convert PowerShell foreach loops converted = converted.replace(/foreach\s*\(\s*\$([^\\s]+)\s+in\s+\$([^)]+)\)\s*\{/gi, 'for $1 in $$2; do'); // Convert PowerShell string tests converted = converted.replace(/\[string\]::IsNullOrWhiteSpace\(\$([^)]+)\)/gi, '[ -z "$$1" ]'); // Convert exit statements converted = converted.replace(/exit\s+(\d+)/gi, 'exit $1'); // Convert PowerShell else statements converted = converted.replace(/\}\s*else\s*\{/gi, 'else'); // Clean up remaining braces converted = converted.replace(/\}/gi, 'fi').replace(/fi\s*fi/gi, 'fi'); return converted; } /** * Convert Batch script to Shell */ convertBatchToShell(script) { return script // Directory operations .replace(/mkdir\s+([^\\s&|]+)/gi, 'mkdir -p "$1"') .replace(/rmdir\s+\/s\s+([^\\s&|]+)/gi, 'rm -rf "$1"') .replace(/del\s+([^\\s&|]+)/gi, 'rm "$1"') // Output operations .replace(/echo\s+(.+)/gi, 'echo $1') .replace(/@echo\s+off/gi, '# Echo off equivalent') // File operations .replace(/copy\s+([^\\s&|]+)\s+([^\\s&|]+)/gi, 'cp "$1" "$2"') .replace(/move\s+([^\\s&|]+)\s+([^\\s&|]+)/gi, 'mv "$1" "$2"') .replace(/type\s+([^\\s&|]+)/gi, 'cat "$1"') // Directory listing .replace(/dir\s+([^\\s&|]+)/gi, 'ls "$1"') .replace(/dir$/gi, 'ls') // Environment variables .replace(/%([A-Z_]+)%/g, '$$$1') .replace(/set\s+([A-Z_]+)=([^\\s&|]+)/gi, 'export $1="$2"') // Control flow .replace(/if\s+exist\s+([^\\s&|]+)/gi, 'if [ -e "$1" ]') .replace(/goto\s+([^\\s&|]+)/gi, '# goto $1 - not directly supported in shell') // Path separators .replace(/\\\\/g, '/'); } /** * Adjust interpreter-based scripts for Unix */ adjustForUnix(script, type) { let adjusted = script; if (type === 'python') { adjusted = adjusted // Virtual environment activation .replace(/venv\\\\Scripts\\\\activate/g, 'venv/bin/activate') .replace(/source\s+venv\\\\Scripts\\\\activate/g, 'source venv/bin/activate') // Path separators .replace(/\\\\/g, '/'); } if (type === 'nodejs') { adjusted = adjusted // npm/yarn commands work the same // Path separators .replace(/\\\\/g, '/'); } return adjusted; } /** * Adjust interpreter-based scripts for Windows */ adjustForWindows(script, type) { let adjusted = script; if (type === 'python') { adjusted = adjusted // Virtual environment activation .replace(/venv\/bin\/activate/g, 'venv\\\\Scripts\\\\activate') .replace(/source\s+venv\/bin\/activate/g, 'venv\\\\Scripts\\\\activate.bat') // Path separators .replace(/\//g, '\\\\'); } if (type === 'nodejs') { adjusted = adjusted // npm/yarn commands work the same // Path separators .replace(/\//g, '\\\\'); } return adjusted; } /** * Generate a cross-platform script using abstracted commands */ generateCrossPlatformScript(script, originalType) { // For now, create a simplified cross-platform version with comments const lines = script.split('\n'); const crossPlatformLines = []; crossPlatformLines.push('# Cross-platform script - automatically generated'); crossPlatformLines.push('# Original type: ' + originalType); crossPlatformLines.push(''); for (const line of lines) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('//')) { crossPlatformLines.push(line); continue; } // Convert common operations to cross-platform comments if (trimmed.includes('mkdir')) { crossPlatformLines.push('# Create directory: ' + this.extractPath(trimmed)); } else if (trimmed.includes('touch') || trimmed.includes('New-Item') && trimmed.includes('File')) { crossPlatformLines.push('# Create file: ' + this.extractPath(trimmed)); } else if (trimmed.includes('echo') || trimmed.includes('Write-Output') || trimmed.includes('Write-Host')) { crossPlatformLines.push('# Output: ' + this.extractMessage(trimmed)); } else if (trimmed.includes('ls') || trimmed.includes('Get-ChildItem') || trimmed.includes('dir')) { crossPlatformLines.push('# List directory: ' + this.extractPath(trimmed)); } else { crossPlatformLines.push('# Execute: ' + trimmed); } } return crossPlatformLines.join('\n'); } /** * Extract file/directory path from command */ extractPath(command) { const pathMatch = command.match(/["']([^"']+)["']/) || command.match(/\s+([^\\s]+)$/); return pathMatch ? pathMatch[1] : 'unknown'; } /** * Extract message from echo/output command */ extractMessage(command) { const messageMatch = command.match(/echo\s+"([^"]+)"/) || command.match(/echo\s+'([^']+)'/) || command.match(/Write-Output\s+"([^"]+)"/) || command.match(/Write-Host\s+"([^"]+)"/); return messageMatch ? messageMatch[1] : command.replace(/^.*echo\s+|^.*Write-Output\s+|^.*Write-Host\s+/, ''); } /** * Get the best script version for current platform */ getBestScriptForPlatform(command, currentPlatform) { const isWindows = currentPlatform === 'win32'; // Priority order for script selection if (isWindows) { if (command.script_windows) return command.script_windows; if (command.script_cross_platform) return command.script_cross_platform; return command.script_original; } else { if (command.script_unix) return command.script_unix; if (command.script_cross_platform) return command.script_cross_platform; return command.script_original; } } } exports.AdvancedScriptConverter = AdvancedScriptConverter; //# sourceMappingURL=scriptConverter.js.map