Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/lib/install/deps.js')
-rw-r--r--deps/npm/lib/install/deps.js134
1 files changed, 80 insertions, 54 deletions
diff --git a/deps/npm/lib/install/deps.js b/deps/npm/lib/install/deps.js
index edc317f846d..886e8419135 100644
--- a/deps/npm/lib/install/deps.js
+++ b/deps/npm/lib/install/deps.js
@@ -10,6 +10,7 @@ var iferr = require('iferr')
var npa = require('npm-package-arg')
var validate = require('aproba')
var realizePackageSpecifier = require('realize-package-specifier')
+var asap = require('asap')
var dezalgo = require('dezalgo')
var fetchPackageMetadata = require('../fetch-package-metadata.js')
var andAddParentToErrors = require('./and-add-parent-to-errors.js')
@@ -78,15 +79,17 @@ function doesChildVersionMatch (child, requested, requestor) {
return semver.satisfies(child.package.version, requested.spec)
}
+// TODO: Rename to maybe computeMetadata or computeRelationships
exports.recalculateMetadata = function (tree, log, next) {
recalculateMetadata(tree, log, {}, next)
}
+exports._childDependencySpecifier = childDependencySpecifier
function childDependencySpecifier (tree, name, spec, cb) {
if (!tree.resolved) tree.resolved = {}
if (!tree.resolved[name]) tree.resolved[name] = {}
if (tree.resolved[name][spec]) {
- return process.nextTick(function () {
+ return asap(function () {
cb(null, tree.resolved[name][spec])
})
}
@@ -101,19 +104,24 @@ function recalculateMetadata (tree, log, seen, next) {
validate('OOOF', arguments)
if (seen[tree.path]) return next()
seen[tree.path] = true
- if (tree.parent == null) resetMetadata(tree)
- function markDeps (spec, done) {
- validate('SF', arguments)
- var matched = spec.match(/^(@?[^@]+)@(.*)$/)
- childDependencySpecifier(tree, matched[1], matched[2], function (er, req) {
+ if (tree.parent == null) {
+ resetMetadata(tree)
+ tree.isTop = true
+ }
+
+ function markDeps (toMark, done) {
+ var name = toMark.name
+ var spec = toMark.spec
+ var kind = toMark.kind
+ childDependencySpecifier(tree, name, spec, function (er, req) {
if (er || !req.name) return done()
var child = findRequirement(tree, req.name, req)
if (child) {
resolveWithExistingModule(child, tree, log, andIgnoreErrors(done))
- } else if (tree.package.dependencies[req.name] != null) {
+ } else if (kind === 'dep') {
tree.missingDeps[req.name] = req.rawSpec
done()
- } else if (tree.package.devDependencies[req.name] != null) {
+ } else if (kind === 'dev') {
tree.missingDevDeps[req.name] = req.rawSpec
done()
} else {
@@ -121,15 +129,16 @@ function recalculateMetadata (tree, log, seen, next) {
}
})
}
- function specs (deps) {
- return Object.keys(deps).map(function (depname) { return depname + '@' + deps[depname] })
+
+ function makeMarkable (deps, kind) {
+ if (!deps) return []
+ return Object.keys(deps).map(function (depname) { return { name: depname, spec: deps[depname], kind: kind } })
}
// Ensure dependencies and dev dependencies are marked as required
- var tomark = specs(tree.package.dependencies)
- if (!tree.parent && (npm.config.get('dev') || !npm.config.get('production'))) {
- tomark = union(tomark, specs(tree.package.devDependencies))
- }
+ var tomark = makeMarkable(tree.package.dependencies, 'dep')
+ if (tree.isTop) tomark = union(tomark, makeMarkable(tree.package.devDependencies, 'dev'))
+
// Ensure any children ONLY from a shrinkwrap are also included
var childrenOnlyInShrinkwrap = tree.children.filter(function (child) {
return child.fromShrinkwrap &&
@@ -137,7 +146,13 @@ function recalculateMetadata (tree, log, seen, next) {
!tree.package.devDependencies[child.package.name]
})
var tomarkOnlyInShrinkwrap = childrenOnlyInShrinkwrap.map(function (child) {
- return child.package._spec
+ var name = child.package.name
+ var matched = child.package._spec.match(/^@?[^@]+@(.*)$/)
+ var spec = matched ? matched[1] : child.package._spec
+ var kind = tree.package.dependencies[name] ? 'dep'
+ : tree.package.devDependencies[name] ? 'dev'
+ : 'dep'
+ return { name: name, spec: spec, kind: kind }
})
tomark = union(tomark, tomarkOnlyInShrinkwrap)
@@ -148,9 +163,7 @@ function recalculateMetadata (tree, log, seen, next) {
[asyncMap, tomark, markDeps],
[asyncMap, tree.children, function (child, done) { recalculateMetadata(child, log, seen, done) }]
], function () {
- tree.userRequired = tree.package._requiredBy.some(function (req) { return req === '#USER' })
- tree.existing = tree.package._requiredBy.some(function (req) { return req === '#EXISTING' })
- tree.package._location = flatNameFromTree(tree)
+ tree.location = flatNameFromTree(tree)
next(null, tree)
})
}
@@ -158,18 +171,23 @@ function recalculateMetadata (tree, log, seen, next) {
function addRequiredDep (tree, child, cb) {
isDep(tree, child, function (childIsDep, childIsProdDep, childIsDevDep) {
if (!childIsDep) return cb(false)
- var name = childIsProdDep ? flatNameFromTree(tree) : '#DEV:' + flatNameFromTree(tree)
- replaceModuleName(child.package, '_requiredBy', name)
- replaceModule(child, 'requiredBy', tree)
- replaceModule(tree, 'requires', child)
+ replaceModuleByPath(child, 'requiredBy', tree)
+ replaceModuleByName(tree, 'requires', child)
+ if (childIsProdDep && tree.missingDeps) delete tree.missingDeps[moduleName(child)]
+ if (childIsDevDep && tree.missingDevDeps) delete tree.missingDevDeps[moduleName(child)]
cb(true)
})
}
-exports._removeObsoleteDep = removeObsoleteDep
+exports.removeObsoleteDep = removeObsoleteDep
function removeObsoleteDep (child) {
if (child.removed) return
child.removed = true
+ // remove from physical tree
+ if (child.parent) {
+ child.parent.children = child.parent.children.filter(function (pchild) { return pchild !== child })
+ }
+ // remove from logical tree
var requires = child.requires || []
requires.forEach(function (requirement) {
requirement.requiredBy = requirement.requiredBy.filter(function (reqBy) { return reqBy !== child })
@@ -243,9 +261,7 @@ exports.loadRequestedDeps = function (args, tree, saveToDependencies, log, next)
// won't be when we're done), flag it as "depending" on the user
// themselves, so we don't remove it as a dep that no longer exists
addRequiredDep(tree, child, function (childIsDep) {
- if (!childIsDep) {
- replaceModuleName(child.package, '_requiredBy', '#USER')
- }
+ if (!childIsDep) child.userRequired = true
depLoaded(null, child, tracker)
})
}))
@@ -266,13 +282,13 @@ exports.removeDeps = function (args, tree, saveToDependencies, log, next) {
validate('AOOF', [args, tree, log, next])
args.forEach(function (pkg) {
var pkgName = moduleName(pkg)
+ var toRemove = tree.children.filter(moduleNameMatches(pkgName))
+ var pkgToRemove = toRemove[0] || createChild({package: {name: pkgName}})
if (saveToDependencies) {
- var toRemove = tree.children.filter(moduleNameMatches(pkgName))
- var pkgToRemove = toRemove[0] || createChild({package: {name: pkgName}})
- replaceModule(tree, 'removed', pkgToRemove)
+ replaceModuleByPath(tree, 'removed', pkgToRemove)
pkgToRemove.save = saveToDependencies
}
- tree.children = tree.children.filter(noModuleNameMatches(pkgName))
+ removeObsoleteDep(pkgToRemove)
})
log.finish()
next()
@@ -313,7 +329,6 @@ var failedDependency = exports.failedDependency = function (tree, name_pkg) {
pkg = name_pkg
name = moduleName(pkg)
}
-
tree.children = tree.children.filter(noModuleNameMatches(name))
if (isDepOptional(tree, name)) {
@@ -322,10 +337,14 @@ var failedDependency = exports.failedDependency = function (tree, name_pkg) {
tree.failed = true
- if (!tree.parent) return true
+ if (tree.isTop) return true
if (tree.userRequired) return true
+ removeObsoleteDep(tree)
+
+ if (!tree.requiredBy) return false
+
for (var ii = 0; ii < tree.requiredBy.length; ++ii) {
var requireParent = tree.requiredBy[ii]
if (failedDependency(requireParent, tree.package)) {
@@ -367,7 +386,7 @@ function andHandleOptionalErrors (log, tree, name, done) {
exports.loadDeps = loadDeps
function loadDeps (tree, log, next) {
validate('OOF', arguments)
- if (tree.loaded || (tree.parent && tree.parent.failed)) return andFinishTracker.now(log, next)
+ if (tree.loaded || (tree.parent && tree.parent.failed) || tree.removed) return andFinishTracker.now(log, next)
if (tree.parent) tree.loaded = true
if (!tree.package.dependencies) tree.package.dependencies = {}
asyncMap(Object.keys(tree.package.dependencies), function (dep, done) {
@@ -446,38 +465,44 @@ function resolveWithExistingModule (child, tree, log, next) {
var updatePhantomChildren = exports.updatePhantomChildren = function (current, child) {
validate('OO', arguments)
while (current && current !== child.parent) {
- // FIXME: phantomChildren doesn't actually belong in the package.json
- if (!current.package._phantomChildren) current.package._phantomChildren = {}
- current.package._phantomChildren[moduleName(child)] = child.package.version
+ if (!current.phantomChildren) current.phantomChildren = {}
+ current.phantomChildren[moduleName(child)] = child
current = current.parent
}
}
function flatNameFromTree (tree) {
validate('O', arguments)
- if (!tree.parent) return '/'
+ if (tree.isTop) return '/'
var path = flatNameFromTree(tree.parent)
if (path !== '/') path += '/'
return flatName(path, tree)
}
-exports._replaceModuleName = replaceModuleName
-function replaceModuleName (obj, key, name) {
- validate('OSS', arguments)
- obj[key] = union(obj[key] || [], [name])
+exports._replaceModuleByPath = replaceModuleByPath
+function replaceModuleByPath (obj, key, child) {
+ return replaceModule(obj, key, child, function (replacing, child) {
+ return replacing.path === child.path
+ })
+}
+
+exports._replaceModuleByName = replaceModuleByName
+function replaceModuleByName (obj, key, child) {
+ var childName = moduleName(child)
+ return replaceModule(obj, key, child, function (replacing, child) {
+ return moduleName(replacing) === childName
+ })
}
-exports._replaceModule = replaceModule
-function replaceModule (obj, key, child) {
- validate('OSO', arguments)
+function replaceModule (obj, key, child, matchBy) {
+ validate('OSOF', arguments)
if (!obj[key]) obj[key] = []
// we replace children with a new array object instead of mutating it
// because mutating it results in weird failure states.
// I would very much like to know _why_ this is. =/
var children = [].concat(obj[key])
- var childName = moduleName(child)
for (var replaceAt = 0; replaceAt < children.length; ++replaceAt) {
- if (moduleName(children[replaceAt]) === childName) break
+ if (matchBy(children[replaceAt], child)) break
}
var replacing = children.splice(replaceAt, 1, child)
obj[key] = children
@@ -514,15 +539,17 @@ function resolveWithNewModule (pkg, tree, log, next) {
children: pkg._bundled || [],
isLink: tree.isLink
})
+ delete pkg._bundled
+ var hasBundled = child.children.length
- var replaced = replaceModule(parent, 'children', child)
+ var replaced = replaceModuleByName(parent, 'children', child)
if (replaced) removeObsoleteDep(replaced)
addRequiredDep(tree, child, function () {
- pkg._location = flatNameFromTree(child)
+ child.location = flatNameFromTree(child)
if (tree.parent && parent !== tree) updatePhantomChildren(tree.parent, child)
- if (pkg._bundled) {
+ if (hasBundled) {
inflateBundled(child, child.children)
}
@@ -584,7 +611,7 @@ var findRequirement = exports.findRequirement = function (tree, name, requested,
if (matches.length) return matches[0]
return null
}
- if (!tree.parent) return null
+ if (tree.isTop) return null
return findRequirement(tree.parent, name, requested, requestor)
}
@@ -618,13 +645,12 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr
return null
}
- // FIXME: phantomChildren doesn't actually belong in the package.json
- if (tree.package._phantomChildren && tree.package._phantomChildren[pkg.name]) return null
+ if (tree.phantomChildren && tree.phantomChildren[pkg.name]) return null
- if (!tree.parent) return tree
+ if (tree.isTop) return tree
if (tree.isGlobal) return tree
- if (npm.config.get('global-style') && !tree.parent.parent) return tree
+ if (npm.config.get('global-style') && tree.parent.isTop) return tree
if (npm.config.get('legacy-bundling')) return tree
return (earliestInstallable(requiredBy, tree.parent, pkg) || tree)