11cb0ef41Sopenharmony_ciconst { 21cb0ef41Sopenharmony_ci MAX_SAFE_COMPONENT_LENGTH, 31cb0ef41Sopenharmony_ci MAX_SAFE_BUILD_LENGTH, 41cb0ef41Sopenharmony_ci MAX_LENGTH, 51cb0ef41Sopenharmony_ci} = require('./constants') 61cb0ef41Sopenharmony_ciconst debug = require('./debug') 71cb0ef41Sopenharmony_ciexports = module.exports = {} 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci// The actual regexps go on exports.re 101cb0ef41Sopenharmony_ciconst re = exports.re = [] 111cb0ef41Sopenharmony_ciconst safeRe = exports.safeRe = [] 121cb0ef41Sopenharmony_ciconst src = exports.src = [] 131cb0ef41Sopenharmony_ciconst t = exports.t = {} 141cb0ef41Sopenharmony_cilet R = 0 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ciconst LETTERDASHNUMBER = '[a-zA-Z0-9-]' 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci// Replace some greedy regex tokens to prevent regex dos issues. These regex are 191cb0ef41Sopenharmony_ci// used internally via the safeRe object since all inputs in this library get 201cb0ef41Sopenharmony_ci// normalized first to trim and collapse all extra whitespace. The original 211cb0ef41Sopenharmony_ci// regexes are exported for userland consumption and lower level usage. A 221cb0ef41Sopenharmony_ci// future breaking change could export the safer regex only with a note that 231cb0ef41Sopenharmony_ci// all input should have extra whitespace removed. 241cb0ef41Sopenharmony_ciconst safeRegexReplacements = [ 251cb0ef41Sopenharmony_ci ['\\s', 1], 261cb0ef41Sopenharmony_ci ['\\d', MAX_LENGTH], 271cb0ef41Sopenharmony_ci [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], 281cb0ef41Sopenharmony_ci] 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ciconst makeSafeRegex = (value) => { 311cb0ef41Sopenharmony_ci for (const [token, max] of safeRegexReplacements) { 321cb0ef41Sopenharmony_ci value = value 331cb0ef41Sopenharmony_ci .split(`${token}*`).join(`${token}{0,${max}}`) 341cb0ef41Sopenharmony_ci .split(`${token}+`).join(`${token}{1,${max}}`) 351cb0ef41Sopenharmony_ci } 361cb0ef41Sopenharmony_ci return value 371cb0ef41Sopenharmony_ci} 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ciconst createToken = (name, value, isGlobal) => { 401cb0ef41Sopenharmony_ci const safe = makeSafeRegex(value) 411cb0ef41Sopenharmony_ci const index = R++ 421cb0ef41Sopenharmony_ci debug(name, index, value) 431cb0ef41Sopenharmony_ci t[name] = index 441cb0ef41Sopenharmony_ci src[index] = value 451cb0ef41Sopenharmony_ci re[index] = new RegExp(value, isGlobal ? 'g' : undefined) 461cb0ef41Sopenharmony_ci safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined) 471cb0ef41Sopenharmony_ci} 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci// The following Regular Expressions can be used for tokenizing, 501cb0ef41Sopenharmony_ci// validating, and parsing SemVer version strings. 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci// ## Numeric Identifier 531cb0ef41Sopenharmony_ci// A single `0`, or a non-zero digit followed by zero or more digits. 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_cicreateToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') 561cb0ef41Sopenharmony_cicreateToken('NUMERICIDENTIFIERLOOSE', '\\d+') 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci// ## Non-numeric Identifier 591cb0ef41Sopenharmony_ci// Zero or more digits, followed by a letter or hyphen, and then zero or 601cb0ef41Sopenharmony_ci// more letters, digits, or hyphens. 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_cicreateToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`) 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci// ## Main Version 651cb0ef41Sopenharmony_ci// Three dot-separated numeric identifiers. 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_cicreateToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` + 681cb0ef41Sopenharmony_ci `(${src[t.NUMERICIDENTIFIER]})\\.` + 691cb0ef41Sopenharmony_ci `(${src[t.NUMERICIDENTIFIER]})`) 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_cicreateToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + 721cb0ef41Sopenharmony_ci `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + 731cb0ef41Sopenharmony_ci `(${src[t.NUMERICIDENTIFIERLOOSE]})`) 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci// ## Pre-release Version Identifier 761cb0ef41Sopenharmony_ci// A numeric identifier, or a non-numeric identifier. 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_cicreateToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER] 791cb0ef41Sopenharmony_ci}|${src[t.NONNUMERICIDENTIFIER]})`) 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_cicreateToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE] 821cb0ef41Sopenharmony_ci}|${src[t.NONNUMERICIDENTIFIER]})`) 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci// ## Pre-release Version 851cb0ef41Sopenharmony_ci// Hyphen, followed by one or more dot-separated pre-release version 861cb0ef41Sopenharmony_ci// identifiers. 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_cicreateToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER] 891cb0ef41Sopenharmony_ci}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`) 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_cicreateToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] 921cb0ef41Sopenharmony_ci}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`) 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci// ## Build Metadata Identifier 951cb0ef41Sopenharmony_ci// Any combination of digits, letters, or hyphens. 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_cicreateToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`) 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci// ## Build Metadata 1001cb0ef41Sopenharmony_ci// Plus sign, followed by one or more period-separated build metadata 1011cb0ef41Sopenharmony_ci// identifiers. 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_cicreateToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER] 1041cb0ef41Sopenharmony_ci}(?:\\.${src[t.BUILDIDENTIFIER]})*))`) 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci// ## Full Version String 1071cb0ef41Sopenharmony_ci// A main version, followed optionally by a pre-release version and 1081cb0ef41Sopenharmony_ci// build metadata. 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci// Note that the only major, minor, patch, and pre-release sections of 1111cb0ef41Sopenharmony_ci// the version string are capturing groups. The build metadata is not a 1121cb0ef41Sopenharmony_ci// capturing group, because it should not ever be used in version 1131cb0ef41Sopenharmony_ci// comparison. 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_cicreateToken('FULLPLAIN', `v?${src[t.MAINVERSION] 1161cb0ef41Sopenharmony_ci}${src[t.PRERELEASE]}?${ 1171cb0ef41Sopenharmony_ci src[t.BUILD]}?`) 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_cicreateToken('FULL', `^${src[t.FULLPLAIN]}$`) 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. 1221cb0ef41Sopenharmony_ci// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty 1231cb0ef41Sopenharmony_ci// common in the npm registry. 1241cb0ef41Sopenharmony_cicreateToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE] 1251cb0ef41Sopenharmony_ci}${src[t.PRERELEASELOOSE]}?${ 1261cb0ef41Sopenharmony_ci src[t.BUILD]}?`) 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_cicreateToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`) 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_cicreateToken('GTLT', '((?:<|>)?=?)') 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci// Something like "2.*" or "1.2.x". 1331cb0ef41Sopenharmony_ci// Note that "x.x" is a valid xRange identifer, meaning "any version" 1341cb0ef41Sopenharmony_ci// Only the first item is strictly required. 1351cb0ef41Sopenharmony_cicreateToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`) 1361cb0ef41Sopenharmony_cicreateToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`) 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_cicreateToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` + 1391cb0ef41Sopenharmony_ci `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + 1401cb0ef41Sopenharmony_ci `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + 1411cb0ef41Sopenharmony_ci `(?:${src[t.PRERELEASE]})?${ 1421cb0ef41Sopenharmony_ci src[t.BUILD]}?` + 1431cb0ef41Sopenharmony_ci `)?)?`) 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_cicreateToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` + 1461cb0ef41Sopenharmony_ci `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + 1471cb0ef41Sopenharmony_ci `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + 1481cb0ef41Sopenharmony_ci `(?:${src[t.PRERELEASELOOSE]})?${ 1491cb0ef41Sopenharmony_ci src[t.BUILD]}?` + 1501cb0ef41Sopenharmony_ci `)?)?`) 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_cicreateToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`) 1531cb0ef41Sopenharmony_cicreateToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci// Coercion. 1561cb0ef41Sopenharmony_ci// Extract anything that could conceivably be a part of a valid semver 1571cb0ef41Sopenharmony_cicreateToken('COERCEPLAIN', `${'(^|[^\\d])' + 1581cb0ef41Sopenharmony_ci '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + 1591cb0ef41Sopenharmony_ci `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + 1601cb0ef41Sopenharmony_ci `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) 1611cb0ef41Sopenharmony_cicreateToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`) 1621cb0ef41Sopenharmony_cicreateToken('COERCEFULL', src[t.COERCEPLAIN] + 1631cb0ef41Sopenharmony_ci `(?:${src[t.PRERELEASE]})?` + 1641cb0ef41Sopenharmony_ci `(?:${src[t.BUILD]})?` + 1651cb0ef41Sopenharmony_ci `(?:$|[^\\d])`) 1661cb0ef41Sopenharmony_cicreateToken('COERCERTL', src[t.COERCE], true) 1671cb0ef41Sopenharmony_cicreateToken('COERCERTLFULL', src[t.COERCEFULL], true) 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci// Tilde ranges. 1701cb0ef41Sopenharmony_ci// Meaning is "reasonably at or greater than" 1711cb0ef41Sopenharmony_cicreateToken('LONETILDE', '(?:~>?)') 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_cicreateToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true) 1741cb0ef41Sopenharmony_ciexports.tildeTrimReplace = '$1~' 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_cicreateToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`) 1771cb0ef41Sopenharmony_cicreateToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`) 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci// Caret ranges. 1801cb0ef41Sopenharmony_ci// Meaning is "at least and backwards compatible with" 1811cb0ef41Sopenharmony_cicreateToken('LONECARET', '(?:\\^)') 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_cicreateToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true) 1841cb0ef41Sopenharmony_ciexports.caretTrimReplace = '$1^' 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_cicreateToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`) 1871cb0ef41Sopenharmony_cicreateToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`) 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci// A simple gt/lt/eq thing, or just "" to indicate "any version" 1901cb0ef41Sopenharmony_cicreateToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`) 1911cb0ef41Sopenharmony_cicreateToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`) 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci// An expression to strip any whitespace between the gtlt and the thing 1941cb0ef41Sopenharmony_ci// it modifies, so that `> 1.2.3` ==> `>1.2.3` 1951cb0ef41Sopenharmony_cicreateToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT] 1961cb0ef41Sopenharmony_ci}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true) 1971cb0ef41Sopenharmony_ciexports.comparatorTrimReplace = '$1$2$3' 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci// Something like `1.2.3 - 1.2.4` 2001cb0ef41Sopenharmony_ci// Note that these all use the loose form, because they'll be 2011cb0ef41Sopenharmony_ci// checked against either the strict or loose comparator form 2021cb0ef41Sopenharmony_ci// later. 2031cb0ef41Sopenharmony_cicreateToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` + 2041cb0ef41Sopenharmony_ci `\\s+-\\s+` + 2051cb0ef41Sopenharmony_ci `(${src[t.XRANGEPLAIN]})` + 2061cb0ef41Sopenharmony_ci `\\s*$`) 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_cicreateToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` + 2091cb0ef41Sopenharmony_ci `\\s+-\\s+` + 2101cb0ef41Sopenharmony_ci `(${src[t.XRANGEPLAINLOOSE]})` + 2111cb0ef41Sopenharmony_ci `\\s*$`) 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci// Star ranges basically just allow anything at all. 2141cb0ef41Sopenharmony_cicreateToken('STAR', '(<|>)?=?\\s*\\*') 2151cb0ef41Sopenharmony_ci// >=0.0.0 is like a star 2161cb0ef41Sopenharmony_cicreateToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$') 2171cb0ef41Sopenharmony_cicreateToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$') 218