Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

Commit

Permalink
support abbreviated versions of commands
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Oct 28, 2010
1 parent 4b8fb10 commit 4f8b35e
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 38 deletions.
106 changes: 106 additions & 0 deletions lib/utils/abbrev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@

module.exports = exports = abbrev.abbrev = abbrev

abbrev.monkeyPatch = monkeyPatch

function monkeyPatch () {
Array.prototype.abbrev = function () { return abbrev(this) }
Object.prototype.abbrev = function () { return abbrev(Object.keys(this)) }
}

function abbrev (list) {
if (arguments.length !== 1 || !Array.isArray(list)) {
list = Array.prototype.slice.call(arguments, 0)
}
for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
}

// sort them lexicographically, so that they're next to their nearest kin
args = args.sort(lexSort)

// walk through each, seeing how much it has in common with the next and previous
var abbrevs = {}
, prev = ""
for (var i = 0, l = args.length ; i < l ; i ++) {
var current = args[i]
, next = args[i + 1] || ""
, nextMatches = true
, prevMatches = true
if (current === next) continue
for (var j = 0, cl = current.length ; j < cl ; j ++) {
var curChar = current.charAt(j)
nextMatches = nextMatches && curChar === next.charAt(j)
prevMatches = prevMatches && curChar === prev.charAt(j)
if (nextMatches || prevMatches) continue
else {
j ++
break
}
}
prev = current
if (j === cl) {
abbrevs[current] = current
continue
}
for (var a = current.substr(0, j) ; j <= cl ; j ++) {
abbrevs[a] = current
a += current.charAt(j)
}
}
return abbrevs
}

function lexSort (a, b) {
return a === b ? 0 : a > b ? 1 : -1
}


// tests
if (module === require.main) {

var assert = require("assert")
, sys
sys = require(process.binding("native").util ? "util" : "sys")

console.log("running tests")
function test (list, expect) {
var actual = abbrev(list)
assert.deepEqual(actual, expect,
"abbrev("+sys.inspect(list)+") === " + sys.inspect(expect) + "\n"+
"actual: "+sys.inspect(actual))
actual = abbrev.apply(exports, list)
assert.deepEqual(abbrev.apply(exports, list), expect,
"abbrev("+list.map(JSON.stringify).join(",")+") === " + sys.inspect(expect) + "\n"+
"actual: "+sys.inspect(actual))
}

test([ "ruby", "ruby", "rules", "rules", "rules" ],
{ rub: 'ruby'
, ruby: 'ruby'
, rul: 'rules'
, rule: 'rules'
, rules: 'rules'
})
test(["fool", "foom", "pool", "pope"],
{ fool: 'fool'
, foom: 'foom'
, poo: 'pool'
, pool: 'pool'
, pop: 'pope'
, pope: 'pope'
})
test(["a", "ab", "abc", "abcd", "abcde", "acde"],
{ a: 'a'
, ab: 'ab'
, abc: 'abc'
, abcd: 'abcd'
, abcde: 'abcde'
, ac: 'acde'
, acd: 'acde'
, acde: 'acde'
})

console.log("pass")

}
92 changes: 54 additions & 38 deletions npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var npm = exports
, fs = require("./lib/utils/graceful-fs")
, path = require("path")
, mkdir = require("./lib/utils/mkdir-p")
, abbrev = require("./lib/utils/abbrev")

npm.commands = {}
npm.ELIFECYCLE = {}
Expand All @@ -26,44 +27,59 @@ try {
}

var commandCache = {}
; [ "install"
, "activate"
, "deactivate"
, "uninstall"
, "build"
, "link"
, "publish"
, "tag"
, "adduser"
, "config"
, "help"
, "cache"
, "test"
, "stop"
, "start"
, "restart"
, "unpublish"
, "list"
, "ls"
, "rm"
, "owner"
, "update"
, "update-dependents"
, "view"
, "repl"
, "rebuild"
, "bundle"
, "outdated"
, "init"
].forEach(function (c) {
Object.defineProperty(npm.commands, c, { get : function () {
c = c === "list" ? "ls"
: c === "rm" ? "uninstall"
: c
if (c in commandCache) return commandCache[c]
return commandCache[c] = require(__dirname+"/lib/"+c)
}, enumerable: true})
})
// short names for common things
, aliases = { "rm" : "uninstall"
, "r" : "uninstall"
, "rb" : "rebuild"
, "bn" : "bundle"
, "list" : "ls"
, "ln" : "link"
, "i" : "install"
, "u" : "update"
, "up" : "update"
, "c" : "config"
}
, aliasNames = Object.keys(aliases)
// these are filenames in ./lib
, cmdList = [ "install"
, "activate"
, "deactivate"
, "uninstall"
, "build"
, "link"
, "publish"
, "tag"
, "adduser"
, "config"
, "help"
, "cache"
, "test"
, "stop"
, "start"
, "restart"
, "unpublish"
, "ls"
, "owner"
, "update"
, "update-dependents"
, "view"
, "repl"
, "rebuild"
, "bundle"
, "outdated"
, "init"
]
, fullList = cmdList.concat(aliasNames)
, abbrevs = abbrev(fullList)

Object.keys(abbrevs).forEach(function (c) {
Object.defineProperty(npm.commands, c, { get : function () {
var a = abbrevs[c]
if (aliases[a]) a = aliases[a]
if (commandCache[a]) return commandCache[a]
return commandCache[a] = require(__dirname+"/lib/"+a)
}, enumerable: fullList.indexOf(c) !== -1 })
})

var loaded = false
npm.load = function (conf, cb) {
Expand Down

0 comments on commit 4f8b35e

Please sign in to comment.