apisurf
Version:
Analyze API surface changes between npm package versions to catch breaking changes
65 lines (64 loc) • 2.77 kB
JavaScript
/**
* Determines the type of version bump between two semver versions
*/
export function getVersionBumpType(fromVersion, toVersion) {
// Handle versions with more than 3 parts by considering them as patch suffixes
// e.g., 1.0.0.0 -> major=1, minor=0, patch=0, suffix=.0
const normalizeVersion = (version) => {
const parts = version.split('.');
if (parts.length < 3) {
return { major: NaN, minor: NaN, patch: NaN, hasPrerelease: false, hasFourthPart: false, fourthPart: 0 };
}
// For versions with 4+ parts, we need special handling
const hasFourthPart = parts.length >= 4;
const fourthPart = hasFourthPart ? parseInt(parts[3].split('-')[0]) : 0;
return {
major: parseInt(parts[0]),
minor: parseInt(parts[1]),
patch: parseInt(parts[2].split('-')[0]), // Parse patch, removing prerelease
hasPrerelease: version.includes('-'),
hasFourthPart,
fourthPart
};
};
const from = normalizeVersion(fromVersion);
const to = normalizeVersion(toVersion);
// Check if any parsed numbers are NaN
if (isNaN(from.major) || isNaN(from.minor) || isNaN(from.patch) ||
isNaN(to.major) || isNaN(to.minor) || isNaN(to.patch)) {
return 'unknown';
}
// For prerelease determination:
// If either version has a prerelease tag, and the base versions differ by only patch or less,
// consider it a prerelease change
if (from.hasPrerelease || to.hasPrerelease) {
// Check if this is a pure prerelease change (same base version)
if (from.major === to.major && from.minor === to.minor && from.patch === to.patch) {
return 'prerelease';
}
// If moving from stable to prerelease with patch bump (e.g., 1.0.0 -> 1.0.1-alpha)
// This is considered a prerelease because the stable version hasn't actually changed yet
if (!from.hasPrerelease && to.hasPrerelease) {
if (from.major === to.major && from.minor === to.minor) {
return 'prerelease';
}
}
}
// Regular version comparison
if (to.major > from.major) {
return 'major';
}
else if (to.major === from.major && to.minor > from.minor) {
return 'minor';
}
else if (to.major === from.major && to.minor === from.minor && to.patch > from.patch) {
return 'patch';
}
else if (to.major === from.major && to.minor === from.minor && to.patch === from.patch) {
// Handle 4th part versions like 1.0.0.0 -> 1.0.0.1
if (from.hasFourthPart && to.hasFourthPart && to.fourthPart > from.fourthPart) {
return 'patch';
}
}
return 'unknown';
}