1 var url = require("url")
2 var assert = require("assert")
3 var util = require("util")
4 var semver = require("semver")
5 var path = require("path")
6 var HostedGit = require("hosted-git-info")
10 var isWindows = process.platform === "win32" || global.FAKE_WINDOWS
11 var slashRe = isWindows ? /\\|[/]/ : /[/]/
13 var parseName = /^(?:@([^/]+?)[/])?([^/]+?)$/
14 var nameAt = /^(@([^/]+?)[/])?([^/]+?)@/
15 var debug = util.debuglog ? util.debuglog("npa")
16 : /\bnpa\b/i.test(process.env.NODE_DEBUG || "")
18 console.error("NPA: " + util.format.apply(util, arguments).split("\n").join("\nNPA: "))
21 function validName (name) {
23 debug("not a name %j", name)
27 if (!n || n.charAt(0) === "."
28 || !n.match(/^[a-zA-Z0-9]/)
29 || n.match(/[/()&?#|<>@:%\s\\*'"!~`]/)
30 || n.toLowerCase() === "node_modules"
31 || n !== encodeURIComponent(n)
32 || n.toLowerCase() === "favicon.ico") {
33 debug("not a valid name %j", name)
40 assert.equal(typeof arg, "string")
47 // See if it's something like foo@...
48 var nameparse = arg.match(nameAt)
49 debug("nameparse", nameparse)
50 if (nameparse && validName(nameparse[3]) &&
51 (!nameparse[2] || validName(nameparse[2]))) {
52 res.name = (nameparse[1] || "") + nameparse[3]
54 res.scope = "@" + nameparse[2]
55 arg = arg.substr(nameparse[0].length)
63 var urlparse = url.parse(arg)
64 debug("urlparse", urlparse)
66 // windows paths look like urls
68 if (isWindows && urlparse && urlparse.protocol &&
69 urlparse.protocol.match(/^[a-zA-Z]:$/)) {
70 debug("windows url-ish local path", urlparse)
74 if (urlparse.protocol || HostedGit.fromUrl(arg)) {
75 return parseUrl(res, arg, urlparse)
78 // at this point, it's not a url, and not hosted
79 // If it's a valid name, and doesn't already have a name, then assume
82 // if it's got / chars in it, then assume that it's local.
85 if (arg == '') arg = 'latest'
86 var version = semver.valid(arg, true)
87 var range = semver.validRange(arg, true)
95 } else if (slashRe.test(arg)) {
102 var p = arg.match(parseName)
103 if (p && validName(p[2]) &&
104 (!p[1] || validName(p[1]))) {
110 res.scope = "@" + p[1]
119 function parseLocal (res, arg) {
120 // turns out nearly every character is allowed in fs paths
121 if (/\0/.test(arg)) {
122 throw new Error("Invalid Path: " + JSON.stringify(arg))
125 res.spec = path.resolve(arg)
128 function parseUrl (res, arg, urlparse) {
129 var gitHost = HostedGit.fromUrl(arg)
132 res.spec = gitHost.toString(),
136 sshUrl: gitHost.sshurl(),
137 httpsUrl: gitHost.https(),
138 gitUrl: gitHost.git(),
139 shortcut: gitHost.shortcut(),
140 directUrl: gitHost.file("package.json")
144 // check the protocol, and then see if it's git or not
145 switch (urlparse.protocol) {
154 res.spec = arg.replace(/^git[+]/, "")
165 res.spec = urlparse.pathname
169 throw new Error("Unsupported URL Type: " + arg)
178 if (!(this instanceof Result)) return new Result
180 Result.prototype.name = null
181 Result.prototype.type = null
182 Result.prototype.spec = null
183 Result.prototype.raw = null
184 Result.prototype.hosted = null