| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 | const {  MAX_SAFE_COMPONENT_LENGTH,  MAX_SAFE_BUILD_LENGTH,  MAX_LENGTH,} = require('./constants')const debug = require('./debug')exports = module.exports = {}// The actual regexps go on exports.reconst re = exports.re = []const safeRe = exports.safeRe = []const src = exports.src = []const safeSrc = exports.safeSrc = []const t = exports.t = {}let R = 0const LETTERDASHNUMBER = '[a-zA-Z0-9-]'// Replace some greedy regex tokens to prevent regex dos issues. These regex are// used internally via the safeRe object since all inputs in this library get// normalized first to trim and collapse all extra whitespace. The original// regexes are exported for userland consumption and lower level usage. A// future breaking change could export the safer regex only with a note that// all input should have extra whitespace removed.const safeRegexReplacements = [  ['\\s', 1],  ['\\d', MAX_LENGTH],  [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],]const makeSafeRegex = (value) => {  for (const [token, max] of safeRegexReplacements) {    value = value      .split(`${token}*`).join(`${token}{0,${max}}`)      .split(`${token}+`).join(`${token}{1,${max}}`)  }  return value}const createToken = (name, value, isGlobal) => {  const safe = makeSafeRegex(value)  const index = R++  debug(name, index, value)  t[name] = index  src[index] = value  safeSrc[index] = safe  re[index] = new RegExp(value, isGlobal ? 'g' : undefined)  safeRe[index] = new RegExp(safe, 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', '\\d+')// ## 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-]${LETTERDASHNUMBER}*`)// ## 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', `${LETTERDASHNUMBER}+`)// ## 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 semvercreateToken('COERCEPLAIN', `${'(^|[^\\d])' +              '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +              `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +              `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`)createToken('COERCEFULL', src[t.COERCEPLAIN] +              `(?:${src[t.PRERELEASE]})?` +              `(?:${src[t.BUILD]})?` +              `(?:$|[^\\d])`)createToken('COERCERTL', src[t.COERCE], true)createToken('COERCERTLFULL', src[t.COERCEFULL], 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 starcreateToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$')createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$')
 |