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