Spaces:
Running
Running
| const debug = require('../internal/debug') | |
| const { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants') | |
| const { safeRe: re, t } = require('../internal/re') | |
| const parseOptions = require('../internal/parse-options') | |
| const { compareIdentifiers } = require('../internal/identifiers') | |
| class SemVer { | |
| constructor (version, options) { | |
| options = parseOptions(options) | |
| if (version instanceof SemVer) { | |
| if (version.loose === !!options.loose && | |
| version.includePrerelease === !!options.includePrerelease) { | |
| return version | |
| } else { | |
| version = version.version | |
| } | |
| } else if (typeof version !== 'string') { | |
| throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`) | |
| } | |
| if (version.length > MAX_LENGTH) { | |
| throw new TypeError( | |
| `version is longer than ${MAX_LENGTH} characters` | |
| ) | |
| } | |
| debug('SemVer', version, options) | |
| this.options = options | |
| this.loose = !!options.loose | |
| // this isn't actually relevant for versions, but keep it so that we | |
| // don't run into trouble passing this.options around. | |
| this.includePrerelease = !!options.includePrerelease | |
| const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]) | |
| if (!m) { | |
| throw new TypeError(`Invalid Version: ${version}`) | |
| } | |
| this.raw = version | |
| // these are actually numbers | |
| this.major = +m[1] | |
| this.minor = +m[2] | |
| this.patch = +m[3] | |
| if (this.major > MAX_SAFE_INTEGER || this.major < 0) { | |
| throw new TypeError('Invalid major version') | |
| } | |
| if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { | |
| throw new TypeError('Invalid minor version') | |
| } | |
| if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { | |
| throw new TypeError('Invalid patch version') | |
| } | |
| // numberify any prerelease numeric ids | |
| if (!m[4]) { | |
| this.prerelease = [] | |
| } else { | |
| this.prerelease = m[4].split('.').map((id) => { | |
| if (/^[0-9]+$/.test(id)) { | |
| const num = +id | |
| if (num >= 0 && num < MAX_SAFE_INTEGER) { | |
| return num | |
| } | |
| } | |
| return id | |
| }) | |
| } | |
| this.build = m[5] ? m[5].split('.') : [] | |
| this.format() | |
| } | |
| format () { | |
| this.version = `${this.major}.${this.minor}.${this.patch}` | |
| if (this.prerelease.length) { | |
| this.version += `-${this.prerelease.join('.')}` | |
| } | |
| return this.version | |
| } | |
| toString () { | |
| return this.version | |
| } | |
| compare (other) { | |
| debug('SemVer.compare', this.version, this.options, other) | |
| if (!(other instanceof SemVer)) { | |
| if (typeof other === 'string' && other === this.version) { | |
| return 0 | |
| } | |
| other = new SemVer(other, this.options) | |
| } | |
| if (other.version === this.version) { | |
| return 0 | |
| } | |
| return this.compareMain(other) || this.comparePre(other) | |
| } | |
| compareMain (other) { | |
| if (!(other instanceof SemVer)) { | |
| other = new SemVer(other, this.options) | |
| } | |
| if (this.major < other.major) { | |
| return -1 | |
| } | |
| if (this.major > other.major) { | |
| return 1 | |
| } | |
| if (this.minor < other.minor) { | |
| return -1 | |
| } | |
| if (this.minor > other.minor) { | |
| return 1 | |
| } | |
| if (this.patch < other.patch) { | |
| return -1 | |
| } | |
| if (this.patch > other.patch) { | |
| return 1 | |
| } | |
| return 0 | |
| } | |
| comparePre (other) { | |
| if (!(other instanceof SemVer)) { | |
| other = new SemVer(other, this.options) | |
| } | |
| // NOT having a prerelease is > having one | |
| if (this.prerelease.length && !other.prerelease.length) { | |
| return -1 | |
| } else if (!this.prerelease.length && other.prerelease.length) { | |
| return 1 | |
| } else if (!this.prerelease.length && !other.prerelease.length) { | |
| return 0 | |
| } | |
| let i = 0 | |
| do { | |
| const a = this.prerelease[i] | |
| const b = other.prerelease[i] | |
| debug('prerelease compare', i, a, b) | |
| if (a === undefined && b === undefined) { | |
| return 0 | |
| } else if (b === undefined) { | |
| return 1 | |
| } else if (a === undefined) { | |
| return -1 | |
| } else if (a === b) { | |
| continue | |
| } else { | |
| return compareIdentifiers(a, b) | |
| } | |
| } while (++i) | |
| } | |
| compareBuild (other) { | |
| if (!(other instanceof SemVer)) { | |
| other = new SemVer(other, this.options) | |
| } | |
| let i = 0 | |
| do { | |
| const a = this.build[i] | |
| const b = other.build[i] | |
| debug('build compare', i, a, b) | |
| if (a === undefined && b === undefined) { | |
| return 0 | |
| } else if (b === undefined) { | |
| return 1 | |
| } else if (a === undefined) { | |
| return -1 | |
| } else if (a === b) { | |
| continue | |
| } else { | |
| return compareIdentifiers(a, b) | |
| } | |
| } while (++i) | |
| } | |
| // preminor will bump the version up to the next minor release, and immediately | |
| // down to pre-release. premajor and prepatch work the same way. | |
| inc (release, identifier, identifierBase) { | |
| if (release.startsWith('pre')) { | |
| if (!identifier && identifierBase === false) { | |
| throw new Error('invalid increment argument: identifier is empty') | |
| } | |
| // Avoid an invalid semver results | |
| if (identifier) { | |
| const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]) | |
| if (!match || match[1] !== identifier) { | |
| throw new Error(`invalid identifier: ${identifier}`) | |
| } | |
| } | |
| } | |
| switch (release) { | |
| case 'premajor': | |
| this.prerelease.length = 0 | |
| this.patch = 0 | |
| this.minor = 0 | |
| this.major++ | |
| this.inc('pre', identifier, identifierBase) | |
| break | |
| case 'preminor': | |
| this.prerelease.length = 0 | |
| this.patch = 0 | |
| this.minor++ | |
| this.inc('pre', identifier, identifierBase) | |
| break | |
| case 'prepatch': | |
| // If this is already a prerelease, it will bump to the next version | |
| // drop any prereleases that might already exist, since they are not | |
| // relevant at this point. | |
| this.prerelease.length = 0 | |
| this.inc('patch', identifier, identifierBase) | |
| this.inc('pre', identifier, identifierBase) | |
| break | |
| // If the input is a non-prerelease version, this acts the same as | |
| // prepatch. | |
| case 'prerelease': | |
| if (this.prerelease.length === 0) { | |
| this.inc('patch', identifier, identifierBase) | |
| } | |
| this.inc('pre', identifier, identifierBase) | |
| break | |
| case 'release': | |
| if (this.prerelease.length === 0) { | |
| throw new Error(`version ${this.raw} is not a prerelease`) | |
| } | |
| this.prerelease.length = 0 | |
| break | |
| case 'major': | |
| // If this is a pre-major version, bump up to the same major version. | |
| // Otherwise increment major. | |
| // 1.0.0-5 bumps to 1.0.0 | |
| // 1.1.0 bumps to 2.0.0 | |
| if ( | |
| this.minor !== 0 || | |
| this.patch !== 0 || | |
| this.prerelease.length === 0 | |
| ) { | |
| this.major++ | |
| } | |
| this.minor = 0 | |
| this.patch = 0 | |
| this.prerelease = [] | |
| break | |
| case 'minor': | |
| // If this is a pre-minor version, bump up to the same minor version. | |
| // Otherwise increment minor. | |
| // 1.2.0-5 bumps to 1.2.0 | |
| // 1.2.1 bumps to 1.3.0 | |
| if (this.patch !== 0 || this.prerelease.length === 0) { | |
| this.minor++ | |
| } | |
| this.patch = 0 | |
| this.prerelease = [] | |
| break | |
| case 'patch': | |
| // If this is not a pre-release version, it will increment the patch. | |
| // If it is a pre-release it will bump up to the same patch version. | |
| // 1.2.0-5 patches to 1.2.0 | |
| // 1.2.0 patches to 1.2.1 | |
| if (this.prerelease.length === 0) { | |
| this.patch++ | |
| } | |
| this.prerelease = [] | |
| break | |
| // This probably shouldn't be used publicly. | |
| // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction. | |
| case 'pre': { | |
| const base = Number(identifierBase) ? 1 : 0 | |
| if (this.prerelease.length === 0) { | |
| this.prerelease = [base] | |
| } else { | |
| let i = this.prerelease.length | |
| while (--i >= 0) { | |
| if (typeof this.prerelease[i] === 'number') { | |
| this.prerelease[i]++ | |
| i = -2 | |
| } | |
| } | |
| if (i === -1) { | |
| // didn't increment anything | |
| if (identifier === this.prerelease.join('.') && identifierBase === false) { | |
| throw new Error('invalid increment argument: identifier already exists') | |
| } | |
| this.prerelease.push(base) | |
| } | |
| } | |
| if (identifier) { | |
| // 1.2.0-beta.1 bumps to 1.2.0-beta.2, | |
| // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 | |
| let prerelease = [identifier, base] | |
| if (identifierBase === false) { | |
| prerelease = [identifier] | |
| } | |
| if (compareIdentifiers(this.prerelease[0], identifier) === 0) { | |
| if (isNaN(this.prerelease[1])) { | |
| this.prerelease = prerelease | |
| } | |
| } else { | |
| this.prerelease = prerelease | |
| } | |
| } | |
| break | |
| } | |
| default: | |
| throw new Error(`invalid increment argument: ${release}`) | |
| } | |
| this.raw = this.format() | |
| if (this.build.length) { | |
| this.raw += `+${this.build.join('.')}` | |
| } | |
| return this | |
| } | |
| } | |
| module.exports = SemVer | |