npm-pick-manifest
Advanced tools
Comparing version 6.0.0 to 6.1.0
@@ -5,2 +5,10 @@ # Changelog | ||
## [6.1.0](https://github.com/npm/npm-pick-manifest/compare/v6.0.0...v6.1.0) (2020-04-07) | ||
### Features | ||
* add 'avoid' semver range option ([c64973d](https://github.com/npm/npm-pick-manifest/commit/c64973d63ddf6797edf41c20df641f816d30ff03)) | ||
* add avoidStrict option to strictly avoid ([c268796](https://github.com/npm/npm-pick-manifest/commit/c2687967b6294f5ce01aa6b59071e79272dc57de)), closes [#30](https://github.com/npm/npm-pick-manifest/issues/30) | ||
## [6.0.0](https://github.com/npm/npm-pick-manifest/compare/v5.0.0...v6.0.0) (2020-02-18) | ||
@@ -7,0 +15,0 @@ |
77
index.js
@@ -19,2 +19,11 @@ 'use strict' | ||
const avoidSemverOpt = { includePrerelease: true, loose: true } | ||
const shouldAvoid = (ver, avoid) => | ||
avoid && semver.satisfies(ver, avoid, avoidSemverOpt) | ||
const decorateAvoid = (result, avoid) => | ||
result && shouldAvoid(result.version, avoid) | ||
? { ...result, _shouldAvoid: true } | ||
: result | ||
const pickManifest = (packument, wanted, opts) => { | ||
@@ -26,3 +35,5 @@ const { | ||
npmVersion = null, | ||
includeStaged = false | ||
includeStaged = false, | ||
avoid = null, | ||
avoidStrict = false | ||
} = opts | ||
@@ -32,2 +43,42 @@ | ||
const versions = packument.versions || {} | ||
if (avoidStrict) { | ||
const looseOpts = { | ||
...opts, | ||
avoidStrict: false | ||
} | ||
const result = pickManifest(packument, wanted, looseOpts) | ||
if (!result || !result._shouldAvoid) { | ||
return result | ||
} | ||
const caret = pickManifest(packument, `^${result.version}`, looseOpts) | ||
if (!caret || !caret._shouldAvoid) { | ||
return { | ||
...caret, | ||
_outsideDependencyRange: true, | ||
_isSemVerMajor: false | ||
} | ||
} | ||
const star = pickManifest(packument, '*', looseOpts) | ||
if (!star || !star._shouldAvoid) { | ||
return { | ||
...star, | ||
_outsideDependencyRange: true, | ||
_isSemVerMajor: true | ||
} | ||
} | ||
throw Object.assign(new Error(`No avoidable versions for ${name}`), { | ||
code: 'ETARGET', | ||
name, | ||
wanted, | ||
avoid, | ||
before, | ||
versions: Object.keys(versions) | ||
}) | ||
} | ||
const staged = (includeStaged && packument.stagedVersions && | ||
@@ -55,3 +106,3 @@ packument.stagedVersions.versions) || {} | ||
if (isBefore(verTimes, ver, time)) { | ||
return versions[ver] || staged[ver] || restricted[ver] | ||
return decorateAvoid(versions[ver] || staged[ver] || restricted[ver], avoid) | ||
} else { | ||
@@ -66,3 +117,3 @@ return pickManifest(packument, `<=${ver}`, opts) | ||
const mani = versions[ver] || staged[ver] || restricted[ver] | ||
return isBefore(verTimes, ver, time) ? mani : null | ||
return isBefore(verTimes, ver, time) ? decorateAvoid(mani, avoid) : null | ||
} | ||
@@ -74,4 +125,8 @@ | ||
// if the range is *, then we prefer the 'latest' if available | ||
// but skip this if it should be avoided, in that case we have | ||
// to try a little harder. | ||
const defaultVer = distTags[defaultTag] | ||
if (defaultVer && (range === '*' || semver.satisfies(defaultVer, range, { loose: true }))) { | ||
if (defaultVer && | ||
(range === '*' || semver.satisfies(defaultVer, range, { loose: true })) && | ||
!shouldAvoid(defaultVer, avoid)) { | ||
const mani = versions[defaultVer] | ||
@@ -90,3 +145,3 @@ if (mani && isBefore(verTimes, defaultVer, time)) { | ||
if (!allEntries.length) { | ||
throw Object.assign(new Error(`No valid versions available for ${name}`), { | ||
throw Object.assign(new Error(`No versions available for ${name}`), { | ||
code: 'ENOVERSIONS', | ||
@@ -96,2 +151,3 @@ name, | ||
wanted, | ||
before, | ||
versions: Object.keys(versions) | ||
@@ -101,2 +157,3 @@ }) | ||
const sortSemverOpt = { loose: true } | ||
const entries = allEntries.filter(([ver, mani]) => | ||
@@ -107,2 +164,4 @@ semver.satisfies(ver, range, { loose: true })) | ||
const [verb, manib] = b | ||
const notavoida = !shouldAvoid(vera, avoid) | ||
const notavoidb = !shouldAvoid(verb, avoid) | ||
const notrestra = !restricted[a] | ||
@@ -117,2 +176,3 @@ const notrestrb = !restricted[b] | ||
// sort by: | ||
// - not an avoided version | ||
// - not restricted | ||
@@ -124,3 +184,4 @@ // - not staged | ||
// - semver | ||
return (notrestrb - notrestra) || | ||
return (notavoidb - notavoida) || | ||
(notrestrb - notrestra) || | ||
(notstageb - notstagea) || | ||
@@ -130,6 +191,6 @@ ((notdeprb && engineb) - (notdepra && enginea)) || | ||
(notdeprb - notdepra) || | ||
semver.rcompare(vera, verb, { loose: true }) | ||
semver.rcompare(vera, verb, sortSemverOpt) | ||
}) | ||
return entries[0] && entries[0][1] | ||
return decorateAvoid(entries[0] && entries[0][1], avoid) | ||
} | ||
@@ -136,0 +197,0 @@ |
{ | ||
"name": "npm-pick-manifest", | ||
"version": "6.0.0", | ||
"version": "6.1.0", | ||
"description": "Resolves a matching manifest from a package metadata document according to standard npm semver resolution rules.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -93,3 +93,27 @@ # npm-pick-manifest [![npm version](https://img.shields.io/npm/v/npm-pick-manifest.svg)](https://npm.im/npm-pick-manifest) [![license](https://img.shields.io/npm/l/npm-pick-manifest.svg)](https://npm.im/npm-pick-manifest) [![Travis](https://img.shields.io/travis/npm/npm-pick-manifest.svg)](https://travis-ci.org/npm/npm-pick-manifest) [![Coverage Status](https://coveralls.io/repos/github/npm/npm-pick-manifest/badge.svg?branch=latest)](https://coveralls.io/github/npm/npm-pick-manifest?branch=latest) | ||
then this particular check is skipped.) | ||
* `avoid` - String, default `null`. A SemVer range of | ||
versions that should be avoided. An avoided version MAY be selected if | ||
there is no other option, so when using this for version selection ensure | ||
that you check the result against the range to see if there was no | ||
alternative available. | ||
* `avoidStrict` Boolean, default `false`. If set to true, then | ||
`pickManifest` will never return a version in the `avoid` range. If the | ||
only available version in the `wanted` range is a version that should be | ||
avoided, then it will return a version _outside_ the `wanted` range, | ||
preferring to do so without making a SemVer-major jump, if possible. If | ||
there are no versions outside the `avoid` range, then throw an | ||
`ETARGET` error. It does this by calling pickManifest first with the | ||
`wanted` range, then with a `^` affixed to the version returned by the | ||
`wanted` range, and then with a `*` version range, and throwing if | ||
nothing could be found to satisfy the avoidance request. | ||
Return value is the manifest as it exists in the packument, possibly | ||
decorated with the following boolean flags: | ||
* `_shouldAvoid` The version is in the `avoid` range. Watch out! | ||
* `_outsideDependencyRange` The version is outside the `wanted` range, | ||
because `avoidStrict: true` was set. | ||
* `_isSemVerMajor` The `_outsideDependencyRange` result is a SemVer-major | ||
step up from the version returned by the `wanted` range. | ||
### Algorithm | ||
@@ -118,13 +142,15 @@ | ||
and select the top item: | ||
1. Prioritize versions that are not in `policyRestrictions` over those | ||
1. Prioritize versions that are not in the `avoid` range over those | ||
that are. | ||
2. Prioritize published versions over staged versions. | ||
3. Prioritize versions that are not deprecated, and which have a | ||
2. Prioritize versions that are not in `policyRestrictions` over those | ||
that are. | ||
3. Prioritize published versions over staged versions. | ||
4. Prioritize versions that are not deprecated, and which have a | ||
satisfied engines requirement, over those that are either deprecated | ||
or have an engines mismatch. | ||
4. Prioritize versions that have a satisfied engines requirement over | ||
5. Prioritize versions that have a satisfied engines requirement over | ||
those that do not. | ||
5. Prioritize versions that are not are not deprecated (but have a | ||
6. Prioritize versions that are not are not deprecated (but have a | ||
mismatched engines requirement) over those that are deprecated. | ||
6. Prioritize higher SemVer precedence over lower SemVer precedence. | ||
7. Prioritize higher SemVer precedence over lower SemVer precedence. | ||
7. If no manifest was selected, raise an `ETARGET` error. | ||
@@ -131,0 +157,0 @@ 8. If the selected item is in the `policyRestrictions.versions` list, raise |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
22473
187
158
0