UNPKG

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