Skip to content

Commit

Permalink
Merge pull request #7709 from jasongrout/updaterange
Browse files Browse the repository at this point in the history
Teach update-dependency about more range specifiers and make it adopt the current range for any tag
  • Loading branch information
Steven Silvester committed Jan 2, 2020
2 parents 35cdd43 + de44e89 commit 2648e13
Showing 1 changed file with 44 additions and 21 deletions.
65 changes: 44 additions & 21 deletions buildutils/src/update-dependency.ts
Expand Up @@ -12,32 +12,55 @@ import commander from 'commander';
import semver from 'semver';

let versionCache = new Map();
const tags = /^([~^]?)([\w\-.]*)$/;

/**
* Matches a simple semver range, where the version number could be an npm tag.
*/
const SEMVER_RANGE = /^(~|\^|=|<|>|<=|>=)?([\w\-.]*)$/;

/**
* Get the specifier we should use
*
* @param currentSpecifier - The current package version.
* @param suggestedSpecifier - The package version we would like to use.
*
* #### Notes
* If the suggested specifier is not a valid range, we assume it is of the
* form ${RANGE}${TAG}, where TAG is an npm tag (such as 'latest') and RANGE
* is either a semver range indicator (one of `~, ^, >, <, =, >=, <=`), or is
* not given (in which case the current specifier range prefix is used).
*/
async function getSpecifier(
currentSpecifier: string,
suggestedSpecifier: string
) {
// we have an special case where `latest` will use the same current specifier
// e.g. when using latest:
// ^current should result in ^new
// ~current should result in ~new
if (semver.validRange(suggestedSpecifier)) {
return suggestedSpecifier;
}

if (semver.validRange(suggestedSpecifier) === null) {
// We have a tag, with possibly a range specifier, such as ^latest
let specifier = suggestedSpecifier;
if (specifier === 'latest') {
specifier = currentSpecifier;
}
let match = specifier.match(tags);
// The suggested specifier is not a valid range, so we assume it
// references a tag
let [, suggestedSigil, suggestedTag] =
suggestedSpecifier.match(SEMVER_RANGE) ?? [];

if (!suggestedTag) {
throw Error(`Invalid version specifier: ${suggestedSpecifier}`);
}

// A tag with no sigil adopts the sigil from the current specification
if (!suggestedSigil) {
let match = currentSpecifier.match(SEMVER_RANGE);
if (match === null) {
throw Error(`Invalid version specifier: ${specifier}`);
throw Error(
`Current version range is not recognized: ${currentSpecifier}`
);
}
let [, currentSigil] = match;
if (currentSigil) {
suggestedSigil = currentSigil;
}
specifier = match[1] + suggestedSpecifier;
return specifier;
} else {
return suggestedSpecifier;
}
return `${suggestedSigil}${suggestedTag}`;
}

async function getVersion(pkg: string, specifier: string) {
Expand All @@ -47,7 +70,7 @@ async function getVersion(pkg: string, specifier: string) {
}
if (semver.validRange(specifier) === null) {
// We have a tag, with possibly a range specifier, such as ^latest
let match = specifier.match(tags);
let match = specifier.match(SEMVER_RANGE);
if (match === null) {
throw Error(`Invalid version specifier: ${specifier}`);
}
Expand All @@ -70,10 +93,10 @@ async function getVersion(pkg: string, specifier: string) {
*/
function subset(range1: string, range2: string): boolean {
try {
const [, r1, version1] = range1.match(tags)!;
const [, r2] = range2.match(tags)!;
const [, r1, version1] = range1.match(SEMVER_RANGE) ?? [];
const [, r2] = range2.match(SEMVER_RANGE) ?? [];
return (
['', '~', '^'].indexOf(r1) >= 0 &&
['', '>=', '=', '~', '^'].includes(r1) &&
r1 === r2 &&
!!semver.valid(version1) &&
semver.satisfies(version1, range2)
Expand Down

0 comments on commit 2648e13

Please sign in to comment.