209 lines
3.9 KiB
JavaScript
209 lines
3.9 KiB
JavaScript
const errors = require('./errors')
|
|
|
|
class Version {
|
|
constructor(major, minor, patch, opts = {}) {
|
|
const { prerelease = [], build = [] } = opts
|
|
|
|
this.major = major
|
|
this.minor = minor
|
|
this.patch = patch
|
|
this.prerelease = prerelease
|
|
this.build = build
|
|
}
|
|
|
|
compare(version) {
|
|
return exports.compare(this, version)
|
|
}
|
|
|
|
toString() {
|
|
let result = `${this.major}.${this.minor}.${this.patch}`
|
|
|
|
if (this.prerelease.length) {
|
|
result += '-' + this.prerelease.join('.')
|
|
}
|
|
|
|
if (this.build.length) {
|
|
result += '+' + this.build.join('.')
|
|
}
|
|
|
|
return result
|
|
}
|
|
}
|
|
|
|
module.exports = exports = Version
|
|
|
|
exports.parse = function parse(
|
|
input,
|
|
state = { position: 0, partial: false, range: false }
|
|
) {
|
|
let i = state.position
|
|
let c
|
|
|
|
const unexpected = (expected) => {
|
|
let msg
|
|
|
|
if (i >= input.length) {
|
|
msg = `Unexpected end of input in '${input}'`
|
|
} else {
|
|
msg = `Unexpected token '${input[i]}' in '${input}' at position ${i}`
|
|
}
|
|
|
|
if (expected) msg += `, ${expected}`
|
|
|
|
throw errors.INVALID_VERSION(msg, unexpected)
|
|
}
|
|
|
|
const components = [0, 0, 0]
|
|
|
|
let k = 0
|
|
|
|
while (k < 3) {
|
|
c = input[i]
|
|
|
|
if (k > 0) {
|
|
if (c === '.') c = input[++i]
|
|
else if (state.range) break
|
|
else unexpected("expected '.'")
|
|
}
|
|
|
|
if (c === '0') {
|
|
i++
|
|
k++
|
|
} else if (c >= '1' && c <= '9') {
|
|
let j = 0
|
|
do c = input[i + ++j]
|
|
while (c >= '0' && c <= '9')
|
|
|
|
components[k++] = parseInt(input.substring(i, i + j))
|
|
|
|
i += j
|
|
} else unexpected('expected /[0-9]/')
|
|
}
|
|
|
|
const prerelease = []
|
|
|
|
if (k === 3 && input[i] === '-') {
|
|
i++
|
|
|
|
while (true) {
|
|
c = input[i]
|
|
|
|
let tag = ''
|
|
let j = 0
|
|
|
|
while (c >= '0' && c <= '9') c = input[i + ++j]
|
|
|
|
let isNumeric = false
|
|
|
|
if (j) {
|
|
tag += input.substring(i, i + j)
|
|
|
|
c = input[(i += j)]
|
|
|
|
isNumeric = tag[0] !== '0' || tag.length === 1
|
|
}
|
|
|
|
j = 0
|
|
|
|
while (
|
|
(c >= '0' && c <= '9') ||
|
|
(c >= 'a' && c <= 'z') ||
|
|
(c >= 'A' && c <= 'Z') ||
|
|
c === '-'
|
|
)
|
|
c = input[i + ++j]
|
|
|
|
if (j) {
|
|
tag += input.substring(i, i + j)
|
|
|
|
c = input[(i += j)]
|
|
} else if (!isNumeric) unexpected('expected /[a-zA-Z-]/')
|
|
|
|
prerelease.push(tag)
|
|
|
|
if (c === '.') c = input[++i]
|
|
else break
|
|
}
|
|
}
|
|
|
|
const build = []
|
|
|
|
if (k === 3 && input[i] === '+') {
|
|
i++
|
|
|
|
while (true) {
|
|
c = input[i]
|
|
|
|
let tag = ''
|
|
let j = 0
|
|
|
|
while (
|
|
(c >= '0' && c <= '9') ||
|
|
(c >= 'a' && c <= 'z') ||
|
|
(c >= 'A' && c <= 'Z') ||
|
|
c === '-'
|
|
)
|
|
c = input[i + ++j]
|
|
|
|
if (j) {
|
|
tag += input.substring(i, i + j)
|
|
|
|
c = input[(i += j)]
|
|
} else unexpected('expected /[0-9a-zA-Z-]/')
|
|
|
|
build.push(tag)
|
|
|
|
if (c === '.') c = input[++i]
|
|
else break
|
|
}
|
|
}
|
|
|
|
if (i < input.length && state.partial === false) {
|
|
unexpected('expected end of input')
|
|
}
|
|
|
|
state.position = i
|
|
|
|
return new Version(...components, { prerelease, build })
|
|
}
|
|
|
|
const integer = /^[0-9]+$/
|
|
|
|
exports.compare = function compare(a, b) {
|
|
if (a.major > b.major) return 1
|
|
if (a.major < b.major) return -1
|
|
|
|
if (a.minor > b.minor) return 1
|
|
if (a.minor < b.minor) return -1
|
|
|
|
if (a.patch > b.patch) return 1
|
|
if (a.patch < b.patch) return -1
|
|
|
|
if (a.prerelease.length === 0) return b.prerelease.length === 0 ? 0 : 1
|
|
if (b.prerelease.length === 0) return -1
|
|
|
|
let i = 0
|
|
do {
|
|
let x = a.prerelease[i]
|
|
let y = b.prerelease[i]
|
|
|
|
if (x === undefined) return y === undefined ? 0 : -1
|
|
if (y === undefined) return 1
|
|
|
|
if (x === y) continue
|
|
|
|
const xInt = integer.test(x)
|
|
const yInt = integer.test(y)
|
|
|
|
if (xInt && yInt) {
|
|
x = +x
|
|
y = +y
|
|
} else {
|
|
if (xInt) return -1
|
|
if (yInt) return 1
|
|
}
|
|
|
|
return x > y ? 1 : -1
|
|
} while (++i)
|
|
}
|