semver 7.3.2 → 7.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,12 +5,7 @@ class Comparator {
5
5
  return ANY
6
6
  }
7
7
  constructor (comp, options) {
8
- if (!options || typeof options !== 'object') {
9
- options = {
10
- loose: !!options,
11
- includePrerelease: false
12
- }
13
- }
8
+ options = parseOptions(options)
14
9
 
15
10
  if (comp instanceof Comparator) {
16
11
  if (comp.loose === !!options.loose) {
@@ -132,6 +127,7 @@ class Comparator {
132
127
 
133
128
  module.exports = Comparator
134
129
 
130
+ const parseOptions = require('../internal/parse-options')
135
131
  const {re, t} = require('../internal/re')
136
132
  const cmp = require('../functions/cmp')
137
133
  const debug = require('../internal/debug')
package/classes/range.js CHANGED
@@ -1,12 +1,7 @@
1
1
  // hoisted class for cyclic dependency
2
2
  class Range {
3
3
  constructor (range, options) {
4
- if (!options || typeof options !== 'object') {
5
- options = {
6
- loose: !!options,
7
- includePrerelease: false
8
- }
9
- }
4
+ options = parseOptions(options)
10
5
 
11
6
  if (range instanceof Range) {
12
7
  if (
@@ -46,6 +41,24 @@ class Range {
46
41
  throw new TypeError(`Invalid SemVer Range: ${range}`)
47
42
  }
48
43
 
44
+ // if we have any that are not the null set, throw out null sets.
45
+ if (this.set.length > 1) {
46
+ // keep the first one, in case they're all null sets
47
+ const first = this.set[0]
48
+ this.set = this.set.filter(c => !isNullSet(c[0]))
49
+ if (this.set.length === 0)
50
+ this.set = [first]
51
+ else if (this.set.length > 1) {
52
+ // if we have any that are *, then the range is just *
53
+ for (const c of this.set) {
54
+ if (c.length === 1 && isAny(c[0])) {
55
+ this.set = [c]
56
+ break
57
+ }
58
+ }
59
+ }
60
+ }
61
+
49
62
  this.format()
50
63
  }
51
64
 
@@ -64,8 +77,17 @@ class Range {
64
77
  }
65
78
 
66
79
  parseRange (range) {
67
- const loose = this.options.loose
68
80
  range = range.trim()
81
+
82
+ // memoize range parsing for performance.
83
+ // this is a very hot path, and fully deterministic.
84
+ const memoOpts = Object.keys(this.options).join(',')
85
+ const memoKey = `parseRange:${memoOpts}:${range}`
86
+ const cached = cache.get(memoKey)
87
+ if (cached)
88
+ return cached
89
+
90
+ const loose = this.options.loose
69
91
  // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
70
92
  const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
71
93
  range = range.replace(hr, hyphenReplace(this.options.includePrerelease))
@@ -87,15 +109,33 @@ class Range {
87
109
  // ready to be split into comparators.
88
110
 
89
111
  const compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
90
- return range
112
+ const rangeList = range
91
113
  .split(' ')
92
114
  .map(comp => parseComparator(comp, this.options))
93
115
  .join(' ')
94
116
  .split(/\s+/)
117
+ // >=0.0.0 is equivalent to *
95
118
  .map(comp => replaceGTE0(comp, this.options))
96
119
  // in loose mode, throw out any that are not valid comparators
97
120
  .filter(this.options.loose ? comp => !!comp.match(compRe) : () => true)
98
121
  .map(comp => new Comparator(comp, this.options))
122
+
123
+ // if any comparators are the null set, then replace with JUST null set
124
+ // if more than one comparator, remove any * comparators
125
+ // also, don't include the same comparator more than once
126
+ const l = rangeList.length
127
+ const rangeMap = new Map()
128
+ for (const comp of rangeList) {
129
+ if (isNullSet(comp))
130
+ return [comp]
131
+ rangeMap.set(comp.value, comp)
132
+ }
133
+ if (rangeMap.size > 1 && rangeMap.has(''))
134
+ rangeMap.delete('')
135
+
136
+ const result = [...rangeMap.values()]
137
+ cache.set(memoKey, result)
138
+ return result
99
139
  }
100
140
 
101
141
  intersects (range, options) {
@@ -144,6 +184,10 @@ class Range {
144
184
  }
145
185
  module.exports = Range
146
186
 
187
+ const LRU = require('lru-cache')
188
+ const cache = new LRU({ max: 1000 })
189
+
190
+ const parseOptions = require('../internal/parse-options')
147
191
  const Comparator = require('./comparator')
148
192
  const debug = require('../internal/debug')
149
193
  const SemVer = require('./semver')
@@ -155,6 +199,9 @@ const {
155
199
  caretTrimReplace
156
200
  } = require('../internal/re')
157
201
 
202
+ const isNullSet = c => c.value === '<0.0.0-0'
203
+ const isAny = c => c.value === ''
204
+
158
205
  // take a set of comparators and determine whether there
159
206
  // exists a version which can satisfy it
160
207
  const isSatisfiable = (comparators, options) => {
package/classes/semver.js CHANGED
@@ -2,15 +2,12 @@ const debug = require('../internal/debug')
2
2
  const { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')
3
3
  const { re, t } = require('../internal/re')
4
4
 
5
+ const parseOptions = require('../internal/parse-options')
5
6
  const { compareIdentifiers } = require('../internal/identifiers')
6
7
  class SemVer {
7
8
  constructor (version, options) {
8
- if (!options || typeof options !== 'object') {
9
- options = {
10
- loose: !!options,
11
- includePrerelease: false
12
- }
13
- }
9
+ options = parseOptions(options)
10
+
14
11
  if (version instanceof SemVer) {
15
12
  if (version.loose === !!options.loose &&
16
13
  version.includePrerelease === !!options.includePrerelease) {
@@ -2,13 +2,9 @@ const {MAX_LENGTH} = require('../internal/constants')
2
2
  const { re, t } = require('../internal/re')
3
3
  const SemVer = require('../classes/semver')
4
4
 
5
+ const parseOptions = require('../internal/parse-options')
5
6
  const parse = (version, options) => {
6
- if (!options || typeof options !== 'object') {
7
- options = {
8
- loose: !!options,
9
- includePrerelease: false
10
- }
11
- }
7
+ options = parseOptions(options)
12
8
 
13
9
  if (version instanceof SemVer) {
14
10
  return version
@@ -0,0 +1,11 @@
1
+ // parse out just the options we care about so we always get a consistent
2
+ // obj with keys in a consistent order.
3
+ const opts = ['includePrerelease', 'loose', 'rtl']
4
+ const parseOptions = options =>
5
+ !options ? {}
6
+ : typeof options !== 'object' ? { loose: true }
7
+ : opts.filter(k => options[k]).reduce((options, k) => {
8
+ options[k] = true
9
+ return options
10
+ }, {})
11
+ module.exports = parseOptions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "semver",
3
- "version": "7.3.2",
3
+ "version": "7.3.3",
4
4
  "description": "The semantic version parser used by npm.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -16,7 +16,7 @@
16
16
  "license": "ISC",
17
17
  "repository": "https://github.com/npm/node-semver",
18
18
  "bin": {
19
- "semver": "./bin/semver.js"
19
+ "semver": "bin/semver.js"
20
20
  },
21
21
  "files": [
22
22
  "bin/**/*.js",
@@ -34,5 +34,8 @@
34
34
  },
35
35
  "engines": {
36
36
  "node": ">=10"
37
+ },
38
+ "dependencies": {
39
+ "lru-cache": "^4.1.5"
37
40
  }
38
41
  }
@@ -19,6 +19,7 @@ const minVersion = (range, loose) => {
19
19
  for (let i = 0; i < range.set.length; ++i) {
20
20
  const comparators = range.set[i]
21
21
 
22
+ let setMin = null
22
23
  comparators.forEach((comparator) => {
23
24
  // Clone to avoid manipulating the comparator's semver object.
24
25
  const compver = new SemVer(comparator.semver.version)
@@ -33,8 +34,8 @@ const minVersion = (range, loose) => {
33
34
  /* fallthrough */
34
35
  case '':
35
36
  case '>=':
36
- if (!minver || gt(minver, compver)) {
37
- minver = compver
37
+ if (!setMin || gt(compver, setMin)) {
38
+ setMin = compver
38
39
  }
39
40
  break
40
41
  case '<':
@@ -46,6 +47,8 @@ const minVersion = (range, loose) => {
46
47
  throw new Error(`Unexpected operation: ${comparator.operator}`)
47
48
  }
48
49
  })
50
+ if (setMin && (!minver || gt(minver, setMin)))
51
+ minver = setMin
49
52
  }
50
53
 
51
54
  if (minver && range.test(minver)) {
package/ranges/outside.js CHANGED
@@ -32,7 +32,7 @@ const outside = (version, range, hilo, options) => {
32
32
  throw new TypeError('Must provide a hilo val of "<" or ">"')
33
33
  }
34
34
 
35
- // If it satisifes the range it is not outside
35
+ // If it satisfies the range it is not outside
36
36
  if (satisfies(version, range, options)) {
37
37
  return false
38
38
  }
package/ranges/subset.js CHANGED
@@ -21,15 +21,18 @@ const compare = require('../functions/compare.js')
21
21
  // - If EQ satisfies every C, return true
22
22
  // - Else return false
23
23
  // - If GT
24
- // - If GT is lower than any > or >= comp in C, return false
24
+ // - If GT.semver is lower than any > or >= comp in C, return false
25
25
  // - If GT is >=, and GT.semver does not satisfy every C, return false
26
26
  // - If LT
27
- // - If LT.semver is greater than that of any > comp in C, return false
27
+ // - If LT.semver is greater than any < or <= comp in C, return false
28
28
  // - If LT is <=, and LT.semver does not satisfy every C, return false
29
29
  // - If any C is a = range, and GT or LT are set, return false
30
30
  // - Else return true
31
31
 
32
32
  const subset = (sub, dom, options) => {
33
+ if (sub === dom)
34
+ return true
35
+
33
36
  sub = new Range(sub, options)
34
37
  dom = new Range(dom, options)
35
38
  let sawNonNull = false
@@ -52,6 +55,9 @@ const subset = (sub, dom, options) => {
52
55
  }
53
56
 
54
57
  const simpleSubset = (sub, dom, options) => {
58
+ if (sub === dom)
59
+ return true
60
+
55
61
  if (sub.length === 1 && sub[0].semver === ANY)
56
62
  return dom.length === 1 && dom[0].semver === ANY
57
63
 
@@ -90,6 +96,7 @@ const simpleSubset = (sub, dom, options) => {
90
96
  if (!satisfies(eq, String(c), options))
91
97
  return false
92
98
  }
99
+
93
100
  return true
94
101
  }
95
102
 
@@ -101,7 +108,7 @@ const simpleSubset = (sub, dom, options) => {
101
108
  if (gt) {
102
109
  if (c.operator === '>' || c.operator === '>=') {
103
110
  higher = higherGT(gt, c, options)
104
- if (higher === c)
111
+ if (higher === c && higher !== gt)
105
112
  return false
106
113
  } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options))
107
114
  return false
@@ -109,7 +116,7 @@ const simpleSubset = (sub, dom, options) => {
109
116
  if (lt) {
110
117
  if (c.operator === '<' || c.operator === '<=') {
111
118
  lower = lowerLT(lt, c, options)
112
- if (lower === c)
119
+ if (lower === c && lower !== lt)
113
120
  return false
114
121
  } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options))
115
122
  return false