mirror of https://github.com/nodejs/node.git
122 lines
3.1 KiB
JavaScript
122 lines
3.1 KiB
JavaScript
'use strict'
|
|
|
|
const figgyPudding = require('figgy-pudding')
|
|
const npa = require('npm-package-arg')
|
|
const semver = require('semver')
|
|
|
|
const PickerOpts = figgyPudding({
|
|
defaultTag: { default: 'latest' },
|
|
enjoyBy: {},
|
|
includeDeprecated: { default: false }
|
|
})
|
|
|
|
module.exports = pickManifest
|
|
function pickManifest (packument, wanted, opts) {
|
|
opts = PickerOpts(opts)
|
|
const time = opts.enjoyBy && packument.time && +(new Date(opts.enjoyBy))
|
|
const spec = npa.resolve(packument.name, wanted)
|
|
const type = spec.type
|
|
if (type === 'version' || type === 'range') {
|
|
wanted = semver.clean(wanted, true) || wanted
|
|
}
|
|
const distTags = packument['dist-tags'] || {}
|
|
const versions = Object.keys(packument.versions || {}).filter(v => {
|
|
return semver.valid(v, true)
|
|
})
|
|
|
|
function enjoyableBy (v) {
|
|
return !time || (
|
|
packument.time[v] && time >= +(new Date(packument.time[v]))
|
|
)
|
|
}
|
|
|
|
let err
|
|
|
|
if (!versions.length) {
|
|
err = new Error(`No valid versions available for ${packument.name}`)
|
|
err.code = 'ENOVERSIONS'
|
|
err.name = packument.name
|
|
err.type = type
|
|
err.wanted = wanted
|
|
throw err
|
|
}
|
|
|
|
let target
|
|
|
|
if (type === 'tag' && enjoyableBy(distTags[wanted])) {
|
|
target = distTags[wanted]
|
|
} else if (type === 'version') {
|
|
target = wanted
|
|
} else if (type !== 'range' && enjoyableBy(distTags[wanted])) {
|
|
throw new Error('Only tag, version, and range are supported')
|
|
}
|
|
|
|
const tagVersion = distTags[opts.defaultTag]
|
|
|
|
if (
|
|
!target &&
|
|
tagVersion &&
|
|
packument.versions[tagVersion] &&
|
|
enjoyableBy(tagVersion) &&
|
|
semver.satisfies(tagVersion, wanted, true)
|
|
) {
|
|
target = tagVersion
|
|
}
|
|
|
|
if (!target && !opts.includeDeprecated) {
|
|
const undeprecated = versions.filter(v => !packument.versions[v].deprecated && enjoyableBy(v)
|
|
)
|
|
target = semver.maxSatisfying(undeprecated, wanted, true)
|
|
}
|
|
if (!target) {
|
|
const stillFresh = versions.filter(enjoyableBy)
|
|
target = semver.maxSatisfying(stillFresh, wanted, true)
|
|
}
|
|
|
|
if (!target && wanted === '*' && enjoyableBy(tagVersion)) {
|
|
// This specific corner is meant for the case where
|
|
// someone is using `*` as a selector, but all versions
|
|
// are pre-releases, which don't match ranges at all.
|
|
target = tagVersion
|
|
}
|
|
|
|
if (
|
|
!target &&
|
|
time &&
|
|
type === 'tag' &&
|
|
distTags[wanted] &&
|
|
!enjoyableBy(distTags[wanted])
|
|
) {
|
|
const stillFresh = versions.filter(v =>
|
|
enjoyableBy(v) && semver.lte(v, distTags[wanted], true)
|
|
).sort(semver.rcompare)
|
|
target = stillFresh[0]
|
|
}
|
|
|
|
const manifest = (
|
|
target &&
|
|
packument.versions[target]
|
|
)
|
|
if (!manifest) {
|
|
err = new Error(
|
|
`No matching version found for ${packument.name}@${wanted}${
|
|
opts.enjoyBy
|
|
? ` with an Enjoy By date of ${
|
|
new Date(opts.enjoyBy).toLocaleString()
|
|
}. Maybe try a different date?`
|
|
: ''
|
|
}`
|
|
)
|
|
err.code = 'ETARGET'
|
|
err.name = packument.name
|
|
err.type = type
|
|
err.wanted = wanted
|
|
err.versions = versions
|
|
err.distTags = distTags
|
|
err.defaultTag = opts.defaultTag
|
|
throw err
|
|
} else {
|
|
return manifest
|
|
}
|
|
}
|