UNPKG

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