feat(ivy): Add support for Ivy version scheme (#3541)
This commit is contained in:
Родитель
d1c18c84d0
Коммит
d68da97edd
|
@ -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",
|
||||
|
|
|
@ -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]) => {
|
||||
|
|
Загрузка…
Ссылка в новой задаче