aboutsummaryrefslogtreecommitdiff
path: root/deps/npm/lib/install
diff options
context:
space:
mode:
authorKat Marchán <kzm@sykosomatic.org>2017-12-07 14:05:23 -0800
committerMyles Borins <mylesborins@google.com>2018-01-19 11:32:08 -0500
commitd3b1c971bcf0177b17c649c3aeca1a94cbc3fff5 (patch)
tree321928c015be00cdbe11715297d2d2fc45802263 /deps/npm/lib/install
parentbfe41fe88e7421f441067a79fb7512cf5935a2bb (diff)
downloadandroid-node-v8-d3b1c971bcf0177b17c649c3aeca1a94cbc3fff5.tar.gz
android-node-v8-d3b1c971bcf0177b17c649c3aeca1a94cbc3fff5.tar.bz2
android-node-v8-d3b1c971bcf0177b17c649c3aeca1a94cbc3fff5.zip
deps: upgrade npm to 5.6.0
PR-URL: https://github.com/nodejs/node/pull/17777 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Diffstat (limited to 'deps/npm/lib/install')
-rw-r--r--deps/npm/lib/install/action/build.js2
-rw-r--r--deps/npm/lib/install/action/extract.js3
-rw-r--r--deps/npm/lib/install/action/fetch.js6
-rw-r--r--deps/npm/lib/install/action/finalize.js21
-rw-r--r--deps/npm/lib/install/action/refresh-package-json.js2
-rw-r--r--deps/npm/lib/install/actions.js13
-rw-r--r--deps/npm/lib/install/deps.js63
-rw-r--r--deps/npm/lib/install/diff-trees.js152
-rw-r--r--deps/npm/lib/install/inflate-shrinkwrap.js7
-rw-r--r--deps/npm/lib/install/realize-shrinkwrap-specifier.js3
-rw-r--r--deps/npm/lib/install/save.js2
11 files changed, 175 insertions, 99 deletions
diff --git a/deps/npm/lib/install/action/build.js b/deps/npm/lib/install/action/build.js
index f59b852e84..be2c141f0d 100644
--- a/deps/npm/lib/install/action/build.js
+++ b/deps/npm/lib/install/action/build.js
@@ -7,7 +7,7 @@ var packageId = require('../../utils/package-id.js')
module.exports = function (staging, pkg, log, next) {
log.silly('build', packageId(pkg))
chain([
- [build.linkStuff, pkg.package, pkg.path, npm.config.get('global'), true],
+ [build.linkStuff, pkg.package, pkg.path, npm.config.get('global')],
[build.writeBuiltinConf, pkg.package, pkg.path]
], next)
}
diff --git a/deps/npm/lib/install/action/extract.js b/deps/npm/lib/install/action/extract.js
index 8e80d4adda..6b827f36ea 100644
--- a/deps/npm/lib/install/action/extract.js
+++ b/deps/npm/lib/install/action/extract.js
@@ -16,6 +16,7 @@ let pacoteOpts
const path = require('path')
const localWorker = require('./extract-worker.js')
const workerFarm = require('worker-farm')
+const isRegistry = require('../../utils/is-registry.js')
const WORKER_PATH = require.resolve('./extract-worker.js')
let workers
@@ -72,7 +73,7 @@ function extract (staging, pkg, log) {
let msg = args
const spec = typeof args[0] === 'string' ? npa(args[0]) : args[0]
args[0] = spec.raw
- if (ENABLE_WORKERS && (spec.registry || spec.type === 'remote')) {
+ if (ENABLE_WORKERS && (isRegistry(spec) || spec.type === 'remote')) {
// We can't serialize these options
opts.loglevel = opts.log.level
opts.log = null
diff --git a/deps/npm/lib/install/action/fetch.js b/deps/npm/lib/install/action/fetch.js
index 474e00b05c..a4d760fe82 100644
--- a/deps/npm/lib/install/action/fetch.js
+++ b/deps/npm/lib/install/action/fetch.js
@@ -1,5 +1,8 @@
'use strict'
+const BB = require('bluebird')
+
+const finished = BB.promisify(require('mississippi').finished)
const packageId = require('../../utils/package-id.js')
const pacote = require('pacote')
const pacoteOpts = require('../../config/pacote')
@@ -8,5 +11,6 @@ module.exports = fetch
function fetch (staging, pkg, log, next) {
log.silly('fetch', packageId(pkg))
const opts = pacoteOpts({integrity: pkg.package._integrity})
- pacote.prefetch(pkg.package._requested, opts).then(() => next(), next)
+ return finished(pacote.tarball.stream(pkg.package._requested, opts))
+ .then(() => next(), next)
}
diff --git a/deps/npm/lib/install/action/finalize.js b/deps/npm/lib/install/action/finalize.js
index a50ec8a6bd..e46f1b9d83 100644
--- a/deps/npm/lib/install/action/finalize.js
+++ b/deps/npm/lib/install/action/finalize.js
@@ -7,11 +7,13 @@ const mkdirp = Bluebird.promisify(require('mkdirp'))
const lstat = Bluebird.promisify(fs.lstat)
const readdir = Bluebird.promisify(fs.readdir)
const symlink = Bluebird.promisify(fs.symlink)
-const gentlyRm = require('../../utils/gently-rm')
+const gentlyRm = Bluebird.promisify(require('../../utils/gently-rm'))
const moduleStagingPath = require('../module-staging-path.js')
const move = require('move-concurrently')
const moveOpts = {fs: fs, Promise: Bluebird, maxConcurrency: 4}
const getRequested = require('../get-requested.js')
+const log = require('npmlog')
+const packageId = require('../../utils/package-id.js')
module.exports = function (staging, pkg, log) {
log.silly('finalize', pkg.realpath)
@@ -88,8 +90,17 @@ module.exports = function (staging, pkg, log) {
}
}
-module.exports.rollback = function (top, staging, pkg, next) {
- const requested = pkg.package._requested || getRequested(pkg)
- if (requested && requested.type === 'directory') return next()
- gentlyRm(pkg.path, false, top, next)
+module.exports.rollback = function (top, staging, pkg) {
+ return Bluebird.try(() => {
+ const requested = pkg.package._requested || getRequested(pkg)
+ if (requested && requested.type === 'directory') return Promise.resolve()
+ // strictly speaking rolling back a finalize should ONLY remove module that
+ // was being finalized, not any of the things under it. But currently
+ // those modules are guaranteed to be useless so we may as well remove them too.
+ // When/if we separate `commit` step and can rollback to previous versions
+ // of upgraded modules then we'll need to revisit this…
+ return gentlyRm(pkg.path, false, top).catch((err) => {
+ log.warn('rollback', `Rolling back ${packageId(pkg)} failed (this is probably harmless): ${err.message ? err.message : err}`)
+ })
+ })
}
diff --git a/deps/npm/lib/install/action/refresh-package-json.js b/deps/npm/lib/install/action/refresh-package-json.js
index 42f8012100..32e6444444 100644
--- a/deps/npm/lib/install/action/refresh-package-json.js
+++ b/deps/npm/lib/install/action/refresh-package-json.js
@@ -14,7 +14,7 @@ module.exports = function (staging, pkg, log) {
return readJson(path.join(pkg.path, 'package.json'), false).then((metadata) => {
Object.keys(pkg.package).forEach(function (key) {
- if (key !== 'dependencies' && !isEmpty(pkg.package[key])) {
+ if (key !== 'version' && key !== 'dependencies' && !isEmpty(pkg.package[key])) {
metadata[key] = pkg.package[key]
}
})
diff --git a/deps/npm/lib/install/actions.js b/deps/npm/lib/install/actions.js
index 9f0dcfa5dc..9608a943a5 100644
--- a/deps/npm/lib/install/actions.js
+++ b/deps/npm/lib/install/actions.js
@@ -83,10 +83,8 @@ function markAsFailed (pkg) {
if (pkg.failed) return
pkg.failed = true
pkg.requires.forEach((req) => {
- req.requiredBy = req.requiredBy.filter((reqReqBy) => {
- return reqReqBy !== pkg
- })
- if (req.requiredBy.length === 0 && !req.userRequired) {
+ var requiredBy = req.requiredBy.filter((reqReqBy) => !reqReqBy.failed)
+ if (requiredBy.length === 0 && !req.userRequired) {
markAsFailed(req)
}
})
@@ -94,12 +92,7 @@ function markAsFailed (pkg) {
function handleOptionalDepErrors (pkg, err) {
markAsFailed(pkg)
- var anyFatal = pkg.userRequired || pkg.isTop
- for (var ii = 0; ii < pkg.requiredBy.length; ++ii) {
- var parent = pkg.requiredBy[ii]
- var isFatal = failedDependency(parent, pkg)
- if (isFatal) anyFatal = true
- }
+ var anyFatal = failedDependency(pkg)
if (anyFatal) {
throw err
} else {
diff --git a/deps/npm/lib/install/deps.js b/deps/npm/lib/install/deps.js
index c93907a416..93c4adffd7 100644
--- a/deps/npm/lib/install/deps.js
+++ b/deps/npm/lib/install/deps.js
@@ -32,6 +32,7 @@ var reportOptionalFailure = require('./report-optional-failure.js')
var getSaveType = require('./save.js').getSaveType
var unixFormatPath = require('../utils/unix-format-path.js')
var isExtraneous = require('./is-extraneous.js')
+var isRegistry = require('../utils/is-registry.js')
// The export functions in this module mutate a dependency tree, adding
// items to them.
@@ -121,7 +122,7 @@ function computeMetadata (tree, seen) {
}
}
- tree.children.filter((child) => !child.removed && !child.failed).forEach((child) => computeMetadata(child, seen))
+ tree.children.filter((child) => !child.removed).forEach((child) => computeMetadata(child, seen))
return tree
}
@@ -276,7 +277,7 @@ function isNotEmpty (value) {
return value != null && value !== ''
}
-module.exports.computeVersionSpec = computeVersionSpec
+exports.computeVersionSpec = computeVersionSpec
function computeVersionSpec (tree, child) {
validate('OO', arguments)
var requested
@@ -288,7 +289,7 @@ function computeVersionSpec (tree, child) {
} else {
requested = npa.resolve(child.package.name, child.package.version)
}
- if (requested.registry) {
+ if (isRegistry(requested)) {
var version = child.package.version
var rangeDescriptor = ''
if (semver.valid(version, true) &&
@@ -308,10 +309,6 @@ function moduleNameMatches (name) {
return function (child) { return moduleName(child) === name }
}
-function noModuleNameMatches (name) {
- return function (child) { return moduleName(child) !== name }
-}
-
// while this implementation does not require async calling, doing so
// gives this a consistent interface with loadDeps et al
exports.removeDeps = function (args, tree, saveToDependencies, next) {
@@ -377,19 +374,12 @@ function isDepOptional (tree, name, pkg) {
return false
}
-var failedDependency = exports.failedDependency = function (tree, name_pkg) {
- var name
- var pkg = {}
- if (typeof name_pkg === 'string') {
- name = name_pkg
- } else {
- pkg = name_pkg
- name = moduleName(pkg)
- }
- tree.children = tree.children.filter(noModuleNameMatches(name))
-
- if (isDepOptional(tree, name, pkg)) {
- return false
+exports.failedDependency = failedDependency
+function failedDependency (tree, name, pkg) {
+ if (name) {
+ if (isDepOptional(tree, name, pkg || {})) {
+ return false
+ }
}
tree.failed = true
@@ -398,17 +388,16 @@ var failedDependency = exports.failedDependency = function (tree, name_pkg) {
if (tree.userRequired) return true
- removeObsoleteDep(tree)
-
if (!tree.requiredBy) return false
+ let anyFailed = false
for (var ii = 0; ii < tree.requiredBy.length; ++ii) {
var requireParent = tree.requiredBy[ii]
- if (failedDependency(requireParent, tree.package)) {
- return true
+ if (failedDependency(requireParent, moduleName(tree), tree)) {
+ anyFailed = true
}
}
- return false
+ return anyFailed
}
function andHandleOptionalErrors (log, tree, name, done) {
@@ -418,7 +407,6 @@ function andHandleOptionalErrors (log, tree, name, done) {
if (!er) return done(er, child, childLog)
var isFatal = failedDependency(tree, name)
if (er && !isFatal) {
- tree.children = tree.children.filter(noModuleNameMatches(name))
reportOptionalFailure(tree, name, er)
return done()
} else {
@@ -443,7 +431,7 @@ function prefetchDeps (tree, deps, log, next) {
var allDependencies = Object.keys(deps).map((dep) => {
return npa.resolve(dep, deps[dep])
}).filter((dep) => {
- return dep.registry &&
+ return isRegistry(dep) &&
!seen.has(dep.toString()) &&
!findRequirement(tree, dep.name, dep)
})
@@ -601,8 +589,9 @@ function resolveWithNewModule (pkg, tree, log, next) {
validate('OOOF', arguments)
log.silly('resolveWithNewModule', packageId(pkg), 'checking installable status')
- return isInstallable(pkg, iferr(next, function () {
- addBundled(pkg, iferr(next, function () {
+ return isInstallable(pkg, (err) => {
+ let installable = !err
+ addBundled(pkg, (bundleErr) => {
var parent = earliestInstallable(tree, tree, pkg) || tree
var isLink = pkg._requested.type === 'directory'
var child = createChild({
@@ -613,8 +602,9 @@ function resolveWithNewModule (pkg, tree, log, next) {
children: pkg._bundled || [],
isLink: isLink,
isInLink: parent.isLink,
- knownInstallable: true
+ knownInstallable: installable
})
+ if (!installable || bundleErr) child.failed = true
delete pkg._bundled
var hasBundled = child.children.length
@@ -630,13 +620,14 @@ function resolveWithNewModule (pkg, tree, log, next) {
}
if (pkg._shrinkwrap && pkg._shrinkwrap.dependencies) {
- return inflateShrinkwrap(child, pkg._shrinkwrap, function (er) {
- next(er, child, log)
+ return inflateShrinkwrap(child, pkg._shrinkwrap, (swErr) => {
+ if (swErr) child.failed = true
+ next(err || bundleErr || swErr, child, log)
})
}
- next(null, child, log)
- }))
- }))
+ next(err || bundleErr, child, log)
+ })
+ })
}
var validatePeerDeps = exports.validatePeerDeps = function (tree, onInvalid) {
@@ -669,7 +660,7 @@ var findRequirement = exports.findRequirement = function (tree, name, requested,
validate('OSO', [tree, name, requested])
if (!requestor) requestor = tree
var nameMatch = function (child) {
- return moduleName(child) === name && child.parent && !child.removed && !child.failed
+ return moduleName(child) === name && child.parent && !child.removed
}
var versionMatch = function (child) {
return doesChildVersionMatch(child, requested, requestor)
diff --git a/deps/npm/lib/install/diff-trees.js b/deps/npm/lib/install/diff-trees.js
index ac4f421a50..4316f351cc 100644
--- a/deps/npm/lib/install/diff-trees.js
+++ b/deps/npm/lib/install/diff-trees.js
@@ -6,41 +6,98 @@ var flattenTree = require('./flatten-tree.js')
var isOnlyDev = require('./is-only-dev.js')
var log = require('npmlog')
var path = require('path')
+var ssri = require('ssri')
+var moduleName = require('../utils/module-name.js')
-function nonRegistrySource (pkg) {
- validate('O', arguments)
- var requested = pkg._requested || (pkg._from && npa(pkg._from))
- if (!requested) return false
+// we don't use get-requested because we're operating on files on disk, and
+// we don't want to extropolate from what _should_ be there.
+function pkgRequested (pkg) {
+ return pkg._requested || (pkg._resolved && npa(pkg._resolved)) || (pkg._from && npa(pkg._from))
+}
- if (requested.type === 'hosted') return true
- if (requested.type === 'file' || requested.type === 'directory') return true
+function nonRegistrySource (requested) {
+ if (fromGit(requested)) return true
+ if (fromLocal(requested)) return true
+ if (fromRemote(requested)) return true
return false
}
-function pkgAreEquiv (aa, bb) {
- var aaSha = (aa.dist && aa.dist.integrity) || aa._integrity
- var bbSha = (bb.dist && bb.dist.integrity) || bb._integrity
- if (aaSha === bbSha) return true
- if (aaSha || bbSha) return false
- if (nonRegistrySource(aa) || nonRegistrySource(bb)) return false
- if (aa.version === bb.version) return true
+function fromRemote (requested) {
+ if (requested.type === 'remote') return true
+}
+
+function fromLocal (requested) {
+ // local is an npm@3 type that meant "file"
+ if (requested.type === 'file' || requested.type === 'directory' || requested.type === 'local') return true
+ return false
+}
+
+function fromGit (requested) {
+ if (requested.type === 'hosted' || requested.type === 'git') return true
return false
}
-function getUniqueId (pkg) {
- var versionspec = pkg._integrity
+function pkgIntegrity (pkg) {
+ try {
+ // dist is provided by the registry
+ var sri = (pkg.dist && pkg.dist.integrity) ||
+ // _integrity is provided by pacote
+ pkg._integrity ||
+ // _shasum is legacy
+ (pkg._shasum && ssri.fromHex(pkg._shasum, 'sha1').toString())
+ if (!sri) return
+ var integrity = ssri.parse(sri)
+ if (Object.keys(integrity).length === 0) return
+ return integrity
+ } catch (ex) {
+ return
+ }
+}
- if (!versionspec && nonRegistrySource(pkg)) {
- if (pkg._requested) {
- versionspec = pkg._requested.fetchSpec
- } else if (pkg._from) {
- versionspec = npa(pkg._from).fetchSpec
+function sriMatch (aa, bb) {
+ if (!aa || !bb) return false
+ for (let algo of Object.keys(aa)) {
+ if (!bb[algo]) continue
+ for (let aaHash of aa[algo]) {
+ for (let bbHash of bb[algo]) {
+ return aaHash.digest === bbHash.digest
+ }
}
}
- if (!versionspec) {
- versionspec = pkg.version
+ return false
+}
+
+function pkgAreEquiv (aa, bb) {
+ // coming in we know they share a path…
+
+ // if they share package metadata _identity_, they're the same thing
+ if (aa.package === bb.package) return true
+ // if they share integrity information, they're the same thing
+ var aaIntegrity = pkgIntegrity(aa.package)
+ var bbIntegrity = pkgIntegrity(bb.package)
+ if (aaIntegrity || bbIntegrity) return sriMatch(aaIntegrity, bbIntegrity)
+
+ // if they're links and they share the same target, they're the same thing
+ if (aa.isLink && bb.isLink) return aa.realpath === bb.realpath
+
+ // if we can't determine both their sources then we have no way to know
+ // if they're the same thing, so we have to assume they aren't
+ var aaReq = pkgRequested(aa.package)
+ var bbReq = pkgRequested(bb.package)
+ if (!aaReq || !bbReq) return false
+
+ if (fromGit(aaReq) && fromGit(bbReq)) {
+ // if both are git and share a _resolved specifier (one with the
+ // comittish replaced by a commit hash) then they're the same
+ return aa.package._resolved && bb.package._resolved &&
+ aa.package._resolved === bb.package._resolved
}
- return pkg.name + '@' + versionspec
+
+ // we have to give up trying to find matches for non-registry sources at this point…
+ if (nonRegistrySource(aaReq) || nonRegistrySource(bbReq)) return false
+
+ // finally, if they ARE a registry source then version matching counts
+ return aa.package.version === bb.package.version
}
function pushAll (aa, bb) {
@@ -118,41 +175,56 @@ var diffTrees = module.exports._diffTrees = function (oldTree, newTree) {
var flatOldTree = flattenTree(oldTree)
var flatNewTree = flattenTree(newTree)
var toRemove = {}
- var toRemoveByUniqueId = {}
- // find differences
+ var toRemoveByName = {}
+
+ // Build our tentative remove list. We don't add remove actions yet
+ // because we might resuse them as part of a move.
Object.keys(flatOldTree).forEach(function (flatname) {
+ if (flatname === '/') return
if (flatNewTree[flatname]) return
var pkg = flatOldTree[flatname]
if (pkg.isInLink && /^[.][.][/\\]/.test(path.relative(newTree.realpath, pkg.realpath))) return
toRemove[flatname] = pkg
- var pkgunique = getUniqueId(pkg.package)
- if (!toRemoveByUniqueId[pkgunique]) toRemoveByUniqueId[pkgunique] = []
- toRemoveByUniqueId[pkgunique].push(flatname)
+ var name = moduleName(pkg)
+ if (!toRemoveByName[name]) toRemoveByName[name] = []
+ toRemoveByName[name].push({flatname: flatname, pkg: pkg})
})
- Object.keys(flatNewTree).forEach(function (path) {
- var pkg = flatNewTree[path]
- pkg.oldPkg = flatOldTree[path]
- if (pkg.oldPkg) {
- if (!pkg.userRequired && pkgAreEquiv(pkg.oldPkg.package, pkg.package)) return
+
+ // generate our add/update/move actions
+ Object.keys(flatNewTree).forEach(function (flatname) {
+ if (flatname === '/') return
+ var pkg = flatNewTree[flatname]
+ var oldPkg = pkg.oldPkg = flatOldTree[flatname]
+ if (oldPkg) {
+ // if the versions are equivalent then we don't need to update… unless
+ // the user explicitly asked us to.
+ if (!pkg.userRequired && pkgAreEquiv(oldPkg, pkg)) return
setAction(differences, 'update', pkg)
} else {
- var vername = getUniqueId(pkg.package)
- var removing = toRemoveByUniqueId[vername] && toRemoveByUniqueId[vername].length
+ var name = moduleName(pkg)
+ // find any packages we're removing that share the same name and are equivalent
+ var removing = (toRemoveByName[name] || []).filter((rm) => pkgAreEquiv(rm.pkg, pkg))
var bundlesOrFromBundle = pkg.fromBundle || pkg.package.bundleDependencies
- if (removing && !bundlesOrFromBundle) {
- var flatname = toRemoveByUniqueId[vername].shift()
- pkg.fromPath = toRemove[flatname].path
+ // if we have any removes that match AND we're not working with a bundle then upgrade to a move
+ if (removing.length && !bundlesOrFromBundle) {
+ var toMv = removing.shift()
+ toRemoveByName[name] = toRemoveByName[name].filter((rm) => rm !== toMv)
+ pkg.fromPath = toMv.pkg.path
setAction(differences, 'move', pkg)
- delete toRemove[flatname]
+ delete toRemove[toMv.flatname]
+ // we don't generate add actions for things found in links (which already exist on disk) or
+ // for bundled modules (which will be installed when we install their parent)
} else if (!(pkg.isInLink && pkg.fromBundle)) {
setAction(differences, 'add', pkg)
}
}
})
+
+ // finally generate our remove actions from any not consumed by moves
Object
.keys(toRemove)
- .map((path) => toRemove[path])
+ .map((flatname) => toRemove[flatname])
.forEach((pkg) => setAction(differences, 'remove', pkg))
const includeDev = npm.config.get('dev') ||
diff --git a/deps/npm/lib/install/inflate-shrinkwrap.js b/deps/npm/lib/install/inflate-shrinkwrap.js
index 48be93d095..43ac9136f0 100644
--- a/deps/npm/lib/install/inflate-shrinkwrap.js
+++ b/deps/npm/lib/install/inflate-shrinkwrap.js
@@ -13,6 +13,7 @@ const npm = require('../npm.js')
const realizeShrinkwrapSpecifier = require('./realize-shrinkwrap-specifier.js')
const validate = require('aproba')
const path = require('path')
+const isRegistry = require('../utils/is-registry.js')
module.exports = function (tree, sw, opts, finishInflating) {
if (!fetchPackageMetadata) {
@@ -147,7 +148,7 @@ function adaptResolved (requested, resolved) {
const registry = requested.scope
? npm.config.get(`${requested.scope}:registry`) || npm.config.get('registry')
: npm.config.get('registry')
- if (!requested.registry || (resolved && resolved.indexOf(registry) === 0)) {
+ if (!isRegistry(requested) || (resolved && resolved.indexOf(registry) === 0)) {
// Nothing to worry about here. Pass it through.
return resolved
} else {
@@ -199,7 +200,7 @@ function childIsEquivalent (sw, requested, child) {
if (child.isLink && requested.type === 'directory') return path.relative(child.realpath, requested.fetchSpec) === ''
if (sw.resolved) return child.package._resolved === sw.resolved
- if (!requested.registry && sw.from) return child.package._from === sw.from
- if (!requested.registry && child.package._resolved) return sw.version === child.package._resolved
+ if (!isRegistry(requested) && sw.from) return child.package._from === sw.from
+ if (!isRegistry(requested) && child.package._resolved) return sw.version === child.package._resolved
return child.package.version === sw.version
}
diff --git a/deps/npm/lib/install/realize-shrinkwrap-specifier.js b/deps/npm/lib/install/realize-shrinkwrap-specifier.js
index ac700278ff..e4b14b1f0d 100644
--- a/deps/npm/lib/install/realize-shrinkwrap-specifier.js
+++ b/deps/npm/lib/install/realize-shrinkwrap-specifier.js
@@ -1,5 +1,6 @@
'use strict'
var npa = require('npm-package-arg')
+const isRegistry = require('../utils/is-registry.js')
module.exports = function (name, sw, where) {
try {
@@ -7,7 +8,7 @@ module.exports = function (name, sw, where) {
return npa.resolve(name, sw.version, where)
} else if (sw.from) {
const spec = npa(sw.from, where)
- if (spec.registry && sw.version) {
+ if (isRegistry(spec) && sw.version) {
return npa.resolve(name, sw.version, where)
} else if (!sw.resolved) {
return spec
diff --git a/deps/npm/lib/install/save.js b/deps/npm/lib/install/save.js
index e1a94fcff7..f0c61f555d 100644
--- a/deps/npm/lib/install/save.js
+++ b/deps/npm/lib/install/save.js
@@ -39,6 +39,8 @@ function andWarnErrors (cb) {
}
}
+exports.saveShrinkwrap = saveShrinkwrap
+
function saveShrinkwrap (tree, next) {
validate('OF', arguments)
if (!npm.config.get('shrinkwrap') || !npm.config.get('package-lock')) {