check-dependency-version-consistency
Version:
Ensures dependencies are on consistent versions across a monorepo.
74 lines (73 loc) • 3.61 kB
JavaScript
import chalk from 'chalk';
import { compareVersionRangesSafe, getIncreasedLatestVersion, } from './semver.js';
import { table } from 'table';
/**
* Returns human-readable tables describing mismatching dependency versions.
*/
export function dependenciesToMismatchSummary(dependencies) {
const mismatchingDependencyVersions = Object.entries(dependencies)
.filter(([, value]) => value.isMismatching)
.map(([dependency, value]) => ({ dependency, versions: value.versions }));
if (mismatchingDependencyVersions.length === 0) {
throw new Error('No mismatching versions to output.');
}
const tables = mismatchingDependencyVersions
.map((object) => {
const headers = [chalk.bold(object.dependency), 'Usages', 'Packages'];
const usageCounts = object.versions.map((versionObject) => versionObject.packages.length);
const latestUsageCount = Math.max(...usageCounts);
const hasMultipleUsageCounts = !usageCounts.every((count) => count === latestUsageCount);
const rows = [...object.versions]
.sort((a, b) => compareVersionRangesSafe(b.version, a.version))
.map((versionObject) => {
const usageCount = versionObject.packages.length;
const packageNames = versionObject.packages.map((package_) => package_.name);
const packageListSentence = usageCount > 3
? `${packageNames.slice(0, 3).join(', ')}, and ${String(usageCount - 3)} other${usageCount - 3 === 1 ? '' : 's'}`
: packageNames.join(', ');
return [
chalk.redBright(versionObject.version),
// Bold the usage count if it's the latest, as long as it's not the only usage count present.
usageCount === latestUsageCount && hasMultipleUsageCounts
? chalk.bold(usageCount)
: usageCount,
packageListSentence,
];
});
return table([headers, ...rows]);
})
.join('');
return [
`Found ${String(mismatchingDependencyVersions.length)} ${mismatchingDependencyVersions.length === 1 ? 'dependency' : 'dependencies'} with mismatching versions across the workspace. Fix with \`--fix\`.`,
tables,
].join('\n');
}
/**
* Returns a summary of the mismatching dependency versions that were fixed.
*/
export function dependenciesToFixedSummary(dependencies) {
const mismatchingDependencyVersions = Object.entries(dependencies)
.filter(([, value]) => value.isMismatching)
.map(([dependency, value]) => ({ dependency, versions: value.versions }));
if (mismatchingDependencyVersions.length === 0) {
throw new Error('No fixes to output.');
}
const dependenciesAndFixedVersions = mismatchingDependencyVersions
.flatMap((mismatchingVersion) => {
let version;
try {
version = getIncreasedLatestVersion(mismatchingVersion.versions.map((v) => v.version));
}
catch {
return []; // Ignore this dependency since unable to get the version that we would have fixed it to.
}
return {
dependency: mismatchingVersion.dependency,
version,
};
})
.sort((a, b) => a.dependency.localeCompare(b.dependency));
return `Fixed versions for ${String(dependenciesAndFixedVersions.length)} ${dependenciesAndFixedVersions.length === 1 ? 'dependency' : 'dependencies'}: ${dependenciesAndFixedVersions
.map((object) => `${object.dependency}@${object.version}`)
.join(', ')}`;
}