]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/install.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / lib / install.js
diff --git a/org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/install.js b/org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/install.js
new file mode 100644 (file)
index 0000000..72575d1
--- /dev/null
@@ -0,0 +1,1196 @@
+// npm install <pkg> <pkg> <pkg>
+//
+// See doc/cli/npm-install.md for more description
+//
+// Managing contexts...
+// there's a lot of state associated with an "install" operation, including
+// packages that are already installed, parent packages, current shrinkwrap, and
+// so on. We maintain this state in a "context" object that gets passed around.
+// every time we dive into a deeper node_modules folder, the "family" list that
+// gets passed along uses the previous "family" list as its __proto__.  Any
+// "resolved precise dependency" things that aren't already on this object get
+// added, and then that's passed to the next generation of installation.
+
+module.exports = install
+
+install.usage = "npm install"
+              + "\nnpm install <pkg>"
+              + "\nnpm install <pkg>@<tag>"
+              + "\nnpm install <pkg>@<version>"
+              + "\nnpm install <pkg>@<version range>"
+              + "\nnpm install <folder>"
+              + "\nnpm install <tarball file>"
+              + "\nnpm install <tarball url>"
+              + "\nnpm install <git:// url>"
+              + "\nnpm install <github username>/<github project>"
+              + "\n\nCan specify one or more: npm install ./foo.tgz bar@stable /some/folder"
+              + "\nIf no argument is supplied and ./npm-shrinkwrap.json is "
+              + "\npresent, installs dependencies specified in the shrinkwrap."
+              + "\nOtherwise, installs dependencies from ./package.json."
+
+install.completion = function (opts, cb) {
+  // install can complete to a folder with a package.json, or any package.
+  // if it has a slash, then it's gotta be a folder
+  // if it starts with https?://, then just give up, because it's a url
+  if (/^https?:\/\//.test(opts.partialWord)) {
+    // do not complete to URLs
+    return cb(null, [])
+  }
+
+  if (/\//.test(opts.partialWord)) {
+    // Complete fully to folder if there is exactly one match and it
+    // is a folder containing a package.json file.  If that is not the
+    // case we return 0 matches, which will trigger the default bash
+    // complete.
+    var lastSlashIdx = opts.partialWord.lastIndexOf("/")
+    var partialName = opts.partialWord.slice(lastSlashIdx + 1)
+    var partialPath = opts.partialWord.slice(0, lastSlashIdx)
+    if (partialPath === "") partialPath = "/"
+
+    function annotatePackageDirMatch (sibling, cb) {
+      var fullPath = path.join(partialPath, sibling)
+      if (sibling.slice(0, partialName.length) !== partialName) {
+        return cb(null, null) // not name match
+      }
+      fs.readdir(fullPath, function (err, contents) {
+        if (err) return cb(null, { isPackage: false })
+
+        cb(
+          null,
+          {
+            fullPath: fullPath,
+            isPackage: contents.indexOf("package.json") !== -1
+          }
+        )
+      })
+    }
+
+    return fs.readdir(partialPath, function (err, siblings) {
+      if (err) return cb(null, []) // invalid dir: no matching
+
+      asyncMap(siblings, annotatePackageDirMatch, function (err, matches) {
+        if (err) return cb(err)
+
+        var cleaned = matches.filter(function (x) { return x !== null })
+        if (cleaned.length !== 1) return cb(null, [])
+        if (!cleaned[0].isPackage) return cb(null, [])
+
+        // Success - only one match and it is a package dir
+        return cb(null, [cleaned[0].fullPath])
+      })
+    })
+  }
+
+  // FIXME: there used to be registry completion here, but it stopped making
+  // sense somewhere around 50,000 packages on the registry
+  cb()
+}
+
+var npm = require("./npm.js")
+  , semver = require("semver")
+  , readJson = require("read-package-json")
+  , readInstalled = require("read-installed")
+  , log = require("npmlog")
+  , path = require("path")
+  , fs = require("graceful-fs")
+  , writeFileAtomic = require("write-file-atomic")
+  , cache = require("./cache.js")
+  , asyncMap = require("slide").asyncMap
+  , chain = require("slide").chain
+  , url = require("url")
+  , mkdir = require("mkdirp")
+  , lifecycle = require("./utils/lifecycle.js")
+  , archy = require("archy")
+  , npmInstallChecks = require("npm-install-checks")
+  , sortedObject = require("sorted-object")
+  , mapToRegistry = require("./utils/map-to-registry.js")
+  , npa = require("npm-package-arg")
+  , inflight = require("inflight")
+  , locker = require("./utils/locker.js")
+  , lock = locker.lock
+  , unlock = locker.unlock
+  , warnStrict = require("./utils/warn-deprecated.js")("engineStrict")
+  , warnPeers = require("./utils/warn-deprecated.js")("peerDependencies")
+
+function install (args, cb_) {
+  var hasArguments = !!args.length
+
+  function cb (er, installed) {
+    if (er) return cb_(er)
+
+    validateInstall(where, function (er, problem) {
+      if (er) return cb_(er)
+
+      if (problem) {
+        var peerInvalidError = new Error("The package " + problem._id +
+          " does not satisfy its siblings' peerDependencies requirements!")
+        peerInvalidError.code = "EPEERINVALID"
+        peerInvalidError.packageName = problem.name
+        peerInvalidError.packageVersion = problem.version
+        peerInvalidError.peersDepending = problem.peersDepending
+        return cb(peerInvalidError)
+      }
+
+      var tree = treeify(installed || [])
+        , pretty = prettify(tree, installed).trim()
+
+      if (pretty) console.log(pretty)
+      save(where, installed, tree, pretty, hasArguments, cb_)
+    })
+  }
+
+  // the /path/to/node_modules/..
+  var where = path.resolve(npm.dir, "..")
+
+  // internal api: install(where, what, cb)
+  if (arguments.length === 3) {
+    where = args
+    args = [].concat(cb_) // pass in [] to do default dep-install
+    cb_ = arguments[2]
+    log.verbose("install", "where, what", [where, args])
+  }
+
+  if (!npm.config.get("global")) {
+    args = args.filter(function (a) {
+      return path.resolve(a) !== where
+    })
+  }
+
+  mkdir(where, function (er) {
+    if (er) return cb(er)
+    // install dependencies locally by default,
+    // or install current folder globally
+    if (!args.length) {
+      var opt = { dev: npm.config.get("dev") || !npm.config.get("production") }
+
+      if (npm.config.get("global")) args = ["."]
+      else return readDependencies(null, where, opt, function (er, data) {
+        if (er) {
+          log.error("install", "Couldn't read dependencies")
+          return cb(er)
+        }
+        var deps = Object.keys(data.dependencies || {})
+        log.verbose("install", "where, deps", [where, deps])
+
+        // FIXME: Install peerDependencies as direct dependencies, but only at
+        // the top level. Should only last until peerDependencies are nerfed to
+        // no longer implicitly install themselves.
+        var peers = []
+        Object.keys(data.peerDependencies || {}).forEach(function (dep) {
+          if (!data.dependencies[dep]) {
+            log.verbose(
+              "install",
+              "peerDependency", dep, "wasn't going to be installed; adding"
+            )
+            warnPeers([
+              "The peer dependency "+dep+" included from "+data.name+" will no",
+              "longer be automatically installed to fulfill the peerDependency ",
+              "in npm 3+. Your application will need to depend on it explicitly."
+            ], dep+","+data.name)
+            peers.push(dep)
+          }
+        })
+        log.verbose("install", "where, peers", [where, peers])
+
+        var context = { family: {}
+                      , ancestors: {}
+                      , explicit: false
+                      , parent: data
+                      , root: true
+                      , wrap: null }
+
+        if (data.name === path.basename(where) &&
+            path.basename(path.dirname(where)) === "node_modules") {
+          // Only include in ancestry if it can actually be required.
+          // Otherwise, it does not count.
+          context.family[data.name] =
+            context.ancestors[data.name] = data.version
+        }
+
+        installManyTop(deps.map(function (dep) {
+          var target = data.dependencies[dep]
+          return dep + "@" + target
+        }).concat(peers.map(function (dep) {
+          var target = data.peerDependencies[dep]
+          return dep + "@" + target
+        })), where, context, function(er, results) {
+          if (er || npm.config.get("production")) return cb(er, results)
+          lifecycle(data, "prepublish", where, function(er) {
+            return cb(er, results)
+          })
+        })
+      })
+    }
+
+    // initial "family" is the name:version of the root, if it's got
+    // a package.json file.
+    var jsonPath = path.resolve(where, "package.json")
+    log.verbose('install', 'initial load of', jsonPath)
+    readJson(jsonPath, log.warn, function (er, data) {
+      if (er
+          && er.code !== "ENOENT"
+          && er.code !== "ENOTDIR") return cb(er)
+      if (er) data = null
+      var context = { family: {}
+                    , ancestors: {}
+                    , explicit: true
+                    , parent: data
+                    , root: true
+                    , wrap: null }
+      if (data && data.name === path.basename(where) &&
+          path.basename(path.dirname(where)) === "node_modules") {
+        context.family[data.name] = context.ancestors[data.name] = data.version
+      }
+      var fn = npm.config.get("global") ? installMany : installManyTop
+      fn(args, where, context, cb)
+    })
+  })
+}
+
+function validateInstall (where, cb) {
+  var jsonPath = path.resolve(where, 'package.json')
+  log.verbose('validateInstall', 'loading', jsonPath, 'for validation')
+  readJson(jsonPath, log.warn, function (er, data) {
+    if (er
+        && er.code !== 'ENOENT'
+        && er.code !== 'ENOTDIR') return cb(er)
+
+    if (data && data.engineStrict) {
+      warnStrict([
+        "Per-package engineStrict (found in this package's package.json) ",
+        "won't be used in npm 3+. Use the config setting `engine-strict` instead."
+      ], data.name)
+    }
+
+    readInstalled(where, { log: log.warn, dev: true }, function (er, data) {
+      if (er) return cb(er)
+
+      cb(null, findPeerInvalid_(data.dependencies, []))
+    })
+  })
+}
+
+function findPeerInvalid_ (packageMap, fpiList) {
+  if (fpiList.indexOf(packageMap) !== -1)
+    return undefined
+
+  fpiList.push(packageMap)
+
+  for (var packageName in packageMap) {
+    var pkg = packageMap[packageName]
+
+    if (pkg.peerInvalid) {
+      var peersDepending = {}
+      for (var peerName in packageMap) {
+        var peer = packageMap[peerName]
+        if (peer.peerDependencies && peer.peerDependencies[packageName]) {
+          peersDepending[peer.name + "@" + peer.version] =
+            peer.peerDependencies[packageName]
+        }
+      }
+      return { name: pkg.name, peersDepending: peersDepending, version: pkg.version, _id: pkg._id }
+    }
+
+    if (pkg.dependencies) {
+      var invalid = findPeerInvalid_(pkg.dependencies, fpiList)
+      if (invalid)
+        return invalid
+    }
+  }
+
+  return null
+}
+
+// reads dependencies for the package at "where". There are several cases,
+// depending on our current state and the package's configuration:
+//
+// 1. If "context" is specified, then we examine the context to see if there's a
+//    shrinkwrap there. In that case, dependencies are read from the shrinkwrap.
+// 2. Otherwise, if an npm-shrinkwrap.json file is present, dependencies are
+//    read from there.
+// 3. Otherwise, dependencies come from package.json.
+//
+// Regardless of which case we fall into, "cb" is invoked with a first argument
+// describing the full package (as though readJson had been used) but with
+// "dependencies" read as described above. The second argument to "cb" is the
+// shrinkwrap to use in processing this package's dependencies, which may be
+// "wrap" (in case 1) or a new shrinkwrap (in case 2).
+function readDependencies (context, where, opts, cb) {
+  var wrap = context ? context.wrap : null
+
+  var jsonPath = path.resolve(where, 'package.json')
+  log.verbose('readDependencies', 'loading dependencies from', jsonPath)
+  readJson(jsonPath, log.warn, function (er, data) {
+    if (er && er.code === "ENOENT") er.code = "ENOPACKAGEJSON"
+    if (er) return cb(er)
+
+    if (opts && opts.dev) {
+      if (!data.dependencies) data.dependencies = {}
+      Object.keys(data.devDependencies || {}).forEach(function (k) {
+        if (data.dependencies[k]) {
+          log.warn("package.json", "Dependency '%s' exists in both dependencies " +
+                   "and devDependencies, using '%s@%s' from dependencies",
+                    k, k, data.dependencies[k])
+        } else {
+          data.dependencies[k] = data.devDependencies[k]
+        }
+      })
+    }
+
+    if (!npm.config.get("optional") && data.optionalDependencies) {
+      Object.keys(data.optionalDependencies).forEach(function (d) {
+        delete data.dependencies[d]
+      })
+    }
+
+    // User has opted out of shrinkwraps entirely
+    if (npm.config.get("shrinkwrap") === false)
+      return cb(null, data, null)
+
+    if (wrap) {
+      log.verbose("readDependencies: using existing wrap", [where, wrap])
+      var rv = {}
+      Object.keys(data).forEach(function (key) {
+        rv[key] = data[key]
+      })
+      rv.dependencies = {}
+      Object.keys(wrap).forEach(function (key) {
+        log.verbose("from wrap", [key, wrap[key]])
+        rv.dependencies[key] = readWrap(wrap[key])
+      })
+      log.verbose("readDependencies returned deps", rv.dependencies)
+      return cb(null, rv, wrap)
+    }
+
+    var wrapfile = path.resolve(where, "npm-shrinkwrap.json")
+
+    fs.readFile(wrapfile, "utf8", function (er, wrapjson) {
+      if (er) return cb(null, data, null)
+
+      log.verbose("readDependencies", "npm-shrinkwrap.json is overriding dependencies")
+      var newwrap
+      try {
+        newwrap = JSON.parse(wrapjson)
+      } catch (ex) {
+        return cb(ex)
+      }
+
+      log.info("shrinkwrap", "file %j", wrapfile)
+      var rv = {}
+      Object.keys(data).forEach(function (key) {
+        rv[key] = data[key]
+      })
+      rv.dependencies = {}
+      Object.keys(newwrap.dependencies || {}).forEach(function (key) {
+        rv.dependencies[key] = readWrap(newwrap.dependencies[key])
+      })
+
+      // fold in devDependencies if not already present, at top level
+      if (opts && opts.dev) {
+        Object.keys(data.devDependencies || {}).forEach(function (k) {
+          rv.dependencies[k] = rv.dependencies[k] || data.devDependencies[k]
+        })
+      }
+
+      log.verbose("readDependencies returned deps", rv.dependencies)
+      return cb(null, rv, newwrap.dependencies)
+    })
+  })
+}
+
+function readWrap (w) {
+  return (w.resolved) ? w.resolved
+       : (w.from && url.parse(w.from).protocol) ? w.from
+       : w.version
+}
+
+// if the -S|--save option is specified, then write installed packages
+// as dependencies to a package.json file.
+function save (where, installed, tree, pretty, hasArguments, cb) {
+  if (!hasArguments ||
+      !npm.config.get("save") &&
+      !npm.config.get("save-dev") &&
+      !npm.config.get("save-optional") ||
+      npm.config.get("global")) {
+    return cb(null, installed, tree, pretty)
+  }
+
+  var saveBundle = npm.config.get("save-bundle")
+  var savePrefix = npm.config.get("save-prefix")
+
+  // each item in the tree is a top-level thing that should be saved
+  // to the package.json file.
+  // The relevant tree shape is { <folder>: {what:<pkg>} }
+  var saveTarget = path.resolve(where, "package.json")
+
+  asyncMap(Object.keys(tree), function (k, cb) {
+    // if "from" is remote, git, or hosted, then save that instead.
+    var t = tree[k]
+      , f = npa(t.from)
+      , a = npa(t.what)
+      , w = [a.name, a.spec]
+
+
+    fs.stat(t.from, function (er){
+      if (!er) {
+        w[1] = "file:" + t.from
+      } else if (['hosted', 'git', 'remote'].indexOf(f.type) !== -1) {
+        w[1] = t.from
+      }
+      cb(null, [w])
+    })
+  }
+  , function (er, arr) {
+      var things = arr.reduce(function (set, k) {
+        var rangeDescriptor = semver.valid(k[1], true) &&
+                              semver.gte(k[1], "0.1.0", true) &&
+                              !npm.config.get("save-exact")
+                            ? savePrefix : ""
+        set[k[0]] = rangeDescriptor + k[1]
+        return set
+      }, {})
+
+
+    // don't use readJson, because we don't want to do all the other
+    // tricky npm-specific stuff that's in there.
+    fs.readFile(saveTarget, function (er, data) {
+      // ignore errors here, just don't save it.
+      try {
+        data = JSON.parse(data.toString("utf8"))
+      } catch (ex) {
+        er = ex
+      }
+
+      if (er) {
+        return cb(null, installed, tree, pretty)
+      }
+
+      var deps = npm.config.get("save-optional") ? "optionalDependencies"
+               : npm.config.get("save-dev") ? "devDependencies"
+               : "dependencies"
+
+      if (saveBundle) {
+        var bundle = data.bundleDependencies || data.bundledDependencies
+        delete data.bundledDependencies
+        if (!Array.isArray(bundle)) bundle = []
+        data.bundleDependencies = bundle.sort()
+      }
+
+      log.verbose("save", "saving", things)
+      data[deps] = data[deps] || {}
+      Object.keys(things).forEach(function (t) {
+        data[deps][t] = things[t]
+        if (saveBundle) {
+          var i = bundle.indexOf(t)
+          if (i === -1) bundle.push(t)
+          data.bundleDependencies = bundle.sort()
+        }
+      })
+
+      data[deps] = sortedObject(data[deps])
+
+      log.silly("save", "writing", saveTarget)
+      data = JSON.stringify(data, null, 2) + "\n"
+      writeFileAtomic(saveTarget, data, function (er) {
+        cb(er, installed, tree, pretty)
+      })
+    })
+  })
+}
+
+
+// Outputting *all* the installed modules is a bit confusing,
+// because the length of the path does not make it clear
+// that the submodules are not immediately require()able.
+// TODO: Show the complete tree, ls-style, but only if --long is provided
+function prettify (tree, installed) {
+  function red (set, kv) {
+    set[kv[0]] = kv[1]
+    return set
+  }
+
+  if (npm.config.get("json")) {
+    tree = Object.keys(tree).map(function (p) {
+      if (!tree[p]) return null
+      var what = npa(tree[p].what)
+        , name = what.name
+        , version = what.spec
+        , o = { name: name, version: version, from: tree[p].from }
+      o.dependencies = tree[p].children.map(function P (dep) {
+         var what = npa(dep.what)
+           , name = what.name
+           , version = what.spec
+           , o = { version: version, from: dep.from }
+         o.dependencies = dep.children.map(P).reduce(red, {})
+         return [name, o]
+       }).reduce(red, {})
+       return o
+    })
+
+    return JSON.stringify(tree, null, 2)
+  }
+  if (npm.config.get("parseable")) return parseable(installed)
+
+  return Object.keys(tree).map(function (p) {
+    return archy({ label: tree[p].what + " " + p
+                 , nodes: (tree[p].children || []).map(function P (c) {
+                     if (npm.config.get("long")) {
+                       return { label: c.what, nodes: c.children.map(P) }
+                     }
+                     var g = c.children.map(function (g) {
+                       return g.what
+                     }).join(", ")
+                     if (g) g = " (" + g + ")"
+                     return c.what + g
+                   })
+                 }, "", { unicode: npm.config.get("unicode") })
+  }).join("\n")
+}
+
+function parseable (installed) {
+  var long = npm.config.get("long")
+    , cwd = process.cwd()
+  return installed.map(function (item) {
+    return path.resolve(cwd, item[1]) +
+         ( long ?  ":" + item[0] : "" )
+  }).join("\n")
+}
+
+function treeify (installed) {
+  // each item is [what, where, parent, parentDir]
+  // If no parent, then report it.
+  // otherwise, tack it into the parent's children list.
+  // If the parent isn't a top-level then ignore it.
+  var whatWhere = installed.reduce(function (l, r) {
+    var parentDir = r[3]
+      , parent = r[2]
+      , where = r[1]
+      , what = r[0]
+      , from = r[4]
+    l[where] = { parentDir: parentDir
+               , parent: parent
+               , children: []
+               , where: where
+               , what: what
+               , from: from }
+    return l
+  }, {})
+
+  // log.warn("install", whatWhere, "whatWhere")
+  return Object.keys(whatWhere).reduce(function (l, r) {
+    var ww = whatWhere[r]
+    //log.warn("r, ww", [r, ww])
+    if (!ww.parent) {
+      l[r] = ww
+    } else {
+      var p = whatWhere[ww.parentDir]
+      if (p) p.children.push(ww)
+      else l[r] = ww
+    }
+    return l
+  }, {})
+}
+
+
+// just like installMany, but also add the existing packages in
+// where/node_modules to the family object.
+function installManyTop (what, where, context, cb_) {
+  function cb (er, d) {
+    if (context.explicit || er) return cb_(er, d)
+    // since this wasn't an explicit install, let's build the top
+    // folder, so that `npm install` also runs the lifecycle scripts.
+    npm.commands.build([where], false, true, function (er) {
+      return cb_(er, d)
+    })
+  }
+
+  if (context.explicit) return next()
+
+  var jsonPath = path.join(where, 'package.json')
+  log.verbose('installManyTop', 'reading for lifecycle', jsonPath)
+  readJson(jsonPath, log.warn, function (er, data) {
+    if (er) return next(er)
+    lifecycle(data, "preinstall", where, next)
+  })
+
+  function next (er) {
+    if (er) return cb(er)
+    installManyTop_(what, where, context, cb)
+  }
+}
+
+function installManyTop_ (what, where, context, cb) {
+  var nm = path.resolve(where, "node_modules")
+
+  fs.readdir(nm, function (er, pkgs) {
+    if (er) return installMany(what, where, context, cb)
+
+    var scopes = [], unscoped = []
+    pkgs.filter(function (p) {
+      return !p.match(/^[\._-]/)
+    }).forEach(function (p) {
+      // @names deserve deeper investigation
+      if (p[0] === "@") {
+        scopes.push(p)
+      }
+      else {
+        unscoped.push(p)
+      }
+    })
+
+    maybeScoped(scopes, nm, function (er, scoped) {
+      if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
+      // recombine unscoped with @scope/package packages
+      asyncMap(unscoped.concat(scoped).map(function (p) {
+        return path.resolve(nm, p, "package.json")
+      }), function (jsonPath, cb) {
+        log.verbose('installManyTop', 'reading scoped package data from', jsonPath)
+        readJson(jsonPath, log.info, function (er, data) {
+          if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
+          if (er) return cb(null, [])
+          cb(null, [[data.name, data.version]])
+        })
+      }, function (er, packages) {
+        // if there's nothing in node_modules, then don't freak out.
+        if (er) packages = []
+        // add all the existing packages to the family list.
+        // however, do not add to the ancestors list.
+        packages.forEach(function (p) {
+          context.family[p[0]] = p[1]
+        })
+        installMany(what, where, context, cb)
+      })
+    })
+  })
+}
+
+function maybeScoped (scopes, where, cb) {
+  // find packages in scopes
+  asyncMap(scopes, function (scope, cb) {
+    fs.readdir(path.resolve(where, scope), function (er, scoped) {
+      if (er) return cb(er)
+      var paths = scoped.map(function (p) {
+        return path.join(scope, p)
+      })
+      cb(null, paths)
+    })
+  }, cb)
+}
+
+function installMany (what, where, context, cb) {
+  // readDependencies takes care of figuring out whether the list of
+  // dependencies we'll iterate below comes from an existing shrinkwrap from a
+  // parent level, a new shrinkwrap at this level, or package.json at this
+  // level, as well as which shrinkwrap (if any) our dependencies should use.
+  var opt = { dev: npm.config.get("dev") }
+  readDependencies(context, where, opt, function (er, data, wrap) {
+    if (er) data = {}
+
+    var parent = data
+
+    // if we're explicitly installing "what" into "where", then the shrinkwrap
+    // for "where" doesn't apply. This would be the case if someone were adding
+    // a new package to a shrinkwrapped package. (data.dependencies will not be
+    // used here except to indicate what packages are already present, so
+    // there's no harm in using that.)
+    if (context.explicit) wrap = null
+
+    var deps = data.dependencies || {}
+    var devDeps = data.devDependencies || {}
+
+    // what is a list of things.
+    // resolve each one.
+    asyncMap( what
+            , targetResolver(where, context, deps, devDeps)
+            , function (er, targets) {
+
+      if (er) return cb(er)
+
+      var bundled = data.bundleDependencies || data.bundledDependencies || []
+      // only take the hit for readInstalled if there are probably bundled
+      // dependencies to read
+      if (bundled.length) {
+        readInstalled(where, { dev: true }, andBuildResolvedTree)
+      } else {
+        andBuildResolvedTree()
+      }
+
+      function andBuildResolvedTree (er, current) {
+        if (er) return cb(er)
+
+        // each target will be a data object corresponding
+        // to a package, folder, or whatever that is in the cache now.
+        var newPrev = Object.create(context.family)
+          , newAnc = Object.create(context.ancestors)
+
+        if (!context.root) {
+          newAnc[data.name] = data.version
+        }
+        bundled.forEach(function (bundle) {
+          var bundleData = current.dependencies[bundle]
+          if ((!bundleData || !bundleData.version) && current.devDependencies) {
+            log.verbose(
+              'installMany', bundle, 'was bundled with',
+              data.name + '@' + data.version +
+                ", but wasn't found in dependencies. Trying devDependencies"
+            )
+            bundleData = current.devDependencies[bundle]
+          }
+
+          if (!bundleData || !bundleData.version) {
+            log.warn(
+              'installMany', bundle, 'was bundled with',
+              data.name + '@' + data.version +
+                ", but bundled package wasn't found in unpacked tree"
+            )
+          } else {
+            log.verbose(
+              'installMany', bundle + '@' + bundleData.version,
+              'was bundled with', data.name + '@' + data.version
+            )
+            newPrev[bundle] = bundleData.version
+          }
+        })
+        targets.forEach(function (t) {
+          newPrev[t.name] = t.version
+        })
+        log.silly("install resolved", targets)
+        targets.filter(function (t) { return t }).forEach(function (t) {
+          log.info("install", "%s into %s", t._id, where)
+        })
+        asyncMap(targets, function (target, cb) {
+          log.info("installOne", target._id)
+          var wrapData = wrap ? wrap[target.name] : null
+          var newWrap = wrapData && wrapData.dependencies
+                      ? wrap[target.name].dependencies || {}
+                      : null
+          var newContext = { family: newPrev
+                           , ancestors: newAnc
+                           , parent: parent
+                           , explicit: false
+                           , wrap: newWrap }
+          installOne(target, where, newContext, cb)
+        }, cb)
+      }
+    })
+  })
+}
+
+function targetResolver (where, context, deps, devDeps) {
+  var alreadyInstalledManually = []
+    , resolveLeft = 0
+    , nm = path.resolve(where, "node_modules")
+    , parent = context.parent
+    , wrap = context.wrap
+
+  if (!context.explicit) readdir(nm)
+
+  function readdir(name) {
+    resolveLeft++
+    fs.readdir(name, function (er, inst) {
+      if (er) return resolveLeft--
+
+      // don't even mess with non-package looking things
+      inst = inst.filter(function (p) {
+        if (!p.match(/^[@\._-]/)) return true
+        // scoped packages
+        readdir(path.join(name, p))
+      })
+
+      asyncMap(inst, function (pkg, cb) {
+        var jsonPath = path.resolve(name, pkg, 'package.json')
+        log.verbose('targetResolver', 'reading package data from', jsonPath)
+        readJson(jsonPath, log.info, function (er, d) {
+          if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
+          // error means it's not a package, most likely.
+          if (er) return cb(null, [])
+
+          // if it's a bundled dep, then assume that anything there is valid.
+          // otherwise, make sure that it's a semver match with what we want.
+          var bd = parent.bundleDependencies
+          var isBundled = bd && bd.indexOf(d.name) !== -1
+          var expectedVersion = deps[d.name] || (devDeps && devDeps[d.name]) || "*"
+          var currentIsSatisfactory = semver.satisfies(d.version, expectedVersion, true)
+          if (isBundled || currentIsSatisfactory || deps[d.name] === d._resolved) {
+            return cb(null, d.name)
+          }
+
+          // see if the package had been previously linked
+          fs.lstat(path.resolve(nm, pkg), function(err, s) {
+            if (err) return cb(null, [])
+            if (s.isSymbolicLink()) {
+              return cb(null, d.name)
+            }
+
+            // something is there, but it's not satisfactory.  Clobber it.
+            return cb(null, [])
+          })
+        })
+      }, function (er, inst) {
+        // this is the list of things that are valid and should be ignored.
+        alreadyInstalledManually = alreadyInstalledManually.concat(inst)
+        resolveLeft--
+      })
+    })
+  }
+
+  var to = 0
+  return function resolver (what, cb) {
+    if (resolveLeft) return setTimeout(function () {
+      resolver(what, cb)
+    }, to++)
+
+    // now we know what's been installed here manually,
+    // or tampered with in some way that npm doesn't want to overwrite.
+    if (alreadyInstalledManually.indexOf(npa(what).name) !== -1) {
+      log.verbose("already installed", "skipping %s %s", what, where)
+      return cb(null, [])
+    }
+
+    // check for a version installed higher in the tree.
+    // If installing from a shrinkwrap, it must match exactly.
+    if (context.family[what]) {
+      log.verbose('install', what, 'is installed as', context.family[what])
+      if (wrap && wrap[what].version === context.family[what]) {
+        log.verbose("shrinkwrap", "use existing", what)
+        return cb(null, [])
+      }
+    }
+
+    // if it's identical to its parent, then it's probably someone
+    // doing `npm install foo` inside of the foo project.  Print
+    // a warning, and skip it.
+    if (parent && parent.name === what && !npm.config.get("force")) {
+      log.warn("install", "Refusing to install %s as a dependency of itself"
+              , what)
+      return cb(null, [])
+    }
+
+    if (wrap) {
+      var name = npa(what).name
+      if (wrap[name]) {
+        var wrapTarget = readWrap(wrap[name])
+        what = name + "@" + wrapTarget
+      } else {
+        log.verbose("shrinkwrap", "skipping %s (not in shrinkwrap)", what)
+      }
+    } else if (deps[what]) {
+      what = what + "@" + deps[what]
+    }
+
+    // This is where we actually fetch the package, if it's not already
+    // in the cache.
+    // If it's a git repo, then we want to install it, even if the parent
+    // already has a matching copy.
+    // If it's not a git repo, and the parent already has that pkg, then
+    // we can skip installing it again.
+    var pkgroot = path.resolve(npm.prefix, (parent && parent._from) || "")
+    cache.add(what, null, pkgroot, false, function (er, data) {
+      if (er && parent && parent.optionalDependencies &&
+          parent.optionalDependencies.hasOwnProperty(npa(what).name)) {
+        log.warn("optional dep failed, continuing", what)
+        log.verbose("optional dep failed, continuing", [what, er])
+        return cb(null, [])
+      }
+
+      var type = npa(what).type
+      var isGit = type === "git" || type === "hosted"
+
+      if (!er &&
+          data &&
+          !context.explicit &&
+          context.family[data.name] === data.version &&
+          !npm.config.get("force") &&
+          !isGit) {
+        log.info("already installed", data.name + "@" + data.version)
+        return cb(null, [])
+      }
+
+
+      if (data && !data._from) data._from = what
+      if (er && parent && parent.name) er.parent = parent.name
+      return cb(er, data || [])
+    })
+  }
+}
+
+// we've already decided to install this.  if anything's in the way,
+// then uninstall it first.
+function installOne (target, where, context, cb) {
+  // the --link flag makes this a "link" command if it's at the
+  // the top level.
+  var isGit = false
+  var type = npa(target._from).type
+  if (target && target._from) isGit = type === 'git' || type === 'hosted'
+
+  if (where === npm.prefix && npm.config.get("link")
+      && !npm.config.get("global") && !isGit) {
+    return localLink(target, where, context, cb)
+  }
+  installOne_(target, where, context, function (er, installedWhat) {
+
+    // check if this one is optional to its parent.
+    if (er && context.parent && context.parent.optionalDependencies &&
+        context.parent.optionalDependencies.hasOwnProperty(target.name)) {
+      log.warn("optional dep failed, continuing", target._id)
+      log.verbose("optional dep failed, continuing", [target._id, er])
+      er = null
+    }
+
+    cb(er, installedWhat)
+  })
+
+}
+
+function localLink (target, where, context, cb) {
+  log.verbose("localLink", target._id)
+  var jsonPath = path.resolve(npm.globalDir, target.name , 'package.json')
+  var parent = context.parent
+
+  log.verbose('localLink', 'reading data to link', target.name, 'from', jsonPath)
+  readJson(jsonPath, log.warn, function (er, data) {
+    function thenLink () {
+      npm.commands.link([target.name], function (er, d) {
+        log.silly("localLink", "back from link", [er, d])
+        cb(er, [resultList(target, where, parent && parent._id)])
+      })
+    }
+
+    if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
+    if (er || data._id === target._id) {
+      if (er) {
+        install( path.resolve(npm.globalDir, "..")
+               , target._id
+               , function (er) {
+          if (er) return cb(er, [])
+          thenLink()
+        })
+      } else thenLink()
+    } else {
+      log.verbose("localLink", "install locally (no link)", target._id)
+      installOne_(target, where, context, cb)
+    }
+  })
+}
+
+function resultList (target, where, parentId) {
+  var nm = path.resolve(where, "node_modules")
+    , targetFolder = path.resolve(nm, target.name)
+    , prettyWhere = where
+
+  if (!npm.config.get("global")) {
+    prettyWhere = path.relative(process.cwd(), where)
+  }
+
+  if (prettyWhere === ".") prettyWhere = null
+
+  if (!npm.config.get("global")) {
+    // print out the folder relative to where we are right now.
+    targetFolder = path.relative(process.cwd(), targetFolder)
+  }
+
+  return [ target._id
+         , targetFolder
+         , prettyWhere && parentId
+         , parentId && prettyWhere
+         , target._from ]
+}
+
+var installed = Object.create(null)
+
+function installOne_ (target, where, context, cb_) {
+  var nm = path.resolve(where, "node_modules")
+    , targetFolder = path.resolve(nm, target.name)
+    , prettyWhere = path.relative(process.cwd(), where)
+    , parent = context.parent
+
+  if (prettyWhere === ".") prettyWhere = null
+
+  cb_ = inflight(target.name + ":" + where, cb_)
+  if (!cb_) {
+    return log.verbose("installOne", "of", target.name, "to", where, "already in flight; waiting")
+  }
+  else {
+    log.verbose("installOne", "of", target.name, "to", where, "not in flight; installing")
+  }
+
+  function cb(er, data) {
+    unlock(nm, target.name, function () { cb_(er, data) })
+  }
+
+  lock(nm, target.name, function (er) {
+    if (er) return cb(er)
+
+    if (targetFolder in installed) {
+      log.error("install", "trying to install", target.version, "to", targetFolder)
+      log.error("install", "but already installed versions", installed[targetFolder])
+      installed[targetFolder].push(target.version)
+    }
+    else {
+      installed[targetFolder] = [target.version]
+    }
+
+    var force = npm.config.get("force")
+      , nodeVersion = npm.config.get("node-version")
+      , strict = npm.config.get("engine-strict")
+      , c = npmInstallChecks
+
+    chain(
+        [ [c.checkEngine, target, npm.version, nodeVersion, force, strict]
+        , [c.checkPlatform, target, force]
+        , [c.checkCycle, target, context.ancestors]
+        , [c.checkGit, targetFolder]
+        , [write, target, targetFolder, context] ]
+      , function (er, d) {
+          if (er) return cb(er)
+
+          d.push(resultList(target, where, parent && parent._id))
+          cb(er, d)
+        }
+      )
+  })
+}
+
+function write (target, targetFolder, context, cb_) {
+  var up = npm.config.get("unsafe-perm")
+    , user = up ? null : npm.config.get("user")
+    , group = up ? null : npm.config.get("group")
+    , family = context.family
+
+  function cb (er, data) {
+    // cache.unpack returns the data object, and all we care about
+    // is the list of installed packages from that last thing.
+    if (!er) return cb_(er, data)
+
+    if (npm.config.get("rollback") === false) return cb_(er)
+    npm.rollbacks.push(targetFolder)
+    cb_(er, data)
+  }
+
+  var bundled = []
+
+  log.silly("install write", "writing", target.name, target.version, "to", targetFolder)
+  chain(
+    [ [ cache.unpack, target.name, target.version, targetFolder, null, null, user, group ],
+      function writePackageJSON (cb) {
+        var jsonPath = path.resolve(targetFolder, 'package.json')
+        log.verbose('write', 'writing to', jsonPath)
+        writeFileAtomic(jsonPath, JSON.stringify(target, null, 2) + '\n', cb)
+      },
+      [ lifecycle, target, "preinstall", targetFolder ],
+      function collectBundled (cb) {
+        if (!target.bundleDependencies) return cb()
+
+        var bd = path.resolve(targetFolder, "node_modules")
+        fs.readdir(bd, function (er, b) {
+          // nothing bundled, maybe
+          if (er) return cb()
+          bundled = b || []
+          cb()
+        })
+      } ]
+
+    // nest the chain so that we can throw away the results returned
+    // up until this point, since we really don't care about it.
+    , function X (er) {
+      if (er) return cb(er)
+
+      // before continuing to installing dependencies, check for a shrinkwrap.
+      var opt = { dev: npm.config.get("dev") }
+      readDependencies(context, targetFolder, opt, function (er, data, wrap) {
+        if (er) return cb(er);
+        var deps = prepareForInstallMany(data, "dependencies", bundled, wrap,
+            family)
+        var depsTargetFolder = targetFolder
+        var depsContext = { family: family
+                          , ancestors: context.ancestors
+                          , parent: target
+                          , explicit: false
+                          , wrap: wrap }
+
+        var actions =
+          [ [ installManyAndBuild, deps, depsTargetFolder, depsContext ] ]
+
+        // FIXME: This is an accident waiting to happen!
+        //
+        // 1. If multiple children at the same level of the tree share a
+        //    peerDependency that's not in the parent's dependencies, because
+        //    the peerDeps don't get added to the family, they will keep
+        //    getting reinstalled (worked around by inflighting installOne).
+        // 2. The installer can't safely build at the parent level because
+        //    that's already being done by the parent's installAndBuild. This
+        //    runs the risk of the peerDependency never getting built.
+        //
+        //  The fix: Don't install peerDependencies; require them to be
+        //  included as explicit dependencies / devDependencies, and warn
+        //  or error when they're missing. See #5080 for more arguments in
+        //  favor of killing implicit peerDependency installs with fire.
+        var peerDeps = prepareForInstallMany(data, "peerDependencies", bundled,
+            wrap, family)
+        peerDeps.forEach(function (pd) {
+            warnPeers([
+              "The peer dependency "+pd+" included from "+data.name+" will no",
+              "longer be automatically installed to fulfill the peerDependency ",
+              "in npm 3+. Your application will need to depend on it explicitly."
+            ], pd+","+data.name)
+        })
+
+        // Package scopes cause an addditional tree level which needs to be
+        // considered when resolving a peerDependency's target folder.
+        var pdTargetFolder
+        if (npa(target.name).scope) {
+          pdTargetFolder = path.resolve(targetFolder, '../../..')
+        } else {
+          pdTargetFolder = path.resolve(targetFolder, '../..')
+        }
+
+        var pdContext = context
+        if (peerDeps.length > 0) {
+          actions.push(
+            [ installMany, peerDeps, pdTargetFolder, pdContext ]
+          )
+        }
+
+        chain(actions, cb)
+      })
+    })
+}
+
+function installManyAndBuild (deps, targetFolder, context, cb) {
+  installMany(deps, targetFolder, context, function (er, d) {
+    log.verbose("about to build", targetFolder)
+    if (er) return cb(er)
+    npm.commands.build( [targetFolder]
+                      , npm.config.get("global")
+                      , true
+                      , function (er) { return cb(er, d) })
+  })
+}
+
+function prepareForInstallMany (packageData, depsKey, bundled, wrap, family) {
+  var deps = Object.keys(packageData[depsKey] || {})
+
+  // don't install bundleDependencies, unless they're missing.
+  if (packageData.bundleDependencies) {
+    deps = deps.filter(function (d) {
+      return packageData.bundleDependencies.indexOf(d) === -1 ||
+             bundled.indexOf(d) === -1
+    })
+  }
+
+  return deps.filter(function (d) {
+    // prefer to not install things that are satisfied by
+    // something in the "family" list, unless we're installing
+    // from a shrinkwrap.
+    if (depsKey !== "peerDependencies" && wrap) return true
+    if (semver.validRange(family[d], true)) {
+      return !semver.satisfies(family[d], packageData[depsKey][d], true)
+    }
+    return true
+  }).map(function (d) {
+    var v = packageData[depsKey][d]
+    var t = d + "@" + v
+    log.silly("prepareForInstallMany", "adding", t, "from", packageData.name, depsKey)
+    return t
+  })
+}