UNPKG

3.79 kBJavaScriptView Raw
1'use strict'
2
3const figgyPudding = require('figgy-pudding')
4const npa = require('npm-package-arg')
5const semver = require('semver')
6
7const PickerOpts = figgyPudding({
8 defaultTag: { default: 'latest' },
9 enjoyBy: {},
10 includeDeprecated: { default: false }
11})
12
13module.exports = pickManifest
14function pickManifest (packument, wanted, opts) {
15 opts = PickerOpts(opts)
16 const time = opts.enjoyBy && packument.time && +(new Date(opts.enjoyBy))
17 const spec = npa.resolve(packument.name, wanted)
18 const type = spec.type
19 if (type === 'version' || type === 'range') {
20 wanted = semver.clean(wanted, true) || wanted
21 }
22 const distTags = packument['dist-tags'] || {}
23 const versions = Object.keys(packument.versions || {}).filter(v => {
24 return semver.valid(v, true)
25 })
26 const policyRestrictions = packument.policyRestrictions
27 const restrictedVersions = policyRestrictions
28 ? Object.keys(policyRestrictions.versions) : []
29
30 function enjoyableBy (v) {
31 return !time || (
32 packument.time[v] && time >= +(new Date(packument.time[v]))
33 )
34 }
35
36 let err
37
38 if (!versions.length && !restrictedVersions.length) {
39 err = new Error(`No valid versions available for ${packument.name}`)
40 err.code = 'ENOVERSIONS'
41 err.name = packument.name
42 err.type = type
43 err.wanted = wanted
44 throw err
45 }
46
47 let target
48
49 if (type === 'tag' && enjoyableBy(distTags[wanted])) {
50 target = distTags[wanted]
51 } else if (type === 'version') {
52 target = wanted
53 } else if (type !== 'range' && enjoyableBy(distTags[wanted])) {
54 throw new Error('Only tag, version, and range are supported')
55 }
56
57 const tagVersion = distTags[opts.defaultTag]
58
59 if (
60 !target &&
61 tagVersion &&
62 packument.versions[tagVersion] &&
63 enjoyableBy(tagVersion) &&
64 semver.satisfies(tagVersion, wanted, true)
65 ) {
66 target = tagVersion
67 }
68
69 if (!target && !opts.includeDeprecated) {
70 const undeprecated = versions.filter(v => !packument.versions[v].deprecated && enjoyableBy(v)
71 )
72 target = semver.maxSatisfying(undeprecated, wanted, true)
73 }
74 if (!target) {
75 const stillFresh = versions.filter(enjoyableBy)
76 target = semver.maxSatisfying(stillFresh, wanted, true)
77 }
78
79 if (!target && wanted === '*' && enjoyableBy(tagVersion)) {
80 // This specific corner is meant for the case where
81 // someone is using `*` as a selector, but all versions
82 // are pre-releases, which don't match ranges at all.
83 target = tagVersion
84 }
85
86 if (
87 !target &&
88 time &&
89 type === 'tag' &&
90 distTags[wanted] &&
91 !enjoyableBy(distTags[wanted])
92 ) {
93 const stillFresh = versions.filter(v =>
94 enjoyableBy(v) && semver.lte(v, distTags[wanted], true)
95 ).sort(semver.rcompare)
96 target = stillFresh[0]
97 }
98
99 if (!target && restrictedVersions) {
100 target = semver.maxSatisfying(restrictedVersions, wanted, true)
101 }
102
103 const manifest = (
104 target &&
105 packument.versions[target]
106 )
107 if (!manifest) {
108 // Check if target is forbidden
109 const isForbidden = target && policyRestrictions && policyRestrictions.versions[target]
110 const pckg = `${packument.name}@${wanted}${
111 opts.enjoyBy
112 ? ` with an Enjoy By date of ${
113 new Date(opts.enjoyBy).toLocaleString()
114 }. Maybe try a different date?`
115 : ''
116 }`
117
118 if (isForbidden) {
119 err = new Error(`Could not download ${pckg} due to policy violations.\n${policyRestrictions.message}\n`)
120 err.code = 'E403'
121 } else {
122 err = new Error(`No matching version found for ${pckg}.`)
123 err.code = 'ETARGET'
124 }
125
126 err.name = packument.name
127 err.type = type
128 err.wanted = wanted
129 err.versions = versions
130 err.distTags = distTags
131 err.defaultTag = opts.defaultTag
132 throw err
133 } else {
134 return manifest
135 }
136}