@@ -6,6 +6,8 @@ const versionUtil = require('../version-util.js');
6
6
const spawn = require ( 'spawn-please' ) ;
7
7
const pacote = require ( 'pacote' ) ;
8
8
9
+ const TIME_FIELDS = [ 'modified' , 'created' ] ;
10
+
9
11
// needed until pacote supports full npm config compatibility
10
12
// See: https://github.com/zkat/pacote/issues/156
11
13
const npmConfig = { } ;
@@ -46,45 +48,81 @@ function parseJson(result, data) {
46
48
* @param {string } packageName Name of the package
47
49
* @param {string } field Field such as "versions" or "dist-tags.latest" are parsed from the pacote result (https://www.npmjs.com/package/pacote#packument)
48
50
* @param {string } currentVersion
49
- * @returns {Promise } Promised result
51
+ * @returns {Promise } Promised result
50
52
*/
51
- function view ( packageName , field , currentVersion ) {
53
+ function viewOne ( packageName , field , currentVersion ) {
54
+ return viewMany ( packageName , [ field ] , currentVersion )
55
+ . then ( result => {
56
+ return result && result [ field ] ;
57
+ } ) ;
58
+ }
59
+
60
+ /**
61
+ * @param {string } packageName Name of the package
62
+ * @param {string[] } fields Array of fields like versions, time, version
63
+ * @param {string } currentVersion
64
+ * @returns {Promise } Promised result
65
+ */
66
+ function viewMany ( packageName , fields , currentVersion ) {
52
67
if ( currentVersion && ( ! semver . validRange ( currentVersion ) || versionUtil . isWildCard ( currentVersion ) ) ) {
53
68
return Promise . resolve ( ) ;
54
69
}
55
70
56
- npmConfig [ 'full-metadata' ] = field === 'time' ;
71
+ npmConfig [ 'full-metadata' ] = _ . includes ( fields , 'time' ) ;
57
72
58
73
return pacote . packument ( packageName , npmConfig ) . then ( result => {
59
- if ( field . startsWith ( 'dist-tags.' ) ) {
60
- const [ tagName , version ] = field . split ( '.' ) ;
61
- if ( result [ tagName ] ) {
62
- return result [ tagName ] [ version ] ;
74
+ const resultObject = { } ;
75
+ _ . each ( fields , ( field ) => {
76
+ if ( field . startsWith ( 'dist-tags.' ) ) {
77
+ const [ tagName , version ] = field . split ( '.' ) ;
78
+ if ( result [ tagName ] ) {
79
+ resultObject [ field ] = result . versions [ result [ tagName ] [ version ] ] ;
80
+ }
81
+ } else {
82
+ resultObject [ field ] = result [ field ] ;
63
83
}
64
- } else if ( field === 'versions' ) {
65
- return Object . keys ( result [ field ] ) ;
66
- } else {
67
- return result [ field ] ;
68
- }
84
+ } ) ;
85
+ return resultObject ;
69
86
} ) ;
70
87
}
71
88
72
89
/**
73
90
* @param {Array } versions Array of all available versions
91
+ * @param {Boolean } pre Enabled prerelease?
74
92
* @returns {Array } An array of versions with the release versions filtered out
75
93
*/
76
- function filterOutPrereleaseVersions ( versions ) {
77
- return _ . filter ( versions , _ . negate ( isPre ) ) ;
94
+ function filterOutPrereleaseVersions ( versions , pre ) {
95
+ return _ . filter ( versions , ( version ) => {
96
+ return pre || _ . negate ( isPre ) ( version ) ;
97
+ } ) ;
78
98
}
79
99
80
100
/**
81
- * @param version
82
- * @returns {boolean } True if the version is any kind of prerelease: alpha, beta, rc, pre
101
+ * @param { String } version
102
+ * @returns {boolean } True if the version is any kind of prerelease: alpha, beta, rc, pre
83
103
*/
84
104
function isPre ( version ) {
85
105
return versionUtil . getPrecision ( version ) === 'release' ;
86
106
}
87
107
108
+ /**
109
+ * @param {{} } versions Object with all versions
110
+ * @param {String } enginesNode Package engines.node range
111
+ * @returns {Array } An array of versions which satisfies engines.node range
112
+ */
113
+ function doesSatisfyEnginesNode ( versions , enginesNode ) {
114
+ if ( ! enginesNode ) {
115
+ return _ . keys ( versions ) ;
116
+ }
117
+ const minVersion = _ . get ( semver . minVersion ( enginesNode ) , 'version' ) ;
118
+ if ( ! minVersion ) {
119
+ return _ . keys ( versions ) ;
120
+ }
121
+ return _ . keys ( versions ) . filter ( ( version ) => {
122
+ let versionEnginesNode = _ . get ( versions [ version ] , 'engines.node' ) ;
123
+ return versionEnginesNode && semver . satisfies ( minVersion , versionEnginesNode ) ;
124
+ } ) ;
125
+ }
88
126
89
127
/**
90
128
* Spawn npm requires a different command on Windows.
@@ -159,78 +197,97 @@ module.exports = {
159
197
/**
160
198
* @param {string } packageName
161
199
* @param {string } currentVersion
162
- * @param {boolean } pre
200
+ * @param {{} } options
163
201
* @returns {Promise }
164
202
*/
165
- latest ( packageName , currentVersion , pre ) {
166
- return view ( packageName , 'dist-tags.latest' , currentVersion )
167
- . then ( version => {
168
- // if latest is not a prerelease version, return it
169
- // if latest is a prerelease version and --pre is specified, return it
170
- if ( ! isPre ( version ) || pre ) {
171
- return version ;
203
+ latest ( packageName , currentVersion , options ) {
204
+ return viewOne ( packageName , 'dist-tags.latest' , currentVersion )
205
+ . then ( latest => {
206
+ // if latest exists and latest not satisfies min version of engines.node, set null to it
207
+ if ( latest && ! doesSatisfyEnginesNode ( { [ latest . version ] : latest } , options . enginesNode ) . length ) {
208
+ latest = null ;
209
+ }
210
+ // if latest exists and latest is not a prerelease version, return it
211
+ // if latest exists and latest is a prerelease version and --pre is specified, return it
212
+ if ( latest && ( ! isPre ( latest . version ) || options . pre ) ) {
213
+ return latest . version ;
172
214
// if latest is a prerelease version and --pre is not specified, find the next
173
215
// version that is not a prerelease
174
216
} else {
175
- return view ( packageName , 'versions' , currentVersion )
176
- . then ( filterOutPrereleaseVersions )
177
- . then ( _ . last ) ;
217
+ return viewOne ( packageName , 'versions' , currentVersion )
218
+ . then ( versions => {
219
+ versions = doesSatisfyEnginesNode ( versions , options . enginesNode ) ;
220
+ return _ . last ( filterOutPrereleaseVersions ( versions , options . pre ) ) ;
221
+ } ) ;
178
222
}
179
223
} ) ;
180
224
} ,
181
225
182
226
/**
183
227
* @param {string } packageName
184
228
* @param {string } currentVersion
185
- * @param {boolean } pre
229
+ * @param {{} } options
186
230
* @returns {Promise }
187
231
*/
188
- newest ( packageName , currentVersion , pre ) {
189
- return view ( packageName , 'time' , currentVersion )
190
- . then ( _ . keys )
191
- . then ( _ . partialRight ( _ . pullAll , [ 'modified' , 'created' ] ) )
232
+ newest ( packageName , currentVersion , options ) {
233
+ return viewMany ( packageName , [ 'time' , 'versions' ] , currentVersion )
234
+ . then ( ( result ) => {
235
+ const versions = doesSatisfyEnginesNode ( result . versions , options . enginesNode ) ;
236
+ _ . keys ( result . time ) . forEach ( ( key ) => {
237
+ if ( ! _ . includes ( TIME_FIELDS , key ) && ! _ . includes ( versions , key ) ) {
238
+ delete result . time [ key ] ;
239
+ }
240
+ } ) ;
241
+ return _ . keys ( result . time ) ;
242
+ } )
243
+ . then ( _ . partialRight ( _ . pullAll , TIME_FIELDS ) )
192
244
. then ( versions => {
193
- return _ . last ( pre ? versions : filterOutPrereleaseVersions ( versions ) ) ;
245
+ return _ . last ( filterOutPrereleaseVersions ( versions , options . pre ) ) ;
194
246
} ) ;
195
247
} ,
196
248
197
249
/**
198
250
* @param {string } packageName
199
251
* @param {string } currentVersion
200
- * @param {boolean } pre
252
+ * @param {{} } options
201
253
* @returns {Promise }
202
254
*/
203
- greatest ( packageName , currentVersion , pre ) {
204
- return view ( packageName , 'versions' , currentVersion )
255
+ greatest ( packageName , currentVersion , options ) {
256
+ return viewOne ( packageName , 'versions' , currentVersion )
205
257
. then ( versions => {
206
- return _ . last ( pre ? versions : filterOutPrereleaseVersions ( versions ) ) ;
258
+ versions = doesSatisfyEnginesNode ( versions , options . enginesNode ) ;
259
+ return _ . last ( filterOutPrereleaseVersions ( versions , options . pre ) ) ;
207
260
} ) ;
208
261
} ,
209
262
210
263
/**
211
264
* @param {string } packageName
212
265
* @param {string } currentVersion
213
- * @param {boolean } pre
266
+ * @param {{} } options
214
267
* @returns {Promise }
215
268
*/
216
- greatestMajor ( packageName , currentVersion , pre ) {
217
- return view ( packageName , 'versions' , currentVersion ) . then ( versions => {
218
- const resultVersions = pre ? versions : filterOutPrereleaseVersions ( versions ) ;
219
- return versionUtil . findGreatestByLevel ( resultVersions , currentVersion , 'major' ) ;
220
- } ) ;
269
+ greatestMajor ( packageName , currentVersion , options ) {
270
+ return viewOne ( packageName , 'versions' , currentVersion )
271
+ . then ( versions => {
272
+ versions = doesSatisfyEnginesNode ( versions , options . enginesNode ) ;
273
+ versions = filterOutPrereleaseVersions ( versions , options . pre ) ;
274
+ return versionUtil . findGreatestByLevel ( versions , currentVersion , 'major' ) ;
275
+ } ) ;
221
276
} ,
222
277
223
278
/**
224
279
* @param {string } packageName
225
280
* @param {string } currentVersion
226
- * @param {boolean } pre
281
+ * @param {{} } options
227
282
* @returns {Promise }
228
283
*/
229
- greatestMinor ( packageName , currentVersion , pre ) {
230
- return view ( packageName , 'versions' , currentVersion ) . then ( versions => {
231
- const resultVersions = pre ? versions : filterOutPrereleaseVersions ( versions ) ;
232
- return versionUtil . findGreatestByLevel ( resultVersions , currentVersion , 'minor' ) ;
233
- } ) ;
284
+ greatestMinor ( packageName , currentVersion , options ) {
285
+ return viewOne ( packageName , 'versions' , currentVersion )
286
+ . then ( versions => {
287
+ versions = doesSatisfyEnginesNode ( versions , options . enginesNode ) ;
288
+ versions = filterOutPrereleaseVersions ( versions , options . pre ) ;
289
+ return versionUtil . findGreatestByLevel ( versions , currentVersion , 'minor' ) ;
290
+ } ) ;
234
291
} ,
235
292
236
293
defaultPrefix
0 commit comments