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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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.semver 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 any < or <= 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. if (sub === dom)
  32. return true
  33. sub = new Range(sub, options)
  34. dom = new Range(dom, options)
  35. let sawNonNull = false
  36. OUTER: for (const simpleSub of sub.set) {
  37. for (const simpleDom of dom.set) {
  38. const isSub = simpleSubset(simpleSub, simpleDom, options)
  39. sawNonNull = sawNonNull || isSub !== null
  40. if (isSub)
  41. continue OUTER
  42. }
  43. // the null set is a subset of everything, but null simple ranges in
  44. // a complex range should be ignored. so if we saw a non-null range,
  45. // then we know this isn't a subset, but if EVERY simple range was null,
  46. // then it is a subset.
  47. if (sawNonNull)
  48. return false
  49. }
  50. return true
  51. }
  52. const simpleSubset = (sub, dom, options) => {
  53. if (sub === dom)
  54. return true
  55. if (sub.length === 1 && sub[0].semver === ANY)
  56. return dom.length === 1 && dom[0].semver === ANY
  57. const eqSet = new Set()
  58. let gt, lt
  59. for (const c of sub) {
  60. if (c.operator === '>' || c.operator === '>=')
  61. gt = higherGT(gt, c, options)
  62. else if (c.operator === '<' || c.operator === '<=')
  63. lt = lowerLT(lt, c, options)
  64. else
  65. eqSet.add(c.semver)
  66. }
  67. if (eqSet.size > 1)
  68. return null
  69. let gtltComp
  70. if (gt && lt) {
  71. gtltComp = compare(gt.semver, lt.semver, options)
  72. if (gtltComp > 0)
  73. return null
  74. else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<='))
  75. return null
  76. }
  77. // will iterate one or zero times
  78. for (const eq of eqSet) {
  79. if (gt && !satisfies(eq, String(gt), options))
  80. return null
  81. if (lt && !satisfies(eq, String(lt), options))
  82. return null
  83. for (const c of dom) {
  84. if (!satisfies(eq, String(c), options))
  85. return false
  86. }
  87. return true
  88. }
  89. let higher, lower
  90. let hasDomLT, hasDomGT
  91. for (const c of dom) {
  92. hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='
  93. hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='
  94. if (gt) {
  95. if (c.operator === '>' || c.operator === '>=') {
  96. higher = higherGT(gt, c, options)
  97. if (higher === c && higher !== gt)
  98. return false
  99. } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options))
  100. return false
  101. }
  102. if (lt) {
  103. if (c.operator === '<' || c.operator === '<=') {
  104. lower = lowerLT(lt, c, options)
  105. if (lower === c && lower !== lt)
  106. return false
  107. } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options))
  108. return false
  109. }
  110. if (!c.operator && (lt || gt) && gtltComp !== 0)
  111. return false
  112. }
  113. // if there was a < or >, and nothing in the dom, then must be false
  114. // UNLESS it was limited by another range in the other direction.
  115. // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0
  116. if (gt && hasDomLT && !lt && gtltComp !== 0)
  117. return false
  118. if (lt && hasDomGT && !gt && gtltComp !== 0)
  119. return false
  120. return true
  121. }
  122. // >=1.2.3 is lower than >1.2.3
  123. const higherGT = (a, b, options) => {
  124. if (!a)
  125. return b
  126. const comp = compare(a.semver, b.semver, options)
  127. return comp > 0 ? a
  128. : comp < 0 ? b
  129. : b.operator === '>' && a.operator === '>=' ? b
  130. : a
  131. }
  132. // <=1.2.3 is higher than <1.2.3
  133. const lowerLT = (a, b, options) => {
  134. if (!a)
  135. return b
  136. const comp = compare(a.semver, b.semver, options)
  137. return comp < 0 ? a
  138. : comp > 0 ? b
  139. : b.operator === '<' && a.operator === '<=' ? b
  140. : a
  141. }
  142. module.exports = subset