11cb0ef41Sopenharmony_ciconst Range = require('../classes/range.js')
21cb0ef41Sopenharmony_ciconst Comparator = require('../classes/comparator.js')
31cb0ef41Sopenharmony_ciconst { ANY } = Comparator
41cb0ef41Sopenharmony_ciconst satisfies = require('../functions/satisfies.js')
51cb0ef41Sopenharmony_ciconst compare = require('../functions/compare.js')
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:
81cb0ef41Sopenharmony_ci// - Every simple range `r1, r2, ...` is a null set, OR
91cb0ef41Sopenharmony_ci// - Every simple range `r1, r2, ...` which is not a null set is a subset of
101cb0ef41Sopenharmony_ci//   some `R1, R2, ...`
111cb0ef41Sopenharmony_ci//
121cb0ef41Sopenharmony_ci// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:
131cb0ef41Sopenharmony_ci// - If c is only the ANY comparator
141cb0ef41Sopenharmony_ci//   - If C is only the ANY comparator, return true
151cb0ef41Sopenharmony_ci//   - Else if in prerelease mode, return false
161cb0ef41Sopenharmony_ci//   - else replace c with `[>=0.0.0]`
171cb0ef41Sopenharmony_ci// - If C is only the ANY comparator
181cb0ef41Sopenharmony_ci//   - if in prerelease mode, return true
191cb0ef41Sopenharmony_ci//   - else replace C with `[>=0.0.0]`
201cb0ef41Sopenharmony_ci// - Let EQ be the set of = comparators in c
211cb0ef41Sopenharmony_ci// - If EQ is more than one, return true (null set)
221cb0ef41Sopenharmony_ci// - Let GT be the highest > or >= comparator in c
231cb0ef41Sopenharmony_ci// - Let LT be the lowest < or <= comparator in c
241cb0ef41Sopenharmony_ci// - If GT and LT, and GT.semver > LT.semver, return true (null set)
251cb0ef41Sopenharmony_ci// - If any C is a = range, and GT or LT are set, return false
261cb0ef41Sopenharmony_ci// - If EQ
271cb0ef41Sopenharmony_ci//   - If GT, and EQ does not satisfy GT, return true (null set)
281cb0ef41Sopenharmony_ci//   - If LT, and EQ does not satisfy LT, return true (null set)
291cb0ef41Sopenharmony_ci//   - If EQ satisfies every C, return true
301cb0ef41Sopenharmony_ci//   - Else return false
311cb0ef41Sopenharmony_ci// - If GT
321cb0ef41Sopenharmony_ci//   - If GT.semver is lower than any > or >= comp in C, return false
331cb0ef41Sopenharmony_ci//   - If GT is >=, and GT.semver does not satisfy every C, return false
341cb0ef41Sopenharmony_ci//   - If GT.semver has a prerelease, and not in prerelease mode
351cb0ef41Sopenharmony_ci//     - If no C has a prerelease and the GT.semver tuple, return false
361cb0ef41Sopenharmony_ci// - If LT
371cb0ef41Sopenharmony_ci//   - If LT.semver is greater than any < or <= comp in C, return false
381cb0ef41Sopenharmony_ci//   - If LT is <=, and LT.semver does not satisfy every C, return false
391cb0ef41Sopenharmony_ci//   - If GT.semver has a prerelease, and not in prerelease mode
401cb0ef41Sopenharmony_ci//     - If no C has a prerelease and the LT.semver tuple, return false
411cb0ef41Sopenharmony_ci// - Else return true
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ciconst subset = (sub, dom, options = {}) => {
441cb0ef41Sopenharmony_ci  if (sub === dom) {
451cb0ef41Sopenharmony_ci    return true
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  sub = new Range(sub, options)
491cb0ef41Sopenharmony_ci  dom = new Range(dom, options)
501cb0ef41Sopenharmony_ci  let sawNonNull = false
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  OUTER: for (const simpleSub of sub.set) {
531cb0ef41Sopenharmony_ci    for (const simpleDom of dom.set) {
541cb0ef41Sopenharmony_ci      const isSub = simpleSubset(simpleSub, simpleDom, options)
551cb0ef41Sopenharmony_ci      sawNonNull = sawNonNull || isSub !== null
561cb0ef41Sopenharmony_ci      if (isSub) {
571cb0ef41Sopenharmony_ci        continue OUTER
581cb0ef41Sopenharmony_ci      }
591cb0ef41Sopenharmony_ci    }
601cb0ef41Sopenharmony_ci    // the null set is a subset of everything, but null simple ranges in
611cb0ef41Sopenharmony_ci    // a complex range should be ignored.  so if we saw a non-null range,
621cb0ef41Sopenharmony_ci    // then we know this isn't a subset, but if EVERY simple range was null,
631cb0ef41Sopenharmony_ci    // then it is a subset.
641cb0ef41Sopenharmony_ci    if (sawNonNull) {
651cb0ef41Sopenharmony_ci      return false
661cb0ef41Sopenharmony_ci    }
671cb0ef41Sopenharmony_ci  }
681cb0ef41Sopenharmony_ci  return true
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ciconst minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]
721cb0ef41Sopenharmony_ciconst minimumVersion = [new Comparator('>=0.0.0')]
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ciconst simpleSubset = (sub, dom, options) => {
751cb0ef41Sopenharmony_ci  if (sub === dom) {
761cb0ef41Sopenharmony_ci    return true
771cb0ef41Sopenharmony_ci  }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  if (sub.length === 1 && sub[0].semver === ANY) {
801cb0ef41Sopenharmony_ci    if (dom.length === 1 && dom[0].semver === ANY) {
811cb0ef41Sopenharmony_ci      return true
821cb0ef41Sopenharmony_ci    } else if (options.includePrerelease) {
831cb0ef41Sopenharmony_ci      sub = minimumVersionWithPreRelease
841cb0ef41Sopenharmony_ci    } else {
851cb0ef41Sopenharmony_ci      sub = minimumVersion
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  if (dom.length === 1 && dom[0].semver === ANY) {
901cb0ef41Sopenharmony_ci    if (options.includePrerelease) {
911cb0ef41Sopenharmony_ci      return true
921cb0ef41Sopenharmony_ci    } else {
931cb0ef41Sopenharmony_ci      dom = minimumVersion
941cb0ef41Sopenharmony_ci    }
951cb0ef41Sopenharmony_ci  }
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  const eqSet = new Set()
981cb0ef41Sopenharmony_ci  let gt, lt
991cb0ef41Sopenharmony_ci  for (const c of sub) {
1001cb0ef41Sopenharmony_ci    if (c.operator === '>' || c.operator === '>=') {
1011cb0ef41Sopenharmony_ci      gt = higherGT(gt, c, options)
1021cb0ef41Sopenharmony_ci    } else if (c.operator === '<' || c.operator === '<=') {
1031cb0ef41Sopenharmony_ci      lt = lowerLT(lt, c, options)
1041cb0ef41Sopenharmony_ci    } else {
1051cb0ef41Sopenharmony_ci      eqSet.add(c.semver)
1061cb0ef41Sopenharmony_ci    }
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  if (eqSet.size > 1) {
1101cb0ef41Sopenharmony_ci    return null
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  let gtltComp
1141cb0ef41Sopenharmony_ci  if (gt && lt) {
1151cb0ef41Sopenharmony_ci    gtltComp = compare(gt.semver, lt.semver, options)
1161cb0ef41Sopenharmony_ci    if (gtltComp > 0) {
1171cb0ef41Sopenharmony_ci      return null
1181cb0ef41Sopenharmony_ci    } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) {
1191cb0ef41Sopenharmony_ci      return null
1201cb0ef41Sopenharmony_ci    }
1211cb0ef41Sopenharmony_ci  }
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  // will iterate one or zero times
1241cb0ef41Sopenharmony_ci  for (const eq of eqSet) {
1251cb0ef41Sopenharmony_ci    if (gt && !satisfies(eq, String(gt), options)) {
1261cb0ef41Sopenharmony_ci      return null
1271cb0ef41Sopenharmony_ci    }
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci    if (lt && !satisfies(eq, String(lt), options)) {
1301cb0ef41Sopenharmony_ci      return null
1311cb0ef41Sopenharmony_ci    }
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci    for (const c of dom) {
1341cb0ef41Sopenharmony_ci      if (!satisfies(eq, String(c), options)) {
1351cb0ef41Sopenharmony_ci        return false
1361cb0ef41Sopenharmony_ci      }
1371cb0ef41Sopenharmony_ci    }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci    return true
1401cb0ef41Sopenharmony_ci  }
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  let higher, lower
1431cb0ef41Sopenharmony_ci  let hasDomLT, hasDomGT
1441cb0ef41Sopenharmony_ci  // if the subset has a prerelease, we need a comparator in the superset
1451cb0ef41Sopenharmony_ci  // with the same tuple and a prerelease, or it's not a subset
1461cb0ef41Sopenharmony_ci  let needDomLTPre = lt &&
1471cb0ef41Sopenharmony_ci    !options.includePrerelease &&
1481cb0ef41Sopenharmony_ci    lt.semver.prerelease.length ? lt.semver : false
1491cb0ef41Sopenharmony_ci  let needDomGTPre = gt &&
1501cb0ef41Sopenharmony_ci    !options.includePrerelease &&
1511cb0ef41Sopenharmony_ci    gt.semver.prerelease.length ? gt.semver : false
1521cb0ef41Sopenharmony_ci  // exception: <1.2.3-0 is the same as <1.2.3
1531cb0ef41Sopenharmony_ci  if (needDomLTPre && needDomLTPre.prerelease.length === 1 &&
1541cb0ef41Sopenharmony_ci      lt.operator === '<' && needDomLTPre.prerelease[0] === 0) {
1551cb0ef41Sopenharmony_ci    needDomLTPre = false
1561cb0ef41Sopenharmony_ci  }
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  for (const c of dom) {
1591cb0ef41Sopenharmony_ci    hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='
1601cb0ef41Sopenharmony_ci    hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='
1611cb0ef41Sopenharmony_ci    if (gt) {
1621cb0ef41Sopenharmony_ci      if (needDomGTPre) {
1631cb0ef41Sopenharmony_ci        if (c.semver.prerelease && c.semver.prerelease.length &&
1641cb0ef41Sopenharmony_ci            c.semver.major === needDomGTPre.major &&
1651cb0ef41Sopenharmony_ci            c.semver.minor === needDomGTPre.minor &&
1661cb0ef41Sopenharmony_ci            c.semver.patch === needDomGTPre.patch) {
1671cb0ef41Sopenharmony_ci          needDomGTPre = false
1681cb0ef41Sopenharmony_ci        }
1691cb0ef41Sopenharmony_ci      }
1701cb0ef41Sopenharmony_ci      if (c.operator === '>' || c.operator === '>=') {
1711cb0ef41Sopenharmony_ci        higher = higherGT(gt, c, options)
1721cb0ef41Sopenharmony_ci        if (higher === c && higher !== gt) {
1731cb0ef41Sopenharmony_ci          return false
1741cb0ef41Sopenharmony_ci        }
1751cb0ef41Sopenharmony_ci      } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {
1761cb0ef41Sopenharmony_ci        return false
1771cb0ef41Sopenharmony_ci      }
1781cb0ef41Sopenharmony_ci    }
1791cb0ef41Sopenharmony_ci    if (lt) {
1801cb0ef41Sopenharmony_ci      if (needDomLTPre) {
1811cb0ef41Sopenharmony_ci        if (c.semver.prerelease && c.semver.prerelease.length &&
1821cb0ef41Sopenharmony_ci            c.semver.major === needDomLTPre.major &&
1831cb0ef41Sopenharmony_ci            c.semver.minor === needDomLTPre.minor &&
1841cb0ef41Sopenharmony_ci            c.semver.patch === needDomLTPre.patch) {
1851cb0ef41Sopenharmony_ci          needDomLTPre = false
1861cb0ef41Sopenharmony_ci        }
1871cb0ef41Sopenharmony_ci      }
1881cb0ef41Sopenharmony_ci      if (c.operator === '<' || c.operator === '<=') {
1891cb0ef41Sopenharmony_ci        lower = lowerLT(lt, c, options)
1901cb0ef41Sopenharmony_ci        if (lower === c && lower !== lt) {
1911cb0ef41Sopenharmony_ci          return false
1921cb0ef41Sopenharmony_ci        }
1931cb0ef41Sopenharmony_ci      } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {
1941cb0ef41Sopenharmony_ci        return false
1951cb0ef41Sopenharmony_ci      }
1961cb0ef41Sopenharmony_ci    }
1971cb0ef41Sopenharmony_ci    if (!c.operator && (lt || gt) && gtltComp !== 0) {
1981cb0ef41Sopenharmony_ci      return false
1991cb0ef41Sopenharmony_ci    }
2001cb0ef41Sopenharmony_ci  }
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  // if there was a < or >, and nothing in the dom, then must be false
2031cb0ef41Sopenharmony_ci  // UNLESS it was limited by another range in the other direction.
2041cb0ef41Sopenharmony_ci  // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0
2051cb0ef41Sopenharmony_ci  if (gt && hasDomLT && !lt && gtltComp !== 0) {
2061cb0ef41Sopenharmony_ci    return false
2071cb0ef41Sopenharmony_ci  }
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci  if (lt && hasDomGT && !gt && gtltComp !== 0) {
2101cb0ef41Sopenharmony_ci    return false
2111cb0ef41Sopenharmony_ci  }
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  // we needed a prerelease range in a specific tuple, but didn't get one
2141cb0ef41Sopenharmony_ci  // then this isn't a subset.  eg >=1.2.3-pre is not a subset of >=1.0.0,
2151cb0ef41Sopenharmony_ci  // because it includes prereleases in the 1.2.3 tuple
2161cb0ef41Sopenharmony_ci  if (needDomGTPre || needDomLTPre) {
2171cb0ef41Sopenharmony_ci    return false
2181cb0ef41Sopenharmony_ci  }
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci  return true
2211cb0ef41Sopenharmony_ci}
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci// >=1.2.3 is lower than >1.2.3
2241cb0ef41Sopenharmony_ciconst higherGT = (a, b, options) => {
2251cb0ef41Sopenharmony_ci  if (!a) {
2261cb0ef41Sopenharmony_ci    return b
2271cb0ef41Sopenharmony_ci  }
2281cb0ef41Sopenharmony_ci  const comp = compare(a.semver, b.semver, options)
2291cb0ef41Sopenharmony_ci  return comp > 0 ? a
2301cb0ef41Sopenharmony_ci    : comp < 0 ? b
2311cb0ef41Sopenharmony_ci    : b.operator === '>' && a.operator === '>=' ? b
2321cb0ef41Sopenharmony_ci    : a
2331cb0ef41Sopenharmony_ci}
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci// <=1.2.3 is higher than <1.2.3
2361cb0ef41Sopenharmony_ciconst lowerLT = (a, b, options) => {
2371cb0ef41Sopenharmony_ci  if (!a) {
2381cb0ef41Sopenharmony_ci    return b
2391cb0ef41Sopenharmony_ci  }
2401cb0ef41Sopenharmony_ci  const comp = compare(a.semver, b.semver, options)
2411cb0ef41Sopenharmony_ci  return comp < 0 ? a
2421cb0ef41Sopenharmony_ci    : comp > 0 ? b
2431cb0ef41Sopenharmony_ci    : b.operator === '<' && a.operator === '<=' ? b
2441cb0ef41Sopenharmony_ci    : a
2451cb0ef41Sopenharmony_ci}
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_cimodule.exports = subset
248