function unpublish (args, cb) { if (args.length > 1) return cb(unpublish.usage) var thing = args.length ? npa(args[0]) : {} , project = thing.name , version = thing.rawSpec log.silly("unpublish", "args[0]", args[0]) log.silly("unpublish", "thing", thing) if (!version && !npm.config.get("force")) { return cb("Refusing to delete entire project.\n" + "Run with --force to do this.\n" + unpublish.usage) } if (!project || path.resolve(project) === npm.prefix) { // if there's a package.json in the current folder, then // read the package name and version out of that. var cwdJson = path.join(process.cwd(), "package.json") return readJson(cwdJson, function (er, data) { if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er) if (er) return cb("Usage:\n" + unpublish.usage) gotProject(data.name, data.version, cb) }) } return gotProject(project, version, cb) }
else args = args.map(function (a) { var p = npa(a) , name = p.name , ver = semver.validRange(p.rawSpec) || "" return [ name, ver ] })
function filter (data, args, set, seen) { if (!set) set = {} if (!seen) seen = {} if (set.hasOwnProperty(data.path)) return set if (seen.hasOwnProperty(data.path)) return set seen[data.path] = true var pass if (!args.length) pass = true // rebuild everything else if (data.name && data._id) { for (var i = 0, l = args.length; i < l; i++) { var arg = args[i] var nv = npa(arg) var n = nv.name var v = nv.rawSpec if (n !== data.name) continue if (!semver.satisfies(data.version, v, true)) continue pass = true break } } if (pass && data._id) { log.verbose('rebuild', 'path, id', [data.path, data._id]) set[data.path] = data._id } // need to also dive through kids, always. // since this isn't an install these won't get auto-built unless // they're not dependencies. Object.keys(data.dependencies || {}).forEach(function (d) { // return var dep = data.dependencies[d] if (typeof dep === 'string') return filter(dep, args, set, seen) }) return set }
function processQueue(graph) { if (typeof progress === 'function') { progress(queue.length); } var work = queue.pop(); // TODO: This will not work for non-npm names (e.g. git+https://, etc.) var escapedName = npa(work.name).escapedName; if (!escapedName) { // this will not work for non-npm packages. e.g. git+https:// , etc. throw new Error('TODO: Escaped name is missing for ' + work.name); } var cached = cache[work.name]; if (cached) { return new Promise(function(resolve) { resolve(processRegistryResponse(cached)); }); } return http(url + escapedName).then(processRegistryResponse); function processRegistryResponse(res) { cache[work.name] = res; traverseDependencies(work, res.data); if (queue.length) { // continue building the graph return processQueue(graph); } return graph; } }
module.exports = function(name) { if (!name) { return null; } return npa(name).name; };
test('fetch-package-metadata provides resolved metadata', function (t) { t.plan(4) var fetchPackageMetadata = require('../../lib/fetch-package-metadata') var testPackage = npa('test-package@>=0.0.0') mr({ port: common.port }, thenFetchMetadata) var server function thenFetchMetadata (err, s) { t.ifError(err, 'setup mock registry') server = s fetchPackageMetadata(testPackage, __dirname, thenVerifyMetadata) } function thenVerifyMetadata (err, pkg) { t.ifError(err, 'fetched metadata') t.equals(pkg._resolved, 'http://localhost:1337/test-package/-/test-package-0.0.0.tgz', '_resolved') t.equals(pkg._integrity, 'sha1-sNMrbEXCWcV4uiADdisgUTG9+9E=', '_integrity') server.close() t.end() } })
module.exports = function (spec, where, cb) { if (where instanceof Function) { cb = where; where = null } if (where == null) where = "." cb = dz(cb) try { var dep = npa(spec) } catch (e) { return cb(e) } if ((dep.type == "range" || dep.type == "version") && dep.name != dep.raw) return cb(null, dep) var specpath = dep.type == "local" ? path.resolve(where, dep.spec) : path.resolve(dep.rawSpec? dep.rawSpec: dep.name) fs.stat(specpath, function (er, s) { if (er) return finalize() if (!s.isDirectory()) return finalize("local") fs.stat(path.join(specpath, "package.json"), function (er) { finalize(er ? null : "directory") }) }) function finalize(type) { if (type != null && type != dep.type) { dep.type = type if (! dep.rawSpec) { dep.rawSpec = dep.name dep.name = null } } if (dep.type == "local" || dep.type == "directory") dep.spec = specpath cb(null, dep) } }
return BB.fromNode((cb) => { let launcher = localWorker let msg = args const spec = typeof args[0] === 'string' ? npa(args[0]) : args[0] args[0] = spec.raw if (ENABLE_WORKERS && (isRegistry(spec) || spec.type === 'remote')) { // We can't serialize these options opts = opts.concat({ loglevel: opts.log.level, log: null, dirPacker: null, Promise: null, _events: null, _eventsCount: null, list: null, sources: null, _maxListeners: null, root: null }) // workers will run things in parallel! launcher = workers try { msg = JSON.stringify(msg) } catch (e) { return cb(e) } } launcher(msg, cb) }).then(() => {
function accessAssertions (subcommand, uri, params, cb) { assert(subcommands.hasOwnProperty(subcommand), 'access subcommand must be one of ' + Object.keys(subcommands).join(', ')) typeChecks({ 'uri': [uri, 'string'], 'params': [params, 'object'], 'auth': [params.auth, 'object'], 'callback': [cb, 'function'] }) if (contains([ 'public', 'restricted' ], subcommand)) { typeChecks({ 'package': [params.package, 'string'] }) assert(!!npa(params.package).scope, 'access commands are only accessible for scoped packages') } if (contains(['grant', 'revoke', 'ls-packages'], subcommand)) { typeChecks({ 'scope': [params.scope, 'string'] }) } if (contains(['grant', 'revoke'], subcommand)) { typeChecks({ 'team': [params.team, 'string'] }) } if (subcommand === 'grant') { typeChecks({ 'permissions': [params.permissions, 'string'] }) assert(params.permissions === 'read-only' || params.permissions === 'read-write', 'permissions must be either read-only or read-write') } }
Project.local = function (name, path, json) { var p = new Project(name, path, true); p.json = json; p.repository = json.repository ? npa(json.name + '@' + json.repository.url) : null; p.dependencies = _.extend({}, json.dependencies, json.devDependencies); return p; };
function addBundled (pkg, next) { validate('OF', arguments) if (!pacoteOpts) { pacoteOpts = require('./config/pacote') } if (pkg._bundled !== undefined) return next(null, pkg) if (!pkg.bundleDependencies && pkg._requested.type !== 'directory') return next(null, pkg) const requested = pkg._requested || npa(pkg._from) if (requested.type === 'directory') { pkg._bundled = null return readPackageTree(pkg._requested.fetchSpec, function (er, tree) { if (tree) pkg._bundled = tree.children return next(null, pkg) }) } pkg._bundled = null const target = tempFilename('unpack') const opts = pacoteOpts({integrity: pkg._integrity}) pacote.extract(pkg._resolved || pkg._requested || npa.resolve(pkg.name, pkg.version), target, opts).then(() => { log.silly('addBundled', 'read tarball') readPackageTree(target, (err, tree) => { if (err) { return next(err) } log.silly('cleanup', 'remove extracted module') rimraf(target, function () { if (tree) { pkg._bundled = tree.children } next(null, pkg) }) }) }, next) }
args = args.map(function (a) { var p = npa(a) var name = p.name var ver = semver.validRange(p.rawSpec) || '' return [ name, ver ] })
function view (args, silent, cb) { if (typeof cb !== "function") cb = silent, silent = false if (!args.length) args = ["."] var pkg = args.shift() , nv = npa(pkg) , name = nv.name , local = (name === "." || !name) if (npm.config.get("global") && local) { return cb(new Error("Cannot use view command in global mode.")) } if (local) { var dir = npm.prefix readJson(path.resolve(dir, "package.json"), function (er, d) { d = d || {} if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er) if (!d.name) return cb(new Error("Invalid package.json")) var p = d.name nv = npa(p) if (pkg && ~pkg.indexOf("@")) { nv.rawSpec = pkg.split("@")[pkg.indexOf("@")] } fetchAndRead(nv, args, silent, cb) }) } else { fetchAndRead(nv, args, silent, cb) } }
var extractPackageName = function() { var packageType; try { packageType = npa(source).type; } catch(e) { return done(e); } if (packageType==="git" || packageType==="hosted") { console.log(" Cloning "+source); npm.commands.cache.add(source,null,null,false,function(err, packageInfo) { if (err) return done(err); if (packageInfo && packageInfo.name) { if (!target) setTarget(packageInfo.name); rack(); } return done("Package has no name"); }); } else { if (!target) setTarget(source); rack(); } };
// 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) }) }
arg.reduce((acc, child, ii) => { if (!acc) { // We might not always be able to find `target` through the given // path. If we can't we'll just ignore it. return } const spec = npa(child) const target = ( acc.requires.find(n => n.package.name === spec.name) || acc.requires.find( n => audit.scrub(n.package.name, this.runId) === spec.name ) ) if (target && ii === arg.length - 1) { target.loaded = false // This kills `hasModernMeta()` and forces a re-fetch target.package = { name: spec.name, version: spec.fetchSpec, _requested: target.package._requested } delete target.fakeChild let parent = target.parent while (parent) { parent.loaded = false parent = parent.parent } target.requiredBy.forEach(par => { par.loaded = false delete par.fakeChild }) } return target }, this.idealTree)
npm.registry.get(uri, options, function (er, pkgs) { if (er) return cb() if (!opts.partialWord) return cb(null, pkgs) var name = npa(opts.partialWord).name pkgs = pkgs.filter(function (p) { return p.indexOf(name) === 0 }) if (pkgs.length !== 1 && opts.partialWord === name) { return cb(null, pkgs) } mapToRegistry(pkgs[0], npm.config, function (er, uri) { if (er) return cb(er) npm.registry.get(uri, options, function (er, d) { if (er) return cb() return cb(null, Object.keys(d["dist-tags"] || {}) .concat(Object.keys(d.versions || {})) .map(function (t) { return pkgs[0] + "@" + t })) }) }) })
function manifest (spec, opts) { opts = optCheck(opts) spec = typeof spec === 'string' ? npa(spec, opts.where) : spec const label = [ spec.name, spec.saveSpec || spec.fetchSpec, spec.type, opts.cache, opts.registry, opts.scope ].join(':') return pinflight(label, () => { const startTime = Date.now() return fetchManifest(spec, opts).then(rawManifest => { return finalizeManifest(rawManifest, spec, opts) }).then(manifest => { if (opts.annotate) { manifest._from = spec.saveSpec || spec.raw manifest._requested = spec manifest._spec = spec.raw manifest._where = opts.where } const elapsedTime = Date.now() - startTime opts.log.silly('pacote', `${spec.type} manifest for ${spec.name}@${spec.saveSpec || spec.fetchSpec} fetched in ${elapsedTime}ms`) return manifest }) }) }
/** * @private */ parsePackage() { if(!this._package) { const npa = require('npm-package-arg') let href = this.href.replace(RE, ''); this._package = npa(href); } return this._package; }
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]) }) }
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 libaccess.lsPackages(username, opts).then(access => { // do a bit of filtering at this point, so that we don't need // to fetch versions for more than one thing, but also don't // accidentally a whole project. let pkgs = Object.keys(access) if (!cliOpts.partialWord || !pkgs.length) { return pkgs } const pp = npa(cliOpts.partialWord).name pkgs = pkgs.filter(p => !p.indexOf(pp)) if (pkgs.length > 1) return pkgs return npmFetch.json(npa(pkgs[0]).escapedName, opts).then(doc => { const vers = Object.keys(doc.versions) if (!vers.length) { return pkgs } else { return vers.map(v => `${pkgs[0]}@${v}`) } }) })
, things = Object.keys(tree).map(function (k) { // if "what" was a url, then save that instead. var t = tree[k] , u = url.parse(t.from) , a = npa(t.what) , w = [a.name, a.spec] if (u && u.protocol) w[1] = t.from return w }).reduce(function (set, k) {
function nonRegistrySource (pkg) { validate('O', arguments) var requested = pkg._requested || (pkg._from && npa(pkg._from)) if (!requested) return false if (requested.type === 'hosted') return true if (requested.type === 'file' || requested.type === 'directory') return true return false }
function mapToRegistry (name, config, cb) { log.silly('mapToRegistry', 'name', name) var registry // the name itself takes precedence var data = npa(name) if (data.scope) { // the name is definitely scoped, so escape now name = name.replace('/', '%2f') log.silly('mapToRegistry', 'scope (from package name)', data.scope) registry = config.get(data.scope + ':registry') if (!registry) { log.verbose('mapToRegistry', 'no registry URL found in name for scope', data.scope) } } // ...then --scope=@scope or --scope=scope var scope = config.get('scope') if (!registry && scope) { // I'm an enabler, sorry if (scope.charAt(0) !== '@') scope = '@' + scope log.silly('mapToRegistry', 'scope (from config)', scope) registry = config.get(scope + ':registry') if (!registry) { log.verbose('mapToRegistry', 'no registry URL found in config for scope', scope) } } // ...and finally use the default registry if (!registry) { log.silly('mapToRegistry', 'using default registry') registry = config.get('registry') } log.silly('mapToRegistry', 'registry', registry) var auth = config.getCredentialsByURI(registry) // normalize registry URL so resolution doesn't drop a piece of registry URL var normalized = registry.slice(-1) !== '/' ? registry + '/' : registry var uri log.silly('mapToRegistry', 'data', data) if (data.type === 'remote') { uri = data.fetchSpec } else { uri = url.resolve(normalized, name) } log.silly('mapToRegistry', 'uri', uri) cb(null, uri, scopeAuth(uri, registry, auth), normalized) }
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 processQueue(graph) { if (typeof progress === 'function') { progress(queue.length); } var work = queue.pop(); var cached = cache[getCacheKey(work)]; if (cached) { return new Promise(function(resolve) { resolve(processRegistryResponse(cached)); }); } if (isRemote(work.version)) { // TODO: This will not download remote dependencies (e.g. git-based) return new Promise(function(resolve) { resolve(processRegistryResponse({data: {}})); }); } var escapedName = npa(work.name).escapedName; if (!escapedName && isHttp(work.name)) { return http(work.name).then(res => { if (res.data) { // TODO: Validate pkg json var pkgJSON = res.data; pkgJSON._id = pkgJSON.name + '@' + pkgJSON.version; var versions = {}; versions[pkgJSON.version] = pkgJSON; return processRegistryResponse({ data: Object.assign({}, { versions: versions }) }); } throw new Error('Unexpected response'); }); } if (!escapedName) { throw new Error('TODO: Escaped name is missing for ' + work.name); } return http(url + escapedName).then(processRegistryResponse); function processRegistryResponse(res) { cache[getCacheKey(work)] = res; traverseDependencies(work, res.data); if (queue.length) { // continue building the graph return processQueue(graph); } return graph; } }
function add (args, where, cb) { // this is hot code. almost everything passes through here. // the args can be any of: // ["url"] // ["pkg", "version"] // ["pkg@version"] // ["pkg", "url"] // This is tricky, because urls can contain @ // Also, in some cases we get [name, null] rather // that just a single argument. var usage = "Usage:\n" + " npm cache add <tarball-url>\n" + " npm cache add <pkg>@<ver>\n" + " npm cache add <tarball>\n" + " npm cache add <folder>\n" , spec , p log.silly("cache add", "args", args) if (args[1] === undefined) args[1] = null // at this point the args length must ==2 if (args[1] !== null) { spec = args[0]+"@"+args[1] } else if (args.length === 2) { spec = args[0] } log.verbose("cache add", "spec", spec) if (!spec) return cb(usage) if (adding <= 0) { npm.spinner.start() } adding ++ cb = afterAdd(cb) // package.json can have local URI ("file:") dependencies which require // normalization p = npa(spec) if (p.type === "local" && where) spec = path.resolve(where, p.spec) log.silly("cache add", "parsed spec", p) // short-circuit local installs fs.stat(spec, function (er, s) { if (er) return addNonLocal(spec, cb) if (!s.isDirectory()) return addAndLogLocal(spec, cb) fs.stat(path.join(spec, "package.json"), function (er) { if (er) return addNonLocal(spec, cb) addAndLogLocal(spec, cb) }) }) }
args = args.map(function (a) { var p = npa(a) var name = p.name // When version spec is missing, we'll skip using it when filtering. // Otherwise, `semver.validRange` would return '*', which won't // match prerelease versions. var ver = (p.rawSpec && (semver.validRange(p.rawSpec) || '')) return [ name, ver, a ] })
function n (er, data) { if (er) return cb(er, data) // install returns [ [folder, pkgId], ... ] // but we definitely installed just one thing. var d = data.filter(function (d) { return !d[3] }) var what = npa(d[0][0]) pp = d[0][1] pkg = what.name target = path.resolve(npm.dir, pkg) next() }