index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /* global define */
  2. (function (root, factory) {
  3. /* istanbul ignore next */
  4. if (typeof define === 'function' && define.amd) {
  5. define([], factory);
  6. } else if (typeof exports === 'object') {
  7. module.exports = factory();
  8. } else {
  9. root.compareVersions = factory();
  10. }
  11. }(this, function () {
  12. var semver = /^v?(?:\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+))?(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
  13. function indexOrEnd(str, q) {
  14. return str.indexOf(q) === -1 ? str.length : str.indexOf(q);
  15. }
  16. function split(v) {
  17. var c = v.replace(/^v/, '').replace(/\+.*$/, '');
  18. var patchIndex = indexOrEnd(c, '-');
  19. var arr = c.substring(0, patchIndex).split('.');
  20. arr.push(c.substring(patchIndex + 1));
  21. return arr;
  22. }
  23. function tryParse(v) {
  24. return isNaN(Number(v)) ? v : Number(v);
  25. }
  26. function validate(version) {
  27. if (typeof version !== 'string') {
  28. throw new TypeError('Invalid argument expected string');
  29. }
  30. if (!semver.test(version)) {
  31. throw new Error('Invalid argument not valid semver (\''+version+'\' received)');
  32. }
  33. }
  34. function compareVersions(v1, v2) {
  35. [v1, v2].forEach(validate);
  36. var s1 = split(v1);
  37. var s2 = split(v2);
  38. for (var i = 0; i < Math.max(s1.length - 1, s2.length - 1); i++) {
  39. var n1 = parseInt(s1[i] || 0, 10);
  40. var n2 = parseInt(s2[i] || 0, 10);
  41. if (n1 > n2) return 1;
  42. if (n2 > n1) return -1;
  43. }
  44. var sp1 = s1[s1.length - 1];
  45. var sp2 = s2[s2.length - 1];
  46. if (sp1 && sp2) {
  47. var p1 = sp1.split('.').map(tryParse);
  48. var p2 = sp2.split('.').map(tryParse);
  49. for (i = 0; i < Math.max(p1.length, p2.length); i++) {
  50. if (p1[i] === undefined || typeof p2[i] === 'string' && typeof p1[i] === 'number') return -1;
  51. if (p2[i] === undefined || typeof p1[i] === 'string' && typeof p2[i] === 'number') return 1;
  52. if (p1[i] > p2[i]) return 1;
  53. if (p2[i] > p1[i]) return -1;
  54. }
  55. } else if (sp1 || sp2) {
  56. return sp1 ? -1 : 1;
  57. }
  58. return 0;
  59. };
  60. var allowedOperators = [
  61. '>',
  62. '>=',
  63. '=',
  64. '<',
  65. '<='
  66. ];
  67. var operatorResMap = {
  68. '>': [1],
  69. '>=': [0, 1],
  70. '=': [0],
  71. '<=': [-1, 0],
  72. '<': [-1]
  73. };
  74. function validateOperator(op) {
  75. if (typeof op !== 'string') {
  76. throw new TypeError('Invalid operator type, expected string but got ' + typeof op);
  77. }
  78. if (allowedOperators.indexOf(op) === -1) {
  79. throw new TypeError('Invalid operator, expected one of ' + allowedOperators.join('|'));
  80. }
  81. }
  82. compareVersions.validate = function(version) {
  83. return typeof version === 'string' && semver.test(version);
  84. }
  85. compareVersions.compare = function (v1, v2, operator) {
  86. // Validate operator
  87. validateOperator(operator);
  88. // since result of compareVersions can only be -1 or 0 or 1
  89. // a simple map can be used to replace switch
  90. var res = compareVersions(v1, v2);
  91. return operatorResMap[operator].indexOf(res) > -1;
  92. }
  93. return compareVersions;
  94. }));