scaffold-scripts
Version:
Simple CLI tool for managing and running your own scripts. Add any script, run it anywhere.
287 lines • 10.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScriptTypeDetector = void 0;
class ScriptTypeDetector {
/**
* Detect script type from content
*/
detectType(script) {
const lines = script.split('\n').map(line => line.trim()).filter(line => line);
if (lines.length === 0) {
return { type: 'shell', interpreters: ['bash'], extensions: ['.sh'] };
}
// Check shebang
const firstLine = lines[0];
if (firstLine.startsWith('#!')) {
return this.detectFromShebang(firstLine);
}
// Analyze content patterns
return this.detectFromContent(script);
}
/**
* Detect the original platform of the script
*/
detectPlatform(script) {
const windowsPatterns = [
/New-Item\s+-ItemType/,
/Get-ChildItem/,
/Write-Output|Write-Host/,
/\$env:/,
/\.ps1\b/,
/Copy-Item|Move-Item/,
/@echo\s+off/i,
/set\s+\w+=/,
/\.bat\b|\.cmd\b/,
/rmdir\s+\/s/,
/\\\\/ // Windows path separators
];
const unixPatterns = [
/mkdir\s+-p/,
/ls\s+/,
/echo\s+/,
/export\s+\w+=/,
/\.sh\b/,
/cp\s+|mv\s+/,
/rm\s+-rf/,
/which\s+/,
/chmod\s+/,
/\//, // Unix path separators
/#!\s*\/.*\/(bash|sh|python|node)/
];
const windowsScore = this.countMatches(script, windowsPatterns);
const unixScore = this.countMatches(script, unixPatterns);
// If scores are close, consider it cross-platform
if (Math.abs(windowsScore - unixScore) <= 1 && windowsScore + unixScore > 0) {
return 'cross-platform';
}
if (windowsScore > unixScore) {
return 'windows';
}
else if (unixScore > windowsScore) {
return 'unix';
}
else {
return 'cross-platform';
}
}
/**
* Detect from shebang line
*/
detectFromShebang(shebang) {
if (shebang.includes('python')) {
return {
type: 'python',
interpreters: ['python', 'python3'],
extensions: ['.py'],
shebang
};
}
if (shebang.includes('node')) {
return {
type: 'nodejs',
interpreters: ['node'],
extensions: ['.js', '.mjs'],
shebang
};
}
if (shebang.includes('bash') || shebang.includes('sh')) {
return {
type: 'shell',
interpreters: ['bash', 'sh'],
extensions: ['.sh'],
shebang
};
}
// Default to shell for unknown shebangs
return {
type: 'shell',
interpreters: ['bash'],
extensions: ['.sh'],
shebang
};
}
/**
* Detect from script content patterns
*/
detectFromContent(script) {
const pythonPatterns = [
/import\s+\w+/,
/from\s+\w+\s+import/,
/def\s+\w+\(/,
/if\s+__name__\s*==\s*['""]__main__['""]:/,
/pip\s+install/,
/python\s+-m\s+venv/,
/\.py\b/,
/input\s*\(/,
/print\s*\(/,
/f["'][^"']*\{[^}]*\}/
];
const nodePatterns = [
/require\s*\(['"]/,
/module\.exports/,
/npm\s+(install|run|start)/,
/yarn\s+(install|run|start)/,
/package\.json/,
/node_modules/,
/\.js\b|\.ts\b|\.mjs\b/
];
const powershellPatterns = [
/Write-Host/,
/Write-Output/,
/Get-\w+/,
/Set-\w+/,
/New-\w+/,
/\$\w+\s*=/,
/\$env:/,
/\.ps1\b/,
/-ForegroundColor/,
/-ItemType/,
/ni\s+-ItemType/,
/New-Item/,
/Copy-Item/,
/Move-Item/,
/Test-Path/,
/Join-Path/,
/Split-Path/,
/Read-Host/,
/\[string\]::/,
/\$LASTEXITCODE/,
/param\s*\(/
];
const batchPatterns = [
/@echo\s+off/i,
/\.bat\b|\.cmd\b/,
/set\s+\w+=/,
/if\s+exist/i,
/goto\s+\w+/i
];
// Count matches for each type
const pythonScore = this.countMatches(script, pythonPatterns);
const nodeScore = this.countMatches(script, nodePatterns);
const powershellScore = this.countMatches(script, powershellPatterns);
const batchScore = this.countMatches(script, batchPatterns);
// Determine the dominant type (prioritize PowerShell detection)
const scores = [
{ type: 'powershell', score: powershellScore, info: { interpreters: ['powershell', 'pwsh'], extensions: ['.ps1'] } },
{ type: 'python', score: pythonScore, info: { interpreters: ['python', 'python3'], extensions: ['.py'] } },
{ type: 'nodejs', score: nodeScore, info: { interpreters: ['node'], extensions: ['.js', '.mjs'] } },
{ type: 'batch', score: batchScore, info: { interpreters: ['cmd'], extensions: ['.bat', '.cmd'] } }
];
const maxScore = Math.max(...scores.map(s => s.score));
if (maxScore === 0) {
// No specific patterns found, default to shell
return { type: 'shell', interpreters: ['bash'], extensions: ['.sh'] };
}
// Check if multiple types have high scores (mixed script)
const highScorers = scores.filter(s => s.score >= maxScore * 0.7);
if (highScorers.length > 1) {
return {
type: 'mixed',
interpreters: highScorers.flatMap(s => s.info.interpreters),
extensions: highScorers.flatMap(s => s.info.extensions)
};
}
const winner = scores.find(s => s.score === maxScore);
return {
type: winner.type,
interpreters: winner.info.interpreters,
extensions: winner.info.extensions
};
}
/**
* Count pattern matches in script
*/
countMatches(script, patterns) {
return patterns.reduce((count, pattern) => {
const matches = script.match(pattern);
return count + (matches ? matches.length : 0);
}, 0);
}
/**
* Generate appropriate execution command for script type
*/
getExecutionCommand(scriptType, scriptPath) {
switch (scriptType.type) {
case 'python':
// Try python3 first, then python
return `python3 "${scriptPath}"`;
case 'nodejs':
return `node "${scriptPath}"`;
case 'powershell':
// Try pwsh first (cross-platform), then fall back to powershell.exe on Windows
if (process.platform === 'win32') {
return `pwsh -ExecutionPolicy Bypass -File "${scriptPath}"`;
}
else {
return `pwsh -File "${scriptPath}"`;
}
case 'batch':
return `"${scriptPath}"`;
case 'shell':
return `bash "${scriptPath}"`;
case 'mixed':
// For mixed scripts, default to shell execution
return `bash "${scriptPath}"`;
default:
return `bash "${scriptPath}"`;
}
}
/**
* Check if required interpreters are available
*/
async checkInterpreterAvailability(scriptType) {
const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
const { promisify } = await Promise.resolve().then(() => __importStar(require('util')));
const execAsync = promisify(exec);
const available = [];
const missing = [];
for (const interpreter of scriptType.interpreters) {
try {
const command = process.platform === 'win32' ?
`where ${interpreter}` :
`which ${interpreter}`;
await execAsync(command);
available.push(interpreter);
}
catch {
missing.push(interpreter);
}
}
return { available, missing };
}
}
exports.ScriptTypeDetector = ScriptTypeDetector;
//# sourceMappingURL=scriptTypeDetector.js.map