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