Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

subset.js 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. const Range = require('../classes/range.js')
  2. const { ANY } = require('../classes/comparator.js')
  3. const satisfies = require('../functions/satisfies.js')
  4. const compare = require('../functions/compare.js')
  5. // Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:
  6. // - Every simple range `r1, r2, ...` is a subset of some `R1, R2, ...`
  7. //
  8. // Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:
  9. // - If c is only the ANY comparator
  10. // - If C is only the ANY comparator, return true
  11. // - Else return false
  12. // - Let EQ be the set of = comparators in c
  13. // - If EQ is more than one, return true (null set)
  14. // - Let GT be the highest > or >= comparator in c
  15. // - Let LT be the lowest < or <= comparator in c
  16. // - If GT and LT, and GT.semver > LT.semver, return true (null set)
  17. // - If EQ
  18. // - If GT, and EQ does not satisfy GT, return true (null set)
  19. // - If LT, and EQ does not satisfy LT, return true (null set)
  20. // - If EQ satisfies every C, return true
  21. // - Else return false
  22. // - If GT
  23. // - If GT is lower than any > or >= comp in C, return false
  24. // - If GT is >=, and GT.semver does not satisfy every C, return false
  25. // - If LT
  26. // - If LT.semver is greater than that of any > comp in C, return false
  27. // - If LT is <=, and LT.semver does not satisfy every C, return false
  28. // - If any C is a = range, and GT or LT are set, return false
  29. // - Else return true
  30. const subset = (sub, dom, options) => {
  31. sub = new Range(sub, options)
  32. dom = new Range(dom, options)
  33. let sawNonNull = false
  34. OUTER: for (const simpleSub of sub.set) {
  35. for (const simpleDom of dom.set) {
  36. const isSub = simpleSubset(simpleSub, simpleDom, options)
  37. sawNonNull = sawNonNull || isSub !== null
  38. if (isSub)
  39. continue OUTER
  40. }
  41. // the null set is a subset of everything, but null simple ranges in
  42. // a complex range should be ignored. so if we saw a non-null range,
  43. // then we know this isn't a subset, but if EVERY simple range was null,
  44. // then it is a subset.
  45. if (sawNonNull)
  46. return false
  47. }
  48. return true
  49. }
  50. const simpleSubset = (sub, dom, options) => {
  51. if (sub.length === 1 && sub[0].semver === ANY)
  52. return dom.length === 1 && dom[0].semver === ANY
  53. const eqSet = new Set()
  54. let gt, lt
  55. for (const c of sub) {
  56. if (c.operator === '>' || c.operator === '>=')
  57. gt = higherGT(gt, c, options)
  58. else if (c.operator === '<' || c.operator === '<=')
  59. lt = lowerLT(lt, c, options)
  60. else
  61. eqSet.add(c.semver)
  62. }
  63. if (eqSet.size > 1)
  64. return null
  65. let gtltComp
  66. if (gt && lt) {
  67. gtltComp = compare(gt.semver, lt.semver, options)
  68. if (gtltComp > 0)
  69. return null
  70. else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<='))
  71. return null
  72. }
  73. // will iterate one or zero times
  74. for (const eq of eqSet) {
  75. if (gt && !satisfies(eq, String(gt), options))
  76. return null
  77. if (lt && !satisfies(eq, String(lt), options))
  78. return null
  79. for (const c of dom) {
  80. if (!satisfies(eq, String(c), options))
  81. return false
  82. }
  83. return true
  84. }
  85. let higher, lower
  86. let hasDomLT, hasDomGT
  87. for (const c of dom) {
  88. hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='
  89. hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='
  90. if (gt) {
  91. if (c.operator === '>' || c.operator === '>=') {
  92. higher = higherGT(gt, c, options)
  93. if (higher === c)
  94. return false
  95. } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options))
  96. return false
  97. }
  98. if (lt) {
  99. if (c.operator === '<' || c.operator === '<=') {
  100. lower = lowerLT(lt, c, options)
  101. if (lower === c)
  102. return false
  103. } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options))
  104. return false
  105. }
  106. if (!c.operator && (lt || gt) && gtltComp !== 0)
  107. return false
  108. }
  109. // if there was a < or >, and nothing in the dom, then must be false
  110. // UNLESS it was limited by another range in the other direction.
  111. // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0
  112. if (gt && hasDomLT && !lt && gtltComp !== 0)
  113. return false
  114. if (lt && hasDomGT && !gt && gtltComp !== 0)
  115. return false
  116. return true
  117. }
  118. // >=1.2.3 is lower than >1.2.3
  119. const higherGT = (a, b, options) => {
  120. if (!a)
  121. return b
  122. const comp = compare(a.semver, b.semver, options)
  123. return comp > 0 ? a
  124. : comp < 0 ? b
  125. : b.operator === '>' && a.operator === '>=' ? b
  126. : a
  127. }
  128. // <=1.2.3 is higher than <1.2.3
  129. const lowerLT = (a, b, options) => {
  130. if (!a)
  131. return b
  132. const comp = compare(a.semver, b.semver, options)
  133. return comp < 0 ? a
  134. : comp > 0 ? b
  135. : b.operator === '<' && a.operator === '<=' ? b
  136. : a
  137. }
  138. module.exports = subset