<commit_before>
// See http://semver.org/
// This implementation is a *hair* less strict in that it allows
// v1.2.3 things, and also tags that don't begin with a char.

var semver = "[v=]*([0-9]+)"                // major
           + "\\.([0-9]+)"                  // minor
           + "\\.([0-9]+)"                  // patch
           + "(-[0-9]+-?)?"                 // build
           + "([a-zA-Z-][a-zA-Z0-9-\.:]*)?" // tag
  , exprComparator = "^((<|>)?=?)("+semver+")$|^$"
  , xRange = "((?:<|>)?=?)([0-9]+|x|X)(?:\\.([0-9]+|x|X)(?:\\.([0-9]+|x|X))?)?"
  , exprSpermy = "(?:~>?)"+xRange
  , expressions = exports.expressions =
    { parse : new RegExp("^\\s*"+semver+"\\s*$")
    , parsePackage : new RegExp("^\\s*([^\/]+)[-@](" +semver+")\\s*$")
    , parseRange : new RegExp(
        "^\\s*(" + semver + ")\\s+-\\s+(" + semver + ")\\s*$")
    , validComparator : new RegExp("^"+exprComparator+"$")
    , parseXRange : new RegExp("^"+xRange+"$")
    , parseSpermy : new RegExp("^"+exprSpermy+"$")
    }
Object.getOwnPropertyNames(expressions).forEach(function (i) {
  exports[i] = function (str) { return (str || "").match(expressions[i]) }
})

exports.rangeReplace = ">=$1 <=$7"
exports.clean = clean
exports.compare = compare
exports.satisfies = satisfies
exports.gt = gt
exports.lt = lt
exports.valid = valid
exports.validPackage = validPackage
exports.validRange = validRange
exports.maxSatisfying = maxSatisfying

function clean (ver) {
  v = exports.parse(ver)
  if (!v) return v
  return [v[1]||'', v[2]||'', v[3]||''].join(".") + (v[4]||'') + (v[5]||'')
}
function valid (version) {
  return exports.parse(version) && version.trim().replace(/^[v=]+/, '')
}
function validPackage (version) {
  return version.match(expressions.parsePackage) && version.trim()
}

// range can be one of:
// "1.0.3 - 2.0.0" range, inclusive, like ">=1.0.3 <=2.0.0"
// ">1.0.2" like 1.0.3 - 9999.9999.9999
// ">=1.0.2" like 1.0.2 - 9999.9999.9999
// "<2.0.0" like 0.0.0 - 1.9999.9999
// ">1.0.2 <2.0.0" like 1.0.3 - 1.9999.9999
var starExpression = /(<|>)?=?\s*\*/g
  , starReplace = ""
  , compTrimExpression = new RegExp("((<|>)?=?)\\s*("+semver+")", "g")
  , compTrimReplace = "$1$3"

function toComparators (range) {
  return (range || "").trim()
    .replace(expressions.parseRange, exports.rangeReplace)
    .split(/\s+/)
      .map(replaceSpermies)
      .map(replaceXRanges)
    .join(" ")
    .replace(compTrimExpression, compTrimReplace)
    .replace(starExpression, starReplace)
    .split("||")
    .map(function (orchunk) {
      return orchunk
        .trim()
        .split(/\s+/)
        .filter(function (c) { return c.match(expressions.validComparator) })
    })
    .filter(function (c) { return c.length })
}

// "2.x","2.x.x" --> ">=2.0.0 <2.1"
// "2.3.x" --> ">=2.3.0 <2.4.0"
function replaceXRanges (ranges) {
  return ranges.split(/\s+/)
               .map(replaceXRange)
               .join(" ")
}
function replaceXRange (version) {
  return version.trim().replace(expressions.parseXRange,
                                function (v, gtlt, M, m, p) {
    var anyX = !M || M.toLowerCase() === "x"
               || !m || m.toLowerCase() === "x"
               || !p || p.toLowerCase() === "x"

    if (gtlt && anyX) {
      // just replace x'es with zeroes
      ;(!M || M.toLowerCase() === "x") && (M = 0)
      ;(!m || m.toLowerCase() === "x") && (m = 0)
      ;(!p || p.toLowerCase() === "x") && (p = 0)
      return gtlt + M+"."+m+"."+p
    }

    if (!M || M.toLowerCase() === "x") {
      return "*" // allow any
    }
    if (!m || m.toLowerCase() === "x") {
      return ">="+M+".0.0 <"+(+M+1)+".0.0"
    }
    if (!p || p.toLowerCase() === "x") {
      return ">="+M+"."+m+".0 <"+M+"."+(+m+1)+".0"
    }
    return v // impossible?
  })
}

// ~, ~> --> * (any, kinda silly)
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
function replaceSpermies (version) {
  return version.trim().replace(expressions.parseSpermy,
                                function (v, gtlt, M, m, p) {
    if (gtlt) throw new Error(
      "Using '"+gtlt+"' with ~ makes no sense. Don't do it.")
    if (!M || M.toLowerCase() === "x") {
      return "*"
    }
    if (!m || m.toLowerCase() === "x") {
      return ">="+M+".0.0 <"+(+M+1)+".0.0"
    }
    if (!p || p.toLowerCase() === "x") {
      return ">="+M+"."+m+".0 <"+M+"."+(+m+1)+".0"
    }
    return ">="+M+"."+m+"."+p+" <"+M+"."+(+m+1)+".0"
  })
}

function validRange (range) {
  range = range.trim().replace(starExpression, starReplace)
  var c = toComparators(range)
  return (c.length === 0)
       ? null
       : c.map(function (c) { return c.join(" ") }).join("||")<commit_msg>add comments about what spermies do, since i can never remember<commit_after>
// See http://semver.org/
// This implementation is a *hair* less strict in that it allows
// v1.2.3 things, and also tags that don't begin with a char.

var semver = "[v=]*([0-9]+)"                // major
           + "\\.([0-9]+)"                  // minor
           + "\\.([0-9]+)"                  // patch
           + "(-[0-9]+-?)?"                 // build
           + "([a-zA-Z-][a-zA-Z0-9-\.:]*)?" // tag
  , exprComparator = "^((<|>)?=?)("+semver+")$|^$"
  , xRange = "((?:<|>)?=?)([0-9]+|x|X)(?:\\.([0-9]+|x|X)(?:\\.([0-9]+|x|X))?)?"
  , exprSpermy = "(?:~>?)"+xRange
  , expressions = exports.expressions =
    { parse : new RegExp("^\\s*"+semver+"\\s*$")
    , parsePackage : new RegExp("^\\s*([^\/]+)[-@](" +semver+")\\s*$")
    , parseRange : new RegExp(
        "^\\s*(" + semver + ")\\s+-\\s+(" + semver + ")\\s*$")
    , validComparator : new RegExp("^"+exprComparator+"$")
    , parseXRange : new RegExp("^"+xRange+"$")
    , parseSpermy : new RegExp("^"+exprSpermy+"$")
    }
Object.getOwnPropertyNames(expressions).forEach(function (i) {
  exports[i] = function (str) { return (str || "").match(expressions[i]) }
})

exports.rangeReplace = ">=$1 <=$7"
exports.clean = clean
exports.compare = compare
exports.satisfies = satisfies
exports.gt = gt
exports.lt = lt
exports.valid = valid
exports.validPackage = validPackage
exports.validRange = validRange
exports.maxSatisfying = maxSatisfying

function clean (ver) {
  v = exports.parse(ver)
  if (!v) return v
  return [v[1]||'', v[2]||'', v[3]||''].join(".") + (v[4]||'') + (v[5]||'')
}
function valid (version) {
  return exports.parse(version) && version.trim().replace(/^[v=]+/, '')
}
function validPackage (version) {
  return version.match(expressions.parsePackage) && version.trim()
}

// range can be one of:
// "1.0.3 - 2.0.0" range, inclusive, like ">=1.0.3 <=2.0.0"
// ">1.0.2" like 1.0.3 - 9999.9999.9999
// ">=1.0.2" like 1.0.2 - 9999.9999.9999
// "<2.0.0" like 0.0.0 - 1.9999.9999
// ">1.0.2 <2.0.0" like 1.0.3 - 1.9999.9999
var starExpression = /(<|>)?=?\s*\*/g
  , starReplace = ""
  , compTrimExpression = new RegExp("((<|>)?=?)\\s*("+semver+")", "g")
  , compTrimReplace = "$1$3"

function toComparators (range) {
  return (range || "").trim()
    .replace(expressions.parseRange, exports.rangeReplace)
    .split(/\s+/)
      .map(replaceSpermies)
      .map(replaceXRanges)
    .join(" ")
    .replace(compTrimExpression, compTrimReplace)
    .replace(starExpression, starReplace)
    .split("||")
    .map(function (orchunk) {
      return orchunk
        .trim()
        .split(/\s+/)
        .filter(function (c) { return c.match(expressions.validComparator) })
    })
    .filter(function (c) { return c.length })
}

// "2.x","2.x.x" --> ">=2.0.0 <2.1"
// "2.3.x" --> ">=2.3.0 <2.4.0"
function replaceXRanges (ranges) {
  return ranges.split(/\s+/)
               .map(replaceXRange)
               .join(" ")
}
function replaceXRange (version) {
  return version.trim().replace(expressions.parseXRange,
                                function (v, gtlt, M, m, p) {
    var anyX = !M || M.toLowerCase() === "x"
               || !m || m.toLowerCase() === "x"
               || !p || p.toLowerCase() === "x"

    if (gtlt && anyX) {
      // just replace x'es with zeroes
      ;(!M || M.toLowerCase() === "x") && (M = 0)
      ;(!m || m.toLowerCase() === "x") && (m = 0)
      ;(!p || p.toLowerCase() === "x") && (p = 0)
      return gtlt + M+"."+m+"."+p
    }

    if (!M || M.toLowerCase() === "x") {
      return "*" // allow any
    }
    if (!m || m.toLowerCase() === "x") {
      return ">="+M+".0.0 <"+(+M+1)+".0.0"
    }
    if (!p || p.toLowerCase() === "x") {
      return ">="+M+"."+m+".0 <"+M+"."+(+m+1)+".0"
    }
    return v // impossible?
  })
}

// ~, ~> --> * (any, kinda silly)
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
function replaceSpermies (version) {
  return version.trim().replace(expressions.parseSpermy,
                                function (v, gtlt, M, m, p) {
    if (gtlt) throw new Error(
      "Using '"+gtlt+"' with ~ makes no sense. Don't do it.")
    if (!M || M.toLowerCase() === "x") {
      return "*"
    }
    // ~1 == >=1.0.0 <2.0.0
    if (!m || m.toLowerCase() === "x") {
      return ">="+M+".0.0 <"+(+M+1)+".0.0"
    }
    // ~1.2 == >=1.2.0 <1.3.0
    if (!p || p.toLowerCase() === "x") {
      return ">="+M+"."+m+".0 <"+M+"."+(+m+1)+".0"
    }
    // ~1.2.3 == >=1.2.3 <1.3.0
    return ">="+M+"."+m+"."+p+" <"+M+"."+(+m+1)+".0"
  })
}

function validRange (range) {
  range = range.trim().replace(starExpression, starReplace)
  var c = toComparators(range)
  return (c.length === 0)
       ? null
       : c.map(function (c) { return c.join(" ") }).join("||")
{'fraction_non_alphanumeric': 0.27457765112965604, 'fraction_numerical': 0.045186240586199876, 'mean_word_length': 2.31433389544688, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 86, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7403736', 'n_tokens_mistral': 4082, 'n_tokens_neox': 4000, 'n_words': 770}