@sun-asterisk/sunlint
Version:
āļø SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards
165 lines (139 loc) ⢠5.41 kB
JavaScript
/**
* Smart Dependency Auto-Installer
* Automatically installs missing peer dependencies when SunLint runs
* Future: Will support package flavor recommendations
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
class SmartInstaller {
constructor() {
this.installedInSession = new Set();
this.packageFlavors = {
'typescript': '@sun-asterisk/sunlint-typescript',
'dart': '@sun-asterisk/sunlint-dart',
'python': '@sun-asterisk/sunlint-python',
'go': '@sun-asterisk/sunlint-go',
'full': '@sun-asterisk/sunlint-full'
};
}
/**
* Detect project type and recommend appropriate packages
*/
detectProjectType(projectRoot) {
const packageJsonPath = path.join(projectRoot, 'package.json');
if (!fs.existsSync(packageJsonPath)) return ['basic'];
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const types = [];
// Check for TypeScript
if (packageJson.devDependencies?.typescript ||
packageJson.dependencies?.typescript ||
fs.existsSync(path.join(projectRoot, 'tsconfig.json'))) {
types.push('typescript');
}
// Check for other languages (future)
if (fs.existsSync(path.join(projectRoot, 'pubspec.yaml'))) {
types.push('dart');
}
if (fs.existsSync(path.join(projectRoot, 'requirements.txt')) ||
fs.existsSync(path.join(projectRoot, 'pyproject.toml'))) {
types.push('python');
}
if (fs.existsSync(path.join(projectRoot, 'go.mod'))) {
types.push('go');
}
return types.length > 0 ? types : ['basic'];
}
/**
* Recommend optimal package flavors instead of individual dependencies
*/
recommendPackageFlavors(missingDeps, projectTypes) {
const recommendations = [];
// If missing TypeScript deps and it's a TS project
if (missingDeps.some(d => d.pkg.includes('@typescript-eslint')) &&
projectTypes.includes('typescript')) {
recommendations.push({
package: '@sun-asterisk/sunlint-typescript',
reason: 'Complete TypeScript analysis support',
replaces: missingDeps.filter(d => d.pkg.includes('typescript')).map(d => d.pkg)
});
}
// If missing many ESLint deps, suggest full package
if (missingDeps.length >= 3 && missingDeps.some(d => d.pkg === 'eslint')) {
recommendations.push({
package: '@sun-asterisk/sunlint-full',
reason: 'Complete ESLint integration with all features',
replaces: missingDeps.map(d => d.pkg)
});
}
return recommendations;
}
/**
* Check if we're in a project that can install dependencies
*/
canAutoInstall() {
// Check if package.json exists in current or parent directories
let currentDir = process.cwd();
const root = path.parse(currentDir).root;
while (currentDir !== root) {
if (fs.existsSync(path.join(currentDir, 'package.json'))) {
return currentDir;
}
currentDir = path.dirname(currentDir);
}
return null;
}
/**
* Auto-install missing dependencies with user confirmation
*/
async autoInstallMissing(missingDeps, context = 'analysis') {
const projectRoot = this.canAutoInstall();
if (!projectRoot) {
this.showManualInstallInstructions(missingDeps);
return false;
}
console.log(`\nš SunLint needs these dependencies for enhanced ${context}:`);
missingDeps.forEach(dep => console.log(` ⢠${dep.pkg} - ${dep.description}`));
const packages = missingDeps.map(d => d.pkg).join(' ');
console.log(`\nš” Install command:`);
console.log(` npm install ${packages} --save-dev`);
// In CI environments, don't auto-install but show clear message
if (process.env.CI || process.env.NODE_ENV === 'test') {
console.log('\nā ļø CI Environment: Add dependencies to package.json for consistent builds');
console.log(' SunLint will continue with available features\n');
return false;
}
// Interactive prompt for auto-install
const shouldAutoInstall = process.env.SUNLINT_AUTO_INSTALL === 'true';
if (shouldAutoInstall) {
try {
console.log('\nš¦ Auto-installing dependencies...');
execSync(`npm install ${packages} --save-dev`, {
cwd: projectRoot,
stdio: 'pipe' // Less noisy
});
console.log('ā
Dependencies installed successfully!');
console.log('š Re-running analysis with full features...\n');
return true;
} catch (error) {
console.log('ā Auto-install failed, continuing with available features');
return false;
}
} else {
console.log('\nš Continuing with available features...');
console.log('š” Set SUNLINT_AUTO_INSTALL=true to enable automatic installation\n');
}
return false;
}
/**
* Show manual installation instructions
*/
showManualInstallInstructions(missingDeps) {
console.log('\nš¦ To enable full functionality, install:');
const packages = missingDeps.map(d => d.pkg).join(' ');
console.log(` npm install ${packages} --save-dev`);
console.log('\nš” Or set SUNLINT_AUTO_INSTALL=true for automatic installation');
console.log(' SunLint will continue with heuristic analysis.\n');
}
}
module.exports = new SmartInstaller();