source: trip-planner-front/node_modules/npm-pick-manifest/index.js@ eed0bf8

Last change on this file since eed0bf8 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.7 KB
Line 
1'use strict'
2
3const npa = require('npm-package-arg')
4const semver = require('semver')
5const { checkEngine } = require('npm-install-checks')
6const normalizeBin = require('npm-normalize-package-bin')
7
8const engineOk = (manifest, npmVersion, nodeVersion) => {
9 try {
10 checkEngine(manifest, npmVersion, nodeVersion)
11 return true
12 } catch (_) {
13 return false
14 }
15}
16
17const isBefore = (verTimes, ver, time) =>
18 !verTimes || !verTimes[ver] || Date.parse(verTimes[ver]) <= time
19
20const avoidSemverOpt = { includePrerelease: true, loose: true }
21const shouldAvoid = (ver, avoid) =>
22 avoid && semver.satisfies(ver, avoid, avoidSemverOpt)
23
24const decorateAvoid = (result, avoid) =>
25 result && shouldAvoid(result.version, avoid)
26 ? { ...result, _shouldAvoid: true }
27 : result
28
29const pickManifest = (packument, wanted, opts) => {
30 const {
31 defaultTag = 'latest',
32 before = null,
33 nodeVersion = process.version,
34 npmVersion = null,
35 includeStaged = false,
36 avoid = null,
37 avoidStrict = false
38 } = opts
39
40 const { name, time: verTimes } = packument
41 const versions = packument.versions || {}
42
43 if (avoidStrict) {
44 const looseOpts = {
45 ...opts,
46 avoidStrict: false
47 }
48
49 const result = pickManifest(packument, wanted, looseOpts)
50 if (!result || !result._shouldAvoid) {
51 return result
52 }
53
54 const caret = pickManifest(packument, `^${result.version}`, looseOpts)
55 if (!caret || !caret._shouldAvoid) {
56 return {
57 ...caret,
58 _outsideDependencyRange: true,
59 _isSemVerMajor: false
60 }
61 }
62
63 const star = pickManifest(packument, '*', looseOpts)
64 if (!star || !star._shouldAvoid) {
65 return {
66 ...star,
67 _outsideDependencyRange: true,
68 _isSemVerMajor: true
69 }
70 }
71
72 throw Object.assign(new Error(`No avoidable versions for ${name}`), {
73 code: 'ETARGET',
74 name,
75 wanted,
76 avoid,
77 before,
78 versions: Object.keys(versions)
79 })
80 }
81
82 const staged = (includeStaged && packument.stagedVersions &&
83 packument.stagedVersions.versions) || {}
84 const restricted = (packument.policyRestrictions &&
85 packument.policyRestrictions.versions) || {}
86
87 const time = before && verTimes ? +(new Date(before)) : Infinity
88 const spec = npa.resolve(name, wanted || defaultTag)
89 const type = spec.type
90 const distTags = packument['dist-tags'] || {}
91
92 if (type !== 'tag' && type !== 'version' && type !== 'range') {
93 throw new Error('Only tag, version, and range are supported')
94 }
95
96 // if the type is 'tag', and not just the implicit default, then it must
97 // be that exactly, or nothing else will do.
98 if (wanted && type === 'tag') {
99 const ver = distTags[wanted]
100 // if the version in the dist-tags is before the before date, then
101 // we use that. Otherwise, we get the highest precedence version
102 // prior to the dist-tag.
103 if (isBefore(verTimes, ver, time)) {
104 return decorateAvoid(versions[ver] || staged[ver] || restricted[ver], avoid)
105 } else {
106 return pickManifest(packument, `<=${ver}`, opts)
107 }
108 }
109
110 // similarly, if a specific version, then only that version will do
111 if (wanted && type === 'version') {
112 const ver = semver.clean(wanted, { loose: true })
113 const mani = versions[ver] || staged[ver] || restricted[ver]
114 return isBefore(verTimes, ver, time) ? decorateAvoid(mani, avoid) : null
115 }
116
117 // ok, sort based on our heuristics, and pick the best fit
118 const range = type === 'range' ? wanted : '*'
119
120 // if the range is *, then we prefer the 'latest' if available
121 // but skip this if it should be avoided, in that case we have
122 // to try a little harder.
123 const defaultVer = distTags[defaultTag]
124 if (defaultVer &&
125 (range === '*' || semver.satisfies(defaultVer, range, { loose: true })) &&
126 !shouldAvoid(defaultVer, avoid)) {
127 const mani = versions[defaultVer]
128 if (mani && isBefore(verTimes, defaultVer, time)) {
129 return mani
130 }
131 }
132
133 // ok, actually have to sort the list and take the winner
134 const allEntries = Object.entries(versions)
135 .concat(Object.entries(staged))
136 .concat(Object.entries(restricted))
137 .filter(([ver, mani]) => isBefore(verTimes, ver, time))
138
139 if (!allEntries.length) {
140 throw Object.assign(new Error(`No versions available for ${name}`), {
141 code: 'ENOVERSIONS',
142 name,
143 type,
144 wanted,
145 before,
146 versions: Object.keys(versions)
147 })
148 }
149
150 const sortSemverOpt = { loose: true }
151 const entries = allEntries.filter(([ver, mani]) =>
152 semver.satisfies(ver, range, { loose: true }))
153 .sort((a, b) => {
154 const [vera, mania] = a
155 const [verb, manib] = b
156 const notavoida = !shouldAvoid(vera, avoid)
157 const notavoidb = !shouldAvoid(verb, avoid)
158 const notrestra = !restricted[a]
159 const notrestrb = !restricted[b]
160 const notstagea = !staged[a]
161 const notstageb = !staged[b]
162 const notdepra = !mania.deprecated
163 const notdeprb = !manib.deprecated
164 const enginea = engineOk(mania, npmVersion, nodeVersion)
165 const engineb = engineOk(manib, npmVersion, nodeVersion)
166 // sort by:
167 // - not an avoided version
168 // - not restricted
169 // - not staged
170 // - not deprecated and engine ok
171 // - engine ok
172 // - not deprecated
173 // - semver
174 return (notavoidb - notavoida) ||
175 (notrestrb - notrestra) ||
176 (notstageb - notstagea) ||
177 ((notdeprb && engineb) - (notdepra && enginea)) ||
178 (engineb - enginea) ||
179 (notdeprb - notdepra) ||
180 semver.rcompare(vera, verb, sortSemverOpt)
181 })
182
183 return decorateAvoid(entries[0] && entries[0][1], avoid)
184}
185
186module.exports = (packument, wanted, opts = {}) => {
187 const mani = pickManifest(packument, wanted, opts)
188 const picked = mani && normalizeBin(mani)
189 const policyRestrictions = packument.policyRestrictions
190 const restricted = (policyRestrictions && policyRestrictions.versions) || {}
191
192 if (picked && !restricted[picked.version]) {
193 return picked
194 }
195
196 const { before = null, defaultTag = 'latest' } = opts
197 const bstr = before ? new Date(before).toLocaleString() : ''
198 const { name } = packument
199 const pckg = `${name}@${wanted}` +
200 (before ? ` with a date before ${bstr}` : '')
201
202 const isForbidden = picked && !!restricted[picked.version]
203 const polMsg = isForbidden ? policyRestrictions.message : ''
204
205 const msg = !isForbidden ? `No matching version found for ${pckg}.`
206 : `Could not download ${pckg} due to policy violations:\n${polMsg}`
207
208 const code = isForbidden ? 'E403' : 'ETARGET'
209 throw Object.assign(new Error(msg), {
210 code,
211 type: npa.resolve(packument.name, wanted).type,
212 wanted,
213 versions: Object.keys(packument.versions),
214 name,
215 distTags: packument['dist-tags'],
216 defaultTag
217 })
218}
Note: See TracBrowser for help on using the repository browser.