sver.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. 'use strict';
  2. var shortSemverRegEx = /^([~\^])?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?$/;
  3. var semverRegEx = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\da-z-]+(?:\.[\da-z-]+)*))?(\+[\da-z-]+)?$/i;
  4. exports.semverRegEx = semverRegEx;
  5. exports.shortSemverRegEx = shortSemverRegEx;
  6. var Symbol = require('es6-symbol');
  7. var MAJOR = Symbol('major');
  8. var MINOR = Symbol('minor');
  9. var PATCH = Symbol('patch');
  10. var PRE = Symbol('pre');
  11. var BUILD = Symbol('build');
  12. var TAG = Symbol('tag');
  13. var numRegEx = /^\d+$/;
  14. function Semver(version) {
  15. var semver = version.match(semverRegEx);
  16. if (!semver) {
  17. this[TAG] = version;
  18. return;
  19. }
  20. this[MAJOR] = parseInt(semver[1], 10);
  21. this[MINOR] = parseInt(semver[2], 10);
  22. this[PATCH] = parseInt(semver[3], 10);
  23. this[PRE] = semver[4] && semver[4].split('.');
  24. this[BUILD] = semver[5];
  25. }
  26. Object.defineProperty(Semver.prototype, 'major', {
  27. get: function major () {
  28. return this[MAJOR];
  29. }
  30. });
  31. Object.defineProperty(Semver.prototype, 'minor', {
  32. get: function minor () {
  33. return this[MINOR];
  34. }
  35. });
  36. Object.defineProperty(Semver.prototype, 'patch', {
  37. get: function patch () {
  38. return this[PATCH];
  39. }
  40. });
  41. Object.defineProperty(Semver.prototype, 'pre', {
  42. get: function pre () {
  43. return this[PRE];
  44. }
  45. });
  46. Object.defineProperty(Semver.prototype, 'build', {
  47. get: function build () {
  48. return this[BUILD];
  49. }
  50. });
  51. Object.defineProperty(Semver.prototype, 'tag', {
  52. get: function tag () {
  53. return this[TAG];
  54. }
  55. });
  56. Semver.prototype.gt = function gt(version) {
  57. return Semver.compare(this, version) === 1;
  58. }
  59. Semver.prototype.lt = function lt (version) {
  60. return Semver.compare(this, version) === -1;
  61. }
  62. Semver.prototype.eq = function eq (version) {
  63. if (!(version instanceof Semver))
  64. version = new Semver(version);
  65. if (this[TAG] && version[TAG])
  66. return this[TAG] === version[TAG];
  67. if (this[TAG] || version[TAG])
  68. return false;
  69. if (this[MAJOR] !== version[MAJOR])
  70. return false;
  71. if (this[MINOR] !== version[MINOR])
  72. return false;
  73. if (this[PATCH] !== version[PATCH])
  74. return false;
  75. if (this[PRE] === undefined && version[PRE] === undefined)
  76. return true;
  77. if (this[PRE] === undefined || version[PRE] === undefined)
  78. return false;
  79. if (this[PRE].length !== version[PRE].length)
  80. return false;
  81. for (var i = 0; i < this[PRE].length; i++) {
  82. if (this[PRE][i] !== version[PRE][i])
  83. return false;
  84. }
  85. return this[BUILD] === version[BUILD];
  86. }
  87. Semver.prototype.matches = function matches (range, unstable) {
  88. unstable = unstable || false;
  89. if (!(range instanceof SemverRange))
  90. range = new SemverRange(range);
  91. return range.has(this, unstable);
  92. }
  93. Semver.prototype.toString = function toString () {
  94. if (this[TAG])
  95. return this[TAG];
  96. return this[MAJOR] + '.' + this[MINOR] + '.' + this[PATCH] + (this[PRE] ? '-' + this[PRE].join('.') : '') + (this[BUILD] ? this[BUILD] : '');
  97. }
  98. Semver.isValid = function isValid (version) {
  99. var semver = version.match(semverRegEx);
  100. return semver && semver[2] !== undefined && semver[3] !== undefined;
  101. }
  102. Semver.compare = function compare (v1, v2) {
  103. if (!(v1 instanceof Semver))
  104. v1 = new Semver(v1);
  105. if (!(v2 instanceof Semver))
  106. v2 = new Semver(v2);
  107. // not semvers - tags have equal precedence
  108. if (v1[TAG] && v2[TAG])
  109. return 0;
  110. // semver beats tag version
  111. if (v1[TAG])
  112. return -1;
  113. if (v2[TAG])
  114. return 1;
  115. // compare version numbers
  116. if (v1[MAJOR] !== v2[MAJOR])
  117. return v1[MAJOR] > v2[MAJOR] ? 1 : -1;
  118. if (v1[MINOR] !== v2[MINOR])
  119. return v1[MINOR] > v2[MINOR] ? 1 : -1;
  120. if (v1[PATCH] !== v2[PATCH])
  121. return v1[PATCH] > v2[PATCH] ? 1 : -1;
  122. if (!v1[PRE] && !v2[PRE])
  123. return 0;
  124. if (!v1[PRE])
  125. return 1;
  126. if (!v2[PRE])
  127. return -1;
  128. // prerelease comparison
  129. for (var i = 0, l = Math.min(v1[PRE].length, v2[PRE].length); i < l; i++) {
  130. if (v1[PRE][i] !== v2[PRE][i]) {
  131. var isNum1 = v1[PRE][i].match(numRegEx);
  132. var isNum2 = v2[PRE][i].match(numRegEx);
  133. // numeric has lower precedence
  134. if (isNum1 && !isNum2)
  135. return -1;
  136. if (isNum2 && !isNum1)
  137. return 1;
  138. // compare parts
  139. if (isNum1 && isNum2)
  140. return parseInt(v1[PRE][i], 10) > parseInt(v2[PRE][i], 10) ? 1 : -1;
  141. else
  142. return v1[PRE][i] > v2[PRE][i] ? 1 : -1;
  143. }
  144. }
  145. if (v1[PRE].length === v2[PRE].length)
  146. return 0;
  147. // more pre-release fields win if equal
  148. return v1[PRE].length > v2[PRE].length ? 1 : -1;
  149. }
  150. exports.Semver = Semver;
  151. var WILDCARD_RANGE = 0;
  152. var MAJOR_RANGE = 1;
  153. var STABLE_RANGE = 2;
  154. var EXACT_RANGE = 3;
  155. var TYPE = Symbol('type');
  156. var VERSION = Symbol('version');
  157. function SemverRange(versionRange) {
  158. if (versionRange === '*' || versionRange === '') {
  159. this[TYPE] = WILDCARD_RANGE;
  160. return;
  161. }
  162. var shortSemver = versionRange.match(shortSemverRegEx);
  163. if (shortSemver) {
  164. if (shortSemver[1])
  165. versionRange = versionRange.substr(1);
  166. if (shortSemver[3] === undefined) {
  167. // ^, ~ mean the same thing for a single major
  168. this[VERSION] = new Semver(versionRange + '.0.0');
  169. this[TYPE] = MAJOR_RANGE;
  170. }
  171. else {
  172. this[VERSION] = new Semver(versionRange + '.0');
  173. // ^ only becomes major range for major > 0
  174. if (shortSemver[1] === '^' && shortSemver[2] !== '0')
  175. this[TYPE] = MAJOR_RANGE;
  176. else
  177. this[TYPE] = STABLE_RANGE;
  178. }
  179. // empty pre array === support prerelease ranges
  180. this[VERSION][PRE] = this[VERSION][PRE] || [];
  181. }
  182. else if (versionRange[0] === '^') {
  183. this[VERSION] = new Semver(versionRange.substr(1));
  184. if (this[VERSION][MAJOR] === 0) {
  185. if (this[VERSION][MINOR] === 0)
  186. this[TYPE] = EXACT_RANGE;
  187. else
  188. this[TYPE] = STABLE_RANGE;
  189. }
  190. else {
  191. this[TYPE] = MAJOR_RANGE;
  192. }
  193. }
  194. else if (versionRange[0] === '~') {
  195. this[VERSION] = new Semver(versionRange.substr(1));
  196. this[TYPE] = STABLE_RANGE;
  197. }
  198. else {
  199. this[VERSION] = new Semver(versionRange);
  200. this[TYPE] = EXACT_RANGE;
  201. }
  202. if (this[VERSION][TAG] && this[TYPE] !== EXACT_RANGE)
  203. this[TYPE] = EXACT_RANGE;
  204. }
  205. Object.defineProperty(SemverRange.prototype, 'isExact', {
  206. get: function isExact () {
  207. return this[TYPE] === EXACT_RANGE;
  208. }
  209. });
  210. Object.defineProperty(SemverRange.prototype, 'isStable', {
  211. get: function isStable () {
  212. return this[TYPE] === STABLE_RANGE;
  213. }
  214. });
  215. Object.defineProperty(SemverRange.prototype, 'isMajor', {
  216. get: function isMajor () {
  217. return this[TYPE] === MAJOR_RANGE;
  218. }
  219. });
  220. Object.defineProperty(SemverRange.prototype, 'isWildcard', {
  221. get: function isWildcard () {
  222. return this[TYPE] === WILDCARD_RANGE;
  223. }
  224. });
  225. Object.defineProperty(SemverRange.prototype, 'type', {
  226. get: function type () {
  227. switch (this[TYPE]) {
  228. case WILDCARD_RANGE:
  229. return 'wildcard';
  230. case MAJOR_RANGE:
  231. return 'major';
  232. case STABLE_RANGE:
  233. return 'stable';
  234. case EXACT_RANGE:
  235. return 'exact';
  236. }
  237. }
  238. });
  239. Object.defineProperty(SemverRange.prototype, 'version', {
  240. get: function version () {
  241. return this[VERSION];
  242. }
  243. });
  244. SemverRange.prototype.gt = function gt (range) {
  245. return SemverRange.compare(this, range) === 1;
  246. }
  247. SemverRange.prototype.lt = function lt (range) {
  248. return SemverRange.compare(this, range) === -1;
  249. }
  250. SemverRange.prototype.eq = function eq (range) {
  251. return SemverRange.compare(this, range) === 0;
  252. }
  253. SemverRange.prototype.has = function has (version, unstable) {
  254. unstable = unstable || false;
  255. if (!(version instanceof Semver))
  256. version = new Semver(version);
  257. if (this[TYPE] === WILDCARD_RANGE)
  258. return true;
  259. if (this[TYPE] === EXACT_RANGE)
  260. return this[VERSION].eq(version);
  261. if (version[TAG])
  262. return false;
  263. if (version.lt(this[VERSION]))
  264. return false;
  265. if (version[PRE] && !unstable)
  266. return this[VERSION][MAJOR] === version[MAJOR] && this[VERSION][MINOR] === version[MINOR] && this[VERSION][PATCH] === version[PATCH];
  267. if (this[TYPE] === MAJOR_RANGE)
  268. return this[VERSION][MAJOR] === version[MAJOR];
  269. return this[VERSION][MAJOR] === version[MAJOR] && this[VERSION][MINOR] === version[MINOR];
  270. }
  271. SemverRange.prototype.contains = function contains (range) {
  272. if (!(range instanceof SemverRange))
  273. range = new SemverRange(range);
  274. if (this[TYPE] === WILDCARD_RANGE)
  275. return true;
  276. if (range[TYPE] === WILDCARD_RANGE)
  277. return false;
  278. return range[TYPE] >= this[TYPE] && this.has(range[VERSION], true);
  279. }
  280. SemverRange.prototype.intersect = function intersect (range) {
  281. if (!(range instanceof SemverRange))
  282. range = new SemverRange(range);
  283. if (this[TYPE] === WILDCARD_RANGE && range[TYPE] === WILDCARD_RANGE)
  284. return this;
  285. if (this[TYPE] === WILDCARD_RANGE)
  286. return range;
  287. if (range[TYPE] === WILDCARD_RANGE)
  288. return this;
  289. if (this[TYPE] === EXACT_RANGE)
  290. return range.has(this[VERSION], true) ? this : undefined;
  291. if (range[TYPE] === EXACT_RANGE)
  292. return this.has(range[VERSION], true) ? range : undefined;
  293. var higherRange, lowerRange, polarity;
  294. if (range[VERSION].gt(this[VERSION])) {
  295. higherRange = range;
  296. lowerRange = this;
  297. polarity = true;
  298. }
  299. else {
  300. higherRange = this;
  301. lowerRange = range;
  302. polarity = false;
  303. }
  304. if (!lowerRange.has(higherRange[VERSION], true))
  305. return;
  306. if (lowerRange[TYPE] === MAJOR_RANGE)
  307. return polarity ? range : this;
  308. var intersection = new SemverRange(higherRange[VERSION].toString());
  309. intersection[TYPE] = STABLE_RANGE;
  310. return intersection;
  311. }
  312. SemverRange.prototype.bestMatch = function bestMatch (versions, unstable) {
  313. unstable = unstable || false;
  314. var self = this;
  315. var maxSemver;
  316. versions.forEach(function(version) {
  317. if (!(version instanceof Semver))
  318. version = new Semver(version);
  319. if (!self.has(version, unstable))
  320. return;
  321. if (!unstable && version[PRE]) {
  322. if (self[TYPE] === WILDCARD_RANGE || !self[VERSION][PRE] || self[VERSION][MAJOR] !== version[MAJOR] ||
  323. self[VERSION][MINOR] !== version[MINOR] || self[VERSION][PATCH] !== version[PATCH])
  324. return;
  325. }
  326. if (!maxSemver) {
  327. maxSemver = version;
  328. }
  329. else if (Semver.compare(version, maxSemver) === 1) {
  330. maxSemver = version;
  331. }
  332. });
  333. return maxSemver;
  334. }
  335. SemverRange.prototype.toString = function toString () {
  336. var version = this[VERSION];
  337. switch (this[TYPE]) {
  338. case WILDCARD_RANGE:
  339. return '*';
  340. case MAJOR_RANGE:
  341. if (version[MAJOR] === 0 && version[MINOR] === 0 && version[PATCH] === 0)
  342. return '0';
  343. if (version[PRE] && version[PRE].length === 0 && version[PATCH] === 0)
  344. return '^' + version[MAJOR] + '.' + version[MINOR];
  345. return '^' + version.toString();
  346. case STABLE_RANGE:
  347. if (version[PRE] && version[PRE].length === 0 && version[PATCH] === 0)
  348. return version[MAJOR] + '.' + version[MINOR];
  349. return '~' + version.toString();
  350. case EXACT_RANGE:
  351. return version.toString();
  352. }
  353. }
  354. SemverRange.match = function match (range, version, unstable) {
  355. unstable = unstable || false;
  356. if (!(version instanceof Semver))
  357. version = new Semver(version);
  358. return version.matches(range, unstable);
  359. }
  360. SemverRange.isValid = function isValid (range) {
  361. var semverRange = new SemverRange(range);
  362. return semverRange[TYPE] !== EXACT_RANGE || semverRange[VERSION][TAG] === undefined;
  363. }
  364. SemverRange.compare = function compare (r1, r2) {
  365. if (!(r1 instanceof SemverRange))
  366. r1 = new SemverRange(r1);
  367. if (!(r2 instanceof SemverRange))
  368. r2 = new SemverRange(r2);
  369. if (r1[TYPE] === WILDCARD_RANGE && r2[TYPE] === WILDCARD_RANGE)
  370. return 0;
  371. if (r1[TYPE] === WILDCARD_RANGE)
  372. return 1;
  373. if (r2[TYPE] === WILDCARD_RANGE)
  374. return -1;
  375. var cmp = Semver.compare(r1[VERSION], r2[VERSION]);
  376. if (cmp !== 0) {
  377. return cmp;
  378. }
  379. if (r1[TYPE] === r2[TYPE])
  380. return 0;
  381. return r1[TYPE] > r2[TYPE] ? 1 : -1;
  382. }
  383. exports.SemverRange = SemverRange;