text: 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(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*$')
  