patch-pulse
Version:
Check for outdated npm dependencies
109 lines • 4.62 kB
JavaScript
import chalk from 'chalk';
import { shouldSkipPackage } from '../services/config.js';
import { getLatestVersion } from '../services/npm.js';
import { ProgressSpinner } from '../ui/progress.js';
import { getUpdateType } from '../utils/getUpdateType.js';
import { isVersionOutdated } from '../utils/isVersionOutdated.js';
export async function checkDependencyVersions(dependencies, category, config) {
if (!dependencies || Object.keys(dependencies).length === 0) {
return [];
}
console.log(chalk.cyan.bold(`${category}:`));
console.log(chalk.cyan('─'.repeat(category.length + 1)));
const packageNames = Object.keys(dependencies);
const progress = new ProgressSpinner();
progress.start(`Checking ${packageNames.length} packages...`);
const concurrencyLimit = 10;
const dependencyInfos = [];
let completedCount = 0;
for (let i = 0; i < packageNames.length; i += concurrencyLimit) {
const batch = packageNames.slice(i, i + concurrencyLimit);
const batchPromises = batch.map(async (packageName) => {
const version = dependencies[packageName];
const isSkipped = shouldSkipPackage({ packageName, config });
let latestVersion;
let isOutdated = false;
let updateType;
if (!isSkipped) {
latestVersion = await getLatestVersion(packageName);
if (latestVersion) {
// Check if the version is outdated (works for both standard semver and version ranges)
isOutdated = isVersionOutdated({
current: version,
latest: latestVersion,
});
updateType = isOutdated
? getUpdateType({ current: version, latest: latestVersion })
: undefined;
}
}
// Update progress for each completed package
completedCount++;
progress.updateMessage(`Checking ${packageNames.length} packages... (${completedCount}/${packageNames.length})`);
return {
packageName,
currentVersion: version,
latestVersion,
isOutdated,
updateType,
isSkipped,
category,
};
});
const batchResults = await Promise.all(batchPromises);
dependencyInfos.push(...batchResults);
}
progress.stop();
displayResults(dependencyInfos);
console.log();
return dependencyInfos;
}
function displayResults(dependencyInfos) {
for (const dep of dependencyInfos) {
let status;
let versionInfo;
if (dep.isSkipped) {
status = chalk.gray('SKIPPED');
versionInfo = dep.currentVersion;
}
else if (!dep.latestVersion) {
status = chalk.red('NOT FOUND');
versionInfo = `${dep.currentVersion} (not found on npm registry)`;
}
else if (['latest', '*'].includes(dep.currentVersion)) {
status = chalk.cyan('LATEST TAG');
versionInfo = `${dep.currentVersion} → ${chalk.cyan(dep.latestVersion)} (actual latest version)`;
}
else if (!/^\d+\.\d+\.\d+/.test(dep.currentVersion)) {
// Handle version ranges
if (dep.isOutdated) {
const updateTypeColor = {
major: chalk.yellow,
minor: chalk.magenta,
patch: chalk.blue,
}[dep.updateType || 'patch'];
status = updateTypeColor(`${dep.updateType?.toUpperCase() || 'UPDATE'}`);
versionInfo = `${dep.currentVersion} → ${chalk.cyan(dep.latestVersion)}`;
}
else {
status = chalk.green('UP TO DATE');
versionInfo = dep.currentVersion;
}
}
else if (dep.isOutdated) {
const updateTypeColor = {
major: chalk.yellow,
minor: chalk.magenta,
patch: chalk.blue,
}[dep.updateType || 'patch'];
status = updateTypeColor(`${dep.updateType?.toUpperCase() || 'UPDATE'}`);
versionInfo = `${dep.currentVersion} → ${chalk.cyan(dep.latestVersion)}`;
}
else {
status = chalk.green('UP TO DATE');
versionInfo = dep.currentVersion;
}
console.log(`${status} ${chalk.white(dep.packageName)} ${chalk.gray(versionInfo)}`);
}
}
//# sourceMappingURL=dependency-checker.js.map