comparator.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. const ANY = Symbol('SemVer ANY')
  2. // hoisted class for cyclic dependency
  3. class Comparator {
  4. static get ANY () {
  5. return ANY
  6. }
  7. constructor (comp, options) {
  8. options = parseOptions(options)
  9. if (comp instanceof Comparator) {
  10. if (comp.loose === !!options.loose) {
  11. return comp
  12. } else {
  13. comp = comp.value
  14. }
  15. }
  16. debug('comparator', comp, options)
  17. this.options = options
  18. this.loose = !!options.loose
  19. this.parse(comp)
  20. if (this.semver === ANY) {
  21. this.value = ''
  22. } else {
  23. this.value = this.operator + this.semver.version
  24. }
  25. debug('comp', this)
  26. }
  27. parse (comp) {
  28. const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
  29. const m = comp.match(r)
  30. if (!m) {
  31. throw new TypeError(`Invalid comparator: ${comp}`)
  32. }
  33. this.operator = m[1] !== undefined ? m[1] : ''
  34. if (this.operator === '=') {
  35. this.operator = ''
  36. }
  37. // if it literally is just '>' or '' then allow anything.
  38. if (!m[2]) {
  39. this.semver = ANY
  40. } else {
  41. this.semver = new SemVer(m[2], this.options.loose)
  42. }
  43. }
  44. toString () {
  45. return this.value
  46. }
  47. test (version) {
  48. debug('Comparator.test', version, this.options.loose)
  49. if (this.semver === ANY || version === ANY) {
  50. return true
  51. }
  52. if (typeof version === 'string') {
  53. try {
  54. version = new SemVer(version, this.options)
  55. } catch (er) {
  56. return false
  57. }
  58. }
  59. return cmp(version, this.operator, this.semver, this.options)
  60. }
  61. intersects (comp, options) {
  62. if (!(comp instanceof Comparator)) {
  63. throw new TypeError('a Comparator is required')
  64. }
  65. if (!options || typeof options !== 'object') {
  66. options = {
  67. loose: !!options,
  68. includePrerelease: false,
  69. }
  70. }
  71. if (this.operator === '') {
  72. if (this.value === '') {
  73. return true
  74. }
  75. return new Range(comp.value, options).test(this.value)
  76. } else if (comp.operator === '') {
  77. if (comp.value === '') {
  78. return true
  79. }
  80. return new Range(this.value, options).test(comp.semver)
  81. }
  82. const sameDirectionIncreasing =
  83. (this.operator === '>=' || this.operator === '>') &&
  84. (comp.operator === '>=' || comp.operator === '>')
  85. const sameDirectionDecreasing =
  86. (this.operator === '<=' || this.operator === '<') &&
  87. (comp.operator === '<=' || comp.operator === '<')
  88. const sameSemVer = this.semver.version === comp.semver.version
  89. const differentDirectionsInclusive =
  90. (this.operator === '>=' || this.operator === '<=') &&
  91. (comp.operator === '>=' || comp.operator === '<=')
  92. const oppositeDirectionsLessThan =
  93. cmp(this.semver, '<', comp.semver, options) &&
  94. (this.operator === '>=' || this.operator === '>') &&
  95. (comp.operator === '<=' || comp.operator === '<')
  96. const oppositeDirectionsGreaterThan =
  97. cmp(this.semver, '>', comp.semver, options) &&
  98. (this.operator === '<=' || this.operator === '<') &&
  99. (comp.operator === '>=' || comp.operator === '>')
  100. return (
  101. sameDirectionIncreasing ||
  102. sameDirectionDecreasing ||
  103. (sameSemVer && differentDirectionsInclusive) ||
  104. oppositeDirectionsLessThan ||
  105. oppositeDirectionsGreaterThan
  106. )
  107. }
  108. }
  109. module.exports = Comparator
  110. const parseOptions = require('../internal/parse-options')
  111. const { re, t } = require('../internal/re')
  112. const cmp = require('../functions/cmp')
  113. const debug = require('../internal/debug')
  114. const SemVer = require('./semver')
  115. const Range = require('./range')