UNPKG

dependency-guardian

Version:

A powerful dependency management and analysis tool for Node.js projects

121 lines (95 loc) 3.67 kB
const fs = require('fs').promises; const path = require('path'); const axios = require('axios'); const semver = require('semver'); const logger = require('../utils/logger'); const cache = require('../utils/cache'); const Dependency = require('../models/dependency'); class DependencyScanner { constructor() { this.cache = cache; } async readPackageJson(projectPath) { try { const packageJsonPath = path.join(projectPath, 'package.json'); const content = await fs.readFile(packageJsonPath, 'utf8'); return JSON.parse(content); } catch (error) { logger.error('Failed to read package.json:', error); throw new Error('Could not read package.json'); } } async scanDependencies(dependencies, type = 'dependencies') { const results = []; for (const [name, version] of Object.entries(dependencies)) { try { const dep = new Dependency(name, version, type); const latestVersion = await this.getLatestVersion(name); dep.latestVersion = latestVersion; dep.updateType = this.determineUpdateType(version, latestVersion); dep.suggestedUpdate = this.getSuggestedUpdate(version, latestVersion); results.push(dep); } catch (error) { logger.debug(`Failed to scan dependency ${name}:`, error); results.push(new Dependency(name, version, type)); } } return results; } async getLatestVersion(packageName) { const cacheKey = `npm-version-${packageName}`; const cached = this.cache.get(cacheKey); if (cached) { return cached; } try { const response = await axios.get(`https://registry.npmjs.org/${packageName}`); const latestVersion = response.data['dist-tags'].latest; this.cache.set(cacheKey, latestVersion); return latestVersion; } catch (error) { logger.debug(`Failed to get latest version for ${packageName}:`, error); throw new Error(`Could not fetch latest version for ${packageName}`); } } determineUpdateType(currentVersion, latestVersion) { if (!semver.valid(semver.clean(currentVersion)) || !semver.valid(latestVersion)) { return 'unknown'; } const current = semver.clean(currentVersion); if (semver.eq(current, latestVersion)) { return 'current'; } if (semver.major(latestVersion) > semver.major(current)) { return 'major'; } if (semver.minor(latestVersion) > semver.minor(current)) { return 'minor'; } if (semver.patch(latestVersion) > semver.patch(current)) { return 'patch'; } return 'unknown'; } getSuggestedUpdate(currentVersion, latestVersion) { if (!semver.valid(semver.clean(currentVersion)) || !semver.valid(latestVersion)) { return null; } const current = semver.clean(currentVersion); if (semver.eq(current, latestVersion)) { return null; } // Suggest the next safe version based on semver const major = semver.major(current); const minor = semver.minor(current); const patch = semver.patch(current); if (semver.satisfies(latestVersion, `^${major}.${minor}.${patch}`)) { return latestVersion; // Safe update within current range } if (semver.satisfies(latestVersion, `^${major}.0.0`)) { return `^${major}.${semver.minor(latestVersion)}.0`; // Safe minor update } return `^${semver.major(latestVersion)}.0.0`; // Major update (breaking changes) } } module.exports = new DependencyScanner();