You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
6.5 KiB
182 lines
6.5 KiB
const { MAX_SAFE_COMPONENT_LENGTH } = require('./constants') |
|
const debug = require('./debug') |
|
exports = module.exports = {} |
|
|
|
// The actual regexps go on exports.re |
|
const re = exports.re = [] |
|
const src = exports.src = [] |
|
const t = exports.t = {} |
|
let R = 0 |
|
|
|
const createToken = (name, value, isGlobal) => { |
|
const index = R++ |
|
debug(name, index, value) |
|
t[name] = index |
|
src[index] = value |
|
re[index] = new RegExp(value, isGlobal ? 'g' : undefined) |
|
} |
|
|
|
// The following Regular Expressions can be used for tokenizing, |
|
// validating, and parsing SemVer version strings. |
|
|
|
// ## Numeric Identifier |
|
// A single `0`, or a non-zero digit followed by zero or more digits. |
|
|
|
createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') |
|
createToken('NUMERICIDENTIFIERLOOSE', '[0-9]+') |
|
|
|
// ## Non-numeric Identifier |
|
// Zero or more digits, followed by a letter or hyphen, and then zero or |
|
// more letters, digits, or hyphens. |
|
|
|
createToken('NONNUMERICIDENTIFIER', '\\d*[a-zA-Z-][a-zA-Z0-9-]*') |
|
|
|
// ## Main Version |
|
// Three dot-separated numeric identifiers. |
|
|
|
createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` + |
|
`(${src[t.NUMERICIDENTIFIER]})\\.` + |
|
`(${src[t.NUMERICIDENTIFIER]})`) |
|
|
|
createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + |
|
`(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + |
|
`(${src[t.NUMERICIDENTIFIERLOOSE]})`) |
|
|
|
// ## Pre-release Version Identifier |
|
// A numeric identifier, or a non-numeric identifier. |
|
|
|
createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER] |
|
}|${src[t.NONNUMERICIDENTIFIER]})`) |
|
|
|
createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE] |
|
}|${src[t.NONNUMERICIDENTIFIER]})`) |
|
|
|
// ## Pre-release Version |
|
// Hyphen, followed by one or more dot-separated pre-release version |
|
// identifiers. |
|
|
|
createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER] |
|
}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`) |
|
|
|
createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] |
|
}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`) |
|
|
|
// ## Build Metadata Identifier |
|
// Any combination of digits, letters, or hyphens. |
|
|
|
createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+') |
|
|
|
// ## Build Metadata |
|
// Plus sign, followed by one or more period-separated build metadata |
|
// identifiers. |
|
|
|
createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER] |
|
}(?:\\.${src[t.BUILDIDENTIFIER]})*))`) |
|
|
|
// ## Full Version String |
|
// A main version, followed optionally by a pre-release version and |
|
// build metadata. |
|
|
|
// Note that the only major, minor, patch, and pre-release sections of |
|
// the version string are capturing groups. The build metadata is not a |
|
// capturing group, because it should not ever be used in version |
|
// comparison. |
|
|
|
createToken('FULLPLAIN', `v?${src[t.MAINVERSION] |
|
}${src[t.PRERELEASE]}?${ |
|
src[t.BUILD]}?`) |
|
|
|
createToken('FULL', `^${src[t.FULLPLAIN]}$`) |
|
|
|
// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. |
|
// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty |
|
// common in the npm registry. |
|
createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE] |
|
}${src[t.PRERELEASELOOSE]}?${ |
|
src[t.BUILD]}?`) |
|
|
|
createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`) |
|
|
|
createToken('GTLT', '((?:<|>)?=?)') |
|
|
|
// Something like "2.*" or "1.2.x". |
|
// Note that "x.x" is a valid xRange identifer, meaning "any version" |
|
// Only the first item is strictly required. |
|
createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`) |
|
createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`) |
|
|
|
createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` + |
|
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` + |
|
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` + |
|
`(?:${src[t.PRERELEASE]})?${ |
|
src[t.BUILD]}?` + |
|
`)?)?`) |
|
|
|
createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` + |
|
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + |
|
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + |
|
`(?:${src[t.PRERELEASELOOSE]})?${ |
|
src[t.BUILD]}?` + |
|
`)?)?`) |
|
|
|
createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`) |
|
createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) |
|
|
|
// Coercion. |
|
// Extract anything that could conceivably be a part of a valid semver |
|
createToken('COERCE', `${'(^|[^\\d])' + |
|
'(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + |
|
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + |
|
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + |
|
`(?:$|[^\\d])`) |
|
createToken('COERCERTL', src[t.COERCE], true) |
|
|
|
// Tilde ranges. |
|
// Meaning is "reasonably at or greater than" |
|
createToken('LONETILDE', '(?:~>?)') |
|
|
|
createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true) |
|
exports.tildeTrimReplace = '$1~' |
|
|
|
createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`) |
|
createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`) |
|
|
|
// Caret ranges. |
|
// Meaning is "at least and backwards compatible with" |
|
createToken('LONECARET', '(?:\\^)') |
|
|
|
createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true) |
|
exports.caretTrimReplace = '$1^' |
|
|
|
createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`) |
|
createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`) |
|
|
|
// A simple gt/lt/eq thing, or just "" to indicate "any version" |
|
createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`) |
|
createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`) |
|
|
|
// An expression to strip any whitespace between the gtlt and the thing |
|
// it modifies, so that `> 1.2.3` ==> `>1.2.3` |
|
createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT] |
|
}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true) |
|
exports.comparatorTrimReplace = '$1$2$3' |
|
|
|
// Something like `1.2.3 - 1.2.4` |
|
// Note that these all use the loose form, because they'll be |
|
// checked against either the strict or loose comparator form |
|
// later. |
|
createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` + |
|
`\\s+-\\s+` + |
|
`(${src[t.XRANGEPLAIN]})` + |
|
`\\s*$`) |
|
|
|
createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` + |
|
`\\s+-\\s+` + |
|
`(${src[t.XRANGEPLAINLOOSE]})` + |
|
`\\s*$`) |
|
|
|
// Star ranges basically just allow anything at all. |
|
createToken('STAR', '(<|>)?=?\\s*\\*') |
|
// >=0.0.0 is like a star |
|
createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$') |
|
createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$')
|
|
|