1 | const debug = require('../internal/debug')
|
2 | const { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')
|
3 | const { re, t } = require('../internal/re')
|
4 |
|
5 | const { compareIdentifiers } = require('../internal/identifiers')
|
6 | class SemVer {
|
7 | constructor (version, options) {
|
8 | if (!options || typeof options !== 'object') {
|
9 | options = {
|
10 | loose: !!options,
|
11 | includePrerelease: false
|
12 | }
|
13 | }
|
14 | if (version instanceof SemVer) {
|
15 | if (version.loose === !!options.loose &&
|
16 | version.includePrerelease === !!options.includePrerelease) {
|
17 | return version
|
18 | } else {
|
19 | version = version.version
|
20 | }
|
21 | } else if (typeof version !== 'string') {
|
22 | throw new TypeError(`Invalid Version: ${version}`)
|
23 | }
|
24 |
|
25 | if (version.length > MAX_LENGTH) {
|
26 | throw new TypeError(
|
27 | `version is longer than ${MAX_LENGTH} characters`
|
28 | )
|
29 | }
|
30 |
|
31 | debug('SemVer', version, options)
|
32 | this.options = options
|
33 | this.loose = !!options.loose
|
34 |
|
35 |
|
36 | this.includePrerelease = !!options.includePrerelease
|
37 |
|
38 | const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])
|
39 |
|
40 | if (!m) {
|
41 | throw new TypeError(`Invalid Version: ${version}`)
|
42 | }
|
43 |
|
44 | this.raw = version
|
45 |
|
46 |
|
47 | this.major = +m[1]
|
48 | this.minor = +m[2]
|
49 | this.patch = +m[3]
|
50 |
|
51 | if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
|
52 | throw new TypeError('Invalid major version')
|
53 | }
|
54 |
|
55 | if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
|
56 | throw new TypeError('Invalid minor version')
|
57 | }
|
58 |
|
59 | if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
|
60 | throw new TypeError('Invalid patch version')
|
61 | }
|
62 |
|
63 |
|
64 | if (!m[4]) {
|
65 | this.prerelease = []
|
66 | } else {
|
67 | this.prerelease = m[4].split('.').map((id) => {
|
68 | if (/^[0-9]+$/.test(id)) {
|
69 | const num = +id
|
70 | if (num >= 0 && num < MAX_SAFE_INTEGER) {
|
71 | return num
|
72 | }
|
73 | }
|
74 | return id
|
75 | })
|
76 | }
|
77 |
|
78 | this.build = m[5] ? m[5].split('.') : []
|
79 | this.format()
|
80 | }
|
81 |
|
82 | format () {
|
83 | this.version = `${this.major}.${this.minor}.${this.patch}`
|
84 | if (this.prerelease.length) {
|
85 | this.version += `-${this.prerelease.join('.')}`
|
86 | }
|
87 | return this.version
|
88 | }
|
89 |
|
90 | toString () {
|
91 | return this.version
|
92 | }
|
93 |
|
94 | compare (other) {
|
95 | debug('SemVer.compare', this.version, this.options, other)
|
96 | if (!(other instanceof SemVer)) {
|
97 | if (typeof other === 'string' && other === this.version) {
|
98 | return 0
|
99 | }
|
100 | other = new SemVer(other, this.options)
|
101 | }
|
102 |
|
103 | if (other.version === this.version) {
|
104 | return 0
|
105 | }
|
106 |
|
107 | return this.compareMain(other) || this.comparePre(other)
|
108 | }
|
109 |
|
110 | compareMain (other) {
|
111 | if (!(other instanceof SemVer)) {
|
112 | other = new SemVer(other, this.options)
|
113 | }
|
114 |
|
115 | return (
|
116 | compareIdentifiers(this.major, other.major) ||
|
117 | compareIdentifiers(this.minor, other.minor) ||
|
118 | compareIdentifiers(this.patch, other.patch)
|
119 | )
|
120 | }
|
121 |
|
122 | comparePre (other) {
|
123 | if (!(other instanceof SemVer)) {
|
124 | other = new SemVer(other, this.options)
|
125 | }
|
126 |
|
127 |
|
128 | if (this.prerelease.length && !other.prerelease.length) {
|
129 | return -1
|
130 | } else if (!this.prerelease.length && other.prerelease.length) {
|
131 | return 1
|
132 | } else if (!this.prerelease.length && !other.prerelease.length) {
|
133 | return 0
|
134 | }
|
135 |
|
136 | let i = 0
|
137 | do {
|
138 | const a = this.prerelease[i]
|
139 | const b = other.prerelease[i]
|
140 | debug('prerelease compare', i, a, b)
|
141 | if (a === undefined && b === undefined) {
|
142 | return 0
|
143 | } else if (b === undefined) {
|
144 | return 1
|
145 | } else if (a === undefined) {
|
146 | return -1
|
147 | } else if (a === b) {
|
148 | continue
|
149 | } else {
|
150 | return compareIdentifiers(a, b)
|
151 | }
|
152 | } while (++i)
|
153 | }
|
154 |
|
155 | compareBuild (other) {
|
156 | if (!(other instanceof SemVer)) {
|
157 | other = new SemVer(other, this.options)
|
158 | }
|
159 |
|
160 | let i = 0
|
161 | do {
|
162 | const a = this.build[i]
|
163 | const b = other.build[i]
|
164 | debug('prerelease compare', i, a, b)
|
165 | if (a === undefined && b === undefined) {
|
166 | return 0
|
167 | } else if (b === undefined) {
|
168 | return 1
|
169 | } else if (a === undefined) {
|
170 | return -1
|
171 | } else if (a === b) {
|
172 | continue
|
173 | } else {
|
174 | return compareIdentifiers(a, b)
|
175 | }
|
176 | } while (++i)
|
177 | }
|
178 |
|
179 |
|
180 |
|
181 | inc (release, identifier) {
|
182 | switch (release) {
|
183 | case 'premajor':
|
184 | this.prerelease.length = 0
|
185 | this.patch = 0
|
186 | this.minor = 0
|
187 | this.major++
|
188 | this.inc('pre', identifier)
|
189 | break
|
190 | case 'preminor':
|
191 | this.prerelease.length = 0
|
192 | this.patch = 0
|
193 | this.minor++
|
194 | this.inc('pre', identifier)
|
195 | break
|
196 | case 'prepatch':
|
197 |
|
198 |
|
199 |
|
200 | this.prerelease.length = 0
|
201 | this.inc('patch', identifier)
|
202 | this.inc('pre', identifier)
|
203 | break
|
204 |
|
205 |
|
206 | case 'prerelease':
|
207 | if (this.prerelease.length === 0) {
|
208 | this.inc('patch', identifier)
|
209 | }
|
210 | this.inc('pre', identifier)
|
211 | break
|
212 |
|
213 | case 'major':
|
214 |
|
215 |
|
216 |
|
217 |
|
218 | if (
|
219 | this.minor !== 0 ||
|
220 | this.patch !== 0 ||
|
221 | this.prerelease.length === 0
|
222 | ) {
|
223 | this.major++
|
224 | }
|
225 | this.minor = 0
|
226 | this.patch = 0
|
227 | this.prerelease = []
|
228 | break
|
229 | case 'minor':
|
230 |
|
231 |
|
232 |
|
233 |
|
234 | if (this.patch !== 0 || this.prerelease.length === 0) {
|
235 | this.minor++
|
236 | }
|
237 | this.patch = 0
|
238 | this.prerelease = []
|
239 | break
|
240 | case 'patch':
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | if (this.prerelease.length === 0) {
|
246 | this.patch++
|
247 | }
|
248 | this.prerelease = []
|
249 | break
|
250 |
|
251 |
|
252 | case 'pre':
|
253 | if (this.prerelease.length === 0) {
|
254 | this.prerelease = [0]
|
255 | } else {
|
256 | let i = this.prerelease.length
|
257 | while (--i >= 0) {
|
258 | if (typeof this.prerelease[i] === 'number') {
|
259 | this.prerelease[i]++
|
260 | i = -2
|
261 | }
|
262 | }
|
263 | if (i === -1) {
|
264 |
|
265 | this.prerelease.push(0)
|
266 | }
|
267 | }
|
268 | if (identifier) {
|
269 |
|
270 |
|
271 | if (this.prerelease[0] === identifier) {
|
272 | if (isNaN(this.prerelease[1])) {
|
273 | this.prerelease = [identifier, 0]
|
274 | }
|
275 | } else {
|
276 | this.prerelease = [identifier, 0]
|
277 | }
|
278 | }
|
279 | break
|
280 |
|
281 | default:
|
282 | throw new Error(`invalid increment argument: ${release}`)
|
283 | }
|
284 | this.format()
|
285 | this.raw = this.version
|
286 | return this
|
287 | }
|
288 | }
|
289 |
|
290 | module.exports = SemVer
|