Skip to content

Commit

Permalink
Handle prerelease version nuances (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
snyamathi authored Feb 1, 2018
1 parent 3ce27f6 commit feaee22
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 5 deletions.
30 changes: 25 additions & 5 deletions src/semver-intersect.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,26 @@ function createShorthand (range) {
}

function ensureCompatible(range, ...bounds) {
const { version } = parseRange(range);
const { prerelease, version } = parseRange(range);

bounds.forEach(bound => {
if (bound && !semver.satisfies(version, bound)) {
throw new Error(`Range ${range} is not compatible with ${bound}`);
if (!bound || semver.satisfies(version, bound)) {
return;
}

if (prerelease) {
if (parseRange(bound).prerelease) {
// If both bounds are pre-release versions, either can satisfy the other
if (semver.satisfies(parseRange(bound).version, range)) {
return;
}
} else if (semver.satisfies(version, `${range} ${bound}`)) {
// If only our version is a pre-release version, don't fail on 1.0.0-a <2.0.0
return;
}
}

throw new Error(`Range ${range} is not compatible with ${bound}`);
});
}

Expand All @@ -75,7 +90,11 @@ function intersect (...ranges) {
ranges = expandRanges(...ranges);

const bounds = ranges.reduce(({ lowerBound, upperBound }, range) => {
const { condition } = parseRange(range);
const { condition, prerelease } = parseRange(range);

if (prerelease) {
ensureCompatible(range, lowerBound, upperBound);
}

// Exact version number specified, must be compatible with both bounds
if (condition === '=') {
Expand Down Expand Up @@ -127,7 +146,8 @@ function mergeBounds (range, bound) {
function parseRange (range) {
const condition = regex.condition.exec(range)[1] || '=';
const version = regex.version.exec(range)[1];
return { condition, version };
const prerelease = semver.prerelease(version);
return { condition, prerelease, version };
}

function union (a, b) {
Expand Down
36 changes: 36 additions & 0 deletions tests/unit/semver-intersect.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,39 @@ describe('intersect', () => {
const result = intersect('^4.0.0', '~4.3.0');
expect(result).to.equal('~4.3.0');
});
it('should handle pre-release versions mixed with versions', () => {
const result = intersect('^1.0.0-alpha.3', '^1.2.0');
expect(result).to.equal('^1.2.0');
});
it('should handle compatible pre-release versions', () => {
const result = intersect('^1.0.0-alpha.3', '^1.0.0-alpha.4');
expect(result).to.equal('^1.0.0-alpha.4');
});
it('should handle compatible pre-release versions without a dot', () => {
const result = intersect('^0.14.0-beta2', '^0.14.0-beta3');
expect(result).to.equal('^0.14.0-beta3');
});
it('should handle compatible pre-release versions with the same preid', () => {
const result = intersect('^0.14.0-beta', '^0.14.0-beta4');
expect(result).to.equal('^0.14.0-beta4');
});
it('should handle incompatible pre-release versions (different patch version)', () => {
const call = intersect.bind(null, '^1.9.0-alpha', '^1.9.1-alpha');
expect(call).to.throw('Range >=1.9.1-alpha is not compatible with >=1.9.0-alpha');
});
it('should handle compatible pre-release versions (preid lower in alphabetical order)', () => {
expect(intersect('^1.9.0-alpha', '^1.9.0-beta')).to.equal('^1.9.0-beta');
expect(intersect('^1.9.0-beta', '^1.9.0-alpha')).to.equal('^1.9.0-beta');
expect(intersect('^1.9.0-alpha.1', '^1.9.0-beta.2')).to.equal('^1.9.0-beta.2');
});
it('should handle incompatible pre-release versions (specific version)', () => {
expect(intersect.bind(null, '1.9.0-alpha.1', '^1.9.0-alpha.2'))
.to.throw('Range >=1.9.0-alpha.2 is not compatible with <=1.9.0-alpha.1');
expect(intersect.bind(null, '1.9.0-alpha.1', '1.9.0-alpha.0'))
.to.throw('Range 1.9.0-alpha.0 is not compatible with >=1.9.0-alpha.1');
expect(intersect.bind(null, '1.9.0-rc3', '^1.9.0-rc4'))
.to.throw('Range >=1.9.0-rc4 is not compatible with <=1.9.0-rc3');
});
it('should return an exact version intersected with a range', () => {
const result = intersect('1.5.16', '^1.0.0');
expect(result).to.equal('1.5.16');
Expand Down Expand Up @@ -173,14 +206,17 @@ describe('parseRange', () => {
it('return the comparison condition and version', () => {
expect(parseRange('<5.0.0')).to.deep.equal({
condition: '<',
prerelease: null,
version: '5.0.0'
});
expect(parseRange('>=4.0.0')).to.deep.equal({
condition: '>=',
prerelease: null,
version: '4.0.0'
});
expect(parseRange('3.0.0')).to.deep.equal({
condition: '=',
prerelease: null,
version: '3.0.0'
});
});
Expand Down

0 comments on commit feaee22

Please sign in to comment.