diff options
author | isaacs <i@izs.me> | 2020-08-04 08:56:34 +0300 |
---|---|---|
committer | isaacs <i@izs.me> | 2020-08-04 11:03:34 +0300 |
commit | 108a4fcb5da23c34690b4767a4c5f7f93ab99c0d (patch) | |
tree | 15254742f9e81012fd8d50d6621d9178d2f6977d /lib | |
parent | 0b63d5078a5858b83dba943720c6d6dfe6eb808f (diff) |
refactor and lint commands, make consistent
Still pending test coverage for most of these, but wanted to give them a
clean sweep to get the "load-all-commands" tests passing.
The following changes are in here:
- All commands now have a `completion()` method and a usage string that
uses the same `usage` util consistently.
- The `silent` argument to many commands has been removed.
- All commands use the `cmd = ${cmd}(args).then(() => cb()).catch(cb)`
pattern consistently.
Full test coverage for all commands is still lacking, and will have to
be done prior to the GA v7 release.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/adduser.js | 72 | ||||
-rw-r--r-- | lib/bin.js | 35 | ||||
-rw-r--r-- | lib/cache.js | 141 | ||||
-rw-r--r-- | lib/doctor.js | 8 | ||||
-rw-r--r-- | lib/fund.js | 2 | ||||
-rw-r--r-- | lib/help-search.js | 284 | ||||
-rw-r--r-- | lib/hook.js | 71 | ||||
-rw-r--r-- | lib/logout.js | 62 | ||||
-rw-r--r-- | lib/pack.js | 35 | ||||
-rw-r--r-- | lib/ping.js | 48 | ||||
-rw-r--r-- | lib/prefix.js | 23 | ||||
-rw-r--r-- | lib/publish.js | 26 | ||||
-rw-r--r-- | lib/root.js | 19 | ||||
-rw-r--r-- | lib/stars.js | 55 | ||||
-rw-r--r-- | lib/team.js | 183 | ||||
-rw-r--r-- | lib/unpublish.js | 2 | ||||
-rw-r--r-- | lib/update.js | 16 | ||||
-rw-r--r-- | lib/utils/get-identity.js | 8 | ||||
-rw-r--r-- | lib/utils/lifecycle-cmd.js | 3 | ||||
-rw-r--r-- | lib/version.js | 85 | ||||
-rw-r--r-- | lib/view.js | 27 | ||||
-rw-r--r-- | lib/whoami.js | 28 |
22 files changed, 564 insertions, 669 deletions
diff --git a/lib/adduser.js b/lib/adduser.js index 07199e55c..4ef9edbab 100644 --- a/lib/adduser.js +++ b/lib/adduser.js @@ -1,50 +1,60 @@ -module.exports = adduser - const log = require('npmlog') const npm = require('./npm.js') -const usage = require('./utils/usage') -let crypto - -try { - crypto = require('crypto') -} catch (ex) {} +const usageUtil = require('./utils/usage.js') -adduser.usage = usage( +const usage = usageUtil( 'adduser', 'npm adduser [--registry=url] [--scope=@orgname] [--always-auth]' ) -function adduser (args, cb) { - if (!crypto) { - return cb(new Error( - 'You must compile node with ssl support to use the adduser feature' - )) - } +const completion = require('./utils/completion/none.js') - let registry = npm.flatOptions.registry - const scope = npm.flatOptions.scope - const creds = npm.config.getCredentialsByURI(registry) +const cmd = (args, cb) => adduser(args).then(() => cb()).catch(cb) +const getRegistry = opts => { + const { scope, registry } = opts if (scope) { - const scopedRegistry = npm.config.get(scope + ':registry') + const scopedRegistry = npm.config.get(`${scope}:registry`) const cliRegistry = npm.config.get('registry', 'cli') - if (scopedRegistry && !cliRegistry) registry = scopedRegistry + if (scopedRegistry && !cliRegistry) { + return scopedRegistry + } } + return registry +} - log.disableProgress() - - let auth +const getAuthType = ({ authType }) => { try { - auth = require('./auth/' + npm.flatOptions.authType) + return require('./auth/' + authType) } catch (e) { - return cb(new Error('no such auth module')) + throw new Error('no such auth module') } - auth.login(creds, registry, scope, function (err, newCreds) { - if (err) return cb(err) +} + +const adduser = async args => { + const registry = getRegistry(npm.flatOptions) + const { scope } = npm.flatOptions + const creds = npm.config.getCredentialsByURI(registry) - npm.config.del('_token', 'user') // prevent legacy pollution - if (scope) npm.config.set(scope + ':registry', registry, 'user') - npm.config.setCredentialsByURI(registry, newCreds) - npm.config.save('user', cb) + log.disableProgress() + + const auth = getAuthType(npm.flatOptions) + + // XXX make auth.login() promise-returning so we don't have to wrap here + await new Promise((res, rej) => { + auth.login(creds, registry, scope, function (er, newCreds) { + if (er) { + return rej(er) + } + + npm.config.del('_token', 'user') // prevent legacy pollution + if (scope) { + npm.config.set(scope + ':registry', registry, 'user') + } + npm.config.setCredentialsByURI(registry, newCreds) + npm.config.save('user', er => er ? rej(er) : res()) + }) }) } + +module.exports = Object.assign(cmd, { completion, usage }) diff --git a/lib/bin.js b/lib/bin.js index c15a7752c..e2b2a31da 100644 --- a/lib/bin.js +++ b/lib/bin.js @@ -1,23 +1,16 @@ -module.exports = bin - -var npm = require('./npm.js') -var osenv = require('osenv') -var output = require('./utils/output.js') - -bin.usage = 'npm bin [--global]' - -function bin (args, silent, cb) { - if (typeof cb !== 'function') { - cb = silent - silent = false - } - var b = npm.bin - var PATH = osenv.path() - - if (!silent) output(b) - process.nextTick(cb.bind(this, null, b)) - - if (npm.config.get('global') && PATH.indexOf(b) === -1) { - process.stderr.write('(not in PATH env variable)\n') +const osenv = require('osenv') +const npm = require('./npm.js') +const output = require('./utils/output.js') +const usageUtil = require('./utils/usage.js') +const completion = require('./utils/completion/none.js') +const cmd = (args, cb) => bin(args).then(() => cb()).catch(cb) +const usage = usageUtil('bin', 'npm bin [-g]') +const bin = async (args, cb) => { + const b = npm.bin + const PATH = osenv.path() + output(b) + if (npm.flatOptions.global && !PATH.includes(b)) { + console.error('(not in PATH env variable)') } } +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/cache.js b/lib/cache.js index b5417ba81..a47665c1e 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,7 +1,3 @@ -'use strict' -/* eslint-disable standard/no-callback-literal */ - -const assert = require('assert') const cacache = require('cacache') const { promisify } = require('util') const log = require('npmlog') @@ -11,16 +7,20 @@ const pacote = require('pacote') const path = require('path') const rimraf = promisify(require('rimraf')) -cache.usage = 'npm cache add <tarball file>' + - '\nnpm cache add <folder>' + - '\nnpm cache add <tarball url>' + - '\nnpm cache add <git url>' + - '\nnpm cache add <name>@<version>' + - '\nnpm cache clean' + - '\nnpm cache verify' +const usageUtil = require('./utils/usage.js') + +const usage = usageUtil('cache', + 'npm cache add <tarball file>' + + '\nnpm cache add <folder>' + + '\nnpm cache add <tarball url>' + + '\nnpm cache add <git url>' + + '\nnpm cache add <name>@<version>' + + '\nnpm cache clean' + + '\nnpm cache verify' +) -cache.completion = function (opts, cb) { - var argv = opts.conf.argv.remain +const completion = (opts, cb) => { + const argv = opts.conf.argv.remain if (argv.length === 2) { return cb(null, ['add', 'clean']) } @@ -33,40 +33,38 @@ cache.completion = function (opts, cb) { } } -exports = module.exports = cache -function cache (args, cb) { +const cmd = (args, cb) => cache(args).then(() => cb()).catch(cb) + +const cache = async (args) => { const cmd = args.shift() - let result switch (cmd) { case 'rm': case 'clear': case 'clean': - result = clean(args) - break + return await clean(args) case 'add': - result = add(args, npm.prefix) - break + return await add(args, npm.prefix) case 'verify': case 'check': - result = verify() - break - default: return cb('Usage: ' + cache.usage) - } - if (!result || !result.then) { - throw new Error(`npm cache ${cmd} handler did not return a Promise`) + return await verify() + default: + throw usage } - result.then(() => cb(), cb) } // npm cache clean [pkg]* -cache.clean = clean -function clean (args) { - if (!args) args = [] +const clean = async (args) => { if (args.length) { - return Promise.reject(new Error('npm cache clear does not accept arguments')) + throw new Error('npm cache clear does not accept arguments') } const cachePath = path.join(npm.cache, '_cacache') - if (!npm.config.get('force')) { - return Promise.reject(new Error("As of npm@5, the npm cache self-heals from corruption issues and data extracted from the cache is guaranteed to be valid. If you want to make sure everything is consistent, use 'npm cache verify' instead. On the other hand, if you're debugging an issue with the installer, you can use `npm install --cache /tmp/empty-cache` to use a temporary cache instead of nuking the actual one.\n\nIf you're sure you want to delete the entire cache, rerun this command with --force.")) + if (!npm.flatOptions.force) { + throw new Error('As of npm@5, the npm cache self-heals from corruption ' + + 'issues and data extracted from the cache is guaranteed to be valid. ' + + 'If you want to make sure everything is consistent, use `npm cache ' + + 'verify` instead. On the other hand, if you\'re debugging an issue ' + + 'with the installer, you can use `npm install --cache /tmp/empty-cache` ' + + 'to use a temporary cache instead of nuking the actual one.\n\n' + + 'If you\'re sure you want to delete the entire cache, rerun this ' + + 'command with --force.') } - // TODO - remove specific packages or package versions return rimraf(cachePath) } @@ -74,55 +72,46 @@ function clean (args) { // npm cache add <pkg> <ver> // npm cache add <tarball> // npm cache add <folder> -cache.add = function (pkg, ver, where, scrub) { - assert(typeof pkg === 'string', 'must include name of package to install') - if (scrub) { - return clean([]).then(() => { - return add([pkg, ver], where) - }) - } - return add([pkg, ver], where) -} - -function add (args, where) { - 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' - var spec +const add = async (args, where) => { + const 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' 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] - } + const spec = args[0] + + (args[1] === undefined || args[1] === null ? `@${args[1]}` : '') + log.verbose('cache add', 'spec', spec) - if (!spec) return Promise.reject(new Error(usage)) + if (!spec) { + throw new Error(usage) + } + log.silly('cache add', 'parsed spec', spec) const opts = { ...npm.flatOptions, where } - return pacote.tarball.stream(spec, stream => { + + // we ask pacote for the thing, and then just throw the data + // away so that it tee-pipes it into the cache like it does + // for a normal request. + await pacote.tarball.stream(spec, stream => { stream.resume() return stream.promise() }, opts) } -cache.verify = verify -function verify () { - const cache = path.join(npm.config.get('cache'), '_cacache') - let prefix = cache - if (prefix.indexOf(process.env.HOME) === 0) { - prefix = '~' + prefix.substr(process.env.HOME.length) - } - return cacache.verify(cache).then((stats) => { - output(`Cache verified and compressed (${prefix}):`) - output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`) - stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`) - stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) - stats.missingContent && output(`Missing content: ${stats.missingContent}`) - output(`Index entries: ${stats.totalEntries}`) - output(`Finished in ${stats.runTime.total / 1000}s`) - }) +const verify = async () => { + const cache = path.join(npm.cache, '_cacache') + const prefix = cache.indexOf(process.env.HOME) === 0 + ? `~${cache.substr(process.env.HOME.length)}` + : cache + const stats = await cacache.verify(cache) + output(`Cache verified and compressed (${prefix}):`) + output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`) + stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`) + stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) + stats.missingContent && output(`Missing content: ${stats.missingContent}`) + output(`Index entries: ${stats.totalEntries}`) + output(`Finished in ${stats.runTime.total / 1000}s`) } + +module.exports = Object.assign(cmd, { completion, usage }) diff --git a/lib/doctor.js b/lib/doctor.js index 96094e634..46aa0e1e7 100644 --- a/lib/doctor.js +++ b/lib/doctor.js @@ -23,9 +23,9 @@ const verifyCachedFiles = require('./doctor/verify-cached-files') const globalNodeModules = path.join(npm.config.globalPrefix, 'lib', 'node_modules') const localNodeModules = path.join(npm.config.localPrefix, 'node_modules') -module.exports = doctor - -doctor.usage = 'npm doctor' +const usageUtil = require('./utils/usage.js') +const usage = usageUtil('doctor', 'npm doctor') +const completion = require('./utils/completion/none.js') function doctor (args, silent, cb) { args = args || {} @@ -111,3 +111,5 @@ function makePretty (p) { return list } + +module.exports = Object.assign(doctor, { completion, usage }) diff --git a/lib/fund.js b/lib/fund.js index 7fe781c94..fde01f469 100644 --- a/lib/fund.js +++ b/lib/fund.js @@ -1,5 +1,3 @@ -'use strict' - const archy = require('archy') const Arborist = require('@npmcli/arborist') const chalk = require('chalk') diff --git a/lib/help-search.js b/lib/help-search.js index 1c2a71c8a..8c29e7b74 100644 --- a/lib/help-search.js +++ b/lib/help-search.js @@ -1,77 +1,63 @@ +const fs = require('fs') +const path = require('path') +const npm = require('./npm.js') +const glob = require('glob') +const color = require('ansicolors') +const output = require('./utils/output.js') +const usageUtil = require('./utils/usage.js') +const { promisify } = require('util') +const readFile = promisify(fs.readFile) + +const usage = usageUtil('help-search', 'npm help-search <text>') +const completion = require('./utils/completion/none.js') + +const cmd = (args, cb) => helpSearch(args).then(() => cb()).catch(cb) + +const helpSearch = async args => { + if (!args.length) { + throw usage + } -module.exports = helpSearch - -var fs = require('graceful-fs') -var path = require('path') -var asyncMap = require('slide').asyncMap -var npm = require('./npm.js') -var glob = require('glob') -var color = require('ansicolors') -var output = require('./utils/output.js') + const docPath = path.resolve(__dirname, '..', 'docs/content') -helpSearch.usage = 'npm help-search <text>' + // XXX: make glob return a promise and remove this wrapping + const files = await new Promise((res, rej) => + glob(`${docPath}/*/*.md`, (er, files) => er ? rej(er) : res(files))) -function helpSearch (args, silent, cb) { - if (typeof cb !== 'function') { - cb = silent - silent = false - } - if (!args.length) return cb(helpSearch.usage) - - var docPath = path.resolve(__dirname, '..', 'doc') - return glob(docPath + '/*/*.md', function (er, files) { - if (er) return cb(er) - readFiles(files, function (er, data) { - if (er) return cb(er) - searchFiles(args, data, function (er, results) { - if (er) return cb(er) - formatResults(args, results, cb) - }) - }) - }) + const data = await readFiles(files) + const results = await searchFiles(args, data, files) + output(formatResults(args, results)) } -function readFiles (files, cb) { - var res = {} - asyncMap(files, function (file, cb) { - fs.readFile(file, 'utf8', function (er, data) { - res[file] = data - return cb(er) - }) - }, function (er) { - return cb(er, res) - }) +const readFiles = async files => { + const res = {} + await Promise.all(files.map(async file => { + res[file] = (await readFile(file, 'utf8')) + .replace(/^---\n(.*\n)*?---\n/, '').trim() + })) + return res } -function searchFiles (args, files, cb) { - var results = [] - Object.keys(files).forEach(function (file) { - var data = files[file] - +const searchFiles = async (args, data, files) => { + const results = [] + for (const [file, content] of Object.entries(data)) { + const lowerCase = content.toLowerCase() // skip if no matches at all - var match - for (var a = 0, l = args.length; a < l && !match; a++) { - match = data.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 + if (!args.some(a => lowerCase.includes(a.toLowerCase()))) { + continue } - if (!match) return - var lines = data.split(/\n+/) + const lines = content.split(/\n+/) // if a line has a search term, then skip it and the next line. // if the next line has a search term, then skip all 3 // otherwise, set the line to null. then remove the nulls. - l = lines.length - for (var i = 0; i < l; i++) { - var line = lines[i] - var nextLine = lines[i + 1] - var ll - - match = false + for (let i = 0; i < lines.length; i++) { + const line = lines[i] + const nextLine = lines[i + 1] + let match = false if (nextLine) { - for (a = 0, ll = args.length; a < ll && !match; a++) { - match = nextLine.toLowerCase() - .indexOf(args[a].toLowerCase()) !== -1 - } + match = args.some(a => nextLine.toLowerCase().includes(a.toLowerCase())) if (match) { // skip over the next line, and the line after it. i += 2 @@ -79,10 +65,8 @@ function searchFiles (args, files, cb) { } } - match = false - for (a = 0, ll = args.length; a < ll && !match; a++) { - match = line.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 - } + match = args.some(a => line.toLowerCase().includes(a.toLowerCase())) + if (match) { // skip over the next line i++ @@ -93,120 +77,128 @@ function searchFiles (args, files, cb) { } // now squish any string of nulls into a single null - lines = lines.reduce(function (l, r) { - if (!(r === null && l[l.length - 1] === null)) l.push(r) + const pruned = lines.reduce((l, r) => { + if (!(r === null && l[l.length - 1] === null)) { + l.push(r) + } return l }, []) - if (lines[lines.length - 1] === null) lines.pop() - if (lines[0] === null) lines.shift() + if (pruned[pruned.length - 1] === null) { + pruned.pop() + } + if (pruned[0] === null) { + pruned.shift() + } - // now see how many args were found at all. - var found = {} - var totalHits = 0 - lines.forEach(function (line) { - args.forEach(function (arg) { - var hit = (line || '').toLowerCase() + // now count how many args were found + const found = {} + let totalHits = 0 + for (const line of pruned) { + for (const arg of args) { + const hit = (line || '').toLowerCase() .split(arg.toLowerCase()).length - 1 + if (hit > 0) { found[arg] = (found[arg] || 0) + hit totalHits += hit } - }) - }) - - var cmd = 'npm help ' - if (path.basename(path.dirname(file)) === 'api') { - cmd = 'npm apihelp ' + } } - cmd += path.basename(file, '.md').replace(/^npm-/, '') + + const cmd = 'npm help ' + + path.basename(file, '.md').replace(/^npm-/, '') results.push({ - file: file, - cmd: cmd, - lines: lines, + file, + cmd, + lines: pruned, found: Object.keys(found), hits: found, - totalHits: totalHits + totalHits }) - }) + } // if only one result, then just show that help section. if (results.length === 1) { - return npm.commands.help([results[0].file.replace(/\.md$/, '')], cb) - } - - if (results.length === 0) { - output('No results for ' + args.map(JSON.stringify).join(' ')) - return cb() + npm.commands.help([results[0].file.replace(/\.md$/, '')], er => { + if (er) { + throw er + } + }) + return [] } // sort results by number of results found, then by number of hits // then by number of matching lines - results = results.sort(function (a, b) { - return a.found.length > b.found.length ? -1 - : a.found.length < b.found.length ? 1 - : a.totalHits > b.totalHits ? -1 - : a.totalHits < b.totalHits ? 1 - : a.lines.length > b.lines.length ? -1 - : a.lines.length < b.lines.length ? 1 - : 0 - }) - - cb(null, results) + return results.sort((a, b) => + a.found.length > b.found.length ? -1 + : a.found.length < b.found.length ? 1 + : a.totalHits > b.totalHits ? -1 + : a.totalHits < b.totalHits ? 1 + : a.lines.length > b.lines.length ? -1 + : a.lines.length < b.lines.length ? 1 + : 0).slice(0, 10) } -function formatResults (args, results, cb) { - if (!results) return cb(null) - - var cols = Math.min(process.stdout.columns || Infinity, 80) + 1 - - var out = results.map(function (res) { - var out = res.cmd - var r = Object.keys(res.hits) - .map(function (k) { - return k + ':' + res.hits[k] - }).sort(function (a, b) { - return a > b ? 1 : -1 - }).join(' ') - - out += ((new Array(Math.max(1, cols - out.length - r.length))) - .join(' ')) + r +const formatResults = (args, results) => { + if (!results) { + return 'No results for ' + args.map(JSON.stringify).join(' ') + } - if (!npm.config.get('long')) return out + const cols = Math.min(process.stdout.columns || Infinity, 80) + 1 - out = '\n\n' + out + '\n' + - (new Array(cols)).join('—') + '\n' + - res.lines.map(function (line, i) { - if (line === null || i > 3) return '' - for (var out = line, a = 0, l = args.length; a < l; a++) { - var finder = out.toLowerCase().split(args[a].toLowerCase()) - var newOut = '' - var p = 0 + const out = results.map(res => { + const out = [res.cmd] + const r = Object.keys(res.hits) + .map(k => `${k}:${res.hits[k]}`) + .sort((a, b) => a > b ? 1 : -1) + .join(' ') - finder.forEach(function (f) { - newOut += out.substr(p, f.length) + out.push(' '.repeat((Math.max(1, cols - out.join(' ').length - r.length - 1)))) + out.push(r) - var hilit = out.substr(p + f.length, args[a].length) - if (npm.color) hilit = color.bgBlack(color.red(hilit)) - newOut += hilit + if (!npm.flatOptions.long) { + return out.join('') + } - p += f.length + args[a].length - }) + out.unshift('\n\n') + out.push('\n') + out.push('-'.repeat(cols - 1) + '\n') + res.lines.forEach((line, i) => { + if (line === null || i > 3) { + return + } + if (!npm.color) { + out.push(line + '\n') + return + } + const hilitLine = [] + for (const arg of args) { + const finder = line.toLowerCase().split(arg.toLowerCase()) + let p = 0 + for (const f of finder) { + hilitLine.push(line.substr(p, f.length)) + const word = line.substr(p + f.length, arg.length) + const hilit = color.bgBlack(color.red(word)) + hilitLine.push(hilit) + p += f.length + arg.length } + } + out.push(hilitLine.join('') + '\n') + }) - return newOut - }).join('\n').trim() - return out + return out.join('') }).join('\n') - if (results.length && !npm.config.get('long')) { - out = 'Top hits for ' + (args.map(JSON.stringify).join(' ')) + '\n' + - (new Array(cols)).join('—') + '\n' + - out + '\n' + - (new Array(cols)).join('—') + '\n' + - '(run with -l or --long to see more context)' - } + const finalOut = results.length && !npm.flatOptions.long + ? 'Top hits for ' + (args.map(JSON.stringify).join(' ')) + '\n' + + '—'.repeat(cols - 1) + '\n' + + out + '\n' + + '—'.repeat(cols - 1) + '\n' + + '(run with -l or --long to see more context)' + : out - output(out.trim()) - cb(null, results) + return finalOut.trim() } + +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/hook.js b/lib/hook.js index d3ad85346..e2c6d76aa 100644 --- a/lib/hook.js +++ b/lib/hook.js @@ -1,59 +1,40 @@ -'use strict' - const hookApi = require('libnpmhook') const npm = require('./npm.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const relativeDate = require('tiny-relative-date') const Table = require('cli-table3') -const validate = require('aproba') -hook.usage = [ +const usageUtil = require('./utils/usage.js') +const usage = usageUtil('hook', [ 'npm hook add <pkg> <url> <secret> [--type=<type>]', 'npm hook ls [pkg]', 'npm hook rm <id>', 'npm hook update <id> <url> <secret>' -].join('\n') +].join('\n')) -hook.completion = (opts, cb) => { - validate('OF', [opts, cb]) - return cb(null, []) // fill in this array with completion values -} +const completion = require('./utils/completion/none.js') -function UsageError () { - throw Object.assign(new Error(hook.usage), { code: 'EUSAGE' }) -} +const cmd = (args, cb) => hook(args).then(() => cb()).catch(cb) -// XXX once completely de-figged this can be changed to -// (args, cb) => hook(args).then ... -module.exports = (args, cb) => Promise.resolve().then(() => { - return hook(args) - .then(val => cb(null, val)) - .catch(err => err.code === 'EUSAGE' ? cb(err.message) : cb(err)) +const hook = async (args) => otplease(npm.flatOptions, opts => { + switch (args[0]) { + case 'add': + return add(args[1], args[2], args[3], opts) + case 'ls': + return ls(args[1], opts) + case 'rm': + return rm(args[1], opts) + case 'update': + case 'up': + return update(args[1], args[2], args[3], opts) + default: + throw usage + } }) -module.exports.usage = hook.usage - -function hook (args) { - return otplease(npm.flatOptions, opts => { - switch (args[0]) { - case 'add': - return add(args[1], args[2], args[3], opts) - case 'ls': - return ls(args[1], opts) - case 'rm': - return rm(args[1], opts) - case 'update': - case 'up': - return update(args[1], args[2], args[3], opts) - default: - UsageError() - } - }) -} - -function add (pkg, uri, secret, opts) { - return hookApi.add(pkg, uri, secret, opts).then(hook => { +const add = (pkg, uri, secret, opts) => { + hookApi.add(pkg, uri, secret, opts).then(hook => { if (opts.json) { output(JSON.stringify(hook, null, 2)) } else if (opts.parseable) { @@ -67,7 +48,7 @@ function add (pkg, uri, secret, opts) { }) } -function ls (pkg, opts) { +const ls = (pkg, opts) => { return hookApi.ls({ ...opts, package: pkg }).then(hooks => { if (opts.json) { output(JSON.stringify(hooks, null, 2)) @@ -108,7 +89,7 @@ function ls (pkg, opts) { }) } -function rm (id, opts) { +const rm = (id, opts) => { return hookApi.rm(id, opts).then(hook => { if (opts.json) { output(JSON.stringify(hook, null, 2)) @@ -123,7 +104,7 @@ function rm (id, opts) { }) } -function update (id, uri, secret, opts) { +const update = (id, uri, secret, opts) => { return hookApi.update(id, uri, secret, opts).then(hook => { if (opts.json) { output(JSON.stringify(hook, null, 2)) @@ -138,9 +119,11 @@ function update (id, uri, secret, opts) { }) } -function hookName (hook) { +const hookName = (hook) => { let target = hook.name if (hook.type === 'scope') { target = '@' + target } if (hook.type === 'owner') { target = '~' + target } return target } + +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/logout.js b/lib/logout.js index 8903f4088..68442791a 100644 --- a/lib/logout.js +++ b/lib/logout.js @@ -1,44 +1,42 @@ -'use strict' - const eu = encodeURIComponent const getAuth = require('npm-registry-fetch/auth.js') const log = require('npmlog') const npm = require('./npm.js') const npmFetch = require('npm-registry-fetch') +const usageUtil = require('./utils/usage.js') -logout.usage = 'npm logout [--registry=<url>] [--scope=<@scope>]' +const usage = usageUtil('logout', 'npm logout [--registry=<url>] [--scope=<@scope>]') +const completion = require('./utils/completion/none.js') -function afterLogout (normalized) { - var scope = npm.config.get('scope') +const cmd = (args, cb) => logout(args).then(() => cb()).catch(cb) - if (scope) npm.config.del(scope + ':registry') +const logout = async args => { + const reg = npmFetch.pickRegistry('foo', npm.flatOptions) + const auth = getAuth(reg, npm.flatOptions) + if (auth.token) { + log.verbose('logout', `clearing token for ${reg}`) + await npmFetch(`/-/user/token/${eu(auth.token)}`, { + ...npm.flatOptions, + method: 'DELETE', + ignoreBody: true + }) + } else if (auth.username || auth.password) { + log.verbose('logout', `clearing user credentials for ${reg}`) + } else { + throw Object.assign(new Error(`not logged in to ${reg}, so can't log out!`), { + code: 'ENEEDAUTH' + }) + } - npm.config.clearCredentialsByURI(normalized) - return new Promise((resolve, reject) => { - npm.config.save('user', er => er ? reject(er) : resolve()) + const scope = npm.config.get('scope') + if (scope) { + npm.config.del(`${scope}:registry`) + } + npm.config.clearCredentialsByURI(reg) + // make npm.config.save() return a promise + await new Promise((res, rej) => { + npm.config.save('user', er => er ? rej(er) : res()) }) } -module.exports = logout -function logout (args, cb) { - const opts = npm.flatOptions - Promise.resolve().then(() => { - const reg = npmFetch.pickRegistry('foo', opts) - const auth = getAuth(reg, opts) - if (auth.token) { - log.verbose('logout', 'clearing session token for', reg) - return npmFetch(`/-/user/token/${eu(auth.token)}`, { - ...opts, - method: 'DELETE', - ignoreBody: true - }).then(() => afterLogout(reg)) - } else if (auth.username || auth.password) { - log.verbose('logout', 'clearing user credentials for', reg) - return afterLogout(reg) - } else { - throw new Error( - 'Not logged in to', reg + ',', "so can't log out." - ) - } - }).then(() => cb(), cb) -} +module.exports = Object.assign(cmd, { completion, usage }) diff --git a/lib/pack.js b/lib/pack.js index 36fd9a228..60a55d34b 100644 --- a/lib/pack.js +++ b/lib/pack.js @@ -1,5 +1,3 @@ -'use strict' - const util = require('util') const log = require('npmlog') const pacote = require('pacote') @@ -7,49 +5,34 @@ const libpack = require('libnpmpack') const npa = require('npm-package-arg') const npm = require('./npm.js') -const output = require('./utils/output.js') const { getContents, logTar } = require('./utils/tar.js') const writeFile = util.promisify(require('fs').writeFile) -cmd.usage = 'npm pack [[<@scope>/]<pkg>...] [--dry-run]' +const completion = require('./utils/completion/none.js') +const usageUtil = require('./utils/usage.js') +const usage = usageUtil('pack', 'npm pack [[<@scope>/]<pkg>...] [--dry-run]') -module.exports = cmd -function cmd (args, silent, cb) { - if (typeof cb !== 'function') { - cb = silent - silent = false - } - pack(args, silent) - .then(() => cb()) - .catch(cb) -} +const cmd = (args, cb) => pack(args).then(() => cb()).catch(cb) -async function pack (args, silent) { +const pack = async (args) => { if (args.length === 0) args = ['.'] const opts = { ...npm.flatOptions } - const { unicode, json } = opts + const { unicode } = opts const tarballs = await Promise.all(args.map((arg) => pack_(arg, opts))) - if (!silent && json) { - output(JSON.stringify(tarballs, null, 2)) - } else if (!silent) { - tarballs.forEach((tar) => { - logTar(tar, { log, unicode }) - }) - } + tarballs.forEach(tar => logTar(tar, { log, unicode })) return tarballs } -async function pack_ (arg, opts) { +const pack_ = async (arg, { dryRun }) => { const spec = npa(arg) const manifest = await pacote.manifest(spec) const filename = `${manifest.name}-${manifest.version}.tgz` const tarballData = await libpack(arg) const pkgContents = await getContents(manifest, tarballData) - const { dryRun } = opts if (!dryRun) { await writeFile(filename, tarballData) @@ -57,3 +40,5 @@ async function pack_ (arg, opts) { return pkgContents } + +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/ping.js b/lib/ping.js index a1c470365..7802657ae 100644 --- a/lib/ping.js +++ b/lib/ping.js @@ -1,40 +1,32 @@ -'use strict' - const fetch = require('npm-registry-fetch') const log = require('npmlog') const npm = require('./npm.js') const output = require('./utils/output.js') +const usageUtil = require('./utils/usage.js') -module.exports = ping - -ping.usage = 'npm ping\nping registry' +const usage = usageUtil('ping', 'npm ping\nping registry') +const completion = require('./utils/completion/none.js') -function ping (args, silent, cb) { - if (typeof cb !== 'function') { - cb = silent - silent = false - } +const cmd = (args, cb) => ping(args).then(() => cb()).catch(cb) +const ping = async args => { const opts = npm.flatOptions const registry = opts.registry log.notice('PING', registry) const start = Date.now() - return fetch('/-/ping?write=true', opts).then( - res => res.json().catch(() => ({})) - ).then(details => { - if (silent) { - } else { - const time = Date.now() - start - log.notice('PONG', `${time / 1000}ms`) - if (npm.config.get('json')) { - output(JSON.stringify({ - registry, - time, - details - }, null, 2)) - } else if (Object.keys(details).length) { - log.notice('PONG', `${JSON.stringify(details, null, 2)}`) - } - } - }).then(() => cb(), cb) + const res = await fetch('/-/ping?write=true', opts) + const details = await res.json().catch(() => ({})) + const time = Date.now() - start + log.notice('PONG', `${time / 1000}ms`) + if (opts.json) { + output(JSON.stringify({ + registry, + time, + details + }, null, 2)) + } else if (Object.keys(details).length) { + log.notice('PONG', `${JSON.stringify(details, null, 2)}`) + } } + +module.exports = Object.assign(cmd, { completion, usage }) diff --git a/lib/prefix.js b/lib/prefix.js index fb20389c4..0a9914473 100644 --- a/lib/prefix.js +++ b/lib/prefix.js @@ -1,15 +1,8 @@ -module.exports = prefix - -var npm = require('./npm.js') -var output = require('./utils/output.js') - -prefix.usage = 'npm prefix [-g]' - -function prefix (args, silent, cb) { - if (typeof cb !== 'function') { - cb = silent - silent = false - } - if (!silent) output(npm.prefix) - process.nextTick(cb.bind(this, null, npm.prefix)) -} +const npm = require('./npm.js') +const output = require('./utils/output.js') +const usageUtil = require('./utils/usage.js') +const completion = require('./utils/completion/none.js') +const cmd = (args, cb) => prefix(args).then(() => cb()).catch(cb) +const usage = usageUtil('prefix', 'npm prefix [-g]') +const prefix = async (args, cb) => output(npm.prefix) +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/publish.js b/lib/publish.js index 13f40a0ba..602d213b6 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -14,20 +14,18 @@ const { getContents, logTar } = require('./utils/tar.js') const readJson = util.promisify(require('read-package-json')) -cmd.usage = 'npm publish [<folder>] [--tag <tag>] [--access <public|restricted>] [--dry-run]' + - "\n\nPublishes '.' if no argument supplied" + - '\n\nSets tag `latest` if no --tag specified' - -module.exports = cmd -function cmd (args, cb) { - publish(args) - .then(() => cb()) - .catch(cb) -} +const completion = require('./utils/completion/none.js') +const usageUtil = require('./utils/usage.js') +const usage = usageUtil('publish', + 'npm publish [<folder>] [--tag <tag>] [--access <public|restricted>] [--dry-run]' + + '\n\nPublishes \'.\' if no argument supplied' + + '\nSets tag `latest` if no --tag specified') + +const cmd = (args, cb) => publish(args).then(() => cb()).catch(cb) -async function publish (args) { +const publish = async args => { if (args.length === 0) args = ['.'] - if (args.length !== 1) throw cmd.usage + if (args.length !== 1) throw usage log.verbose('publish', args) @@ -48,7 +46,7 @@ async function publish (args) { return tarball } -async function publish_ (arg, opts) { +const publish_ = async (arg, opts) => { const { unicode, dryRun, json } = opts let manifest = await readJson(`${arg}/package.json`) @@ -92,3 +90,5 @@ async function publish_ (arg, opts) { return pkgContents } + +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/root.js b/lib/root.js index 97d76c120..27e357655 100644 --- a/lib/root.js +++ b/lib/root.js @@ -1,15 +1,8 @@ -module.exports = root - const npm = require('./npm.js') const output = require('./utils/output.js') - -root.usage = 'npm root [-g]' - -function root (args, silent, cb) { - if (typeof cb !== 'function') { - cb = silent - silent = false - } - if (!silent) output(npm.dir) - process.nextTick(cb.bind(this, null, npm.dir)) -} +const usageUtil = require('./utils/usage.js') +const completion = require('./utils/completion/none.js') +const cmd = (args, cb) => root(args).then(() => cb()).catch(cb) +const usage = usageUtil('root', 'npm root [-g]') +const root = async (args, cb) => output(npm.dir) +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/stars.js b/lib/stars.js index a496108a4..391e3ec86 100644 --- a/lib/stars.js +++ b/lib/stars.js @@ -4,36 +4,33 @@ const npm = require('./npm.js') const fetch = require('npm-registry-fetch') const log = require('npmlog') const output = require('./utils/output.js') -const getItentity = require('./utils/get-identity') +const getIdentity = require('./utils/get-identity.js') +const usageUtil = require('./utils/usage.js') +const usage = usageUtil('stars', 'npm stars [<user>]') +const completion = require('./utils/completion/none.js') -stars.usage = 'npm stars [<user>]' +const cmd = (args, cb) => stars(args).then(() => cb()).catch(cb) -const getUser = (opts, user) => user - ? Promise.resolve(user) - : getItentity(opts) - -module.exports = stars -function stars ([user], cb) { - const opts = npm.flatOptions - return getUser(opts, user).then(usr => { - return fetch.json('/-/_view/starredByUser', { - ...opts, - // Note: key has to be JSON, for CouchDB legacy reasons, hence quoted - query: { key: `"${usr}"` } - }) - }).then(data => data.rows).then(stars => { - if (stars.length === 0) { - log.warn('stars', 'user has not starred any packages.') - } else { - stars.forEach(s => output(s.value)) - } - }).catch(err => { - if (err.code === 'ENEEDAUTH') { - throw Object.assign(new Error("'npm stars' on your own user account requires auth"), { - code: 'ENEEDAUTH' - }) - } else { - throw err +const stars = (args) => { + return stars_(args).catch(er => { + if (er.code === 'ENEEDAUTH') { + log.warn('star', 'auth is required to look up your username') } - }).then(() => cb(), cb) + throw er + }) } + +const stars_ = async ([user = getIdentity(npm.flatOptions)]) => { + const { rows } = await fetch.json('/-/_view/starredByUser', { + ...npm.flatOptions, + query: { key: `"${await user}"` } + }) + if (rows.length === 0) { + log.warn('stars', 'user has not starred any packages') + } + for (const row of rows) { + output(row.value) + } +} + +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/team.js b/lib/team.js index a567bdba3..b0e15e349 100644 --- a/lib/team.js +++ b/lib/team.js @@ -1,17 +1,13 @@ -/* eslint-disable standard/no-callback-literal */ - const columns = require('cli-columns') const libteam = require('libnpmteam') const npm = require('./npm.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') -const usage = require('./utils/usage') - -module.exports = team +const usageUtil = require('./utils/usage') -team.subcommands = ['create', 'destroy', 'add', 'rm', 'ls', 'edit'] +const subcommands = ['create', 'destroy', 'add', 'rm', 'ls', 'edit'] -team.usage = usage( +const usage = usageUtil( 'team', 'npm team create <scope:team> [--otp <otpcode>]\n' + 'npm team destroy <scope:team> [--otp <otpcode>]\n' + @@ -21,14 +17,10 @@ team.usage = usage( 'npm team edit <scope:team>' ) -function UsageError () { - throw Object.assign(new Error(team.usage), { code: 'EUSAGE' }) -} - -team.completion = function (opts, cb) { - var argv = opts.conf.argv.remain +const completion = (opts, cb) => { + const { conf: { argv: { remain: argv } } } = opts if (argv.length === 2) { - return cb(null, team.subcommands) + return cb(null, subcommands) } switch (argv[2]) { case 'ls': @@ -43,12 +35,14 @@ team.completion = function (opts, cb) { } } -function team ([cmd, entity = '', user = ''], cb) { +const cmd = (args, cb) => team(args).then(() => cb()).catch(cb) + +const team = async ([cmd, entity = '', user = '']) => { // Entities are in the format <scope>:<team> // XXX: "description" option to libnpmteam is used as a description of the // team, but in npm's options, this is a boolean meaning "show the // description in npm search output". Hence its being set to null here. - otplease(npm.flatOptions, opts => { + await otplease(npm.flatOptions, opts => { entity = entity.replace(/^@/, '') switch (cmd) { case 'create': return teamCreate(entity, opts) @@ -66,100 +60,91 @@ function team ([cmd, entity = '', user = ''], cb) { case 'edit': throw new Error('`npm team edit` is not implemented yet.') default: - UsageError() + throw usage } - }).then( - data => cb(null, data), - err => err.code === 'EUSAGE' ? cb(err.message) : cb(err) - ) + }) } -function teamCreate (entity, opts) { - return libteam.create(entity, opts).then(() => { - if (opts.json) { - output(JSON.stringify({ - created: true, - team: entity - })) - } else if (opts.parseable) { - output(`${entity}\tcreated`) - } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`+@${entity}`) - } - }) +const teamCreate = async (entity, opts) => { + await libteam.create(entity, opts) + if (opts.json) { + output(JSON.stringify({ + created: true, + team: entity + })) + } else if (opts.parseable) { + output(`${entity}\tcreated`) + } else if (!opts.silent && opts.loglevel !== 'silent') { + output(`+@${entity}`) + } } -function teamDestroy (entity, opts) { - return libteam.destroy(entity, opts).then(() => { - if (opts.json) { - output(JSON.stringify({ - deleted: true, - team: entity - })) - } else if (opts.parseable) { - output(`${entity}\tdeleted`) - } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`-@${entity}`) - } - }) +const teamDestroy = async (entity, opts) => { + await libteam.destroy(entity, opts) + if (opts.json) { + output(JSON.stringify({ + deleted: true, + team: entity + })) + } else if (opts.parseable) { + output(`${entity}\tdeleted`) + } else if (!opts.silent && opts.loglevel !== 'silent') { + output(`-@${entity}`) + } } -function teamAdd (entity, user, opts) { - return libteam.add(user, entity, opts).then(() => { - if (opts.json) { - output(JSON.stringify({ - added: true, - team: entity, - user - })) - } else if (opts.parseable) { - output(`${user}\t${entity}\tadded`) - } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`${user} added to @${entity}`) - } - }) +const teamAdd = async (entity, user, opts) => { + await libteam.add(user, entity, opts) + if (opts.json) { + output(JSON.stringify({ + added: true, + team: entity, + user + })) + } else if (opts.parseable) { + output(`${user}\t${entity}\tadded`) + } else if (!opts.silent && opts.loglevel !== 'silent') { + output(`${user} added to @${entity}`) + } } -function teamRm (entity, user, opts) { - return libteam.rm(user, entity, opts).then(() => { - if (opts.json) { - output(JSON.stringify({ - removed: true, - team: entity, - user - })) - } else if (opts.parseable) { - output(`${user}\t${entity}\tremoved`) - } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`${user} removed from @${entity}`) - } - }) +const teamRm = async (entity, user, opts) => { + await libteam.rm(user, entity, opts) + if (opts.json) { + output(JSON.stringify({ + removed: true, + team: entity, + user + })) + } else if (opts.parseable) { + output(`${user}\t${entity}\tremoved`) + } else if (!opts.silent && opts.loglevel !== 'silent') { + output(`${user} removed from @${entity}`) + } } -function teamListUsers (entity, opts) { - return libteam.lsUsers(entity, opts).then(users => { - users = users.sort() - if (opts.json) { - output(JSON.stringify(users, null, 2)) - } else if (opts.parseable) { - output(users.join('\n')) - } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`\n@${entity} has ${users.length} user${users.length === 1 ? '' : 's'}:\n`) - output(columns(users, { padding: 1 })) - } - }) +const teamListUsers = async (entity, opts) => { + const users = (await libteam.lsUsers(entity, opts)).sort() + if (opts.json) { + output(JSON.stringify(users, null, 2)) + } else if (opts.parseable) { + output(users.join('\n')) + } else if (!opts.silent && opts.loglevel !== 'silent') { + output(`\n@${entity} has ${users.length} user${users.length === 1 ? '' : 's'}:\n`) + output(columns(users, { padding: 1 })) + } } -function teamListTeams (entity, opts) { - return libteam.lsTeams(entity, opts).then(teams => { - teams = teams.sort() - if (opts.json) { - output(JSON.stringify(teams, null, 2)) - } else if (opts.parseable) { - output(teams.join('\n')) - } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`\n@${entity} has ${teams.length} team${teams.length === 1 ? '' : 's'}:\n`) - output(columns(teams.map(t => `@${t}`), { padding: 1 })) - } - }) +const teamListTeams = async (entity, opts) => { + const teams = (await libteam.lsTeams(entity, opts)).sort() + if (opts.json) { + output(JSON.stringify(teams, null, 2)) + } else if (opts.parseable) { + output(teams.join('\n')) + } else if (!opts.silent && opts.loglevel !== 'silent') { + output(`\n@${entity} has ${teams.length} team${teams.length === 1 ? '' : 's'}:\n`) + output(columns(teams.map(t => `@${t}`), { padding: 1 })) + } } + +module.exports = Object.assign(cmd, { completion, usage }) diff --git a/lib/unpublish.js b/lib/unpublish.js index 4cda7afad..ec0f149c5 100644 --- a/lib/unpublish.js +++ b/lib/unpublish.js @@ -1,5 +1,3 @@ -'use strict' - const path = require('path') const util = require('util') const log = require('npmlog') diff --git a/lib/update.js b/lib/update.js index c86ca7d85..7f7773153 100644 --- a/lib/update.js +++ b/lib/update.js @@ -1,24 +1,18 @@ -'use strict' - const path = require('path') const Arborist = require('@npmcli/arborist') const log = require('npmlog') const npm = require('./npm.js') -const usage = require('./utils/usage.js') +const usageUtil = require('./utils/usage.js') const reifyOutput = require('./utils/reify-output.js') +const completion = require('./utils/completion/installed-deep.js') -cmd.usage = usage( +const usage = usageUtil( 'update', 'npm update [-g] [<pkg>...]' ) -module.exports = cmd -function cmd (args, cb) { - update(args, cb) - .then(() => cb()) - .catch(cb) -} +const cmd = (args, cb) => update(args).then(() => cb()).catch(cb) const update = async args => { const update = args.length === 0 ? true : args @@ -40,3 +34,5 @@ const update = async args => { await arb.reify({ update }) reifyOutput(arb) } + +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/utils/get-identity.js b/lib/utils/get-identity.js index 1b0e34b90..bf35f2030 100644 --- a/lib/utils/get-identity.js +++ b/lib/utils/get-identity.js @@ -1,10 +1,8 @@ -'use strict' - const npmFetch = require('npm-registry-fetch') const npm = require('../npm') const needsAuthError = (msg) => - Object.assign(new Error(msg, { code: 'ENEEDAUTH' })) + Object.assign(new Error(msg), { code: 'ENEEDAUTH' }) module.exports = async (opts = {}, spec = null) => { const { registry } = opts @@ -18,7 +16,7 @@ module.exports = async (opts = {}, spec = null) => { if (usernameFromURI) { // Found username; return it - return Promise.resolve(usernameFromURI) + return usernameFromURI } else if (token) { // No username, but we have a token; fetch the username from registry const registryData = await npmFetch.json('/-/whoami', { @@ -28,7 +26,7 @@ module.exports = async (opts = {}, spec = null) => { const { username: usernameFromRegistry } = registryData // Retrieved username from registry; return it if (usernameFromRegistry) { - return Promise.resolve(usernameFromRegistry) + return usernameFromRegistry } else { // Didn't get username from registry; bad token throw needsAuthError( diff --git a/lib/utils/lifecycle-cmd.js b/lib/utils/lifecycle-cmd.js index 3a1eb229b..40a90aa20 100644 --- a/lib/utils/lifecycle-cmd.js +++ b/lib/utils/lifecycle-cmd.js @@ -7,5 +7,6 @@ const usageUtil = require('./usage.js') module.exports = stage => { const cmd = (args, cb) => npm.commands.run([stage, ...args], cb) const usage = usageUtil(stage, `npm ${stage} [-- <args>]`) - return Object.assign(cmd, { usage }) + const completion = require('./completion/none.js') + return Object.assign(cmd, { usage, completion }) } diff --git a/lib/version.js b/lib/version.js index a2e88f615..0cfe5906e 100644 --- a/lib/version.js +++ b/lib/version.js @@ -1,58 +1,71 @@ -'use strict' - const libversion = require('libnpmversion') const npm = require('./npm.js') const output = require('./utils/output.js') +const usageUtil = require('./utils/usage.js') + +const completion = (opts, cb) => { + const none = require('./utils/completion/none.js') + const { conf: { argv: { remain } } } = opts + if (remain.length > 2) { + return none(opts, cb) + } + return cb(null, [ + 'major', + 'minor', + 'patch', + 'premajor', + 'preminor', + 'prepatch', + 'prerelease', + 'from-git' + ]) +} + +const usage = usageUtil('version', +`npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git] +(run in package dir) + +'npm -v' or 'npm --version' to print npm version (${npm.version}) +'npm view <pkg> version' to view a package's published version +'npm ls' to inspect current package/dependency versions` +) -const usage = 'npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]' + - '\n(run in package dir)\n' + - "'npm -v' or 'npm --version' to print npm version " + - '(' + npm.version + ')\n' + - "'npm view <pkg> version' to view a package's " + - 'published version\n' + - "'npm ls' to inspect current package/dependency versions" +const cmd = (args, cb) => version(args).then(() => cb()).catch(cb) -const version = (args, cb) => { +const version = async args => { switch (args.length) { case 0: - list(cb) - break + return list() case 1: - libversion(args[0], { + return output(await libversion(args[0], { ...npm.flatOptions, path: npm.prefix - }).then(newVersion => { - output(newVersion) - cb() - }).catch(cb) - break + })) default: - cb(version.usage) - break + throw version.usage } } -const list = cb => { +const list = async () => { const results = {} const { promisify } = require('util') const { resolve } = require('path') const readFile = promisify(require('fs').readFile) const pj = resolve(npm.prefix, 'package.json') - readFile(pj, 'utf8') + + const pkg = await readFile(pj, 'utf8') .then(data => JSON.parse(data)) - .catch(er => ({})) - .then(pkg => { - if (pkg && pkg.name && pkg.version) { - results[pkg.name] = pkg.version - } - results.npm = npm.version - for (const [key, version] of Object.entries(process.versions)) { - results[key] = version - } - - output(npm.flatOptions.json ? JSON.stringify(results, null, 2) : results) - cb() - }) + .catch(() => ({})) + + if (pkg.name && pkg.version) { + results[pkg.name] = pkg.version + } + results.npm = npm.version + for (const [key, version] of Object.entries(process.versions)) { + results[key] = version + } + + output(npm.flatOptions.json ? JSON.stringify(results, null, 2) : results) } -module.exports = Object.assign(version, { usage }) +module.exports = Object.assign(cmd, { usage, completion }) diff --git a/lib/view.js b/lib/view.js index 2c89eb9ae..054c006cd 100644 --- a/lib/view.js +++ b/lib/view.js @@ -1,7 +1,4 @@ -'use strict' - // npm view [pkg [pkg ...]] -module.exports = view const byteSize = require('byte-size') const color = require('ansicolors') @@ -23,15 +20,7 @@ const usage = usageUtil( 'npm view [<@scope>/]<pkg>[@<version>] [<field>[.subfield]...]' ) -const cmd = (args, silent, cb) => { - if (typeof cb !== 'function') { - cb = silent - silent = false - } - view(args, silent, cb) - .then(() => cb()) - .catch(cb) -} +const cmd = (args, cb) => view(args).then(() => cb()).catch(cb) const completion = async (opts, cb) => { if (opts.conf.argv.remain.length <= 2) { @@ -71,7 +60,7 @@ const completion = async (opts, cb) => { } } -async function view (args, silent) { +const view = async args => { if (!args.length) args = ['.'] const opts = npm.flatOptions @@ -98,13 +87,13 @@ async function view (args, silent) { if (pkg && ~pkg.indexOf('@')) { nv.rawSpec = pkg.split('@')[pkg.indexOf('@')] } - await fetchAndRead(nv, args, silent, opts) + await fetchAndRead(nv, args, opts) } else { - await fetchAndRead(nv, args, silent, opts) + await fetchAndRead(nv, args, opts) } } -async function fetchAndRead (nv, args, silent, opts) { +const fetchAndRead = async (nv, args, opts) => { // get the data about this package let version = nv.rawSpec || npm.flatOptions.defaultTag @@ -155,9 +144,7 @@ async function fetchAndRead (nv, args, silent, opts) { log.silly('view', retval) } - if (silent) { - return retval - } else if ( + if ( !opts.json && args.length === 1 && args[0] === '' @@ -175,7 +162,7 @@ async function fetchAndRead (nv, args, silent, opts) { } } -async function prettyView (packument, manifest, opts) { +const prettyView = async (packument, manifest, opts) => { // More modern, pretty printing of default view const unicode = opts.unicode const tags = [] diff --git a/lib/whoami.js b/lib/whoami.js index a2caf4547..8e1c1d052 100644 --- a/lib/whoami.js +++ b/lib/whoami.js @@ -1,25 +1,17 @@ -'use strict' - const npm = require('./npm.js') const output = require('./utils/output.js') -const getIdentity = require('./utils/get-identity') +const getIdentity = require('./utils/get-identity.js') +const usageUtil = require('./utils/usage.js') +const completion = require('./utils/completion/none.js') -module.exports = whoami +const cmd = (args, cb) => whoami(args).then(() => cb()).catch(cb) -whoami.usage = 'npm whoami [--registry <registry>]\n(just prints username according to given registry)' +const usage = usageUtil('whoami', 'npm whoami [--registry <registry>]\n(just prints username according to given registry)') -function whoami ([spec], silent, cb) { - // FIXME: need tighter checking on this, but is a breaking change - if (typeof cb !== 'function') { - cb = silent - silent = false - } +const whoami = async ([spec]) => { const opts = npm.flatOptions - getIdentity(opts, spec).then(username => { - if (silent) {} else if (opts.json) { - output(JSON.stringify(username)) - } else { - output(username) - } - }).then(() => cb(), cb) + const username = await getIdentity(opts, spec) + output(opts.json ? JSON.stringify(username) : username) } + +module.exports = Object.assign(cmd, { completion, usage }) |