feat(ivy): Add support for Ivy version scheme (#3541)

This commit is contained in:
Sergio Zharinov 2019-04-22 14:53:01 +04:00 коммит произвёл Rhys Arkins
Родитель d1c18c84d0
Коммит d68da97edd
7 изменённых файлов: 309 добавлений и 11 удалений

Просмотреть файл

@ -404,6 +404,7 @@ const options = [
'docker',
'hashicorp',
'hex',
'ivy',
'loose',
'maven',
'node',

Просмотреть файл

@ -0,0 +1,73 @@
const {
equals,
getMajor,
getMinor,
getPatch,
isGreaterThan,
isSingleVersion,
isStable,
matches: mavenMatches,
maxSatisfyingVersion,
minSatisfyingVersion,
getNewValue,
sortVersions,
} = require('../maven/index');
const { TYPE_QUALIFIER, tokenize, isSubversion } = require('../maven/compare');
const {
REV_TYPE_LATEST,
REV_TYPE_SUBREV,
parseDynamicRevision,
} = require('./parse');
function isVersion(str) {
if (!str) {
return false;
}
return isSingleVersion(str) || !!parseDynamicRevision(str);
}
function matches(a, b) {
if (!a) return false;
if (!b) return false;
const dynamicRevision = parseDynamicRevision(b);
if (!dynamicRevision) return equals(a, b);
const { type, value } = dynamicRevision;
if (type === REV_TYPE_LATEST) {
if (!value) return true;
const tokens = tokenize(a);
if (tokens.length) {
const token = tokens[tokens.length - 1];
if (token.type === TYPE_QUALIFIER) {
return token.val.toLowerCase() === value;
}
}
return false;
}
if (type === REV_TYPE_SUBREV) {
return isSubversion(value, a);
}
return mavenMatches(a, value);
}
module.exports = {
equals,
getMajor,
getMinor,
getPatch,
isCompatible: isVersion,
isGreaterThan,
isSingleVersion,
isStable,
isValid: isVersion,
isVersion,
matches,
maxSatisfyingVersion,
minSatisfyingVersion,
getNewValue,
sortVersions,
};

Просмотреть файл

@ -0,0 +1,46 @@
const { isSingleVersion, parseRange, rangeToStr } = require('../maven/compare');
const REV_TYPE_LATEST = 'REV_TYPE_LATEST';
const REV_TYPE_SUBREV = 'REV_TYPE_SUBREVISION';
const REV_TYPE_RANGE = 'REV_TYPE_RANGE';
function parseDynamicRevision(str) {
if (!str) return null;
const LATEST_REGEX = /^latest\.|^latest$/i;
if (LATEST_REGEX.test(str)) {
const value = str.replace(LATEST_REGEX, '').toLowerCase() || null;
return {
type: REV_TYPE_LATEST,
value: value !== 'integration' ? value : null,
};
}
const SUBREV_REGEX = /\.\+$/;
if (SUBREV_REGEX.test(str)) {
const value = str.replace(SUBREV_REGEX, '');
if (isSingleVersion(value)) {
return {
type: REV_TYPE_SUBREV,
value,
};
}
}
const range = parseRange(str);
if (range && range.length === 1) {
return {
type: REV_TYPE_RANGE,
value: rangeToStr(range),
};
}
return null;
}
module.exports = {
REV_TYPE_LATEST,
REV_TYPE_SUBREV,
REV_TYPE_RANGE,
parseDynamicRevision,
};

Просмотреть файл

@ -240,8 +240,10 @@ function parseRange(rangeStr) {
return {
leftType: null,
leftValue: null,
leftBracket: null,
rightType: null,
rightValue: null,
rightBracket: null,
};
}
@ -257,18 +259,22 @@ function parseRange(rangeStr) {
result.push({
leftType: INCLUDING_POINT,
leftValue: ver,
leftBracket: '[',
rightType: INCLUDING_POINT,
rightValue: ver,
rightBracket: ']',
});
interval = emptyInterval();
} else if (subStr[0] === '[') {
const ver = subStr.slice(1);
interval.leftType = INCLUDING_POINT;
interval.leftValue = ver;
} else if (subStr[0] === '(') {
interval.leftBracket = '[';
} else if (subStr[0] === '(' || subStr[0] === ']') {
const ver = subStr.slice(1);
interval.leftType = EXCLUDING_POINT;
interval.leftValue = ver;
interval.leftBracket = subStr[0];
} else {
result = null;
}
@ -276,12 +282,14 @@ function parseRange(rangeStr) {
const ver = subStr.slice(0, -1);
interval.rightType = INCLUDING_POINT;
interval.rightValue = ver;
interval.rightBracket = ']';
result.push(interval);
interval = emptyInterval();
} else if (/\)$/.test(subStr)) {
} else if (/\)$/.test(subStr) || /\[$/.test(subStr)) {
const ver = subStr.slice(0, -1);
interval.rightType = EXCLUDING_POINT;
interval.rightValue = ver;
interval.rightBracket = /\)$/.test(subStr) ? ')' : '[';
result.push(interval);
interval = emptyInterval();
} else {
@ -324,26 +332,26 @@ function parseRange(rangeStr) {
function rangeToStr(fullRange) {
if (fullRange === null) return null;
const leftBracket = val => (val.leftType === INCLUDING_POINT ? '[' : '(');
const rightBracket = val => (val.rightType === INCLUDING_POINT ? ']' : ')');
const valToStr = val => (val === null ? '' : val);
if (fullRange.length === 1) {
const val = fullRange[0];
if (val.leftValue === val.rightValue) {
return `${leftBracket(val)}${valToStr(val.leftValue)}${rightBracket(
val
)}`;
const { leftBracket, rightBracket, leftValue, rightValue } = fullRange[0];
if (
leftValue === rightValue &&
leftBracket === '[' &&
rightBracket === ']'
) {
return `[${valToStr(leftValue)}]`;
}
}
const intervals = fullRange.map(val =>
[
leftBracket(val),
val.leftBracket,
valToStr(val.leftValue),
',',
valToStr(val.rightValue),
rightBracket(val),
val.rightBracket,
].join('')
);
return intervals.join(',');
@ -389,12 +397,31 @@ function autoExtendMavenRange(currentRepresentation, newValue) {
return rangeToStr(range);
}
function isSubversion(majorVersion, minorVersion) {
const majorTokens = tokenize(majorVersion);
const minorTokens = tokenize(minorVersion);
let result = true;
const len = majorTokens.length;
for (let idx = 0; idx < len; idx += 1) {
const major = majorTokens[idx];
const minor = minorTokens[idx] || nullFor(majorTokens[idx]);
const cmpResult = tokenCmp(major, minor);
if (cmpResult !== 0) {
result = false;
break;
}
}
return result;
}
module.exports = {
PREFIX_DOT,
PREFIX_HYPHEN,
TYPE_NUMBER,
TYPE_QUALIFIER,
tokenize,
isSubversion,
compare,
isSingleVersion,
isVersion,

Просмотреть файл

@ -260,6 +260,7 @@
"docker",
"hashicorp",
"hex",
"ivy",
"loose",
"maven",
"node",

128
test/versioning/ivy.spec.js Normal file
Просмотреть файл

@ -0,0 +1,128 @@
const {
REV_TYPE_LATEST,
REV_TYPE_SUBREV,
REV_TYPE_RANGE,
parseDynamicRevision,
} = require('../../lib/versioning/ivy/parse');
const { isVersion, matches } = require('../../lib/versioning/ivy/index');
describe('versioning/ivy/match', () => {
it('parses dynamic revisions', () => {
expect(parseDynamicRevision(null)).toBeNull();
expect(parseDynamicRevision('')).toBeNull();
expect(parseDynamicRevision('latest')).toEqual({
type: REV_TYPE_LATEST,
value: null,
});
expect(parseDynamicRevision('latest.release')).toEqual({
type: REV_TYPE_LATEST,
value: 'release',
});
expect(parseDynamicRevision('latest.milestone')).toEqual({
type: REV_TYPE_LATEST,
value: 'milestone',
});
expect(parseDynamicRevision('latest.integration')).toEqual({
type: REV_TYPE_LATEST,
value: null,
});
expect(parseDynamicRevision('.+')).toBeNull();
expect(parseDynamicRevision('1.0.+')).toEqual({
type: REV_TYPE_SUBREV,
value: '1.0',
});
expect(parseDynamicRevision('1.2.3.+')).toEqual({
type: REV_TYPE_SUBREV,
value: '1.2.3',
});
[
'[1.0,2.0]',
'[1.0,2.0[',
']1.0,2.0]',
']1.0,2.0[',
'[1.0,)',
']1.0,)',
'(,2.0]',
'(,2.0[',
].forEach(value => {
expect(parseDynamicRevision(value)).toEqual({
type: REV_TYPE_RANGE,
value,
});
});
expect(parseDynamicRevision('[0,1),(1,)')).toBeNull();
});
});
describe('versioning/ivy/index', () => {
it('validates version string', () => {
expect(isVersion('')).toBe(false);
expect(isVersion('1.0.0')).toBe(true);
expect(isVersion('0')).toBe(true);
expect(isVersion('0.1-2-sp')).toBe(true);
expect(isVersion('1-final')).toBe(true);
expect(isVersion('v1.0.0')).toBe(true);
expect(isVersion('x1.0.0')).toBe(true);
expect(isVersion('2.1.1.RELEASE')).toBe(true);
expect(isVersion('Greenwich.SR1')).toBe(true);
expect(isVersion('.1')).toBe(false);
expect(isVersion('1.')).toBe(false);
expect(isVersion('-1')).toBe(false);
expect(isVersion('1-')).toBe(false);
expect(isVersion('latest')).toBe(true);
expect(isVersion('latest.release')).toBe(true);
expect(isVersion('latest.milestone')).toBe(true);
expect(isVersion('latest.integration')).toBe(true);
expect(isVersion('1.0.+')).toBe(true);
expect(isVersion('1.0+')).toBe(false);
expect(isVersion(']0,1[')).toBe(true);
expect(isVersion('[0,1]')).toBe(true);
expect(isVersion('[0,1),(1,2]')).toBe(false);
});
it('matches against dynamic revisions', () => {
expect(matches('', 'latest')).toBe(false);
expect(matches('0', '')).toBe(false);
expect(matches('0', 'latest')).toBe(true);
expect(matches('0', 'latest.integration')).toBe(true);
expect(matches('0', 'latest.release')).toBe(false);
expect(matches('release', 'latest.release')).toBe(true);
expect(matches('0.release', 'latest.release')).toBe(true);
expect(matches('0-release', 'latest.release')).toBe(true);
expect(matches('0release', 'latest.release')).toBe(true);
expect(matches('0.RELEASE', 'latest.release')).toBe(true);
expect(matches('0', 'latest.milestone')).toBe(false);
expect(matches('milestone', 'latest.milestone')).toBe(true);
expect(matches('0.milestone', 'latest.milestone')).toBe(true);
expect(matches('0-milestone', 'latest.milestone')).toBe(true);
expect(matches('0milestone', 'latest.milestone')).toBe(true);
expect(matches('0.MILESTONE', 'latest.milestone')).toBe(true);
expect(matches('0', '1.0.+')).toBe(false);
expect(matches('1.1.0', '1.2.+')).toBe(false);
expect(matches('1.2.0', '1.2.+')).toBe(true);
expect(matches('1.2.milestone', '1.2.+')).toBe(true);
expect(matches('1.3', '1.2.+')).toBe(false);
expect(matches('1', '1')).toBe(true);
expect(matches('1', '0')).toBe(false);
expect(matches('1', '[0,1]')).toBe(true);
expect(matches('0', '(0,1)')).toBe(false);
expect(matches('0', '(0,1[')).toBe(false);
expect(matches('0', ']0,1)')).toBe(false);
expect(matches('1', '(0,1)')).toBe(false);
expect(matches('1', '(0,2)')).toBe(true);
expect(matches('1', '[0,2]')).toBe(true);
expect(matches('1', '(,1]')).toBe(true);
expect(matches('1', '(,1)')).toBe(false);
expect(matches('1', '[1,)')).toBe(true);
expect(matches('1', '(1,)')).toBe(false);
});
});

Просмотреть файл

@ -122,68 +122,86 @@ describe('versioning/maven/compare', () => {
{
leftType: 'INCLUDING_POINT',
leftValue: '1.0',
leftBracket: '[',
rightType: 'INCLUDING_POINT',
rightValue: '1.0',
rightBracket: ']',
},
],
'(,1.0]': [
{
leftType: 'EXCLUDING_POINT',
leftValue: null,
leftBracket: '(',
rightType: 'INCLUDING_POINT',
rightValue: '1.0',
rightBracket: ']',
},
],
'[1.2,1.3]': [
{
leftType: 'INCLUDING_POINT',
leftValue: '1.2',
leftBracket: '[',
rightType: 'INCLUDING_POINT',
rightValue: '1.3',
rightBracket: ']',
},
],
'[1.0,2.0)': [
{
leftType: 'INCLUDING_POINT',
leftValue: '1.0',
leftBracket: '[',
rightType: 'EXCLUDING_POINT',
rightValue: '2.0',
rightBracket: ')',
},
],
'[1.5,)': [
{
leftType: 'INCLUDING_POINT',
leftValue: '1.5',
leftBracket: '[',
rightType: 'EXCLUDING_POINT',
rightValue: null,
rightBracket: ')',
},
],
'(,1.0],[1.2,)': [
{
leftType: 'EXCLUDING_POINT',
leftValue: null,
leftBracket: '(',
rightType: 'INCLUDING_POINT',
rightValue: '1.0',
rightBracket: ']',
},
{
leftType: 'INCLUDING_POINT',
leftValue: '1.2',
leftBracket: '[',
rightType: 'EXCLUDING_POINT',
rightValue: null,
rightBracket: ')',
},
],
'(,1.1),(1.1,)': [
{
leftType: 'EXCLUDING_POINT',
leftValue: null,
leftBracket: '(',
rightType: 'EXCLUDING_POINT',
rightValue: '1.1',
rightBracket: ')',
},
{
leftType: 'EXCLUDING_POINT',
leftValue: '1.1',
leftBracket: '(',
rightType: 'EXCLUDING_POINT',
rightValue: null,
rightBracket: ')',
},
],
};
@ -205,9 +223,13 @@ describe('versioning/maven/compare', () => {
['[1.0.0,1.2.3]', '1.2.4', '[1.0.0,1.2.4]'],
['[1.0.0,1.2.23]', '1.1.0', '[1.0.0,1.2.23]'],
['(,1.0]', '2.0', '(,2.0]'],
['],1.0]', '2.0', '],2.0]'],
['(,1.0)', '2.0', '(,2.0)'],
['],1.0[', '2.0', '],2.0['],
['[1.0,1.2],[1.3,1.5)', '1.2.4', '[1.0,1.2.4],[1.3,1.5)'],
['[1.0,1.2],[1.3,1.5[', '1.2.4', '[1.0,1.2.4],[1.3,1.5['],
['[1.2.3,)', '1.2.4', '[1.2.4,)'],
['[1.2.3,[', '1.2.4', '[1.2.4,['],
['[1.2.3,]', '1.2.4', '[1.2.3,]'], // invalid range
];
sample.forEach(([oldRepr, newValue, newRepr]) => {