semver-intersect.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. 'use strict';
  2. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  3. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  4. var semver = require('semver');
  5. var regex = {
  6. condition: /^([<=>]+)?/,
  7. majorVersion: /\d+/,
  8. minMax: /^>=([\d]+\.[\d]+\.[\d]+(?:-[\w.]+)?) <=?([\d]+\.[\d]+\.[\d]+)$/,
  9. version: /([\d]+\.[\d]+\.[\d]+(?:-[\w.]+)?)$/,
  10. whitespace: /\s+/
  11. };
  12. function createShorthand(range) {
  13. var match = regex.minMax.exec(range);
  14. if (!match) {
  15. return range;
  16. }
  17. var _match$slice = match.slice(1),
  18. _match$slice2 = _slicedToArray(_match$slice, 2),
  19. min = _match$slice2[0],
  20. max = _match$slice2[1];
  21. if (min === max) {
  22. // Exact range
  23. return min;
  24. }
  25. // Stable range with an inclusive max version
  26. if (range.includes('<=')) {
  27. return `${min} - ${max}`;
  28. }
  29. // Special handling for major version 0
  30. if (semver.major(min) === 0 && semver.major(max) === 0) {
  31. // ^0.0.5
  32. if (semver.minor(min) === 0 && semver.minor(max) === 0) {
  33. return `^${min}`;
  34. }
  35. // ~0.0.5
  36. if (semver.minor(min) === 0) {
  37. return `~${min}`;
  38. }
  39. // ^0.5.0
  40. return `^${min}`;
  41. }
  42. if (semver.major(min) !== semver.major(max)) {
  43. if (semver.major(min) === 0) {
  44. return '0';
  45. }
  46. return `^${min}`;
  47. }
  48. return `~${min}`;
  49. }
  50. function ensureCompatible(range) {
  51. var _parseRange = parseRange(range),
  52. prerelease = _parseRange.prerelease,
  53. version = _parseRange.version;
  54. for (var _len = arguments.length, bounds = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  55. bounds[_key - 1] = arguments[_key];
  56. }
  57. bounds.forEach(function (bound) {
  58. if (!bound) {
  59. return;
  60. }
  61. if (semver.satisfies(version, bound) && semver.intersects(range, bound)) {
  62. return;
  63. }
  64. if (prerelease) {
  65. if (parseRange(bound).prerelease) {
  66. // If both bounds are pre-release versions, either can satisfy the other
  67. if (semver.satisfies(parseRange(bound).version, range)) {
  68. return;
  69. }
  70. } else if (semver.satisfies(version, `${range} ${bound}`)) {
  71. // If only our version is a pre-release version, don't fail on 1.0.0-a <2.0.0
  72. return;
  73. }
  74. }
  75. throw new Error(`Range ${range} is not compatible with ${bound}`);
  76. });
  77. }
  78. function expandRanges() {
  79. for (var _len2 = arguments.length, ranges = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  80. ranges[_key2] = arguments[_key2];
  81. }
  82. return ranges.reduce(function (result, range) {
  83. var validRange = semver.validRange(range);
  84. var validRanges = validRange.split(regex.whitespace);
  85. return union(result, validRanges);
  86. }, []);
  87. }
  88. function formatIntersection(_ref) {
  89. var _ref$lowerBound = _ref.lowerBound,
  90. lowerBound = _ref$lowerBound === undefined ? '' : _ref$lowerBound,
  91. _ref$upperBound = _ref.upperBound,
  92. upperBound = _ref$upperBound === undefined ? '' : _ref$upperBound;
  93. if (lowerBound === upperBound) {
  94. return lowerBound;
  95. }
  96. return `${lowerBound} ${upperBound}`.trim();
  97. }
  98. function intersect() {
  99. for (var _len3 = arguments.length, ranges = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
  100. ranges[_key3] = arguments[_key3];
  101. }
  102. ranges = expandRanges.apply(undefined, _toConsumableArray(ranges));
  103. var bounds = ranges.reduce(function (_ref2, range) {
  104. var lowerBound = _ref2.lowerBound,
  105. upperBound = _ref2.upperBound;
  106. var _parseRange2 = parseRange(range),
  107. condition = _parseRange2.condition,
  108. prerelease = _parseRange2.prerelease;
  109. if (prerelease) {
  110. ensureCompatible(range, lowerBound, upperBound);
  111. }
  112. // Exact version number specified, must be compatible with both bounds
  113. if (condition === '=') {
  114. ensureCompatible(range, lowerBound, upperBound);
  115. lowerBound = '>=' + range;
  116. upperBound = '<=' + range;
  117. }
  118. // New lower bound must be less than existing upper bound
  119. if (condition.startsWith('>')) {
  120. ensureCompatible(range, upperBound);
  121. lowerBound = mergeBounds(range, lowerBound);
  122. }
  123. // And vice versa
  124. if (condition.startsWith('<')) {
  125. ensureCompatible(range, lowerBound);
  126. upperBound = mergeBounds(range, upperBound);
  127. }
  128. return { lowerBound, upperBound };
  129. }, {});
  130. var range = formatIntersection(bounds);
  131. var shorthand = createShorthand(range);
  132. return shorthand;
  133. }
  134. function mergeBounds(range, bound) {
  135. if (!bound) {
  136. return range;
  137. }
  138. var _parseRange3 = parseRange(range),
  139. condition = _parseRange3.condition,
  140. version = _parseRange3.version;
  141. var boundingVersion = parseRange(bound).version;
  142. var comparator = condition.startsWith('<') ? semver.lt : semver.gt;
  143. var strict = condition === '<' || condition === '>';
  144. if (comparator(version, boundingVersion)) {
  145. return range;
  146. } else if (strict && semver.eq(version, boundingVersion)) {
  147. return range;
  148. } else {
  149. return bound;
  150. }
  151. }
  152. function parseRange(range) {
  153. var condition = regex.condition.exec(range)[1] || '=';
  154. var version = regex.version.exec(range)[1];
  155. var prerelease = semver.prerelease(version);
  156. return { condition, prerelease, version };
  157. }
  158. function union(a, b) {
  159. return b.reduce(function (result, value) {
  160. if (result.indexOf(value) === -1) {
  161. result.push(value);
  162. }
  163. return result;
  164. }, a);
  165. }
  166. module.exports.default = intersect;
  167. module.exports.createShorthand = createShorthand;
  168. module.exports.ensureCompatible = ensureCompatible;
  169. module.exports.expandRanges = expandRanges;
  170. module.exports.formatIntersection = formatIntersection;
  171. module.exports.intersect = intersect;
  172. module.exports.mergeBounds = mergeBounds;
  173. module.exports.parseRange = parseRange;
  174. module.exports.union = union;