diff options
Diffstat (limited to 'node_modules/read-installed/read-installed.js')
-rw-r--r-- | node_modules/read-installed/read-installed.js | 147 |
1 files changed, 84 insertions, 63 deletions
diff --git a/node_modules/read-installed/read-installed.js b/node_modules/read-installed/read-installed.js index 3574e6c2f..713d2633c 100644 --- a/node_modules/read-installed/read-installed.js +++ b/node_modules/read-installed/read-installed.js @@ -101,6 +101,8 @@ var url = require("url") var util = require("util") var extend = require("util-extend") +var debug = require("debuglog")("read-installed") + module.exports = readInstalled function readInstalled (folder, opts, cb) { @@ -120,23 +122,26 @@ function readInstalled (folder, opts, cb) { opts.log = function () {} opts.dev = !!opts.dev + opts.realpathSeen = {} + opts.findUnmetSeen = [] + readInstalled_(folder, null, null, null, 0, opts, function (er, obj) { if (er) return cb(er) // now obj has all the installed things, where they're installed // figure out the inheritance links, now that the object is built. resolveInheritance(obj, opts) - markExtraneous(obj) + unmarkExtraneous(obj, opts) cb(null, obj) }) } -var rpSeen = {} function readInstalled_ (folder, parent, name, reqver, depth, opts, cb) { var installed , obj , real , link + , realpathSeen = opts.realpathSeen fs.readdir(path.resolve(folder, "node_modules"), function (er, i) { // error indicates that nothing is installed here @@ -161,7 +166,7 @@ function readInstalled_ (folder, parent, name, reqver, depth, opts, cb) { return next(er) } fs.realpath(folder, function (er, rp) { - //console.error("realpath(%j) = %j", folder, rp) + debug("realpath(%j) = %j", folder, rp) real = rp if (st.isSymbolicLink()) link = rp next(er) @@ -176,10 +181,10 @@ function readInstalled_ (folder, parent, name, reqver, depth, opts, cb) { errState = er return cb(null, []) } - //console.error('next', installed, obj && typeof obj, name, real) + debug('next', installed, obj && typeof obj, name, real) if (!installed || !obj || !real || called) return called = true - if (rpSeen[real]) return cb(null, rpSeen[real]) + if (realpathSeen[real]) return cb(null, realpathSeen[real]) if (obj === true) { obj = {dependencies:{}, path:folder} installed.forEach(function (i) { obj.dependencies[i] = "*" }) @@ -188,6 +193,9 @@ function readInstalled_ (folder, parent, name, reqver, depth, opts, cb) { obj.realName = name || obj.name obj.dependencies = obj.dependencies || {} + // At this point, figure out what dependencies we NEED to get met + obj._dependencies = copy(obj.dependencies) + // "foo":"http://blah" and "foo":"latest" are always presumed valid if (reqver && semver.validRange(reqver, true) @@ -195,21 +203,17 @@ function readInstalled_ (folder, parent, name, reqver, depth, opts, cb) { obj.invalid = true } - if (parent) { - var deps = parent.dependencies || {} - var inDeps = name in deps - var devDeps = parent.devDependencies || {} - var inDev = opts.dev && (name in devDeps) - if (!inDeps && !inDev) { - obj.extraneous = true - } - } + // Mark as extraneous at this point. + // This will be un-marked in unmarkExtraneous, where we mark as + // not-extraneous everything that is required in some way from + // the root object. + obj.extraneous = true obj.path = obj.path || folder obj.realPath = real obj.link = link if (parent && !obj.link) obj.parent = parent - rpSeen[real] = obj + realpathSeen[real] = obj obj.depth = depth //if (depth >= opts.depth) return cb(null, obj) asyncMap(installed, function (pkg, cb) { @@ -259,50 +263,45 @@ function resolveInheritance (obj, opts) { findUnmet(obj.dependencies[dep], opts) }) Object.keys(obj.dependencies).forEach(function (dep) { - resolveInheritance(obj.dependencies[dep], opts) + if (typeof obj.dependencies[dep] === "object") { + resolveInheritance(obj.dependencies[dep], opts) + } else { + debug("unmet dep! %s %s@%s", obj.name, dep, obj.dependencies[dep]) + } }) findUnmet(obj, opts) } // find unmet deps by walking up the tree object. // No I/O -var fuSeen = [] function findUnmet (obj, opts) { - if (fuSeen.indexOf(obj) !== -1) return - fuSeen.push(obj) - //console.error("find unmet", obj.name, obj.parent && obj.parent.name) + var findUnmetSeen = opts.findUnmetSeen + if (findUnmetSeen.indexOf(obj) !== -1) return + findUnmetSeen.push(obj) + debug("find unmet parent=%s obj=", obj.parent && obj.parent.name, obj.name || obj) var deps = obj.dependencies = obj.dependencies || {} - //console.error(deps) + debug(deps) Object.keys(deps) .filter(function (d) { return typeof deps[d] === "string" }) .forEach(function (d) { - //console.error("find unmet", obj.name, d, deps[d]) - var r = obj.parent - , found = null - while (r && !found && typeof deps[d] === "string") { - // if r is a valid choice, then use that. - found = r.dependencies[d] - if (!found && r.realName === d) found = r - - if (!found) { - r = r.link ? null : r.parent - continue - } - // "foo":"http://blah" and "foo":"latest" are always presumed valid - if ( typeof deps[d] === "string" - && semver.validRange(deps[d], true) - && !semver.satisfies(found.version, deps[d], true)) { - // the bad thing will happen - opts.log("unmet dependency", obj.path + " requires "+d+"@'"+deps[d] - +"' but will load\n" - +found.path+",\nwhich is version "+found.version - ) - found.invalid = true - } + var found = findDep(obj, d) + debug("finding dep %j", d, found && found.name || found) + // "foo":"http://blah" and "foo":"latest" are always presumed valid + if (typeof deps[d] === "string" && + semver.validRange(deps[d], true) && + found && + !semver.satisfies(found.version, deps[d], true)) { + // the bad thing will happen + opts.log( "unmet dependency" + , obj.path + " requires "+d+"@'"+deps[d] + + "' but will load\n" + + found.path+",\nwhich is version "+found.version ) + found.invalid = true + } + if (found) { deps[d] = found } - }) var peerDeps = obj.peerDependencies = obj.peerDependencies || {} @@ -329,34 +328,56 @@ function findUnmet (obj, opts) { obj.dependencies[d] = peerDeps[d] } else if (!semver.satisfies(dependency.version, peerDeps[d], true)) { dependency.peerInvalid = true - } else { - dependency.extraneous = dependency.extraneous || false } }) return obj } -function recursivelyMarkExtraneous (obj, extraneous) { - // stop recursion if we're not changing anything - if (obj.extraneous === extraneous) return +function unmarkExtraneous (obj, opts) { + // Mark all non-required deps as extraneous. + // start from the root object and mark as non-extraneous all modules + // that haven't been previously flagged as extraneous then propagate + // to all their dependencies + + obj.extraneous = false + var deps = obj._dependencies + if (opts.dev && obj.devDependencies) { + Object.keys(obj.devDependencies).forEach(function (k) { + deps[k] = obj.devDependencies[k] + }) + } - obj.extraneous = extraneous - var deps = obj.dependencies = obj.dependencies || {} - Object.keys(deps).forEach(function(d){ - recursivelyMarkExtraneous(deps[d], extraneous) - }); + if (obj.peerDependencies) { + Object.keys(obj.peerDependencies).forEach(function (k) { + deps[k] = obj.peerDependencies[k] + }) + } + + Object.keys(deps).forEach(function (d) { + var dep = findDep(obj, d) + if (dep && dep.extraneous) { + unmarkExtraneous(dep, opts) + } + }) } -function markExtraneous (obj) { - // start from the root object and mark as non-extraneous all modules that haven't been previously flagged as - // extraneous then propagate to all their dependencies - var deps = obj.dependencies = obj.dependencies || {} - Object.keys(deps).forEach(function(d){ - if (!deps[d].extraneous){ - recursivelyMarkExtraneous(deps[d], false); +// Find the one that will actually be loaded by require() +// so we can make sure it's valid etc. +function findDep (obj, d) { + var r = obj + , found = null + while (r && !found) { + // if r is a valid choice, then use that. + // kinda weird if a pkg depends on itself, but after the first + // iteration of this loop, it indicates a dep cycle. + if (typeof r.dependencies[d] === "object") { + found = r.dependencies[d] } - }); + if (!found && r.realName === d) found = r + r = r.link ? null : r.parent + } + return found } function copy (obj) { |