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

range.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // hoisted class for cyclic dependency
  2. class Range {
  3. constructor (range, options) {
  4. if (!options || typeof options !== 'object') {
  5. options = {
  6. loose: !!options,
  7. includePrerelease: false
  8. }
  9. }
  10. if (range instanceof Range) {
  11. if (
  12. range.loose === !!options.loose &&
  13. range.includePrerelease === !!options.includePrerelease
  14. ) {
  15. return range
  16. } else {
  17. return new Range(range.raw, options)
  18. }
  19. }
  20. if (range instanceof Comparator) {
  21. // just put it in the set and return
  22. this.raw = range.value
  23. this.set = [[range]]
  24. this.format()
  25. return this
  26. }
  27. this.options = options
  28. this.loose = !!options.loose
  29. this.includePrerelease = !!options.includePrerelease
  30. // First, split based on boolean or ||
  31. this.raw = range
  32. this.set = range
  33. .split(/\s*\|\|\s*/)
  34. // map the range to a 2d array of comparators
  35. .map(range => this.parseRange(range.trim()))
  36. // throw out any comparator lists that are empty
  37. // this generally means that it was not a valid range, which is allowed
  38. // in loose mode, but will still throw if the WHOLE range is invalid.
  39. .filter(c => c.length)
  40. if (!this.set.length) {
  41. throw new TypeError(`Invalid SemVer Range: ${range}`)
  42. }
  43. this.format()
  44. }
  45. format () {
  46. this.range = this.set
  47. .map((comps) => {
  48. return comps.join(' ').trim()
  49. })
  50. .join('||')
  51. .trim()
  52. return this.range
  53. }
  54. toString () {
  55. return this.range
  56. }
  57. parseRange (range) {
  58. const loose = this.options.loose
  59. range = range.trim()
  60. // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
  61. const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
  62. range = range.replace(hr, hyphenReplace(this.options.includePrerelease))
  63. debug('hyphen replace', range)
  64. // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
  65. range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
  66. debug('comparator trim', range, re[t.COMPARATORTRIM])
  67. // `~ 1.2.3` => `~1.2.3`
  68. range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
  69. // `^ 1.2.3` => `^1.2.3`
  70. range = range.replace(re[t.CARETTRIM], caretTrimReplace)
  71. // normalize spaces
  72. range = range.split(/\s+/).join(' ')
  73. // At this point, the range is completely trimmed and
  74. // ready to be split into comparators.
  75. const compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
  76. return range
  77. .split(' ')
  78. .map(comp => parseComparator(comp, this.options))
  79. .join(' ')
  80. .split(/\s+/)
  81. .map(comp => replaceGTE0(comp, this.options))
  82. // in loose mode, throw out any that are not valid comparators
  83. .filter(this.options.loose ? comp => !!comp.match(compRe) : () => true)
  84. .map(comp => new Comparator(comp, this.options))
  85. }
  86. intersects (range, options) {
  87. if (!(range instanceof Range)) {
  88. throw new TypeError('a Range is required')
  89. }
  90. return this.set.some((thisComparators) => {
  91. return (
  92. isSatisfiable(thisComparators, options) &&
  93. range.set.some((rangeComparators) => {
  94. return (
  95. isSatisfiable(rangeComparators, options) &&
  96. thisComparators.every((thisComparator) => {
  97. return rangeComparators.every((rangeComparator) => {
  98. return thisComparator.intersects(rangeComparator, options)
  99. })
  100. })
  101. )
  102. })
  103. )
  104. })
  105. }
  106. // if ANY of the sets match ALL of its comparators, then pass
  107. test (version) {
  108. if (!version) {
  109. return false
  110. }
  111. if (typeof version === 'string') {
  112. try {
  113. version = new SemVer(version, this.options)
  114. } catch (er) {
  115. return false
  116. }
  117. }
  118. for (let i = 0; i < this.set.length; i++) {
  119. if (testSet(this.set[i], version, this.options)) {
  120. return true
  121. }
  122. }
  123. return false
  124. }
  125. }
  126. module.exports = Range
  127. const Comparator = require('./comparator')
  128. const debug = require('../internal/debug')
  129. const SemVer = require('./semver')
  130. const {
  131. re,
  132. t,
  133. comparatorTrimReplace,
  134. tildeTrimReplace,
  135. caretTrimReplace
  136. } = require('../internal/re')
  137. // take a set of comparators and determine whether there
  138. // exists a version which can satisfy it
  139. const isSatisfiable = (comparators, options) => {
  140. let result = true
  141. const remainingComparators = comparators.slice()
  142. let testComparator = remainingComparators.pop()
  143. while (result && remainingComparators.length) {
  144. result = remainingComparators.every((otherComparator) => {
  145. return testComparator.intersects(otherComparator, options)
  146. })
  147. testComparator = remainingComparators.pop()
  148. }
  149. return result
  150. }
  151. // comprised of xranges, tildes, stars, and gtlt's at this point.
  152. // already replaced the hyphen ranges
  153. // turn into a set of JUST comparators.
  154. const parseComparator = (comp, options) => {
  155. debug('comp', comp, options)
  156. comp = replaceCarets(comp, options)
  157. debug('caret', comp)
  158. comp = replaceTildes(comp, options)
  159. debug('tildes', comp)
  160. comp = replaceXRanges(comp, options)
  161. debug('xrange', comp)
  162. comp = replaceStars(comp, options)
  163. debug('stars', comp)
  164. return comp
  165. }
  166. const isX = id => !id || id.toLowerCase() === 'x' || id === '*'
  167. // ~, ~> --> * (any, kinda silly)
  168. // ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0
  169. // ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0
  170. // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0
  171. // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0
  172. // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0
  173. const replaceTildes = (comp, options) =>
  174. comp.trim().split(/\s+/).map((comp) => {
  175. return replaceTilde(comp, options)
  176. }).join(' ')
  177. const replaceTilde = (comp, options) => {
  178. const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]
  179. return comp.replace(r, (_, M, m, p, pr) => {
  180. debug('tilde', comp, _, M, m, p, pr)
  181. let ret
  182. if (isX(M)) {
  183. ret = ''
  184. } else if (isX(m)) {
  185. ret = `>=${M}.0.0 <${+M + 1}.0.0-0`
  186. } else if (isX(p)) {
  187. // ~1.2 == >=1.2.0 <1.3.0-0
  188. ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`
  189. } else if (pr) {
  190. debug('replaceTilde pr', pr)
  191. ret = `>=${M}.${m}.${p}-${pr
  192. } <${M}.${+m + 1}.0-0`
  193. } else {
  194. // ~1.2.3 == >=1.2.3 <1.3.0-0
  195. ret = `>=${M}.${m}.${p
  196. } <${M}.${+m + 1}.0-0`
  197. }
  198. debug('tilde return', ret)
  199. return ret
  200. })
  201. }
  202. // ^ --> * (any, kinda silly)
  203. // ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0
  204. // ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0
  205. // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0
  206. // ^1.2.3 --> >=1.2.3 <2.0.0-0
  207. // ^1.2.0 --> >=1.2.0 <2.0.0-0
  208. const replaceCarets = (comp, options) =>
  209. comp.trim().split(/\s+/).map((comp) => {
  210. return replaceCaret(comp, options)
  211. }).join(' ')
  212. const replaceCaret = (comp, options) => {
  213. debug('caret', comp, options)
  214. const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]
  215. const z = options.includePrerelease ? '-0' : ''
  216. return comp.replace(r, (_, M, m, p, pr) => {
  217. debug('caret', comp, _, M, m, p, pr)
  218. let ret
  219. if (isX(M)) {
  220. ret = ''
  221. } else if (isX(m)) {
  222. ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`
  223. } else if (isX(p)) {
  224. if (M === '0') {
  225. ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`
  226. } else {
  227. ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`
  228. }
  229. } else if (pr) {
  230. debug('replaceCaret pr', pr)
  231. if (M === '0') {
  232. if (m === '0') {
  233. ret = `>=${M}.${m}.${p}-${pr
  234. } <${M}.${m}.${+p + 1}-0`
  235. } else {
  236. ret = `>=${M}.${m}.${p}-${pr
  237. } <${M}.${+m + 1}.0-0`
  238. }
  239. } else {
  240. ret = `>=${M}.${m}.${p}-${pr
  241. } <${+M + 1}.0.0-0`
  242. }
  243. } else {
  244. debug('no pr')
  245. if (M === '0') {
  246. if (m === '0') {
  247. ret = `>=${M}.${m}.${p
  248. }${z} <${M}.${m}.${+p + 1}-0`
  249. } else {
  250. ret = `>=${M}.${m}.${p
  251. }${z} <${M}.${+m + 1}.0-0`
  252. }
  253. } else {
  254. ret = `>=${M}.${m}.${p
  255. } <${+M + 1}.0.0-0`
  256. }
  257. }
  258. debug('caret return', ret)
  259. return ret
  260. })
  261. }
  262. const replaceXRanges = (comp, options) => {
  263. debug('replaceXRanges', comp, options)
  264. return comp.split(/\s+/).map((comp) => {
  265. return replaceXRange(comp, options)
  266. }).join(' ')
  267. }
  268. const replaceXRange = (comp, options) => {
  269. comp = comp.trim()
  270. const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]
  271. return comp.replace(r, (ret, gtlt, M, m, p, pr) => {
  272. debug('xRange', comp, ret, gtlt, M, m, p, pr)
  273. const xM = isX(M)
  274. const xm = xM || isX(m)
  275. const xp = xm || isX(p)
  276. const anyX = xp
  277. if (gtlt === '=' && anyX) {
  278. gtlt = ''
  279. }
  280. // if we're including prereleases in the match, then we need
  281. // to fix this to -0, the lowest possible prerelease value
  282. pr = options.includePrerelease ? '-0' : ''
  283. if (xM) {
  284. if (gtlt === '>' || gtlt === '<') {
  285. // nothing is allowed
  286. ret = '<0.0.0-0'
  287. } else {
  288. // nothing is forbidden
  289. ret = '*'
  290. }
  291. } else if (gtlt && anyX) {
  292. // we know patch is an x, because we have any x at all.
  293. // replace X with 0
  294. if (xm) {
  295. m = 0
  296. }
  297. p = 0
  298. if (gtlt === '>') {
  299. // >1 => >=2.0.0
  300. // >1.2 => >=1.3.0
  301. gtlt = '>='
  302. if (xm) {
  303. M = +M + 1
  304. m = 0
  305. p = 0
  306. } else {
  307. m = +m + 1
  308. p = 0
  309. }
  310. } else if (gtlt === '<=') {
  311. // <=0.7.x is actually <0.8.0, since any 0.7.x should
  312. // pass. Similarly, <=7.x is actually <8.0.0, etc.
  313. gtlt = '<'
  314. if (xm) {
  315. M = +M + 1
  316. } else {
  317. m = +m + 1
  318. }
  319. }
  320. if (gtlt === '<')
  321. pr = '-0'
  322. ret = `${gtlt + M}.${m}.${p}${pr}`
  323. } else if (xm) {
  324. ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`
  325. } else if (xp) {
  326. ret = `>=${M}.${m}.0${pr
  327. } <${M}.${+m + 1}.0-0`
  328. }
  329. debug('xRange return', ret)
  330. return ret
  331. })
  332. }
  333. // Because * is AND-ed with everything else in the comparator,
  334. // and '' means "any version", just remove the *s entirely.
  335. const replaceStars = (comp, options) => {
  336. debug('replaceStars', comp, options)
  337. // Looseness is ignored here. star is always as loose as it gets!
  338. return comp.trim().replace(re[t.STAR], '')
  339. }
  340. const replaceGTE0 = (comp, options) => {
  341. debug('replaceGTE0', comp, options)
  342. return comp.trim()
  343. .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')
  344. }
  345. // This function is passed to string.replace(re[t.HYPHENRANGE])
  346. // M, m, patch, prerelease, build
  347. // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
  348. // 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do
  349. // 1.2 - 3.4 => >=1.2.0 <3.5.0-0
  350. const hyphenReplace = incPr => ($0,
  351. from, fM, fm, fp, fpr, fb,
  352. to, tM, tm, tp, tpr, tb) => {
  353. if (isX(fM)) {
  354. from = ''
  355. } else if (isX(fm)) {
  356. from = `>=${fM}.0.0${incPr ? '-0' : ''}`
  357. } else if (isX(fp)) {
  358. from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`
  359. } else if (fpr) {
  360. from = `>=${from}`
  361. } else {
  362. from = `>=${from}${incPr ? '-0' : ''}`
  363. }
  364. if (isX(tM)) {
  365. to = ''
  366. } else if (isX(tm)) {
  367. to = `<${+tM + 1}.0.0-0`
  368. } else if (isX(tp)) {
  369. to = `<${tM}.${+tm + 1}.0-0`
  370. } else if (tpr) {
  371. to = `<=${tM}.${tm}.${tp}-${tpr}`
  372. } else if (incPr) {
  373. to = `<${tM}.${tm}.${+tp + 1}-0`
  374. } else {
  375. to = `<=${to}`
  376. }
  377. return (`${from} ${to}`).trim()
  378. }
  379. const testSet = (set, version, options) => {
  380. for (let i = 0; i < set.length; i++) {
  381. if (!set[i].test(version)) {
  382. return false
  383. }
  384. }
  385. if (version.prerelease.length && !options.includePrerelease) {
  386. // Find the set of versions that are allowed to have prereleases
  387. // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
  388. // That should allow `1.2.3-pr.2` to pass.
  389. // However, `1.2.4-alpha.notready` should NOT be allowed,
  390. // even though it's within the range set by the comparators.
  391. for (let i = 0; i < set.length; i++) {
  392. debug(set[i].semver)
  393. if (set[i].semver === Comparator.ANY) {
  394. continue
  395. }
  396. if (set[i].semver.prerelease.length > 0) {
  397. const allowed = set[i].semver
  398. if (allowed.major === version.major &&
  399. allowed.minor === version.minor &&
  400. allowed.patch === version.patch) {
  401. return true
  402. }
  403. }
  404. }
  405. // Version has a -pre, but it's not one of the ones we like.
  406. return false
  407. }
  408. return true
  409. }