check-outdated
Version:
Light-weight CLI tool to ensure that your dependencies are up to date, otherwise the process is terminated with status code 1.
150 lines (118 loc) • 4.16 kB
JavaScript
/**
* @file Different functionality to work with semantic version numbers.
*/
/** @typedef {import('./colorize').ColorizeProperty} ColorizeProperty */
/**
* Colorize differences in parts of two semantic version numbers.
*
* @public
* @param {readonly [string, string]} versions - Version numbers to compare.
* @param {readonly [ColorizeProperty, ColorizeProperty]} equalColorizers - Styles for the first and second version number, for equal parts.
* @param {readonly [ColorizeProperty, ColorizeProperty]} diffColorizers - Styles for the first and second version number, for unequal parts.
* @returns {[string, string]} The colorized version numbers, in the same order as the input `versions` array.
*/
function semverDiff (versions, equalColorizers, diffColorizers) {
const splitRegExp = /([.+-])/u;
const parts1 = versions[0].split(splitRegExp);
const parts2 = versions[1].split(splitRegExp);
for (let partIndex = 0; partIndex < Math.max(parts1.length, parts2.length); partIndex++) {
if (parts1[partIndex] !== parts2[partIndex]) {
if (parts1[partIndex]) { parts1[partIndex] = diffColorizers[0](parts1[partIndex]); }
if (parts2[partIndex]) { parts2[partIndex] = diffColorizers[1](parts2[partIndex]); }
}
else {
parts1[partIndex] = equalColorizers[0](parts1[partIndex]);
parts2[partIndex] = equalColorizers[1](parts2[partIndex]);
}
}
return [parts1.join(''), parts2.join('')];
}
/**
* Returns the type of the difference between two semantic version numbers.
*
* @public
* @param {string} v1 - First version.
* @param {string} v2 - Second version.
* @returns {'major' | 'minor' | 'patch' | 'prerelease' | 'build' | 'revert' | undefined} The type as `string`, or `undefined` on same version or invalid semver formats.
*/
function semverDiffType (v1, v2) {
if (v1 === v2) {
return undefined;
}
const semverRegExp = /^(\d+).(\d+).(\d+).*?(?:([-+]).+)?$/u;
const match1 = semverRegExp.exec(v1);
if (match1 === null) {
return undefined;
}
const match2 = semverRegExp.exec(v2);
if (match2 === null) {
return undefined;
}
if (Number.parseInt(match2[1], 10) > Number.parseInt(match1[1], 10)) {
return 'major';
}
if (Number.parseInt(match2[1], 10) < Number.parseInt(match1[1], 10)) {
return 'revert';
}
if (Number.parseInt(match2[2], 10) > Number.parseInt(match1[2], 10)) {
return 'minor';
}
if (Number.parseInt(match2[2], 10) < Number.parseInt(match1[2], 10)) {
return 'revert';
}
if (Number.parseInt(match2[3], 10) > Number.parseInt(match1[3], 10)) {
return 'patch';
}
if (Number.parseInt(match2[3], 10) < Number.parseInt(match1[3], 10)) {
return 'revert';
}
if (match2[4] === '-') {
return 'prerelease';
}
if (match2[4] === '+') {
return 'build';
}
return undefined;
}
/**
* Checks if a semver range pattern matches to a specific version.
*
* @public
* @param {string} version - The version to check
* @param {string} pattern - A semver range pattern
* @returns {boolean} `true` if the range pattern matches, otherwise `false`.
*/
function semverInRange (version, pattern) {
const semverRangeRegExp = /^([\^~])?(?:(\d+|\*|x)?(?:\.(\d+|\*|x))?(?:\.(\d+|\*|x))?)?$/u;
/** @type {(string | undefined)[] | null} */
const match = semverRangeRegExp.exec(pattern);
if (match === null) {
return (version === pattern);
}
if (match[2] === '*' || match[2] === 'x') {
return true;
}
const splitRegExp = /[.+-]/u;
const parts = version.split(splitRegExp);
if (match[1] === '^' || match[3] === '*' || match[3] === 'x') {
return (parts[0] === match[2]);
}
if (match[1] === '~') {
return (parts[0] === match[2] && (match[3] === undefined || parts[1] === match[3]) && (match[4] === undefined || Number.parseInt(parts[1], 10) >= Number.parseInt(match[4], 10)));
}
if (match[4] === '*' || match[4] === 'x') {
return (parts[0] === match[2] && parts[1] === match[3]);
}
if (match[3] === undefined) {
return (parts[0] === match[2]);
}
if (match[4] === undefined) {
return (parts[0] === match[2] && parts[1] === match[3]);
}
return (version === pattern);
}
module.exports = {
semverDiff,
semverDiffType,
semverInRange
};