diff options
author | isaacs <i@izs.me> | 2012-07-11 02:59:23 +0400 |
---|---|---|
committer | isaacs <i@izs.me> | 2012-07-11 03:01:05 +0400 |
commit | 3f3a0f91d71f46b0f62cf4879a990b90e2ca5f84 (patch) | |
tree | f76581d8bd7fcd42ad07ab141fa310697778b13f | |
parent | c2b9940a0de5b0db02e184485e9861f56233a8d4 (diff) |
Positional args for ls
-rw-r--r-- | doc/cli/list.md | 20 | ||||
-rw-r--r-- | lib/ls.js | 77 |
2 files changed, 75 insertions, 22 deletions
diff --git a/doc/cli/list.md b/doc/cli/list.md index 93d86cd83..3dd709b62 100644 --- a/doc/cli/list.md +++ b/doc/cli/list.md @@ -3,20 +3,26 @@ npm-ls(1) -- List installed packages ## SYNOPSIS - npm list - npm ls - npm la - npm ll + npm list [<pkg> ...] + npm ls [<pkg> ...] + npm la [<pkg> ...] + npm ll [<pkg> ...] ## DESCRIPTION This command will print to stdout all the versions of packages that are installed, as well as their dependencies, in a tree-structure. -It does not take positional arguments, though you may set config flags -like with any other command, such as `-g` to list global packages. +Positional arguments are `name@version-range` identifiers, which will +limit the results to only the paths to the packages named. Note that +nested packages will *also* show the paths to the specified packages. +For example, running `npm ls promzard` in npm's source tree will show: -It will print out extraneous, missing, and invalid packages. + npm@@VERSION@ /path/to/npm + └─┬ init-package-json@0.0.4 + └── promzard@0.1.5 + +It will show print out extraneous, missing, and invalid packages. When run as `ll` or `la`, it shows extended information by default. @@ -13,22 +13,30 @@ var npm = require("./npm.js") , log = require("npmlog") , path = require("path") , archy = require("archy") + , semver = require("semver") ls.usage = "npm ls" +ls.completion = require("./utils/completion/installed-deep.js") + function ls (args, silent, cb) { if (typeof cb !== "function") cb = silent, silent = false - if (args.length) { - // TODO: it would actually be nice to maybe show the locally - // installed packages only matching the argument names. - log.warn("ls doesn't take positional args. Try the 'search' command") - } - var dir = path.resolve(npm.dir, "..") + // npm ls 'foo@~1.3' bar 'baz@<2' + if (!args) args = [] + else args = args.map(function (a) { + var nv = a.split("@") + , name = nv.shift() + , ver = semver.validRange(nv.join("@")) || "" + + return [ name, ver ] + }) + readInstalled(dir, npm.config.get("depth"), function (er, data) { - var lite = getLite(bfsify(data)) + var bfs = bfsify(data, args) + , lite = getLite(bfs) if (er || silent) return cb(er, data, lite) var long = npm.config.get("long") @@ -36,7 +44,7 @@ function ls (args, silent, cb) { , out if (json) { var seen = [] - var d = long ? bfsify(data) : lite + var d = long ? bfs : lite // the raw data can be circular out = JSON.stringify(d, function (k, o) { if (typeof o === "object") { @@ -46,14 +54,19 @@ function ls (args, silent, cb) { return o }, 2) } else if (npm.config.get("parseable")) { - out = makeParseable(bfsify(data), long, dir) + out = makeParseable(bfs, long, dir) } else if (data) { - out = makeArchy(bfsify(data), long, dir) + out = makeArchy(bfs, long, dir) } output.write(out, function (er) { cb(er, data, lite) }) }) } +// only include +function filter (data, args) { + +} + function alphasort (a, b) { a = a.toLowerCase() b = b.toLowerCase() @@ -124,7 +137,7 @@ function getLite (data, noname) { return lite } -function bfsify (root, current, queue, seen) { +function bfsify (root, args, current, queue, seen) { // walk over the data, and turn it from this: // +-- a // | `-- b @@ -134,6 +147,7 @@ function bfsify (root, current, queue, seen) { // +-- a // `-- b // which looks nicer + args = args || [] current = current || root queue = queue || [] seen = seen || [root] @@ -153,10 +167,37 @@ function bfsify (root, current, queue, seen) { queue.push(dep) seen.push(dep) }) - if (!queue.length) return root - return bfsify(root, queue.shift(), queue, seen) + + if (!queue.length) { + // if there were args, then only show the paths to found nodes. + return filterFound(root, args) + } + return bfsify(root, args, queue.shift(), queue, seen) } +function filterFound (root, args) { + if (!args.length) return root + var deps = root.dependencies + if (deps) Object.keys(deps).forEach(function (d) { + var dep = filterFound(deps[d], args) + + // see if this one itself matches + var found = false + for (var i = 0; !found && i < args.length; i ++) { + if (d === args[i][0]) { + found = semver.satisfies(dep.version, args[i][1]) + } + } + // included explicitly + if (found) dep._found = true + // included because a child was included + if (dep._found && !root._found) root._found = 1 + // not included + if (!dep._found) delete deps[d] + }) + if (!root._found) root._found = false + return root +} function makeArchy (data, long, dir) { var out = makeArchy_(data, long, dir, 0) @@ -178,8 +219,11 @@ function makeArchy_ (data, long, dir, depth, parent, d) { var out = {} // the top level is a bit special. - out.label = data._id ? data._id + " " : "" - if (data.link) out.label += "-> " + data.link + out.label = data._id || "" + if (data._found === true && data._id) { + out.label = "\033[33;40m" + out.label.trim() + "\033[m " + } + if (data.link) out.label += " -> " + data.link if (data.invalid) { if (data.realName !== data.name) out.label += " ("+data.realName+")" @@ -237,10 +281,13 @@ function makeParseable (data, long, dir, depth, parent, d) { .sort(alphasort).map(function (d) { return makeParseable(data.dependencies[d], long, dir, depth + 1, data, d) })) + .filter(function (x) { return x }) .join("\n") } function makeParseable_ (data, long, dir, depth, parent, d) { + if (data.hasOwnProperty("_found") && data._found !== true) return "" + if (typeof data === "string") { if (data.depth < npm.config.get("depth")) { var p = parent.link || parent.path |