diff --git a/deps/npm/AUTHORS b/deps/npm/AUTHORS
index e58d1dffaeaf1d..10189f9c4ba52b 100644
--- a/deps/npm/AUTHORS
+++ b/deps/npm/AUTHORS
@@ -755,3 +755,5 @@ Ikko Ashimine Description
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:
npm@7.6.0 /path/to/npm
+npm@7.6.1 /path/to/npm
└─┬ init-package-json@0.0.4
└── promzard@0.1.5
diff --git a/deps/npm/docs/output/commands/npm-unpublish.html b/deps/npm/docs/output/commands/npm-unpublish.html
index 3ec254a109d470..75751d3408cfa1 100644
--- a/deps/npm/docs/output/commands/npm-unpublish.html
+++ b/deps/npm/docs/output/commands/npm-unpublish.html
@@ -166,7 +166,7 @@ Description
Even if you unpublish a package version, that specific name and version
combination can never be reused. In order to publish the package again,
you must use a new version number. If you unpublish the entire package,
-you may not publish any new versions of that package until 28 days have
+you may not publish any new versions of that package until 24 hours have
passed.
See Also
diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html
index 610396038cad28..21f5e8dd81cc3d 100644
--- a/deps/npm/docs/output/commands/npm.html
+++ b/deps/npm/docs/output/commands/npm.html
@@ -148,7 +148,7 @@ Table of contents
npm <command> [args]
Version
-7.6.0
+7.6.1
Description
npm is the package manager for the Node JavaScript platform. It puts
modules in place so that node can find them, and manages dependency
diff --git a/deps/npm/docs/output/using-npm/scripts.html b/deps/npm/docs/output/using-npm/scripts.html
index bb02d9b1f8092c..e231cfec2ab81e 100644
--- a/deps/npm/docs/output/using-npm/scripts.html
+++ b/deps/npm/docs/output/using-npm/scripts.html
@@ -141,13 +141,21 @@
scripts
Table of contents
-
+
Description
-The "scripts"
property of your package.json
file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running npm run-script <stage>
or npm run <stage>
for short. Pre and post commands with matching names will be run for those as well (e.g. premyscript
, myscript
, postmyscript
). Scripts from dependencies can be run with npm explore <pkg> -- npm run <stage>
.
+The "scripts"
property of your package.json
file supports a number
+of built-in scripts and their preset life cycle events as well as
+arbitrary scripts. These all can be executed by running
+npm run-script <stage>
or npm run <stage>
for short. Pre and post
+commands with matching names will be run for those as well (e.g. premyscript
,
+myscript
, postmyscript
). Scripts from dependencies can be run with
+npm explore <pkg> -- npm run <stage>
.
Pre & Post Scripts
-To create “pre” or “post” scripts for any scripts defined in the "scripts"
section of the package.json
, simply create another script with a matching name and add “pre” or “post” to the beginning of them.
+To create “pre” or “post” scripts for any scripts defined in the
+"scripts"
section of the package.json
, simply create another script
+with a matching name and add “pre” or “post” to the beginning of them.
{
"scripts": {
"precompress": "{{ executes BEFORE the `compress` script }}",
@@ -156,22 +164,47 @@ Pre & Post Scripts
}
}
+In this example npm run compress
would execute these scripts as
+described.
Life Cycle Scripts
-There are some special life cycle scripts that happen only in certain situations. These scripts happen in addition to the “pre” and “post” script.
+There are some special life cycle scripts that happen only in certain
+situations. These scripts happen in addition to the pre<event>
, post<event>
, and
+<event>
scripts.
prepare
, prepublish
, prepublishOnly
, prepack
, postpack
prepare (since npm@4.0.0
)
-- Runs BEFORE the package is packed
-- Runs BEFORE the package is published
-- Runs on local
npm install
without any arguments
-- Run AFTER
prepublish
, but BEFORE prepublishOnly
-- NOTE: If a package being installed through git contains a
prepare
script, its dependencies
and devDependencies
will be installed, and the prepare script will be run, before the package is packaged and installed.
+-
+
Runs any time before the package is packed, i.e. during npm publish
+and npm pack
+
+-
+
Runs BEFORE the package is packed
+
+-
+
Runs BEFORE the package is published
+
+-
+
Runs on local npm install
without any arguments
+
+-
+
Run AFTER prepublish
, but BEFORE prepublishOnly
+
+-
+
NOTE: If a package being installed through git contains a prepare
+script, its dependencies
and devDependencies
will be installed, and
+the prepare script will be run, before the package is packaged and
+installed.
+
+-
+
As of npm@7
these scripts run in the background
+
prepublish (DEPRECATED)
-- Same as
prepare
+- Does not run during
npm publish
, but does run during npm ci
+and npm install
. See below for more info.
prepublishOnly
@@ -184,7 +217,7 @@ Life Cycle Scripts
postpack
-- Runs AFTER the tarball has been generated and moved to its final destination.
+- Runs AFTER the tarball has been generated but before it is moved to its final destination (if at all, publish does not save the tarball locally)
Prepare and Prepublish
Deprecation Note: prepublish
@@ -207,51 +240,106 @@ Prepare and Prepublish
other system tools on the target machines.
Life Cycle Operation Order
-npm publish
+npm cache add
-prepublishOnly
prepare
+
+npm ci
+
+preinstall
+install
+postinstall
prepublish
-publish
-postpublish
+preprepare
+prepare
+postprepare
+
+These all run after the actual installation of modules into
+node_modules
, in order, with no internal actions happening in between
+npm diff
+
+prepare
+
+npm env
+
+env
(You can override the default behavior of npm env
by defining
+a custom env
entry in your scripts
object)
+
+npm install
+These also run when you run npm install -g <pkg-name>
+
+preinstall
+install
+postinstall
+prepublish
+preprepare
+prepare
+postprepare
+If there is a binding.gyp
file in the root of your package and you
+haven’t defined your own install
or preinstall
scripts, npm will
+default the install
command to compile using node-gyp via node-gyp rebuild
+These are run from the scripts of <pkg-name>
npm pack
prepack
+prepare
postpack
-npm install
+npm publish
+
+prepublishOnly
+prepack
+prepare
+postpack
+publish
+postpublish
+
+prepare
will not run during --dry-run
+npm rebuild
preinstall
install
postinstall
+prepare
+
+prepare
is only run if the current directory is a symlink (e.g. with
+linked packages)
+npm restart
+If there is a restart
script defined, these events are run, otherwise
+stop
and start
are both run if present, including their pre
and
+post
iterations)
+
+prerestart
+restart
+postrestart
-Also triggers
+npm run <user defined>
-prepublish
(when on local)
-prepare
(when on local or workspaces)
+pre<user-defined>
+<user-defined>
+post<user-defined>
npm start
-npm run start
has an npm start
shorthand.
prestart
start
poststart
-Default Values
-npm will default some script values based on package contents.
-
--
-
"start": "node server.js"
:
If there is a server.js
file in the root of your package, then npm
-will default the start
command to node server.js
.
-
--
-
"install": "node-gyp rebuild"
:
-If there is a binding.gyp
file in the root of your package and you
-haven’t defined your own install
or preinstall
scripts, npm will
-default the install
command to compile using node-gyp.
-
+will default the start
command to node server.js
. prestart
and
+poststart
will still run in this case.
+npm stop
+
+prestop
+stop
+poststop
+
+npm test
+
+pretest
+test
+posttest
User
When npm is run as root, scripts are always run with the effective uid
@@ -264,14 +352,14 @@
path
If you depend on modules that define executable scripts, like test
suites, then those executables will be added to the PATH
for
executing the scripts. So, if your package.json has this:
-
{
- "name" : "foo",
- "dependencies" : {
- "bar" : "0.1.x"
- },
- "scripts": {
- "start" : "bar ./test"
- }
+{
+ "name" : "foo",
+ "dependencies" : {
+ "bar" : "0.1.x"
+ },
+ "scripts": {
+ "start" : "bar ./test"
+ }
}
then you could run npm start
to execute the bar
script, which is
@@ -292,14 +380,14 @@
Special: package.json “config” ob
The package.json “config” keys are overwritten in the environment if
there is a config param of <name>[@<version>]:<key>
. For example,
if the package.json has this:
-{
- "name" : "foo",
- "config" : {
- "port" : "8080"
- },
- "scripts" : {
- "start" : "node server.js"
- }
+{
+ "name" : "foo",
+ "config" : {
+ "port" : "8080"
+ },
+ "scripts" : {
+ "start" : "node server.js"
+ }
}
and the server.js is this:
@@ -320,10 +408,10 @@ current lifecycle event
Examples
For example, if your package.json contains this:
-{
- "scripts" : {
- "install" : "scripts/install.js",
- "postinstall" : "scripts/postinstall.js",
+{
+ "scripts" : {
+ "install" : "scripts/install.js",
+ "postinstall" : "scripts/postinstall.js",
"uninstall" : "scripts/uninstall.js"
}
}
@@ -336,10 +424,10 @@ Examples
variable.
If you want to run a make command, you can do so. This works just
fine:
-{
- "scripts" : {
- "preinstall" : "./configure",
- "install" : "make && make install",
+{
+ "scripts" : {
+ "preinstall" : "./configure",
+ "install" : "make && make install",
"test" : "make test"
}
}
diff --git a/deps/npm/lib/access.js b/deps/npm/lib/access.js
index 10b1e21e0c5d7e..e11934af43ebc4 100644
--- a/deps/npm/lib/access.js
+++ b/deps/npm/lib/access.js
@@ -3,25 +3,11 @@ const path = require('path')
const libaccess = require('libnpmaccess')
const readPackageJson = require('read-package-json-fast')
-const npm = require('./npm.js')
const output = require('./utils/output.js')
const otplease = require('./utils/otplease.js')
const usageUtil = require('./utils/usage.js')
const getIdentity = require('./utils/get-identity.js')
-const usage = usageUtil(
- 'npm access',
- 'npm access public []\n' +
- 'npm access restricted []\n' +
- 'npm access grant []\n' +
- 'npm access revoke []\n' +
- 'npm access 2fa-required []\n' +
- 'npm access 2fa-not-required []\n' +
- 'npm access ls-packages [||]\n' +
- 'npm access ls-collaborators [ []]\n' +
- 'npm access edit []'
-)
-
const subcommands = [
'public',
'restricted',
@@ -34,152 +20,195 @@ const subcommands = [
'2fa-not-required',
]
-const UsageError = (msg) =>
- Object.assign(new Error(`\nUsage: ${msg}\n\n` + usage), {
- code: 'EUSAGE',
- })
-
-const cmd = (args, cb) =>
- access(args)
- .then(x => cb(null, x))
- .catch(err => err.code === 'EUSAGE'
- ? cb(err.message)
- : cb(err)
+class Access {
+ constructor (npm) {
+ this.npm = npm
+ }
+
+ get usage () {
+ return usageUtil(
+ 'access',
+ 'npm access public []\n' +
+ 'npm access restricted []\n' +
+ 'npm access grant []\n' +
+ 'npm access revoke []\n' +
+ 'npm access 2fa-required []\n' +
+ 'npm access 2fa-not-required []\n' +
+ 'npm access ls-packages [||]\n' +
+ 'npm access ls-collaborators [ []]\n' +
+ 'npm access edit []'
)
+ }
-const access = async ([cmd, ...args], cb) => {
- const fn = subcommands.includes(cmd) && access[cmd]
+ async completion (opts) {
+ const argv = opts.conf.argv.remain
+ if (argv.length === 2)
+ return subcommands
+
+ switch (argv[2]) {
+ case 'grant':
+ if (argv.length === 3)
+ return ['read-only', 'read-write']
+ else
+ return []
+
+ case 'public':
+ case 'restricted':
+ case 'ls-packages':
+ case 'ls-collaborators':
+ case 'edit':
+ case '2fa-required':
+ case '2fa-not-required':
+ case 'revoke':
+ return []
+ default:
+ throw new Error(argv[2] + ' not recognized')
+ }
+ }
- if (!cmd)
- throw UsageError('Subcommand is required.')
+ exec (args, cb) {
+ this.access(args)
+ .then(x => cb(null, x))
+ .catch(err => err.code === 'EUSAGE'
+ ? cb(err.message)
+ : cb(err)
+ )
+ }
- if (!fn)
- throw UsageError(`${cmd} is not a recognized subcommand.`)
+ async access ([cmd, ...args]) {
+ if (!cmd)
+ throw this.usageError('Subcommand is required.')
- return fn(args, { ...npm.flatOptions })
-}
+ if (!subcommands.includes(cmd) || !this[cmd])
+ throw this.usageError(`${cmd} is not a recognized subcommand.`)
-const completion = async (opts) => {
- const argv = opts.conf.argv.remain
- if (argv.length === 2)
- return subcommands
+ return this[cmd](args, { ...this.npm.flatOptions })
+ }
- switch (argv[2]) {
- case 'grant':
- if (argv.length === 3)
- return ['read-only', 'read-write']
- else
- return []
+ public ([pkg], opts) {
+ return this.modifyPackage(pkg, opts, libaccess.public)
+ }
- case 'public':
- case 'restricted':
- case 'ls-packages':
- case 'ls-collaborators':
- case 'edit':
- case '2fa-required':
- case '2fa-not-required':
- case 'revoke':
- return []
- default:
- throw new Error(argv[2] + ' not recognized')
+ restricted ([pkg], opts) {
+ return this.modifyPackage(pkg, opts, libaccess.restricted)
}
-}
-access.public = ([pkg], opts) =>
- modifyPackage(pkg, opts, libaccess.public)
+ async grant ([perms, scopeteam, pkg], opts) {
+ if (!perms || (perms !== 'read-only' && perms !== 'read-write'))
+ throw this.usageError('First argument must be either `read-only` or `read-write`.')
-access.restricted = ([pkg], opts) =>
- modifyPackage(pkg, opts, libaccess.restricted)
+ if (!scopeteam)
+ throw this.usageError('`` argument is required.')
-access.grant = async ([perms, scopeteam, pkg], opts) => {
- if (!perms || (perms !== 'read-only' && perms !== 'read-write'))
- throw UsageError('First argument must be either `read-only` or `read-write`.')
+ const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || []
- if (!scopeteam)
- throw UsageError('`` argument is required.')
+ if (!scope && !team) {
+ throw this.usageError(
+ 'Second argument used incorrect format.\n' +
+ 'Example: @example:developers'
+ )
+ }
- const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || []
+ return this.modifyPackage(pkg, opts, (pkgName, opts) =>
+ libaccess.grant(pkgName, scopeteam, perms, opts), false)
+ }
- if (!scope && !team) {
- throw UsageError(
- 'Second argument used incorrect format.\n' +
- 'Example: @example:developers'
- )
+ async revoke ([scopeteam, pkg], opts) {
+ if (!scopeteam)
+ throw this.usageError('`` argument is required.')
+
+ const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || []
+
+ if (!scope || !team) {
+ throw this.usageError(
+ 'First argument used incorrect format.\n' +
+ 'Example: @example:developers'
+ )
+ }
+
+ return this.modifyPackage(pkg, opts, (pkgName, opts) =>
+ libaccess.revoke(pkgName, scopeteam, opts))
}
- return modifyPackage(pkg, opts, (pkgName, opts) =>
- libaccess.grant(pkgName, scopeteam, perms, opts), false)
-}
+ get ['2fa-required'] () {
+ return this.tfaRequired
+ }
-access.revoke = async ([scopeteam, pkg], opts) => {
- if (!scopeteam)
- throw UsageError('`` argument is required.')
+ tfaRequired ([pkg], opts) {
+ return this.modifyPackage(pkg, opts, libaccess.tfaRequired, false)
+ }
- const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || []
+ get ['2fa-not-required'] () {
+ return this.tfaNotRequired
+ }
- if (!scope || !team) {
- throw UsageError(
- 'First argument used incorrect format.\n' +
- 'Example: @example:developers'
- )
+ tfaNotRequired ([pkg], opts) {
+ return this.modifyPackage(pkg, opts, libaccess.tfaNotRequired, false)
}
- return modifyPackage(pkg, opts, (pkgName, opts) =>
- libaccess.revoke(pkgName, scopeteam, opts))
-}
+ get ['ls-packages'] () {
+ return this.lsPackages
+ }
-access['2fa-required'] = access.tfaRequired = ([pkg], opts) =>
- modifyPackage(pkg, opts, libaccess.tfaRequired, false)
+ async lsPackages ([owner], opts) {
+ if (!owner)
+ owner = await getIdentity(this.npm, opts)
-access['2fa-not-required'] = access.tfaNotRequired = ([pkg], opts) =>
- modifyPackage(pkg, opts, libaccess.tfaNotRequired, false)
+ const pkgs = await libaccess.lsPackages(owner, opts)
-access['ls-packages'] = access.lsPackages = async ([owner], opts) => {
- if (!owner)
- owner = await getIdentity(opts)
+ // TODO - print these out nicely (breaking change)
+ output(JSON.stringify(pkgs, null, 2))
+ }
- const pkgs = await libaccess.lsPackages(owner, opts)
+ get ['ls-collaborators'] () {
+ return this.lsCollaborators
+ }
- // TODO - print these out nicely (breaking change)
- output(JSON.stringify(pkgs, null, 2))
-}
+ async lsCollaborators ([pkg, usr], opts) {
+ const pkgName = await this.getPackage(pkg, false)
+ const collabs = await libaccess.lsCollaborators(pkgName, usr, opts)
-access['ls-collaborators'] = access.lsCollaborators = async ([pkg, usr], opts) => {
- const pkgName = await getPackage(pkg, false)
- const collabs = await libaccess.lsCollaborators(pkgName, usr, opts)
+ // TODO - print these out nicely (breaking change)
+ output(JSON.stringify(collabs, null, 2))
+ }
- // TODO - print these out nicely (breaking change)
- output(JSON.stringify(collabs, null, 2))
-}
+ async edit () {
+ throw new Error('edit subcommand is not implemented yet')
+ }
-access.edit = () =>
- Promise.reject(new Error('edit subcommand is not implemented yet'))
-
-const modifyPackage = (pkg, opts, fn, requireScope = true) =>
- getPackage(pkg, requireScope)
- .then(pkgName => otplease(opts, opts => fn(pkgName, opts)))
-
-const getPackage = async (name, requireScope) => {
- if (name && name.trim())
- return name.trim()
- else {
- try {
- const pkg = await readPackageJson(path.resolve(npm.prefix, 'package.json'))
- name = pkg.name
- } catch (err) {
- if (err.code === 'ENOENT') {
- throw new Error(
- 'no package name passed to command and no package.json found'
- )
- } else
- throw err
+ modifyPackage (pkg, opts, fn, requireScope = true) {
+ return this.getPackage(pkg, requireScope)
+ .then(pkgName => otplease(opts, opts => fn(pkgName, opts)))
+ }
+
+ async getPackage (name, requireScope) {
+ if (name && name.trim())
+ return name.trim()
+ else {
+ try {
+ const pkg = await readPackageJson(path.resolve(this.npm.prefix, 'package.json'))
+ name = pkg.name
+ } catch (err) {
+ if (err.code === 'ENOENT') {
+ throw new Error(
+ 'no package name passed to command and no package.json found'
+ )
+ } else
+ throw err
+ }
+
+ if (requireScope && !name.match(/^@[^/]+\/.*$/))
+ throw this.usageError('This command is only available for scoped packages.')
+ else
+ return name
}
+ }
- if (requireScope && !name.match(/^@[^/]+\/.*$/))
- throw UsageError('This command is only available for scoped packages.')
- else
- return name
+ usageError (msg) {
+ return Object.assign(new Error(`\nUsage: ${msg}\n\n` + this.usage), {
+ code: 'EUSAGE',
+ })
}
}
-module.exports = Object.assign(cmd, { usage, completion, subcommands })
+module.exports = Access
diff --git a/deps/npm/lib/adduser.js b/deps/npm/lib/adduser.js
index c68c2b80f8790b..dac0f5a46840df 100644
--- a/deps/npm/lib/adduser.js
+++ b/deps/npm/lib/adduser.js
@@ -1,5 +1,4 @@
const log = require('npmlog')
-const npm = require('./npm.js')
const output = require('./utils/output.js')
const usageUtil = require('./utils/usage.js')
const replaceInfo = require('./utils/replace-info.js')
@@ -10,66 +9,76 @@ const authTypes = {
sso: require('./auth/sso.js'),
}
-const usage = usageUtil(
- 'adduser',
- 'npm adduser [--registry=url] [--scope=@orgname] [--always-auth]'
-)
+class AddUser {
+ constructor (npm) {
+ this.npm = npm
+ }
-const cmd = (args, cb) => adduser(args).then(() => cb()).catch(cb)
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil(
+ 'adduser',
+ 'npm adduser [--registry=url] [--scope=@orgname] [--always-auth]'
+ )
+ }
-const getRegistry = ({ scope, registry }) => {
- if (scope) {
- const scopedRegistry = npm.config.get(`${scope}:registry`)
- const cliRegistry = npm.config.get('registry', 'cli')
- if (scopedRegistry && !cliRegistry)
- return scopedRegistry
+ exec (args, cb) {
+ this.adduser(args).then(() => cb()).catch(cb)
}
- return registry
-}
-const getAuthType = ({ authType }) => {
- const type = authTypes[authType]
+ async adduser (args) {
+ const { scope } = this.npm.flatOptions
+ const registry = this.getRegistry(this.npm.flatOptions)
+ const auth = this.getAuthType(this.npm.flatOptions)
+ const creds = this.npm.config.getCredentialsByURI(registry)
- if (!type)
- throw new Error('no such auth module')
+ log.disableProgress()
- return type
-}
+ log.notice('', `Log in on ${replaceInfo(registry)}`)
-const updateConfig = async ({ newCreds, registry, scope }) => {
- npm.config.delete('_token', 'user') // prevent legacy pollution
+ const { message, newCreds } = await auth(this.npm, {
+ ...this.npm.flatOptions,
+ creds,
+ registry,
+ scope,
+ })
- if (scope)
- npm.config.set(scope + ':registry', registry, 'user')
+ await this.updateConfig({
+ newCreds,
+ registry,
+ scope,
+ })
- npm.config.setCredentialsByURI(registry, newCreds)
- await npm.config.save('user')
-}
+ output(message)
+ }
-const adduser = async (args) => {
- const { scope } = npm.flatOptions
- const registry = getRegistry(npm.flatOptions)
- const auth = getAuthType(npm.flatOptions)
- const creds = npm.config.getCredentialsByURI(registry)
+ getRegistry ({ scope, registry }) {
+ if (scope) {
+ const scopedRegistry = this.npm.config.get(`${scope}:registry`)
+ const cliRegistry = this.npm.config.get('registry', 'cli')
+ if (scopedRegistry && !cliRegistry)
+ return scopedRegistry
+ }
+ return registry
+ }
- log.disableProgress()
+ getAuthType ({ authType }) {
+ const type = authTypes[authType]
- log.notice('', `Log in on ${replaceInfo(registry)}`)
+ if (!type)
+ throw new Error('no such auth module')
- const { message, newCreds } = await auth({
- ...npm.flatOptions,
- creds,
- registry,
- scope,
- })
+ return type
+ }
- await updateConfig({
- newCreds,
- registry,
- scope,
- })
+ async updateConfig ({ newCreds, registry, scope }) {
+ this.npm.config.delete('_token', 'user') // prevent legacy pollution
- output(message)
-}
+ if (scope)
+ this.npm.config.set(scope + ':registry', registry, 'user')
-module.exports = Object.assign(cmd, { usage })
+ this.npm.config.setCredentialsByURI(registry, newCreds)
+ await this.npm.config.save('user')
+ }
+}
+module.exports = AddUser
diff --git a/deps/npm/lib/audit.js b/deps/npm/lib/audit.js
index 1b31401b1a6b0b..dfa01cb2709fa8 100644
--- a/deps/npm/lib/audit.js
+++ b/deps/npm/lib/audit.js
@@ -1,55 +1,65 @@
const Arborist = require('@npmcli/arborist')
const auditReport = require('npm-audit-report')
-const npm = require('./npm.js')
const output = require('./utils/output.js')
const reifyFinish = require('./utils/reify-finish.js')
const auditError = require('./utils/audit-error.js')
+const usageUtil = require('./utils/usage.js')
-const audit = async args => {
- const arb = new Arborist({
- ...npm.flatOptions,
- audit: true,
- path: npm.prefix,
- })
- const fix = args[0] === 'fix'
- await arb.audit({ fix })
- if (fix)
- await reifyFinish(arb)
- else {
- // will throw if there's an error, because this is an audit command
- auditError(arb.auditReport)
- const reporter = npm.flatOptions.json ? 'json' : 'detail'
- const result = auditReport(arb.auditReport, {
- ...npm.flatOptions,
- reporter,
- })
- process.exitCode = process.exitCode || result.exitCode
- output(result.report)
+class Audit {
+ constructor (npm) {
+ this.npm = npm
}
-}
-const cmd = (args, cb) => audit(args).then(() => cb()).catch(cb)
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil(
+ 'audit',
+ 'npm audit [--json] [--production]' +
+ '\nnpm audit fix ' +
+ '[--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)]'
+ )
+ }
-const usageUtil = require('./utils/usage')
-const usage = usageUtil(
- 'audit',
- 'npm audit [--json] [--production]' +
- '\nnpm audit fix ' +
- '[--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)]'
-)
+ async completion (opts) {
+ const argv = opts.conf.argv.remain
-const completion = async (opts) => {
- const argv = opts.conf.argv.remain
+ if (argv.length === 2)
+ return ['fix']
- if (argv.length === 2)
- return ['fix']
+ switch (argv[2]) {
+ case 'fix':
+ return []
+ default:
+ throw new Error(argv[2] + ' not recognized')
+ }
+ }
- switch (argv[2]) {
- case 'fix':
- return []
- default:
- throw new Error(argv[2] + ' not recognized')
+ exec (args, cb) {
+ this.audit(args).then(() => cb()).catch(cb)
+ }
+
+ async audit (args) {
+ const arb = new Arborist({
+ ...this.npm.flatOptions,
+ audit: true,
+ path: this.npm.prefix,
+ })
+ const fix = args[0] === 'fix'
+ await arb.audit({ fix })
+ if (fix)
+ await reifyFinish(this.npm, arb)
+ else {
+ // will throw if there's an error, because this is an audit command
+ auditError(this.npm, arb.auditReport)
+ const reporter = this.npm.flatOptions.json ? 'json' : 'detail'
+ const result = auditReport(arb.auditReport, {
+ ...this.npm.flatOptions,
+ reporter,
+ })
+ process.exitCode = process.exitCode || result.exitCode
+ output(result.report)
+ }
}
}
-module.exports = Object.assign(cmd, { usage, completion })
+module.exports = Audit
diff --git a/deps/npm/lib/auth/legacy.js b/deps/npm/lib/auth/legacy.js
index f291ca794e7f1b..8659446dc4c021 100644
--- a/deps/npm/lib/auth/legacy.js
+++ b/deps/npm/lib/auth/legacy.js
@@ -4,11 +4,6 @@ const profile = require('npm-profile')
const openUrl = require('../utils/open-url.js')
const read = require('../utils/read-user-info.js')
-// TODO: refactor lib/utils/open-url and its usages
-const openerPromise = (url) => new Promise((resolve, reject) => {
- openUrl(url, 'to complete your login please visit', (er) => er ? reject(er) : resolve())
-})
-
const loginPrompter = async (creds) => {
const opts = { log: log }
@@ -19,7 +14,7 @@ const loginPrompter = async (creds) => {
return creds
}
-const login = async (opts) => {
+const login = async (npm, opts) => {
let res
const requestOTP = async () => {
@@ -54,6 +49,7 @@ const login = async (opts) => {
return newUser
}
+ const openerPromise = (url) => openUrl(npm, url, 'to complete your login please visit')
try {
res = await profile.login(openerPromise, loginPrompter, opts)
} catch (err) {
diff --git a/deps/npm/lib/auth/oauth.js b/deps/npm/lib/auth/oauth.js
index ee45317113421f..99c2ca0ca04b7a 100644
--- a/deps/npm/lib/auth/oauth.js
+++ b/deps/npm/lib/auth/oauth.js
@@ -1,9 +1,8 @@
const sso = require('./sso.js')
-const npm = require('../npm.js')
-const login = (opts) => {
+const login = (npm, opts) => {
npm.config.set('sso-type', 'oauth')
- return sso(opts)
+ return sso(npm, opts)
}
module.exports = login
diff --git a/deps/npm/lib/auth/saml.js b/deps/npm/lib/auth/saml.js
index f30d82849dbf91..3dd31ca013f522 100644
--- a/deps/npm/lib/auth/saml.js
+++ b/deps/npm/lib/auth/saml.js
@@ -1,9 +1,8 @@
const sso = require('./sso.js')
-const npm = require('../npm.js')
-const login = (opts) => {
+const login = (npm, opts) => {
npm.config.set('sso-type', 'saml')
- return sso(opts)
+ return sso(npm, opts)
}
module.exports = login
diff --git a/deps/npm/lib/auth/sso.js b/deps/npm/lib/auth/sso.js
index 378295f5f606f2..56cff3c06e2929 100644
--- a/deps/npm/lib/auth/sso.js
+++ b/deps/npm/lib/auth/sso.js
@@ -7,14 +7,11 @@
// CLI, we can remove this, and fold the lib/auth/legacy.js back into
// lib/adduser.js
-const { promisify } = require('util')
-
const log = require('npmlog')
const profile = require('npm-profile')
const npmFetch = require('npm-registry-fetch')
-const npm = require('../npm.js')
-const openUrl = promisify(require('../utils/open-url.js'))
+const openUrl = require('../utils/open-url.js')
const otplease = require('../utils/otplease.js')
const pollForSession = ({ registry, token, opts }) => {
@@ -38,7 +35,7 @@ function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time))
}
-const login = async ({ creds, registry, scope }) => {
+const login = async (npm, { creds, registry, scope }) => {
log.warn('deprecated', 'SSO --auth-type is deprecated')
const opts = { ...npm.flatOptions, creds, registry, scope }
@@ -65,7 +62,7 @@ const login = async ({ creds, registry, scope }) => {
if (!sso)
throw new Error('no SSO URL returned by services')
- await openUrl(sso, 'to complete your login please visit')
+ await openUrl(npm, sso, 'to complete your login please visit')
const username = await pollForSession({ registry, token, opts })
diff --git a/deps/npm/lib/bin.js b/deps/npm/lib/bin.js
index e627ce22f13a68..11490c41cbcc5f 100644
--- a/deps/npm/lib/bin.js
+++ b/deps/npm/lib/bin.js
@@ -1,13 +1,26 @@
-const npm = require('./npm.js')
const output = require('./utils/output.js')
+const envPath = require('./utils/path.js')
const usageUtil = require('./utils/usage.js')
-const PATH = require('./utils/path.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
- output(b)
- if (npm.flatOptions.global && !PATH.includes(b))
- console.error('(not in PATH env variable)')
+
+class Bin {
+ constructor (npm) {
+ this.npm = npm
+ }
+
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('bin', 'npm bin [-g]')
+ }
+
+ exec (args, cb) {
+ this.bin(args).then(() => cb()).catch(cb)
+ }
+
+ async bin (args) {
+ const b = this.npm.bin
+ output(b)
+ if (this.npm.flatOptions.global && !envPath.includes(b))
+ console.error('(not in PATH env variable)')
+ }
}
-module.exports = Object.assign(cmd, { usage })
+module.exports = Bin
diff --git a/deps/npm/lib/birthday.js b/deps/npm/lib/birthday.js
index 6c71a9e7156689..5ea855512f9f69 100644
--- a/deps/npm/lib/birthday.js
+++ b/deps/npm/lib/birthday.js
@@ -1,11 +1,18 @@
-const npm = require('./npm.js')
-module.exports = (_, cb) => {
- Object.defineProperty(npm, 'flatOptions', {
- value: {
- ...npm.flatOptions,
- package: ['@npmcli/npm-birthday'],
- yes: true,
- },
- })
- return npm.commands.exec(['npm-birthday'], cb)
+class Birthday {
+ constructor (npm) {
+ this.npm = npm
+ Object.defineProperty(this.npm, 'flatOptions', {
+ value: {
+ ...npm.flatOptions,
+ package: ['@npmcli/npm-birthday'],
+ yes: true,
+ },
+ })
+ }
+
+ exec (args, cb) {
+ return this.npm.commands.exec(['npm-birthday'], cb)
+ }
}
+
+module.exports = Birthday
diff --git a/deps/npm/lib/bugs.js b/deps/npm/lib/bugs.js
index 09856313ce883e..fb0d7c92770c7f 100644
--- a/deps/npm/lib/bugs.js
+++ b/deps/npm/lib/bugs.js
@@ -1,46 +1,55 @@
const log = require('npmlog')
const pacote = require('pacote')
-const { promisify } = require('util')
-const openUrl = promisify(require('./utils/open-url.js'))
+const openUrl = require('./utils/open-url.js')
const usageUtil = require('./utils/usage.js')
-const npm = require('./npm.js')
const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js')
-const usage = usageUtil('bugs', 'npm bugs []')
+class Bugs {
+ constructor (npm) {
+ this.npm = npm
+ }
-const cmd = (args, cb) => bugs(args).then(() => cb()).catch(cb)
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('bugs', 'npm bugs []')
+ }
-const bugs = async args => {
- if (!args || !args.length)
- args = ['.']
+ exec (args, cb) {
+ this.bugs(args).then(() => cb()).catch(cb)
+ }
- await Promise.all(args.map(pkg => getBugs(pkg)))
-}
+ async bugs (args) {
+ if (!args || !args.length)
+ args = ['.']
-const getBugsUrl = mani => {
- if (mani.bugs) {
- if (typeof mani.bugs === 'string')
- return mani.bugs
+ await Promise.all(args.map(pkg => this.getBugs(pkg)))
+ }
- if (typeof mani.bugs === 'object' && mani.bugs.url)
- return mani.bugs.url
+ async getBugs (pkg) {
+ const opts = { ...this.npm.flatOptions, fullMetadata: true }
+ const mani = await pacote.manifest(pkg, opts)
+ const url = this.getBugsUrl(mani)
+ log.silly('bugs', 'url', url)
+ await openUrl(this.npm, url, `${mani.name} bug list available at the following URL`)
}
- // try to get it from the repo, if possible
- const info = hostedFromMani(mani)
- if (info)
- return info.bugs()
+ getBugsUrl (mani) {
+ if (mani.bugs) {
+ if (typeof mani.bugs === 'string')
+ return mani.bugs
- // just send them to the website, hopefully that has some info!
- return `https://www.npmjs.com/package/${mani.name}`
-}
+ if (typeof mani.bugs === 'object' && mani.bugs.url)
+ return mani.bugs.url
+ }
-const getBugs = async pkg => {
- const opts = { ...npm.flatOptions, fullMetadata: true }
- const mani = await pacote.manifest(pkg, opts)
- const url = getBugsUrl(mani)
- log.silly('bugs', 'url', url)
- await openUrl(url, `${mani.name} bug list available at the following URL`)
+ // try to get it from the repo, if possible
+ const info = hostedFromMani(mani)
+ if (info)
+ return info.bugs()
+
+ // just send them to the website, hopefully that has some info!
+ return `https://www.npmjs.com/package/${mani.name}`
+ }
}
-module.exports = Object.assign(cmd, { usage })
+module.exports = Bugs
diff --git a/deps/npm/lib/cache.js b/deps/npm/lib/cache.js
index 7b84353b4a19b6..8469559764fb31 100644
--- a/deps/npm/lib/cache.js
+++ b/deps/npm/lib/cache.js
@@ -1,62 +1,69 @@
const cacache = require('cacache')
const { promisify } = require('util')
const log = require('npmlog')
-const npm = require('./npm.js')
const output = require('./utils/output.js')
const pacote = require('pacote')
const path = require('path')
const rimraf = promisify(require('rimraf'))
const usageUtil = require('./utils/usage.js')
+class Cache {
+ constructor (npm) {
+ this.npm = npm
+ }
-const usage = usageUtil('cache',
- 'npm cache add ' +
- '\nnpm cache add ' +
- '\nnpm cache add ' +
- '\nnpm cache add ' +
- '\nnpm cache add @' +
- '\nnpm cache clean' +
- '\nnpm cache verify'
-)
-
-const completion = async (opts) => {
- const argv = opts.conf.argv.remain
- if (argv.length === 2)
- return ['add', 'clean', 'verify']
-
- // TODO - eventually...
- switch (argv[2]) {
- case 'verify':
- case 'clean':
- case 'add':
- return []
+ get usage () {
+ return usageUtil('cache',
+ 'npm cache add ' +
+ '\nnpm cache add ' +
+ '\nnpm cache add ' +
+ '\nnpm cache add ' +
+ '\nnpm cache add @' +
+ '\nnpm cache clean' +
+ '\nnpm cache verify'
+ )
}
-}
-const cmd = (args, cb) => cache(args).then(() => cb()).catch(cb)
-
-const cache = async (args) => {
- const cmd = args.shift()
- switch (cmd) {
- case 'rm': case 'clear': case 'clean':
- return await clean(args)
- case 'add':
- return await add(args)
- case 'verify': case 'check':
- return await verify()
- default:
- throw Object.assign(new Error(usage), { code: 'EUSAGE' })
+ async completion (opts) {
+ const argv = opts.conf.argv.remain
+ if (argv.length === 2)
+ return ['add', 'clean', 'verify']
+
+ // TODO - eventually...
+ switch (argv[2]) {
+ case 'verify':
+ case 'clean':
+ case 'add':
+ return []
+ }
+ }
+
+ exec (args, cb) {
+ this.cache(args).then(() => cb()).catch(cb)
+ }
+
+ async cache (args) {
+ const cmd = args.shift()
+ switch (cmd) {
+ case 'rm': case 'clear': case 'clean':
+ return await this.clean(args)
+ case 'add':
+ return await this.add(args)
+ case 'verify': case 'check':
+ return await this.verify()
+ default:
+ throw Object.assign(new Error(this.usage), { code: 'EUSAGE' })
+ }
}
-}
-// npm cache clean [pkg]*
-const clean = async (args) => {
- if (args.length)
- throw new Error('npm cache clear does not accept arguments')
+ // npm cache clean [pkg]*
+ async clean (args) {
+ if (args.length)
+ throw new Error('npm cache clear does not accept arguments')
- const cachePath = path.join(npm.cache, '_cacache')
- if (!npm.flatOptions.force) {
- throw new Error(`As of npm@5, the npm cache self-heals from corruption issues
+ const cachePath = path.join(this.npm.cache, '_cacache')
+ if (!this.npm.flatOptions.force) {
+ throw new Error(`As of npm@5, the npm cache self-heals from corruption issues
by treating integrity mismatches as cache misses. As a result,
data extracted from the cache is guaranteed to be valid. If you
want to make sure everything is consistent, use \`npm cache verify\`
@@ -70,52 +77,53 @@ temporary cache instead of nuking the actual one.
If you're sure you want to delete the entire cache, rerun this command
with --force.`)
+ }
+ return rimraf(cachePath)
}
- return rimraf(cachePath)
-}
-// npm cache add
-// npm cache add
-// npm cache add
-// npm cache add
-const add = async (args) => {
- const usage = 'Usage:\n' +
- ' npm cache add \n' +
- ' npm cache add @\n' +
- ' npm cache add \n' +
- ' npm cache add \n'
- log.silly('cache add', 'args', args)
- const spec = args[0] && args[0] +
- (args[1] === undefined || args[1] === null ? '' : `@${args[1]}`)
-
- if (!spec)
- throw Object.assign(new Error(usage), { code: 'EUSAGE' })
-
- log.silly('cache add', 'spec', spec)
- const opts = { ...npm.flatOptions }
-
- // 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)
-}
+ // npm cache add
+ // npm cache add
+ // npm cache add
+ // npm cache add
+ async add (args) {
+ const usage = 'Usage:\n' +
+ ' npm cache add \n' +
+ ' npm cache add @\n' +
+ ' npm cache add \n' +
+ ' npm cache add \n'
+ log.silly('cache add', 'args', args)
+ const spec = args[0] && args[0] +
+ (args[1] === undefined || args[1] === null ? '' : `@${args[1]}`)
+
+ if (!spec)
+ throw Object.assign(new Error(usage), { code: 'EUSAGE' })
+
+ log.silly('cache add', 'spec', spec)
+ const opts = { ...this.npm.flatOptions }
-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`)
+ // 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)
+ }
+
+ async verify () {
+ const cache = path.join(this.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 })
+module.exports = Cache
diff --git a/deps/npm/lib/ci.js b/deps/npm/lib/ci.js
index 51c165accef7a6..03a91a60463f2c 100644
--- a/deps/npm/lib/ci.js
+++ b/deps/npm/lib/ci.js
@@ -7,13 +7,8 @@ const fs = require('fs')
const readdir = util.promisify(fs.readdir)
const log = require('npmlog')
-const npm = require('./npm.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil('ci', 'npm ci')
-
-const cmd = (args, cb) => ci().then(() => cb()).catch(cb)
-
const removeNodeModules = async where => {
const rimrafOpts = { glob: false }
process.emit('time', 'npm-ci:rm')
@@ -24,55 +19,70 @@ const removeNodeModules = async where => {
process.emit('timeEnd', 'npm-ci:rm')
}
-const ci = async () => {
- if (npm.flatOptions.global) {
- const err = new Error('`npm ci` does not work for global packages')
- err.code = 'ECIGLOBAL'
- throw err
+class CI {
+ constructor (npm) {
+ this.npm = npm
+ }
+
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('ci', 'npm ci')
}
- const where = npm.prefix
- const { scriptShell, ignoreScripts } = npm.flatOptions
- const arb = new Arborist({ ...npm.flatOptions, path: where })
+ exec (args, cb) {
+ this.ci().then(() => cb()).catch(cb)
+ }
+
+ async ci () {
+ if (this.npm.flatOptions.global) {
+ const err = new Error('`npm ci` does not work for global packages')
+ err.code = 'ECIGLOBAL'
+ throw err
+ }
+
+ const where = this.npm.prefix
+ const { scriptShell, ignoreScripts } = this.npm.flatOptions
+ const arb = new Arborist({ ...this.npm.flatOptions, path: where })
- await Promise.all([
- arb.loadVirtual().catch(er => {
- log.verbose('loadVirtual', er.stack)
- const msg =
- 'The `npm ci` command can only install with an existing package-lock.json or\n' +
- 'npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or\n' +
- 'later to generate a package-lock.json file, then try again.'
- throw new Error(msg)
- }),
- removeNodeModules(where),
- ])
- // npm ci should never modify the lockfile or package.json
- await arb.reify({ ...npm.flatOptions, save: false })
+ await Promise.all([
+ arb.loadVirtual().catch(er => {
+ log.verbose('loadVirtual', er.stack)
+ const msg =
+ 'The `npm ci` command can only install with an existing package-lock.json or\n' +
+ 'npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or\n' +
+ 'later to generate a package-lock.json file, then try again.'
+ throw new Error(msg)
+ }),
+ removeNodeModules(where),
+ ])
+ // npm ci should never modify the lockfile or package.json
+ await arb.reify({ ...this.npm.flatOptions, save: false })
- // run the same set of scripts that `npm install` runs.
- if (!ignoreScripts) {
- const scripts = [
- 'preinstall',
- 'install',
- 'postinstall',
- 'prepublish', // XXX should we remove this finally??
- 'preprepare',
- 'prepare',
- 'postprepare',
- ]
- for (const event of scripts) {
- await runScript({
- path: where,
- args: [],
- scriptShell,
- stdio: 'inherit',
- stdioString: true,
- banner: log.level !== 'silent',
- event,
- })
+ // run the same set of scripts that `npm install` runs.
+ if (!ignoreScripts) {
+ const scripts = [
+ 'preinstall',
+ 'install',
+ 'postinstall',
+ 'prepublish', // XXX should we remove this finally??
+ 'preprepare',
+ 'prepare',
+ 'postprepare',
+ ]
+ for (const event of scripts) {
+ await runScript({
+ path: where,
+ args: [],
+ scriptShell,
+ stdio: 'inherit',
+ stdioString: true,
+ banner: log.level !== 'silent',
+ event,
+ })
+ }
}
+ await reifyFinish(this.npm, arb)
}
- await reifyFinish(arb)
}
-module.exports = Object.assign(cmd, {usage})
+module.exports = CI
diff --git a/deps/npm/lib/completion.js b/deps/npm/lib/completion.js
index b31867d988a69a..4c37e6ef354ef3 100644
--- a/deps/npm/lib/completion.js
+++ b/deps/npm/lib/completion.js
@@ -29,7 +29,6 @@
// as an array.
//
-const npm = require('./npm.js')
const { types, shorthands } = require('./utils/config.js')
const deref = require('./utils/deref-command.js')
const { aliases, cmdList, plumbing } = require('./utils/cmd-list.js')
@@ -44,115 +43,127 @@ const output = require('./utils/output.js')
const fileExists = require('./utils/file-exists.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil('completion', 'source <(npm completion)')
const { promisify } = require('util')
-const cmd = (args, cb) => compl(args).then(() => cb()).catch(cb)
+class Completion {
+ constructor (npm) {
+ this.npm = npm
+ }
-// completion for the completion command
-const completion = async (opts) => {
- if (opts.w > 2)
- return
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('completion', 'source <(npm completion)')
+ }
- const { resolve } = require('path')
- const [bashExists, zshExists] = await Promise.all([
- fileExists(resolve(process.env.HOME, '.bashrc')),
- fileExists(resolve(process.env.HOME, '.zshrc')),
- ])
- const out = []
- if (zshExists)
- out.push(['>>', '~/.zshrc'])
-
- if (bashExists)
- out.push(['>>', '~/.bashrc'])
-
- return out
-}
+ // completion for the completion command
+ async completion (opts) {
+ if (opts.w > 2)
+ return
-const compl = async args => {
- if (isWindowsShell) {
- const msg = 'npm completion supported only in MINGW / Git bash on Windows'
- throw Object.assign(new Error(msg), {
- code: 'ENOTSUP',
- })
+ const { resolve } = require('path')
+ const [bashExists, zshExists] = await Promise.all([
+ fileExists(resolve(process.env.HOME, '.bashrc')),
+ fileExists(resolve(process.env.HOME, '.zshrc')),
+ ])
+ const out = []
+ if (zshExists)
+ out.push(['>>', '~/.zshrc'])
+
+ if (bashExists)
+ out.push(['>>', '~/.bashrc'])
+
+ return out
}
- const { COMP_CWORD, COMP_LINE, COMP_POINT } = process.env
+ exec (args, cb) {
+ this.compl(args).then(() => cb()).catch(cb)
+ }
- // if the COMP_* isn't in the env, then just dump the script.
- if (COMP_CWORD === undefined ||
+ async compl (args) {
+ if (isWindowsShell) {
+ const msg = 'npm completion supported only in MINGW / Git bash on Windows'
+ throw Object.assign(new Error(msg), {
+ code: 'ENOTSUP',
+ })
+ }
+
+ const { COMP_CWORD, COMP_LINE, COMP_POINT } = process.env
+
+ // if the COMP_* isn't in the env, then just dump the script.
+ if (COMP_CWORD === undefined ||
COMP_LINE === undefined ||
COMP_POINT === undefined)
- return dumpScript()
-
- // ok we're actually looking at the envs and outputting the suggestions
- // get the partial line and partial word,
- // if the point isn't at the end.
- // ie, tabbing at: npm foo b|ar
- const w = +COMP_CWORD
- const words = args.map(unescape)
- const word = words[w]
- const line = COMP_LINE
- const point = +COMP_POINT
- const partialLine = line.substr(0, point)
- const partialWords = words.slice(0, w)
-
- // figure out where in that last word the point is.
- const partialWordRaw = args[w]
- let i = partialWordRaw.length
- while (partialWordRaw.substr(0, i) !== partialLine.substr(-1 * i) && i > 0)
- i--
-
- const partialWord = unescape(partialWordRaw.substr(0, i))
- partialWords.push(partialWord)
-
- const opts = {
- words,
- w,
- word,
- line,
- lineLength: line.length,
- point,
- partialLine,
- partialWords,
- partialWord,
- raw: args,
- }
+ return dumpScript()
+
+ // ok we're actually looking at the envs and outputting the suggestions
+ // get the partial line and partial word,
+ // if the point isn't at the end.
+ // ie, tabbing at: npm foo b|ar
+ const w = +COMP_CWORD
+ const words = args.map(unescape)
+ const word = words[w]
+ const line = COMP_LINE
+ const point = +COMP_POINT
+ const partialLine = line.substr(0, point)
+ const partialWords = words.slice(0, w)
+
+ // figure out where in that last word the point is.
+ const partialWordRaw = args[w]
+ let i = partialWordRaw.length
+ while (partialWordRaw.substr(0, i) !== partialLine.substr(-1 * i) && i > 0)
+ i--
+
+ const partialWord = unescape(partialWordRaw.substr(0, i))
+ partialWords.push(partialWord)
+
+ const opts = {
+ words,
+ w,
+ word,
+ line,
+ lineLength: line.length,
+ point,
+ partialLine,
+ partialWords,
+ partialWord,
+ raw: args,
+ }
- if (partialWords.slice(0, -1).indexOf('--') === -1) {
- if (word.charAt(0) === '-')
- return wrap(opts, configCompl(opts))
+ if (partialWords.slice(0, -1).indexOf('--') === -1) {
+ if (word.charAt(0) === '-')
+ return wrap(opts, configCompl(opts))
- if (words[w - 1] &&
+ if (words[w - 1] &&
words[w - 1].charAt(0) === '-' &&
!isFlag(words[w - 1])) {
- // awaiting a value for a non-bool config.
- // don't even try to do this for now
- return wrap(opts, configValueCompl(opts))
+ // awaiting a value for a non-bool config.
+ // don't even try to do this for now
+ return wrap(opts, configValueCompl(opts))
+ }
}
- }
- // try to find the npm command.
- // it's the first thing after all the configs.
- // take a little shortcut and use npm's arg parsing logic.
- // don't have to worry about the last arg being implicitly
- // boolean'ed, since the last block will catch that.
- const parsed = opts.conf =
- nopt(types, shorthands, partialWords.slice(0, -1), 0)
- // check if there's a command already.
- const cmd = parsed.argv.remain[1]
- if (!cmd)
- return wrap(opts, cmdCompl(opts))
-
- Object.keys(parsed).forEach(k => npm.config.set(k, parsed[k]))
-
- // at this point, if words[1] is some kind of npm command,
- // then complete on it.
- // otherwise, do nothing
- const impl = npm.commands[cmd]
- if (impl && impl.completion) {
- const comps = await impl.completion(opts)
- return wrap(opts, comps)
+ // try to find the npm command.
+ // it's the first thing after all the configs.
+ // take a little shortcut and use npm's arg parsing logic.
+ // don't have to worry about the last arg being implicitly
+ // boolean'ed, since the last block will catch that.
+ const parsed = opts.conf =
+ nopt(types, shorthands, partialWords.slice(0, -1), 0)
+ // check if there's a command already.
+ const cmd = parsed.argv.remain[1]
+ if (!cmd)
+ return wrap(opts, cmdCompl(opts))
+
+ Object.keys(parsed).forEach(k => this.npm.config.set(k, parsed[k]))
+
+ // at this point, if words[1] is some kind of npm command,
+ // then complete on it.
+ // otherwise, do nothing
+ const impl = this.npm.commands[cmd]
+ if (impl && impl.completion) {
+ const comps = await impl.completion(opts)
+ return wrap(opts, comps)
+ }
}
}
@@ -266,4 +277,4 @@ const cmdCompl = opts => {
return fullList
}
-module.exports = Object.assign(cmd, { completion, usage })
+module.exports = Completion
diff --git a/deps/npm/lib/config.js b/deps/npm/lib/config.js
index e4da296de8f88a..2805db9b80ec7e 100644
--- a/deps/npm/lib/config.js
+++ b/deps/npm/lib/config.js
@@ -1,4 +1,3 @@
-const npm = require('./npm.js')
const { defaults, types } = require('./utils/config.js')
const usageUtil = require('./utils/usage.js')
const output = require('./utils/output.js')
@@ -13,165 +12,173 @@ const { spawn } = require('child_process')
const { EOL } = require('os')
const ini = require('ini')
-const usage = usageUtil(
- 'config',
- 'npm config set = [= ...]' +
- '\nnpm config get [ [ ...]]' +
- '\nnpm config delete [ ...]' +
- '\nnpm config list [--json]' +
- '\nnpm config edit' +
- '\nnpm set = [= ...]' +
- '\nnpm get [ [ ...]]'
-)
-
-const cmd = (args, cb) => config(args).then(() => cb()).catch(cb)
-
-const completion = async (opts) => {
- const argv = opts.conf.argv.remain
- if (argv[1] !== 'config')
- argv.unshift('config')
-
- if (argv.length === 2) {
- const cmds = ['get', 'set', 'delete', 'ls', 'rm', 'edit']
- if (opts.partialWord !== 'l')
- cmds.push('list')
-
- return cmds
+// take an array of `[key, value, k2=v2, k3, v3, ...]` and turn into
+// { key: value, k2: v2, k3: v3 }
+const keyValues = args => {
+ const kv = {}
+ for (let i = 0; i < args.length; i++) {
+ const arg = args[i].split('=')
+ const key = arg.shift()
+ const val = arg.length ? arg.join('=')
+ : i < args.length - 1 ? args[++i]
+ : ''
+ kv[key.trim()] = val.trim()
}
+ return kv
+}
- const action = argv[2]
- switch (action) {
- case 'set':
- // todo: complete with valid values, if possible.
- if (argv.length > 3)
- return []
+const publicVar = k => !/^(\/\/[^:]+:)?_/.test(k)
- // fallthrough
- /* eslint no-fallthrough:0 */
- case 'get':
- case 'delete':
- case 'rm':
- return Object.keys(types)
- case 'edit':
- case 'list':
- case 'ls':
- default:
- return []
+class Config {
+ constructor (npm) {
+ this.npm = npm
}
-}
-const UsageError = () =>
- Object.assign(new Error(usage), { code: 'EUSAGE' })
+ get usage () {
+ return usageUtil(
+ 'config',
+ 'npm config set = [= ...]' +
+ '\nnpm config get [ [ ...]]' +
+ '\nnpm config delete [ ...]' +
+ '\nnpm config list [--json]' +
+ '\nnpm config edit' +
+ '\nnpm set = [= ...]' +
+ '\nnpm get [ [ ...]]'
+ )
+ }
+
+ async completion (opts) {
+ const argv = opts.conf.argv.remain
+ if (argv[1] !== 'config')
+ argv.unshift('config')
+
+ if (argv.length === 2) {
+ const cmds = ['get', 'set', 'delete', 'ls', 'rm', 'edit']
+ if (opts.partialWord !== 'l')
+ cmds.push('list')
-const config = async ([action, ...args]) => {
- npm.log.disableProgress()
- try {
+ return cmds
+ }
+
+ const action = argv[2]
switch (action) {
case 'set':
- await set(args)
- break
+ // todo: complete with valid values, if possible.
+ if (argv.length > 3)
+ return []
+
+ // fallthrough
+ /* eslint no-fallthrough:0 */
case 'get':
- await get(args)
- break
case 'delete':
case 'rm':
- case 'del':
- await del(args)
- break
+ return Object.keys(types)
+ case 'edit':
case 'list':
case 'ls':
- await (npm.flatOptions.json ? listJson() : list())
- break
- case 'edit':
- await edit()
- break
default:
- throw UsageError()
+ return []
}
- } finally {
- npm.log.enableProgress()
}
-}
-// take an array of `[key, value, k2=v2, k3, v3, ...]` and turn into
-// { key: value, k2: v2, k3: v3 }
-const keyValues = args => {
- const kv = {}
- for (let i = 0; i < args.length; i++) {
- const arg = args[i].split('=')
- const key = arg.shift()
- const val = arg.length ? arg.join('=')
- : i < args.length - 1 ? args[++i]
- : ''
- kv[key.trim()] = val.trim()
+ exec (args, cb) {
+ this.config(args).then(() => cb()).catch(cb)
}
- return kv
-}
-const set = async (args) => {
- if (!args.length)
- throw UsageError()
-
- const where = npm.flatOptions.global ? 'global' : 'user'
- for (const [key, val] of Object.entries(keyValues(args))) {
- npm.log.info('config', 'set %j %j', key, val)
- npm.config.set(key, val || '', where)
- if (!npm.config.validate(where))
- npm.log.warn('config', 'omitting invalid config values')
+ async config ([action, ...args]) {
+ this.npm.log.disableProgress()
+ try {
+ switch (action) {
+ case 'set':
+ await this.set(args)
+ break
+ case 'get':
+ await this.get(args)
+ break
+ case 'delete':
+ case 'rm':
+ case 'del':
+ await this.del(args)
+ break
+ case 'list':
+ case 'ls':
+ await (this.npm.flatOptions.json ? this.listJson() : this.list())
+ break
+ case 'edit':
+ await this.edit()
+ break
+ default:
+ throw this.usageError()
+ }
+ } finally {
+ this.npm.log.enableProgress()
+ }
}
- await npm.config.save(where)
-}
+ async set (args) {
+ if (!args.length)
+ throw this.usageError()
+
+ const where = this.npm.flatOptions.global ? 'global' : 'user'
+ for (const [key, val] of Object.entries(keyValues(args))) {
+ this.npm.log.info('config', 'set %j %j', key, val)
+ this.npm.config.set(key, val || '', where)
+ if (!this.npm.config.validate(where))
+ this.npm.log.warn('config', 'omitting invalid config values')
+ }
+
+ await this.npm.config.save(where)
+ }
-const get = async keys => {
- if (!keys.length)
- return list()
+ async get (keys) {
+ if (!keys.length)
+ return this.list()
- const out = []
- for (const key of keys) {
- if (!publicVar(key))
- throw `The ${key} option is protected, and cannot be retrieved in this way`
+ const out = []
+ for (const key of keys) {
+ if (!publicVar(key))
+ throw `The ${key} option is protected, and cannot be retrieved in this way`
- const pref = keys.length > 1 ? `${key}=` : ''
- out.push(pref + npm.config.get(key))
+ const pref = keys.length > 1 ? `${key}=` : ''
+ out.push(pref + this.npm.config.get(key))
+ }
+ output(out.join('\n'))
}
- output(out.join('\n'))
-}
-const del = async keys => {
- if (!keys.length)
- throw UsageError()
+ async del (keys) {
+ if (!keys.length)
+ throw this.usageError()
- const where = npm.flatOptions.global ? 'global' : 'user'
- for (const key of keys)
- npm.config.delete(key, where)
- await npm.config.save(where)
-}
+ const where = this.npm.flatOptions.global ? 'global' : 'user'
+ for (const key of keys)
+ this.npm.config.delete(key, where)
+ await this.npm.config.save(where)
+ }
-const edit = async () => {
- const { editor: e, global } = npm.flatOptions
- const where = global ? 'global' : 'user'
- const file = npm.config.data.get(where).source
-
- // save first, just to make sure it's synced up
- // this also removes all the comments from the last time we edited it.
- await npm.config.save(where)
-
- const data = (
- await readFile(file, 'utf8').catch(() => '')
- ).replace(/\r\n/g, '\n')
- const defData = Object.entries(defaults).reduce((str, [key, val]) => {
- const obj = { [key]: val }
- const i = ini.stringify(obj)
- .replace(/\r\n/g, '\n') // normalizes output from ini.stringify
- .replace(/\n$/m, '')
- .replace(/^/g, '; ')
- .replace(/\n/g, '\n; ')
- .split('\n')
- return str + '\n' + i
- }, '')
-
- const tmpData = `;;;;
+ async edit () {
+ const { editor: e, global } = this.npm.flatOptions
+ const where = global ? 'global' : 'user'
+ const file = this.npm.config.data.get(where).source
+
+ // save first, just to make sure it's synced up
+ // this also removes all the comments from the last time we edited it.
+ await this.npm.config.save(where)
+
+ const data = (
+ await readFile(file, 'utf8').catch(() => '')
+ ).replace(/\r\n/g, '\n')
+ const defData = Object.entries(defaults).reduce((str, [key, val]) => {
+ const obj = { [key]: val }
+ const i = ini.stringify(obj)
+ .replace(/\r\n/g, '\n') // normalizes output from ini.stringify
+ .replace(/\n$/m, '')
+ .replace(/^/g, '; ')
+ .replace(/\n/g, '\n; ')
+ .split('\n')
+ return str + '\n' + i
+ }, '')
+
+ const tmpData = `;;;;
; npm ${where}config file: ${file}
; this is a simple ini-formatted file
; lines that start with semi-colons are comments
@@ -190,64 +197,67 @@ ${data.split('\n').sort((a, b) => a.localeCompare(b)).join('\n').trim()}
${defData}
`.split('\n').join(EOL)
- await mkdirp(dirname(file))
- await writeFile(file, tmpData, 'utf8')
- await new Promise((resolve, reject) => {
- const [bin, ...args] = e.split(/\s+/)
- const editor = spawn(bin, [...args, file], { stdio: 'inherit' })
- editor.on('exit', (code) => {
- if (code)
- return reject(new Error(`editor process exited with code: ${code}`))
- return resolve()
+ await mkdirp(dirname(file))
+ await writeFile(file, tmpData, 'utf8')
+ await new Promise((resolve, reject) => {
+ const [bin, ...args] = e.split(/\s+/)
+ const editor = spawn(bin, [...args, file], { stdio: 'inherit' })
+ editor.on('exit', (code) => {
+ if (code)
+ return reject(new Error(`editor process exited with code: ${code}`))
+ return resolve()
+ })
})
- })
-}
-
-const publicVar = k => !/^(\/\/[^:]+:)?_/.test(k)
+ }
-const list = async () => {
- const msg = []
- const { long } = npm.flatOptions
- for (const [where, { data, source }] of npm.config.data.entries()) {
- if (where === 'default' && !long)
- continue
+ async list () {
+ const msg = []
+ const { long } = this.npm.flatOptions
+ for (const [where, { data, source }] of this.npm.config.data.entries()) {
+ if (where === 'default' && !long)
+ continue
+
+ const keys = Object.keys(data).sort((a, b) => a.localeCompare(b))
+ if (!keys.length)
+ continue
+
+ msg.push(`; "${where}" config from ${source}`, '')
+ for (const k of keys) {
+ const v = publicVar(k) ? JSON.stringify(data[k]) : '(protected)'
+ const src = this.npm.config.find(k)
+ const overridden = src !== where
+ msg.push((overridden ? '; ' : '') +
+ `${k} = ${v} ${overridden ? `; overridden by ${src}` : ''}`)
+ }
+ msg.push('')
+ }
- const keys = Object.keys(data).sort((a, b) => a.localeCompare(b))
- if (!keys.length)
- continue
-
- msg.push(`; "${where}" config from ${source}`, '')
- for (const k of keys) {
- const v = publicVar(k) ? JSON.stringify(data[k]) : '(protected)'
- const src = npm.config.find(k)
- const overridden = src !== where
- msg.push((overridden ? '; ' : '') +
- `${k} = ${v} ${overridden ? `; overridden by ${src}` : ''}`)
+ if (!long) {
+ msg.push(
+ `; node bin location = ${process.execPath}`,
+ `; cwd = ${process.cwd()}`,
+ `; HOME = ${process.env.HOME}`,
+ '; Run `npm config ls -l` to show all defaults.'
+ )
}
- msg.push('')
- }
- if (!long) {
- msg.push(
- `; node bin location = ${process.execPath}`,
- `; cwd = ${process.cwd()}`,
- `; HOME = ${process.env.HOME}`,
- '; Run `npm config ls -l` to show all defaults.'
- )
+ output(msg.join('\n').trim())
}
- output(msg.join('\n').trim())
-}
+ async listJson () {
+ const publicConf = {}
+ for (const key in this.npm.config.list[0]) {
+ if (!publicVar(key))
+ continue
-const listJson = async () => {
- const publicConf = {}
- for (const key in npm.config.list[0]) {
- if (!publicVar(key))
- continue
+ publicConf[key] = this.npm.config.get(key)
+ }
+ output(JSON.stringify(publicConf, null, 2))
+ }
- publicConf[key] = npm.config.get(key)
+ usageError () {
+ return Object.assign(new Error(this.usage), { code: 'EUSAGE' })
}
- output(JSON.stringify(publicConf, null, 2))
}
-module.exports = Object.assign(cmd, { usage, completion })
+module.exports = Config
diff --git a/deps/npm/lib/dedupe.js b/deps/npm/lib/dedupe.js
index 2211fcac8b4819..59978895effb2b 100644
--- a/deps/npm/lib/dedupe.js
+++ b/deps/npm/lib/dedupe.js
@@ -1,29 +1,39 @@
// dedupe duplicated packages, or find them in the tree
-const npm = require('./npm.js')
const Arborist = require('@npmcli/arborist')
const usageUtil = require('./utils/usage.js')
const reifyFinish = require('./utils/reify-finish.js')
-const usage = usageUtil('dedupe', 'npm dedupe')
+class Dedupe {
+ constructor (npm) {
+ this.npm = npm
+ }
-const cmd = (args, cb) => dedupe(args).then(() => cb()).catch(cb)
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('dedupe', 'npm dedupe')
+ }
-const dedupe = async (args) => {
- if (npm.flatOptions.global) {
- const er = new Error('`npm dedupe` does not work in global mode.')
- er.code = 'EDEDUPEGLOBAL'
- throw er
+ exec (args, cb) {
+ this.dedupe(args).then(() => cb()).catch(cb)
}
- const dryRun = (args && args.dryRun) || npm.flatOptions.dryRun
- const where = npm.prefix
- const arb = new Arborist({
- ...npm.flatOptions,
- path: where,
- dryRun,
- })
- await arb.dedupe(npm.flatOptions)
- await reifyFinish(arb)
+ async dedupe (args) {
+ if (this.npm.config.get('global')) {
+ const er = new Error('`npm dedupe` does not work in global mode.')
+ er.code = 'EDEDUPEGLOBAL'
+ throw er
+ }
+
+ const dryRun = this.npm.config.get('dry-run')
+ const where = this.npm.prefix
+ const arb = new Arborist({
+ ...this.npm.flatOptions,
+ path: where,
+ dryRun,
+ })
+ await arb.dedupe(this.npm.flatOptions)
+ await reifyFinish(this.npm, arb)
+ }
}
-module.exports = Object.assign(cmd, { usage })
+module.exports = Dedupe
diff --git a/deps/npm/lib/deprecate.js b/deps/npm/lib/deprecate.js
index 42d099b544e31d..48f27ab6c35e88 100644
--- a/deps/npm/lib/deprecate.js
+++ b/deps/npm/lib/deprecate.js
@@ -1,4 +1,3 @@
-const npm = require('./npm.js')
const fetch = require('npm-registry-fetch')
const otplease = require('./utils/otplease.js')
const npa = require('npm-package-arg')
@@ -7,67 +6,77 @@ const getIdentity = require('./utils/get-identity.js')
const libaccess = require('libnpmaccess')
const usageUtil = require('./utils/usage.js')
-const UsageError = () =>
- Object.assign(new Error(`\nUsage: ${usage}`), {
- code: 'EUSAGE',
- })
+class Deprecate {
+ constructor (npm) {
+ this.npm = npm
+ }
-const usage = usageUtil(
- 'deprecate',
- 'npm deprecate [@] '
-)
+ get usage () {
+ return usageUtil(
+ 'deprecate',
+ 'npm deprecate [@] '
+ )
+ }
-const completion = async (opts) => {
- if (opts.conf.argv.remain.length > 1)
- return []
+ async completion (opts) {
+ if (opts.conf.argv.remain.length > 1)
+ return []
- const username = await getIdentity(npm.flatOptions)
- const packages = await libaccess.lsPackages(username, npm.flatOptions)
- return Object.keys(packages)
- .filter((name) =>
- packages[name] === 'write' &&
- (opts.conf.argv.remain.length === 0 ||
- name.startsWith(opts.conf.argv.remain[0])))
-}
-
-const cmd = (args, cb) =>
- deprecate(args)
- .then(() => cb())
- .catch(err => cb(err.code === 'EUSAGE' ? err.message : err))
+ const username = await getIdentity(this.npm, this.npm.flatOptions)
+ const packages = await libaccess.lsPackages(username, this.npm.flatOptions)
+ return Object.keys(packages)
+ .filter((name) =>
+ packages[name] === 'write' &&
+ (opts.conf.argv.remain.length === 0 ||
+ name.startsWith(opts.conf.argv.remain[0])))
+ }
-const deprecate = async ([pkg, msg]) => {
- if (!pkg || !msg)
- throw UsageError()
+ exec (args, cb) {
+ this.deprecate(args)
+ .then(() => cb())
+ .catch(err => cb(err.code === 'EUSAGE' ? err.message : err))
+ }
- // fetch the data and make sure it exists.
- const p = npa(pkg)
- // npa makes the default spec "latest", but for deprecation
- // "*" is the appropriate default.
- const spec = p.rawSpec === '' ? '*' : p.fetchSpec
+ async deprecate ([pkg, msg]) {
+ if (!pkg || !msg)
+ throw this.usageError()
- if (semver.validRange(spec, true) === null)
- throw new Error(`invalid version range: ${spec}`)
+ // fetch the data and make sure it exists.
+ const p = npa(pkg)
+ // npa makes the default spec "latest", but for deprecation
+ // "*" is the appropriate default.
+ const spec = p.rawSpec === '' ? '*' : p.fetchSpec
- const uri = '/' + p.escapedName
- const packument = await fetch.json(uri, {
- ...npm.flatOptions,
- spec: p,
- query: { write: true },
- })
+ if (semver.validRange(spec, true) === null)
+ throw new Error(`invalid version range: ${spec}`)
- Object.keys(packument.versions)
- .filter(v => semver.satisfies(v, spec, { includePrerelease: true }))
- .forEach(v => {
- packument.versions[v].deprecated = msg
+ const uri = '/' + p.escapedName
+ const packument = await fetch.json(uri, {
+ ...this.npm.flatOptions,
+ spec: p,
+ query: { write: true },
})
- return otplease(npm.flatOptions, opts => fetch(uri, {
- ...opts,
- spec: p,
- method: 'PUT',
- body: packument,
- ignoreBody: true,
- }))
+ Object.keys(packument.versions)
+ .filter(v => semver.satisfies(v, spec, { includePrerelease: true }))
+ .forEach(v => {
+ packument.versions[v].deprecated = msg
+ })
+
+ return otplease(this.npm.flatOptions, opts => fetch(uri, {
+ ...opts,
+ spec: p,
+ method: 'PUT',
+ body: packument,
+ ignoreBody: true,
+ }))
+ }
+
+ usageError () {
+ return Object.assign(new Error(`\nUsage: ${this.usage}`), {
+ code: 'EUSAGE',
+ })
+ }
}
-module.exports = Object.assign(cmd, { completion, usage })
+module.exports = Deprecate
diff --git a/deps/npm/lib/diff.js b/deps/npm/lib/diff.js
index 9ef5a78a20ce9e..859e6f76feeefa 100644
--- a/deps/npm/lib/diff.js
+++ b/deps/npm/lib/diff.js
@@ -8,258 +8,271 @@ const npmlog = require('npmlog')
const pacote = require('pacote')
const pickManifest = require('npm-pick-manifest')
-const npm = require('./npm.js')
const usageUtil = require('./utils/usage.js')
const output = require('./utils/output.js')
const readLocalPkg = require('./utils/read-local-package.js')
-const usage = usageUtil(
- 'diff',
- 'npm diff [...]' +
- '\nnpm diff --diff= [...]' +
- '\nnpm diff --diff= [--diff=] [...]' +
- '\nnpm diff --diff= [--diff=] [...]' +
- '\nnpm diff [--diff-ignore-all-space] [--diff-name-only] [...] [...]'
-)
-
-const cmd = (args, cb) => diff(args).then(() => cb()).catch(cb)
-
-const where = () => {
- const globalTop = resolve(npm.globalDir, '..')
- const { global } = npm.flatOptions
- return global ? globalTop : npm.prefix
-}
+class Diff {
+ constructor (npm) {
+ this.npm = npm
+ }
-const diff = async (args) => {
- const specs = npm.flatOptions.diff.filter(d => d)
- if (specs.length > 2) {
- throw new TypeError(
- 'Can\'t use more than two --diff arguments.\n\n' +
- `Usage:\n${usage}`
+ get usage () {
+ return usageUtil(
+ 'diff',
+ 'npm diff [...]' +
+ '\nnpm diff --diff= [...]' +
+ '\nnpm diff --diff= [--diff=] [...]' +
+ '\nnpm diff --diff= [--diff=] [...]' +
+ '\nnpm diff [--diff-ignore-all-space] [--diff-name-only] [...] [...]'
)
}
- const [a, b] = await retrieveSpecs(specs)
- npmlog.info('diff', { src: a, dst: b })
-
- const res = await libdiff([a, b], { ...npm.flatOptions, diffFiles: args })
- return output(res)
-}
+ get where () {
+ const globalTop = resolve(this.npm.globalDir, '..')
+ const { global } = this.npm.flatOptions
+ return global ? globalTop : this.npm.prefix
+ }
-const retrieveSpecs = ([a, b]) => {
- // no arguments, defaults to comparing cwd
- // to its latest published registry version
- if (!a)
- return defaultSpec()
+ exec (args, cb) {
+ this.diff(args).then(() => cb()).catch(cb)
+ }
- // single argument, used to compare wanted versions of an
- // installed dependency or to compare the cwd to a published version
- if (!b)
- return transformSingleSpec(a)
+ async diff (args) {
+ const specs = this.npm.flatOptions.diff.filter(d => d)
+ if (specs.length > 2) {
+ throw new TypeError(
+ 'Can\'t use more than two --diff arguments.\n\n' +
+ `Usage:\n${this.usage}`
+ )
+ }
- return convertVersionsToSpecs([a, b])
- .then(findVersionsByPackageName)
-}
+ const [a, b] = await this.retrieveSpecs(specs)
+ npmlog.info('diff', { src: a, dst: b })
-const defaultSpec = async () => {
- let noPackageJson
- let pkgName
- try {
- pkgName = await readLocalPkg()
- } catch (e) {
- npmlog.verbose('diff', 'could not read project dir package.json')
- noPackageJson = true
+ const res = await libdiff([a, b], {
+ ...this.npm.flatOptions,
+ diffFiles: args,
+ where: this.where,
+ })
+ return output(res)
}
- if (!pkgName || noPackageJson) {
- throw new Error(
- 'Needs multiple arguments to compare or run from a project dir.\n\n' +
- `Usage:\n${usage}`
- )
- }
+ async retrieveSpecs ([a, b]) {
+ // no arguments, defaults to comparing cwd
+ // to its latest published registry version
+ if (!a)
+ return this.defaultSpec()
- return [
- `${pkgName}@${npm.flatOptions.defaultTag}`,
- `file:${npm.prefix}`,
- ]
-}
+ // single argument, used to compare wanted versions of an
+ // installed dependency or to compare the cwd to a published version
+ if (!b)
+ return this.transformSingleSpec(a)
-const transformSingleSpec = async (a) => {
- let noPackageJson
- let pkgName
- try {
- pkgName = await readLocalPkg()
- } catch (e) {
- npmlog.verbose('diff', 'could not read project dir package.json')
- noPackageJson = true
+ const specs = await this.convertVersionsToSpecs([a, b])
+ return this.findVersionsByPackageName(specs)
}
- const missingPackageJson = new Error(
- 'Needs multiple arguments to compare or run from a project dir.\n\n' +
- `Usage:\n${usage}`
- )
- const specSelf = () => {
- if (noPackageJson)
- throw missingPackageJson
-
- return `file:${npm.prefix}`
- }
+ async defaultSpec () {
+ let noPackageJson
+ let pkgName
+ try {
+ pkgName = await readLocalPkg(this.npm)
+ } catch (e) {
+ npmlog.verbose('diff', 'could not read project dir package.json')
+ noPackageJson = true
+ }
- // using a valid semver range, that means it should just diff
- // the cwd against a published version to the registry using the
- // same project name and the provided semver range
- if (semver.validRange(a)) {
- if (!pkgName)
- throw missingPackageJson
+ if (!pkgName || noPackageJson) {
+ throw new Error(
+ 'Needs multiple arguments to compare or run from a project dir.\n\n' +
+ `Usage:\n${this.usage}`
+ )
+ }
return [
- `${pkgName}@${a}`,
- specSelf(),
+ `${pkgName}@${this.npm.flatOptions.defaultTag}`,
+ `file:${this.npm.prefix}`,
]
}
- // when using a single package name as arg and it's part of the current
- // install tree, then retrieve the current installed version and compare
- // it against the same value `npm outdated` would suggest you to update to
- const spec = npa(a)
- if (spec.registry) {
- let actualTree
- let node
+ async transformSingleSpec (a) {
+ let noPackageJson
+ let pkgName
try {
- const opts = {
- ...npm.flatOptions,
- path: where(),
- }
- const arb = new Arborist(opts)
- actualTree = await arb.loadActual(opts)
- node = actualTree &&
- actualTree.inventory.query('name', spec.name)
- .values().next().value
+ pkgName = await readLocalPkg(this.npm)
} catch (e) {
- npmlog.verbose('diff', 'failed to load actual install tree')
+ npmlog.verbose('diff', 'could not read project dir package.json')
+ noPackageJson = true
+ }
+ const missingPackageJson = new Error(
+ 'Needs multiple arguments to compare or run from a project dir.\n\n' +
+ `Usage:\n${this.usage}`
+ )
+
+ const specSelf = () => {
+ if (noPackageJson)
+ throw missingPackageJson
+
+ return `file:${this.npm.prefix}`
}
- if (!node || !node.name || !node.package || !node.package.version) {
+ // using a valid semver range, that means it should just diff
+ // the cwd against a published version to the registry using the
+ // same project name and the provided semver range
+ if (semver.validRange(a)) {
+ if (!pkgName)
+ throw missingPackageJson
+
return [
- `${spec.name}@${spec.fetchSpec}`,
+ `${pkgName}@${a}`,
specSelf(),
]
}
- const tryRootNodeSpec = () =>
- (actualTree && actualTree.edgesOut.get(spec.name) || {}).spec
-
- const tryAnySpec = () => {
- for (const edge of node.edgesIn)
- return edge.spec
- }
+ // when using a single package name as arg and it's part of the current
+ // install tree, then retrieve the current installed version and compare
+ // it against the same value `npm outdated` would suggest you to update to
+ const spec = npa(a)
+ if (spec.registry) {
+ let actualTree
+ let node
+ try {
+ const opts = {
+ ...this.npm.flatOptions,
+ path: this.where,
+ }
+ const arb = new Arborist(opts)
+ actualTree = await arb.loadActual(opts)
+ node = actualTree &&
+ actualTree.inventory.query('name', spec.name)
+ .values().next().value
+ } catch (e) {
+ npmlog.verbose('diff', 'failed to load actual install tree')
+ }
- const aSpec = `file:${node.realpath}`
-
- // finds what version of the package to compare against, if a exact
- // version or tag was passed than it should use that, otherwise
- // work from the top of the arborist tree to find the original semver
- // range declared in the package that depends on the package.
- let bSpec
- if (spec.rawSpec)
- bSpec = spec.rawSpec
- else {
- const bTargetVersion =
- tryRootNodeSpec()
- || tryAnySpec()
-
- // figure out what to compare against,
- // follows same logic to npm outdated "Wanted" results
- const packument = await pacote.packument(spec, {
- ...npm.flatOptions,
- preferOnline: true,
- })
- bSpec = pickManifest(
- packument,
- bTargetVersion,
- { ...npm.flatOptions }
- ).version
- }
+ if (!node || !node.name || !node.package || !node.package.version) {
+ return [
+ `${spec.name}@${spec.fetchSpec}`,
+ specSelf(),
+ ]
+ }
- return [
- `${spec.name}@${aSpec}`,
- `${spec.name}@${bSpec}`,
- ]
- } else if (spec.type === 'directory') {
- return [
- `file:${spec.fetchSpec}`,
- specSelf(),
- ]
- } else {
- throw new Error(
- 'Spec type not supported.\n\n' +
- `Usage:\n${usage}`
- )
- }
-}
+ const tryRootNodeSpec = () =>
+ (actualTree && actualTree.edgesOut.get(spec.name) || {}).spec
-const convertVersionsToSpecs = async ([a, b]) => {
- const semverA = semver.validRange(a)
- const semverB = semver.validRange(b)
+ const tryAnySpec = () => {
+ for (const edge of node.edgesIn)
+ return edge.spec
+ }
- // both specs are semver versions, assume current project dir name
- if (semverA && semverB) {
- let pkgName
- try {
- pkgName = await readLocalPkg()
- } catch (e) {
- npmlog.verbose('diff', 'could not read project dir package.json')
- }
+ const aSpec = `file:${node.realpath}`
+
+ // finds what version of the package to compare against, if a exact
+ // version or tag was passed than it should use that, otherwise
+ // work from the top of the arborist tree to find the original semver
+ // range declared in the package that depends on the package.
+ let bSpec
+ if (spec.rawSpec)
+ bSpec = spec.rawSpec
+ else {
+ const bTargetVersion =
+ tryRootNodeSpec()
+ || tryAnySpec()
+
+ // figure out what to compare against,
+ // follows same logic to npm outdated "Wanted" results
+ const packument = await pacote.packument(spec, {
+ ...this.npm.flatOptions,
+ preferOnline: true,
+ })
+ bSpec = pickManifest(
+ packument,
+ bTargetVersion,
+ { ...this.npm.flatOptions }
+ ).version
+ }
- if (!pkgName) {
+ return [
+ `${spec.name}@${aSpec}`,
+ `${spec.name}@${bSpec}`,
+ ]
+ } else if (spec.type === 'directory') {
+ return [
+ `file:${spec.fetchSpec}`,
+ specSelf(),
+ ]
+ } else {
throw new Error(
- 'Needs to be run from a project dir in order to diff two versions.\n\n' +
- `Usage:\n${usage}`
+ 'Spec type not supported.\n\n' +
+ `Usage:\n${this.usage}`
)
}
- return [`${pkgName}@${a}`, `${pkgName}@${b}`]
}
- // otherwise uses the name from the other arg to
- // figure out the spec.name of what to compare
- if (!semverA && semverB)
- return [a, `${npa(a).name}@${b}`]
+ async convertVersionsToSpecs ([a, b]) {
+ const semverA = semver.validRange(a)
+ const semverB = semver.validRange(b)
+
+ // both specs are semver versions, assume current project dir name
+ if (semverA && semverB) {
+ let pkgName
+ try {
+ pkgName = await readLocalPkg(this.npm)
+ } catch (e) {
+ npmlog.verbose('diff', 'could not read project dir package.json')
+ }
+
+ if (!pkgName) {
+ throw new Error(
+ 'Needs to be run from a project dir in order to diff two versions.\n\n' +
+ `Usage:\n${this.usage}`
+ )
+ }
+ return [`${pkgName}@${a}`, `${pkgName}@${b}`]
+ }
- if (semverA && !semverB)
- return [`${npa(b).name}@${a}`, b]
+ // otherwise uses the name from the other arg to
+ // figure out the spec.name of what to compare
+ if (!semverA && semverB)
+ return [a, `${npa(a).name}@${b}`]
- // no valid semver ranges used
- return [a, b]
-}
+ if (semverA && !semverB)
+ return [`${npa(b).name}@${a}`, b]
-const findVersionsByPackageName = async (specs) => {
- let actualTree
- try {
- const opts = {
- ...npm.flatOptions,
- path: where(),
- }
- const arb = new Arborist(opts)
- actualTree = await arb.loadActual(opts)
- } catch (e) {
- npmlog.verbose('diff', 'failed to load actual install tree')
+ // no valid semver ranges used
+ return [a, b]
}
- return specs.map(i => {
- const spec = npa(i)
- if (spec.rawSpec)
- return i
+ async findVersionsByPackageName (specs) {
+ let actualTree
+ try {
+ const opts = {
+ ...this.npm.flatOptions,
+ path: this.where,
+ }
+ const arb = new Arborist(opts)
+ actualTree = await arb.loadActual(opts)
+ } catch (e) {
+ npmlog.verbose('diff', 'failed to load actual install tree')
+ }
+
+ return specs.map(i => {
+ const spec = npa(i)
+ if (spec.rawSpec)
+ return i
- const node = actualTree
- && actualTree.inventory.query('name', spec.name)
- .values().next().value
+ const node = actualTree
+ && actualTree.inventory.query('name', spec.name)
+ .values().next().value
- const res = !node || !node.package || !node.package.version
- ? spec.fetchSpec
- : `file:${node.realpath}`
+ const res = !node || !node.package || !node.package.version
+ ? spec.fetchSpec
+ : `file:${node.realpath}`
- return `${spec.name}@${res}`
- })
+ return `${spec.name}@${res}`
+ })
+ }
}
-module.exports = Object.assign(cmd, { usage })
+module.exports = Diff
diff --git a/deps/npm/lib/dist-tag.js b/deps/npm/lib/dist-tag.js
index e958bb75442229..171a88c527e5d4 100644
--- a/deps/npm/lib/dist-tag.js
+++ b/deps/npm/lib/dist-tag.js
@@ -3,69 +3,77 @@ const npa = require('npm-package-arg')
const regFetch = require('npm-registry-fetch')
const semver = require('semver')
-const npm = require('./npm.js')
const output = require('./utils/output.js')
const otplease = require('./utils/otplease.js')
const readLocalPkgName = require('./utils/read-local-package.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil(
- 'dist-tag',
- 'npm dist-tag add @ []' +
- '\nnpm dist-tag rm ' +
- '\nnpm dist-tag ls []'
-)
-
-const completion = async (opts) => {
- const argv = opts.conf.argv.remain
- if (argv.length === 2)
- return ['add', 'rm', 'ls']
-
- switch (argv[2]) {
- default:
- return []
+class DistTag {
+ constructor (npm) {
+ this.npm = npm
}
-}
-const cmd = (args, cb) => distTag(args).then(() => cb()).catch(cb)
+ get usage () {
+ return usageUtil(
+ 'dist-tag',
+ 'npm dist-tag add @ []' +
+ '\nnpm dist-tag rm ' +
+ '\nnpm dist-tag ls []'
+ )
+ }
-const distTag = async ([cmdName, pkg, tag]) => {
- const opts = npm.flatOptions
- const has = (items) => new Set(items).has(cmdName)
+ async completion (opts) {
+ const argv = opts.conf.argv.remain
+ if (argv.length === 2)
+ return ['add', 'rm', 'ls']
- if (has(['add', 'a', 'set', 's']))
- return add(pkg, tag, opts)
+ switch (argv[2]) {
+ default:
+ return []
+ }
+ }
- if (has(['rm', 'r', 'del', 'd', 'remove']))
- return remove(pkg, tag, opts)
+ exec (args, cb) {
+ this.distTag(args).then(() => cb()).catch(cb)
+ }
- if (has(['ls', 'l', 'sl', 'list']))
- return list(pkg, opts)
+ async distTag ([cmdName, pkg, tag]) {
+ const opts = this.npm.flatOptions
+ const has = (items) => new Set(items).has(cmdName)
- if (!pkg) {
- // when only using the pkg name the default behavior
- // should be listing the existing tags
- return list(cmdName, opts)
- } else
- throw usage
-}
+ if (has(['add', 'a', 'set', 's']))
+ return this.add(pkg, tag, opts)
-function add (spec, tag, opts) {
- spec = npa(spec || '')
- const version = spec.rawSpec
- const defaultTag = tag || opts.defaultTag
+ if (has(['rm', 'r', 'del', 'd', 'remove']))
+ return this.remove(pkg, tag, opts)
- log.verbose('dist-tag add', defaultTag, 'to', spec.name + '@' + version)
+ if (has(['ls', 'l', 'sl', 'list']))
+ return this.list(pkg, opts)
- if (!spec.name || !version || !defaultTag)
- throw usage
+ if (!pkg) {
+ // when only using the pkg name the default behavior
+ // should be listing the existing tags
+ return this.list(cmdName, opts)
+ } else
+ throw this.usage
+ }
+
+ async add (spec, tag, opts) {
+ spec = npa(spec || '')
+ const version = spec.rawSpec
+ const defaultTag = tag || opts.defaultTag
+
+ log.verbose('dist-tag add', defaultTag, 'to', spec.name + '@' + version)
- const t = defaultTag.trim()
+ if (!spec.name || !version || !defaultTag)
+ throw this.usage
- if (semver.validRange(t))
- throw new Error('Tag name must not be a valid SemVer range: ' + t)
+ const t = defaultTag.trim()
- return fetchTags(spec, opts).then(tags => {
+ if (semver.validRange(t))
+ throw new Error('Tag name must not be a valid SemVer range: ' + t)
+
+ const tags = await this.fetchTags(spec, opts)
if (tags[t] === version) {
log.warn('dist-tag add', t, 'is already set to version', version)
return
@@ -82,20 +90,18 @@ function add (spec, tag, opts) {
},
spec,
}
- return otplease(reqOpts, reqOpts => regFetch(url, reqOpts)).then(() => {
- output(`+${t}: ${spec.name}@${version}`)
- })
- })
-}
+ await otplease(reqOpts, reqOpts => regFetch(url, reqOpts))
+ output(`+${t}: ${spec.name}@${version}`)
+ }
-function remove (spec, tag, opts) {
- spec = npa(spec || '')
- log.verbose('dist-tag del', tag, 'from', spec.name)
+ async remove (spec, tag, opts) {
+ spec = npa(spec || '')
+ log.verbose('dist-tag del', tag, 'from', spec.name)
- if (!spec.name)
- throw usage
+ if (!spec.name)
+ throw this.usage
- return fetchTags(spec, opts).then(tags => {
+ const tags = await this.fetchTags(spec, opts)
if (!tags[tag]) {
log.info('dist-tag del', tag, 'is not a dist-tag on', spec.name)
throw new Error(tag + ' is not a dist-tag on ' + spec.name)
@@ -109,50 +115,43 @@ function remove (spec, tag, opts) {
method: 'DELETE',
spec,
}
- return otplease(reqOpts, reqOpts => regFetch(url, reqOpts)).then(() => {
- output(`-${tag}: ${spec.name}@${version}`)
- })
- })
-}
+ await otplease(reqOpts, reqOpts => regFetch(url, reqOpts))
+ output(`-${tag}: ${spec.name}@${version}`)
+ }
-function list (spec, opts) {
- if (!spec) {
- return readLocalPkgName().then(pkg => {
+ async list (spec, opts) {
+ if (!spec) {
+ const pkg = await readLocalPkgName(this.npm)
if (!pkg)
- throw usage
+ throw this.usage
- return list(pkg, opts)
- })
+ return this.list(pkg, opts)
+ }
+ spec = npa(spec)
+
+ try {
+ const tags = await this.fetchTags(spec, opts)
+ const msg =
+ Object.keys(tags).map(k => `${k}: ${tags[k]}`).sort().join('\n')
+ output(msg)
+ return tags
+ } catch (err) {
+ log.error('dist-tag ls', "Couldn't get dist-tag data for", spec)
+ throw err
+ }
}
- spec = npa(spec)
-
- return fetchTags(spec, opts).then(tags => {
- const msg =
- Object.keys(tags).map(k => `${k}: ${tags[k]}`).sort().join('\n')
- output(msg)
- return tags
- }, err => {
- log.error('dist-tag ls', "Couldn't get dist-tag data for", spec)
- throw err
- })
-}
-function fetchTags (spec, opts) {
- return regFetch.json(
- `/-/package/${spec.escapedName}/dist-tags`,
- {
- ...opts,
- 'prefer-online': true,
- spec,
- }
- ).then(data => {
+ async fetchTags (spec, opts) {
+ const data = await regFetch.json(
+ `/-/package/${spec.escapedName}/dist-tags`,
+ { ...opts, 'prefer-online': true, spec }
+ )
if (data && typeof data === 'object')
delete data._etag
if (!data || !Object.keys(data).length)
throw new Error('No dist-tags found for ' + spec.name)
return data
- })
+ }
}
-
-module.exports = Object.assign(cmd, { usage, completion })
+module.exports = DistTag
diff --git a/deps/npm/lib/docs.js b/deps/npm/lib/docs.js
index fa0adb3d373091..2dad7a26db4e74 100644
--- a/deps/npm/lib/docs.js
+++ b/deps/npm/lib/docs.js
@@ -1,39 +1,47 @@
const log = require('npmlog')
const pacote = require('pacote')
-const { promisify } = require('util')
-const openUrl = promisify(require('./utils/open-url.js'))
+const openUrl = require('./utils/open-url.js')
const usageUtil = require('./utils/usage.js')
-const npm = require('./npm.js')
const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js')
-const usage = usageUtil('docs', 'npm docs [ [ ...]]')
-
-const cmd = (args, cb) => docs(args).then(() => cb()).catch(cb)
-
-const docs = async args => {
- if (!args || !args.length)
- args = ['.']
-
- await Promise.all(args.map(pkg => getDocs(pkg)))
-}
-
-const getDocsUrl = mani => {
- if (mani.homepage)
- return mani.homepage
-
- const info = hostedFromMani(mani)
- if (info)
- return info.docs()
-
- return 'https://www.npmjs.com/package/' + mani.name
+class Docs {
+ constructor (npm) {
+ this.npm = npm
+ }
+
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('docs', 'npm docs [ [ ...]]')
+ }
+
+ exec (args, cb) {
+ this.docs(args).then(() => cb()).catch(cb)
+ }
+
+ async docs (args) {
+ if (!args || !args.length)
+ args = ['.']
+
+ await Promise.all(args.map(pkg => this.getDocs(pkg)))
+ }
+
+ async getDocs (pkg) {
+ const opts = { ...this.npm.flatOptions, fullMetadata: true }
+ const mani = await pacote.manifest(pkg, opts)
+ const url = this.getDocsUrl(mani)
+ log.silly('docs', 'url', url)
+ await openUrl(this.npm, url, `${mani.name} docs available at the following URL`)
+ }
+
+ getDocsUrl (mani) {
+ if (mani.homepage)
+ return mani.homepage
+
+ const info = hostedFromMani(mani)
+ if (info)
+ return info.docs()
+
+ return 'https://www.npmjs.com/package/' + mani.name
+ }
}
-
-const getDocs = async pkg => {
- const opts = { ...npm.flatOptions, fullMetadata: true }
- const mani = await pacote.manifest(pkg, opts)
- const url = getDocsUrl(mani)
- log.silly('docs', 'url', url)
- await openUrl(url, `${mani.name} docs available at the following URL`)
-}
-
-module.exports = Object.assign(cmd, { usage })
+module.exports = Docs
diff --git a/deps/npm/lib/doctor.js b/deps/npm/lib/doctor.js
index e149aec1286d54..81860004e344e4 100644
--- a/deps/npm/lib/doctor.js
+++ b/deps/npm/lib/doctor.js
@@ -1,79 +1,22 @@
-const npm = require('./npm.js')
-
+const cacache = require('cacache')
const chalk = require('chalk')
-const ansiTrim = require('./utils/ansi-trim.js')
+const fs = require('fs')
+const fetch = require('make-fetch-happen')
const table = require('text-table')
-const output = require('./utils/output.js')
-const usageUtil = require('./utils/usage.js')
-const usage = usageUtil('doctor', 'npm doctor')
-const { resolve } = require('path')
-
-const ping = require('./utils/ping.js')
-const checkPing = async () => {
- const tracker = npm.log.newItem('checkPing', 1)
- tracker.info('checkPing', 'Pinging registry')
- try {
- await ping(npm.flatOptions)
- return ''
- } catch (er) {
- if (/^E\d{3}$/.test(er.code || ''))
- throw er.code.substr(1) + ' ' + er.message
- else
- throw er.message
- } finally {
- tracker.finish()
- }
-}
-
+const which = require('which')
const pacote = require('pacote')
-const getLatestNpmVersion = async () => {
- const tracker = npm.log.newItem('getLatestNpmVersion', 1)
- tracker.info('getLatestNpmVersion', 'Getting npm package information')
- try {
- const latest = (await pacote.manifest('npm@latest', npm.flatOptions)).version
- if (semver.gte(npm.version, latest))
- return `current: v${npm.version}, latest: v${latest}`
- else
- throw `Use npm v${latest}`
- } finally {
- tracker.finish()
- }
-}
-
+const { resolve } = require('path')
const semver = require('semver')
-const fetch = require('make-fetch-happen')
-const getLatestNodejsVersion = async () => {
- // XXX get the latest in the current major as well
- const current = process.version
- const currentRange = `^${current}`
- const url = 'https://nodejs.org/dist/index.json'
- const tracker = npm.log.newItem('getLatestNodejsVersion', 1)
- tracker.info('getLatestNodejsVersion', 'Getting Node.js release information')
- try {
- const res = await fetch(url, { method: 'GET', ...npm.flatOptions })
- const data = await res.json()
- let maxCurrent = '0.0.0'
- let maxLTS = '0.0.0'
- for (const { lts, version } of data) {
- if (lts && semver.gt(version, maxLTS))
- maxLTS = version
-
- if (semver.satisfies(version, currentRange) &&
- semver.gt(version, maxCurrent))
- maxCurrent = version
- }
- const recommended = semver.gt(maxCurrent, maxLTS) ? maxCurrent : maxLTS
- if (semver.gte(process.version, recommended))
- return `current: ${current}, recommended: ${recommended}`
- else
- throw `Use node ${recommended} (current: ${current})`
- } finally {
- tracker.finish()
- }
-}
-
const { promisify } = require('util')
-const fs = require('fs')
+const ansiTrim = require('./utils/ansi-trim.js')
+const isWindows = require('./utils/is-windows.js')
+const output = require('./utils/output.js')
+const ping = require('./utils/ping.js')
+const usageUtil = require('./utils/usage.js')
+const { defaults: { registry: defaultRegistry } } = require('./utils/config.js')
+const lstat = promisify(fs.lstat)
+const readdir = promisify(fs.readdir)
+const access = promisify(fs.access)
const { R_OK, W_OK, X_OK } = fs.constants
const maskLabel = mask => {
const label = []
@@ -88,200 +31,268 @@ const maskLabel = mask => {
return label.join(', ')
}
-const lstat = promisify(fs.lstat)
-const readdir = promisify(fs.readdir)
-const access = promisify(fs.access)
-const isWindows = require('./utils/is-windows.js')
-const checkFilesPermission = async (root, shouldOwn, mask = null) => {
- if (mask === null)
- mask = shouldOwn ? R_OK | W_OK : R_OK
-
- let ok = true
-
- const tracker = npm.log.newItem(root, 1)
-
- try {
- const uid = process.getuid()
- const gid = process.getgid()
- const files = new Set([root])
- for (const f of files) {
- tracker.silly('checkFilesPermission', f.substr(root.length + 1))
- const st = await lstat(f)
- .catch(er => {
- ok = false
- tracker.warn('checkFilesPermission', 'error getting info for ' + f)
- })
- tracker.completeWork(1)
-
- if (!st)
- continue
+class Doctor {
+ constructor (npm) {
+ this.npm = npm
+ }
- if (shouldOwn && (uid !== st.uid || gid !== st.gid)) {
- tracker.warn('checkFilesPermission', 'should be owner of ' + f)
- ok = false
- }
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('doctor', 'npm doctor')
+ }
- if (!st.isDirectory() && !st.isFile())
- continue
+ exec (args, cb) {
+ this.doctor(args).then(() => cb()).catch(cb)
+ }
+ async doctor (args) {
+ this.npm.log.info('Running checkup')
+
+ // each message is [title, ok, message]
+ const messages = []
+
+ const actions = [
+ ['npm ping', 'checkPing', []],
+ ['npm -v', 'getLatestNpmVersion', []],
+ ['node -v', 'getLatestNodejsVersion', []],
+ ['npm config get registry', 'checkNpmRegistry', []],
+ ['which git', 'getGitPath', []],
+ ...(isWindows ? [] : [
+ ['Perms check on cached files', 'checkFilesPermission', [this.npm.cache, true, R_OK]],
+ ['Perms check on local node_modules', 'checkFilesPermission', [this.npm.localDir, true]],
+ ['Perms check on global node_modules', 'checkFilesPermission', [this.npm.globalDir, false]],
+ ['Perms check on local bin folder', 'checkFilesPermission', [this.npm.localBin, false, R_OK | W_OK | X_OK]],
+ ['Perms check on global bin folder', 'checkFilesPermission', [this.npm.globalBin, false, X_OK]],
+ ]),
+ ['Verify cache contents', 'verifyCachedFiles', [this.npm.flatOptions.cache]],
+ // TODO:
+ // - ensure arborist.loadActual() runs without errors and no invalid edges
+ // - ensure package-lock.json matches loadActual()
+ // - verify loadActual without hidden lock file matches hidden lockfile
+ // - verify all local packages have bins linked
+ ]
+
+ // Do the actual work
+ for (const [msg, fn, args] of actions) {
+ const line = [msg]
try {
- await access(f, mask)
+ line.push(true, await this[fn](...args))
} catch (er) {
- ok = false
- const msg = `Missing permissions on ${f} (expect: ${maskLabel(mask)})`
- tracker.error('checkFilesPermission', msg)
- continue
+ line.push(false, er)
}
+ messages.push(line)
+ }
- if (st.isDirectory()) {
- const entries = await readdir(f)
- .catch(er => {
- ok = false
- tracker.warn('checkFilesPermission', 'error reading directory ' + f)
- return []
- })
- for (const entry of entries)
- files.add(resolve(f, entry))
+ const outHead = ['Check', 'Value', 'Recommendation/Notes']
+ .map(!this.npm.color ? h => h : h => chalk.underline(h))
+ let allOk = true
+ const outBody = messages.map(!this.npm.color
+ ? item => {
+ allOk = allOk && item[1]
+ item[1] = item[1] ? 'ok' : 'not ok'
+ item[2] = String(item[2])
+ return item
}
+ : item => {
+ allOk = allOk && item[1]
+ if (!item[1]) {
+ item[0] = chalk.red(item[0])
+ item[2] = chalk.magenta(String(item[2]))
+ }
+ item[1] = item[1] ? chalk.green('ok') : chalk.red('not ok')
+ return item
+ })
+ const outTable = [outHead, ...outBody]
+ const tableOpts = {
+ stringLength: s => ansiTrim(s).length,
}
- } finally {
- tracker.finish()
- if (!ok) {
- throw `Check the permissions of files in ${root}` +
- (shouldOwn ? ' (should be owned by current user)' : '')
- } else
+
+ const silent = this.npm.log.levels[this.npm.log.level] >
+ this.npm.log.levels.error
+ if (!silent) {
+ output(table(outTable, tableOpts))
+ if (!allOk)
+ console.error('')
+ }
+ if (!allOk)
+ throw 'Some problems found. See above for recommendations.'
+ }
+
+ async checkPing () {
+ const tracker = this.npm.log.newItem('checkPing', 1)
+ tracker.info('checkPing', 'Pinging registry')
+ try {
+ await ping(this.npm.flatOptions)
return ''
+ } catch (er) {
+ if (/^E\d{3}$/.test(er.code || ''))
+ throw er.code.substr(1) + ' ' + er.message
+ else
+ throw er.message
+ } finally {
+ tracker.finish()
+ }
}
-}
-const which = require('which')
-const getGitPath = async () => {
- const tracker = npm.log.newItem('getGitPath', 1)
- tracker.info('getGitPath', 'Finding git in your PATH')
- try {
- return await which('git').catch(er => {
- tracker.warn(er)
- throw "Install git and ensure it's in your PATH."
- })
- } finally {
- tracker.finish()
+ async getLatestNpmVersion () {
+ const tracker = this.npm.log.newItem('getLatestNpmVersion', 1)
+ tracker.info('getLatestNpmVersion', 'Getting npm package information')
+ try {
+ const latest = (await pacote.manifest('npm@latest', this.npm.flatOptions)).version
+ if (semver.gte(this.npm.version, latest))
+ return `current: v${this.npm.version}, latest: v${latest}`
+ else
+ throw `Use npm v${latest}`
+ } finally {
+ tracker.finish()
+ }
}
-}
-const cacache = require('cacache')
-const verifyCachedFiles = async () => {
- const tracker = npm.log.newItem('verifyCachedFiles', 1)
- tracker.info('verifyCachedFiles', 'Verifying the npm cache')
- try {
- const stats = await cacache.verify(npm.flatOptions.cache)
- const {
- badContentCount,
- reclaimedCount,
- missingContent,
- reclaimedSize,
- } = stats
- if (badContentCount || reclaimedCount || missingContent) {
- if (badContentCount)
- tracker.warn('verifyCachedFiles', `Corrupted content removed: ${badContentCount}`)
-
- if (reclaimedCount)
- tracker.warn('verifyCachedFiles', `Content garbage-collected: ${reclaimedCount} (${reclaimedSize} bytes)`)
-
- if (missingContent)
- tracker.warn('verifyCachedFiles', `Missing content: ${missingContent}`)
-
- tracker.warn('verifyCachedFiles', 'Cache issues have been fixed')
+ async getLatestNodejsVersion () {
+ // XXX get the latest in the current major as well
+ const current = process.version
+ const currentRange = `^${current}`
+ const url = 'https://nodejs.org/dist/index.json'
+ const tracker = this.npm.log.newItem('getLatestNodejsVersion', 1)
+ tracker.info('getLatestNodejsVersion', 'Getting Node.js release information')
+ try {
+ const res = await fetch(url, { method: 'GET', ...this.npm.flatOptions })
+ const data = await res.json()
+ let maxCurrent = '0.0.0'
+ let maxLTS = '0.0.0'
+ for (const { lts, version } of data) {
+ if (lts && semver.gt(version, maxLTS))
+ maxLTS = version
+
+ if (semver.satisfies(version, currentRange) &&
+ semver.gt(version, maxCurrent))
+ maxCurrent = version
+ }
+ const recommended = semver.gt(maxCurrent, maxLTS) ? maxCurrent : maxLTS
+ if (semver.gte(process.version, recommended))
+ return `current: ${current}, recommended: ${recommended}`
+ else
+ throw `Use node ${recommended} (current: ${current})`
+ } finally {
+ tracker.finish()
}
- tracker.info('verifyCachedFiles', `Verification complete. Stats: ${
- JSON.stringify(stats, null, 2)
- }`)
- return `verified ${stats.verifiedContent} tarballs`
- } finally {
- tracker.finish()
}
-}
-const { defaults: { registry: defaultRegistry } } = require('./utils/config.js')
-const checkNpmRegistry = async () => {
- if (npm.flatOptions.registry !== defaultRegistry)
- throw `Try \`npm config set registry=${defaultRegistry}\``
- else
- return `using default registry (${defaultRegistry})`
-}
+ async checkFilesPermission (root, shouldOwn, mask = null) {
+ if (mask === null)
+ mask = shouldOwn ? R_OK | W_OK : R_OK
+
+ let ok = true
+
+ const tracker = this.npm.log.newItem(root, 1)
-const cmd = (args, cb) => doctor(args).then(() => cb()).catch(cb)
-
-const doctor = async args => {
- npm.log.info('Running checkup')
-
- // each message is [title, ok, message]
- const messages = []
-
- const actions = [
- ['npm ping', checkPing, []],
- ['npm -v', getLatestNpmVersion, []],
- ['node -v', getLatestNodejsVersion, []],
- ['npm config get registry', checkNpmRegistry, []],
- ['which git', getGitPath, []],
- ...(isWindows ? [] : [
- ['Perms check on cached files', checkFilesPermission, [npm.cache, true, R_OK]],
- ['Perms check on local node_modules', checkFilesPermission, [npm.localDir, true]],
- ['Perms check on global node_modules', checkFilesPermission, [npm.globalDir, false]],
- ['Perms check on local bin folder', checkFilesPermission, [npm.localBin, false, R_OK | W_OK | X_OK]],
- ['Perms check on global bin folder', checkFilesPermission, [npm.globalBin, false, X_OK]],
- ]),
- ['Verify cache contents', verifyCachedFiles, [npm.flatOptions.cache]],
- // TODO:
- // - ensure arborist.loadActual() runs without errors and no invalid edges
- // - ensure package-lock.json matches loadActual()
- // - verify loadActual without hidden lock file matches hidden lockfile
- // - verify all local packages have bins linked
- ]
-
- for (const [msg, fn, args] of actions) {
- const line = [msg]
try {
- line.push(true, await fn(...args))
- } catch (er) {
- line.push(false, er)
+ const uid = process.getuid()
+ const gid = process.getgid()
+ const files = new Set([root])
+ for (const f of files) {
+ tracker.silly('checkFilesPermission', f.substr(root.length + 1))
+ const st = await lstat(f)
+ .catch(er => {
+ ok = false
+ tracker.warn('checkFilesPermission', 'error getting info for ' + f)
+ })
+
+ tracker.completeWork(1)
+
+ if (!st)
+ continue
+
+ if (shouldOwn && (uid !== st.uid || gid !== st.gid)) {
+ tracker.warn('checkFilesPermission', 'should be owner of ' + f)
+ ok = false
+ }
+
+ if (!st.isDirectory() && !st.isFile())
+ continue
+
+ try {
+ await access(f, mask)
+ } catch (er) {
+ ok = false
+ const msg = `Missing permissions on ${f} (expect: ${maskLabel(mask)})`
+ tracker.error('checkFilesPermission', msg)
+ continue
+ }
+
+ if (st.isDirectory()) {
+ const entries = await readdir(f)
+ .catch(er => {
+ ok = false
+ tracker.warn('checkFilesPermission', 'error reading directory ' + f)
+ return []
+ })
+ for (const entry of entries)
+ files.add(resolve(f, entry))
+ }
+ }
+ } finally {
+ tracker.finish()
+ if (!ok) {
+ throw `Check the permissions of files in ${root}` +
+ (shouldOwn ? ' (should be owned by current user)' : '')
+ } else
+ return ''
}
- messages.push(line)
}
- const silent = npm.log.levels[npm.log.level] > npm.log.levels.error
-
- const outHead = ['Check', 'Value', 'Recommendation/Notes']
- .map(!npm.color ? h => h : h => chalk.underline(h))
- let allOk = true
- const outBody = messages.map(!npm.color
- ? item => {
- allOk = allOk && item[1]
- item[1] = item[1] ? 'ok' : 'not ok'
- item[2] = String(item[2])
- return item
+ async getGitPath () {
+ const tracker = this.npm.log.newItem('getGitPath', 1)
+ tracker.info('getGitPath', 'Finding git in your PATH')
+ try {
+ return await which('git').catch(er => {
+ tracker.warn(er)
+ throw "Install git and ensure it's in your PATH."
+ })
+ } finally {
+ tracker.finish()
}
- : item => {
- allOk = allOk && item[1]
- if (!item[1]) {
- item[0] = chalk.red(item[0])
- item[2] = chalk.magenta(String(item[2]))
+ }
+
+ async verifyCachedFiles () {
+ const tracker = this.npm.log.newItem('verifyCachedFiles', 1)
+ tracker.info('verifyCachedFiles', 'Verifying the npm cache')
+ try {
+ const stats = await cacache.verify(this.npm.flatOptions.cache)
+ const {
+ badContentCount,
+ reclaimedCount,
+ missingContent,
+ reclaimedSize,
+ } = stats
+ if (badContentCount || reclaimedCount || missingContent) {
+ if (badContentCount)
+ tracker.warn('verifyCachedFiles', `Corrupted content removed: ${badContentCount}`)
+
+ if (reclaimedCount)
+ tracker.warn('verifyCachedFiles', `Content garbage-collected: ${reclaimedCount} (${reclaimedSize} bytes)`)
+
+ if (missingContent)
+ tracker.warn('verifyCachedFiles', `Missing content: ${missingContent}`)
+
+ tracker.warn('verifyCachedFiles', 'Cache issues have been fixed')
}
- item[1] = item[1] ? chalk.green('ok') : chalk.red('not ok')
- return item
- })
- const outTable = [outHead, ...outBody]
- const tableOpts = {
- stringLength: s => ansiTrim(s).length,
+ tracker.info('verifyCachedFiles', `Verification complete. Stats: ${
+ JSON.stringify(stats, null, 2)
+ }`)
+ return `verified ${stats.verifiedContent} tarballs`
+ } finally {
+ tracker.finish()
+ }
}
- if (!silent) {
- output(table(outTable, tableOpts))
- if (!allOk)
- console.error('')
+ async checkNpmRegistry () {
+ if (this.npm.flatOptions.registry !== defaultRegistry)
+ throw `Try \`npm config set registry=${defaultRegistry}\``
+ else
+ return `using default registry (${defaultRegistry})`
}
- if (!allOk)
- throw 'Some problems found. See above for recommendations.'
}
-module.exports = Object.assign(cmd, { usage })
+module.exports = Doctor
diff --git a/deps/npm/lib/edit.js b/deps/npm/lib/edit.js
index 9ae6349262c2d9..a7dbb38205b02a 100644
--- a/deps/npm/lib/edit.js
+++ b/deps/npm/lib/edit.js
@@ -4,33 +4,55 @@
const { resolve } = require('path')
const fs = require('graceful-fs')
const { spawn } = require('child_process')
-const npm = require('./npm.js')
const usageUtil = require('./utils/usage.js')
const splitPackageNames = require('./utils/split-package-names.js')
-
-const usage = usageUtil('edit', 'npm edit [/...]')
const completion = require('./utils/completion/installed-shallow.js')
-function edit (args, cb) {
- if (args.length !== 1)
- return cb(usage)
-
- const path = splitPackageNames(args[0])
- const dir = resolve(npm.dir, path)
-
- fs.lstat(dir, (err) => {
- if (err)
- return cb(err)
-
- const [bin, ...args] = npm.config.get('editor').split(/\s+/)
- const editor = spawn(bin, [...args, dir], { stdio: 'inherit' })
- editor.on('exit', (code) => {
- if (code)
- return cb(new Error(`editor process exited with code: ${code}`))
-
- npm.commands.rebuild([dir], cb)
+class Edit {
+ constructor (npm) {
+ this.npm = npm
+ }
+
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('edit', 'npm edit [/...]')
+ }
+
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ async completion (opts) {
+ return completion(this.npm, opts)
+ }
+
+ exec (args, cb) {
+ this.edit(args).then(() => cb()).catch(cb)
+ }
+
+ async edit (args) {
+ if (args.length !== 1)
+ throw new Error(this.usage)
+
+ const path = splitPackageNames(args[0])
+ const dir = resolve(this.npm.dir, path)
+
+ // graceful-fs does not promisify
+ await new Promise((resolve, reject) => {
+ fs.lstat(dir, (err) => {
+ if (err)
+ return reject(err)
+ const [bin, ...args] = this.npm.config.get('editor').split(/\s+/)
+ const editor = spawn(bin, [...args, dir], { stdio: 'inherit' })
+ editor.on('exit', (code) => {
+ if (code)
+ return reject(new Error(`editor process exited with code: ${code}`))
+ this.npm.commands.rebuild([dir], (err) => {
+ if (err)
+ return reject(err)
+
+ resolve()
+ })
+ })
+ })
})
- })
+ }
}
-
-module.exports = Object.assign(edit, { completion, usage })
+module.exports = Edit
diff --git a/deps/npm/lib/exec.js b/deps/npm/lib/exec.js
index dab65c23a37b27..d1db49128587e3 100644
--- a/deps/npm/lib/exec.js
+++ b/deps/npm/lib/exec.js
@@ -1,28 +1,18 @@
-const npm = require('./npm.js')
const output = require('./utils/output.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil('exec',
- 'Run a command from a local or remote npm package.\n\n' +
-
- 'npm exec -- [@] [args...]\n' +
- 'npm exec --package=[@] -- [args...]\n' +
- 'npm exec -c \' [args...]\'\n' +
- 'npm exec --package=foo -c \' [args...]\'\n' +
- '\n' +
- 'npx [@] [args...]\n' +
- 'npx -p [@] [args...]\n' +
- 'npx -c \' [args...]\'\n' +
- 'npx -p [@] -c \' [args...]\'' +
- '\n' +
- 'Run without --call or positional args to open interactive subshell\n',
-
- '\n--package= (may be specified multiple times)\n' +
- '-p is a shorthand for --package only when using npx executable\n' +
- '-c --call= (may not be mixed with positional arguments)'
-)
-
const { promisify } = require('util')
const read = promisify(require('read'))
+const mkdirp = require('mkdirp-infer-owner')
+const readPackageJson = require('read-package-json-fast')
+const Arborist = require('@npmcli/arborist')
+const runScript = require('@npmcli/run-script')
+const { resolve, delimiter } = require('path')
+const ciDetect = require('@npmcli/ci-detect')
+const crypto = require('crypto')
+const pacote = require('pacote')
+const npa = require('npm-package-arg')
+const fileExists = require('./utils/file-exists.js')
+const PATH = require('./utils/path.js')
// it's like this:
//
@@ -49,237 +39,258 @@ const read = promisify(require('read'))
// runScript({ pkg, event: 'npx', ... })
// process.env.npm_lifecycle_event = 'npx'
-const mkdirp = require('mkdirp-infer-owner')
-const readPackageJson = require('read-package-json-fast')
-const Arborist = require('@npmcli/arborist')
-const runScript = require('@npmcli/run-script')
-const { resolve, delimiter } = require('path')
-const ciDetect = require('@npmcli/ci-detect')
-const crypto = require('crypto')
-const pacote = require('pacote')
-const npa = require('npm-package-arg')
-const fileExists = require('./utils/file-exists.js')
-const PATH = require('./utils/path.js')
-
-const cmd = (args, cb) => exec(args).then(() => cb()).catch(cb)
-
-const run = async ({ args, call, pathArr, shell }) => {
- // turn list of args into command string
- const script = call || args.shift() || shell
-
- // do the fakey runScript dance
- // still should work if no package.json in cwd
- const realPkg = await readPackageJson(`${npm.localPrefix}/package.json`)
- .catch(() => ({}))
- const pkg = {
- ...realPkg,
- scripts: {
- ...(realPkg.scripts || {}),
- npx: script,
- },
+class Exec {
+ constructor (npm) {
+ this.npm = npm
}
- npm.log.disableProgress()
- try {
- if (script === shell) {
- if (process.stdin.isTTY) {
- if (ciDetect())
- return npm.log.warn('exec', 'Interactive mode disabled in CI environment')
- output(`\nEntering npm script environment\nType 'exit' or ^D when finished\n`)
- }
- }
- return await runScript({
- ...npm.flatOptions,
- pkg,
- banner: false,
- // we always run in cwd, not --prefix
- path: process.cwd(),
- stdioString: true,
- event: 'npx',
- args,
- env: {
- PATH: pathArr.join(delimiter),
- },
- stdio: 'inherit',
- })
- } finally {
- npm.log.enableProgress()
+ get usage () {
+ return usageUtil('exec',
+ 'Run a command from a local or remote npm package.\n\n' +
+
+ 'npm exec -- [@] [args...]\n' +
+ 'npm exec --package=[@] -- [args...]\n' +
+ 'npm exec -c \' [args...]\'\n' +
+ 'npm exec --package=foo -c \' [args...]\'\n' +
+ '\n' +
+ 'npx [@] [args...]\n' +
+ 'npx -p [@] [args...]\n' +
+ 'npx -c \' [args...]\'\n' +
+ 'npx -p [@] -c \' [args...]\'' +
+ '\n' +
+ 'Run without --call or positional args to open interactive subshell\n',
+
+ '\n--package= (may be specified multiple times)\n' +
+ '-p is a shorthand for --package only when using npx executable\n' +
+ '-c --call= (may not be mixed with positional arguments)'
+ )
}
-}
-
-const exec = async args => {
- const { package: packages, call, shell } = npm.flatOptions
- if (call && args.length)
- throw usage
+ exec (args, cb) {
+ this._exec(args).then(() => cb()).catch(cb)
+ }
- const pathArr = [...PATH]
+ // When commands go async and we can dump the boilerplate exec methods this
+ // can be named correctly
+ async _exec (args) {
+ const { package: packages, call, shell } = this.npm.flatOptions
- // nothing to maybe install, skip the arborist dance
- if (!call && !args.length && !packages.length) {
- return await run({
- args,
- call,
- shell,
- pathArr,
- })
- }
+ if (call && args.length)
+ throw this.usage
- const needPackageCommandSwap = args.length && !packages.length
- // if there's an argument and no package has been explicitly asked for
- // check the local and global bin paths for a binary named the same as
- // the argument and run it if it exists, otherwise fall through to
- // the behavior of treating the single argument as a package name
- if (needPackageCommandSwap) {
- let binExists = false
- if (await fileExists(`${npm.localBin}/${args[0]}`)) {
- pathArr.unshift(npm.localBin)
- binExists = true
- } else if (await fileExists(`${npm.globalBin}/${args[0]}`)) {
- pathArr.unshift(npm.globalBin)
- binExists = true
- }
+ const pathArr = [...PATH]
- if (binExists) {
- return await run({
+ // nothing to maybe install, skip the arborist dance
+ if (!call && !args.length && !packages.length) {
+ return await this.run({
args,
call,
- pathArr,
shell,
+ pathArr,
})
}
- packages.push(args[0])
- }
+ const needPackageCommandSwap = args.length && !packages.length
+ // if there's an argument and no package has been explicitly asked for
+ // check the local and global bin paths for a binary named the same as
+ // the argument and run it if it exists, otherwise fall through to
+ // the behavior of treating the single argument as a package name
+ if (needPackageCommandSwap) {
+ let binExists = false
+ if (await fileExists(`${this.npm.localBin}/${args[0]}`)) {
+ pathArr.unshift(this.npm.localBin)
+ binExists = true
+ } else if (await fileExists(`${this.npm.globalBin}/${args[0]}`)) {
+ pathArr.unshift(this.npm.globalBin)
+ binExists = true
+ }
- // If we do `npm exec foo`, and have a `foo` locally, then we'll
- // always use that, so we don't really need to fetch the manifest.
- // So: run npa on each packages entry, and if it is a name with a
- // rawSpec==='', then try to readPackageJson at
- // node_modules/${name}/package.json, and only pacote fetch if
- // that fails.
- const manis = await Promise.all(packages.map(async p => {
- const spec = npa(p, npm.localPrefix)
- if (spec.type === 'tag' && spec.rawSpec === '') {
- // fall through to the pacote.manifest() approach
- try {
- const pj = resolve(npm.localPrefix, 'node_modules', spec.name)
- return await readPackageJson(pj)
- } catch (er) {}
+ if (binExists) {
+ return await this.run({
+ args,
+ call,
+ pathArr,
+ shell,
+ })
+ }
+
+ packages.push(args[0])
}
- // Force preferOnline to true so we are making sure to pull in the latest
- // This is especially useful if the user didn't give us a version, and
- // they expect to be running @latest
- return await pacote.manifest(p, {
- ...npm.flatOptions,
- preferOnline: true,
- })
- }))
-
- if (needPackageCommandSwap)
- args[0] = getBinFromManifest(manis[0])
-
- // figure out whether we need to install stuff, or if local is fine
- const localArb = new Arborist({
- ...npm.flatOptions,
- path: npm.localPrefix,
- })
- const tree = await localArb.loadActual()
-
- // do we have all the packages in manifest list?
- const needInstall = manis.some(mani => manifestMissing(tree, mani))
-
- if (needInstall) {
- const installDir = cacheInstallDir(packages)
- await mkdirp(installDir)
- const arb = new Arborist({ ...npm.flatOptions, path: installDir })
- const tree = await arb.loadActual()
-
- // at this point, we have to ensure that we get the exact same
- // version, because it's something that has only ever been installed
- // by npm exec in the cache install directory
- const add = manis.filter(mani => manifestMissing(tree, {
- ...mani,
- _from: `${mani.name}@${mani.version}`,
+
+ // If we do `npm exec foo`, and have a `foo` locally, then we'll
+ // always use that, so we don't really need to fetch the manifest.
+ // So: run npa on each packages entry, and if it is a name with a
+ // rawSpec==='', then try to readPackageJson at
+ // node_modules/${name}/package.json, and only pacote fetch if
+ // that fails.
+ const manis = await Promise.all(packages.map(async p => {
+ const spec = npa(p, this.npm.localPrefix)
+ if (spec.type === 'tag' && spec.rawSpec === '') {
+ // fall through to the pacote.manifest() approach
+ try {
+ const pj = resolve(this.npm.localPrefix, 'node_modules', spec.name)
+ return await readPackageJson(pj)
+ } catch (er) {}
+ }
+ // Force preferOnline to true so we are making sure to pull in the latest
+ // This is especially useful if the user didn't give us a version, and
+ // they expect to be running @latest
+ return await pacote.manifest(p, {
+ ...this.npm.flatOptions,
+ preferOnline: true,
+ })
}))
- .map(mani => mani._from)
- .sort((a, b) => a.localeCompare(b))
-
- // no need to install if already present
- if (add.length) {
- if (!npm.flatOptions.yes) {
- // set -n to always say no
- if (npm.flatOptions.yes === false)
- throw 'canceled'
-
- if (!process.stdin.isTTY || ciDetect()) {
- npm.log.warn('exec', `The following package${
+
+ if (needPackageCommandSwap)
+ args[0] = this.getBinFromManifest(manis[0])
+
+ // figure out whether we need to install stuff, or if local is fine
+ const localArb = new Arborist({
+ ...this.npm.flatOptions,
+ path: this.npm.localPrefix,
+ })
+ const tree = await localArb.loadActual()
+
+ // do we have all the packages in manifest list?
+ const needInstall = manis.some(mani => this.manifestMissing(tree, mani))
+
+ if (needInstall) {
+ const installDir = this.cacheInstallDir(packages)
+ await mkdirp(installDir)
+ const arb = new Arborist({ ...this.npm.flatOptions, path: installDir })
+ const tree = await arb.loadActual()
+
+ // at this point, we have to ensure that we get the exact same
+ // version, because it's something that has only ever been installed
+ // by npm exec in the cache install directory
+ const add = manis.filter(mani => this.manifestMissing(tree, {
+ ...mani,
+ _from: `${mani.name}@${mani.version}`,
+ }))
+ .map(mani => mani._from)
+ .sort((a, b) => a.localeCompare(b))
+
+ // no need to install if already present
+ if (add.length) {
+ if (!this.npm.flatOptions.yes) {
+ // set -n to always say no
+ if (this.npm.flatOptions.yes === false)
+ throw 'canceled'
+
+ if (!process.stdin.isTTY || ciDetect()) {
+ this.npm.log.warn('exec', `The following package${
add.length === 1 ? ' was' : 's were'
} not found and will be installed: ${
add.map((pkg) => pkg.replace(/@$/, '')).join(', ')
}`)
- } else {
- const addList = add.map(a => ` ${a.replace(/@$/, '')}`)
- .join('\n') + '\n'
- const prompt = `Need to install the following packages:\n${
+ } else {
+ const addList = add.map(a => ` ${a.replace(/@$/, '')}`)
+ .join('\n') + '\n'
+ const prompt = `Need to install the following packages:\n${
addList
}Ok to proceed? `
- const confirm = await read({ prompt, default: 'y' })
- if (confirm.trim().toLowerCase().charAt(0) !== 'y')
- throw 'canceled'
+ const confirm = await read({ prompt, default: 'y' })
+ if (confirm.trim().toLowerCase().charAt(0) !== 'y')
+ throw 'canceled'
+ }
}
+ await arb.reify({ ...this.npm.flatOptions, add })
}
- await arb.reify({ ...npm.flatOptions, add })
+ pathArr.unshift(resolve(installDir, 'node_modules/.bin'))
}
- pathArr.unshift(resolve(installDir, 'node_modules/.bin'))
+
+ return await this.run({ args, call, pathArr, shell })
}
- return await run({ args, call, pathArr, shell })
-}
+ async run ({ args, call, pathArr, shell }) {
+ // turn list of args into command string
+ const script = call || args.shift() || shell
+
+ // do the fakey runScript dance
+ // still should work if no package.json in cwd
+ const realPkg = await readPackageJson(`${this.npm.localPrefix}/package.json`)
+ .catch(() => ({}))
+ const pkg = {
+ ...realPkg,
+ scripts: {
+ ...(realPkg.scripts || {}),
+ npx: script,
+ },
+ }
-const manifestMissing = (tree, mani) => {
- // if the tree doesn't have a child by that name/version, return true
- // true means we need to install it
- const child = tree.children.get(mani.name)
- // if no child, we have to load it
- if (!child)
- return true
+ this.npm.log.disableProgress()
+ try {
+ if (script === shell) {
+ if (process.stdin.isTTY) {
+ if (ciDetect())
+ return this.npm.log.warn('exec', 'Interactive mode disabled in CI environment')
+ output(`\nEntering npm script environment\nType 'exit' or ^D when finished\n`)
+ }
+ }
+ return await runScript({
+ ...this.npm.flatOptions,
+ pkg,
+ banner: false,
+ // we always run in cwd, not --prefix
+ path: process.cwd(),
+ stdioString: true,
+ event: 'npx',
+ args,
+ env: {
+ PATH: pathArr.join(delimiter),
+ },
+ stdio: 'inherit',
+ })
+ } finally {
+ this.npm.log.enableProgress()
+ }
+ }
- // if no version/tag specified, allow whatever's there
- if (mani._from === `${mani.name}@`)
- return false
+ manifestMissing (tree, mani) {
+ // if the tree doesn't have a child by that name/version, return true
+ // true means we need to install it
+ const child = tree.children.get(mani.name)
+ // if no child, we have to load it
+ if (!child)
+ return true
- // otherwise the version has to match what we WOULD get
- return child.version !== mani.version
-}
+ // if no version/tag specified, allow whatever's there
+ if (mani._from === `${mani.name}@`)
+ return false
-const getBinFromManifest = mani => {
- // if we have a bin matching (unscoped portion of) packagename, use that
- // otherwise if there's 1 bin or all bin value is the same (alias), use that,
- // otherwise fail
- const bin = mani.bin || {}
- if (new Set(Object.values(bin)).size === 1)
- return Object.keys(bin)[0]
-
- // XXX probably a util to parse this better?
- const name = mani.name.replace(/^@[^/]+\//, '')
- if (bin[name])
- return name
-
- // XXX need better error message
- throw Object.assign(new Error('could not determine executable to run'), {
- pkgid: mani._id,
- })
-}
+ // otherwise the version has to match what we WOULD get
+ return child.version !== mani.version
+ }
-// only packages not found in ${prefix}/node_modules
-const cacheInstallDir = packages =>
- resolve(npm.config.get('cache'), '_npx', getHash(packages))
+ getBinFromManifest (mani) {
+ // if we have a bin matching (unscoped portion of) packagename, use that
+ // otherwise if there's 1 bin or all bin value is the same (alias), use
+ // that, otherwise fail
+ const bin = mani.bin || {}
+ if (new Set(Object.values(bin)).size === 1)
+ return Object.keys(bin)[0]
+
+ // XXX probably a util to parse this better?
+ const name = mani.name.replace(/^@[^/]+\//, '')
+ if (bin[name])
+ return name
+
+ // XXX need better error message
+ throw Object.assign(new Error('could not determine executable to run'), {
+ pkgid: mani._id,
+ })
+ }
-const getHash = packages =>
- crypto.createHash('sha512')
- .update(packages.sort((a, b) => a.localeCompare(b)).join('\n'))
- .digest('hex')
- .slice(0, 16)
+ cacheInstallDir (packages) {
+ // only packages not found in ${prefix}/node_modules
+ return resolve(this.npm.config.get('cache'), '_npx', this.getHash(packages))
+ }
-module.exports = Object.assign(cmd, { usage })
+ getHash (packages) {
+ return crypto.createHash('sha512')
+ .update(packages.sort((a, b) => a.localeCompare(b)).join('\n'))
+ .digest('hex')
+ .slice(0, 16)
+ }
+}
+module.exports = Exec
diff --git a/deps/npm/lib/explain.js b/deps/npm/lib/explain.js
index a0a4427bccf2cc..01541040ef649c 100644
--- a/deps/npm/lib/explain.js
+++ b/deps/npm/lib/explain.js
@@ -1,5 +1,4 @@
const usageUtil = require('./utils/usage.js')
-const npm = require('./npm.js')
const { explainNode } = require('./utils/explain-dep.js')
const completion = require('./utils/completion/installed-deep.js')
const output = require('./utils/output.js')
@@ -9,86 +8,101 @@ const semver = require('semver')
const { relative, resolve } = require('path')
const validName = require('validate-npm-package-name')
-const usage = usageUtil('explain', 'npm explain ')
-
-const cmd = (args, cb) => explain(args).then(() => cb()).catch(cb)
+class Explain {
+ constructor (npm) {
+ this.npm = npm
+ }
-const explain = async (args) => {
- if (!args.length)
- throw usage
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('explain', 'npm explain ')
+ }
- const arb = new Arborist({ path: npm.prefix, ...npm.flatOptions })
- const tree = await arb.loadActual()
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ async completion (opts) {
+ return completion(this.npm, opts)
+ }
- const nodes = new Set()
- for (const arg of args) {
- for (const node of getNodes(tree, arg))
- nodes.add(node)
+ exec (args, cb) {
+ this.explain(args).then(() => cb()).catch(cb)
}
- if (nodes.size === 0)
- throw `No dependencies found matching ${args.join(', ')}`
- const expls = []
- for (const node of nodes) {
- const { extraneous, dev, optional, devOptional, peer, inBundle } = node
- const expl = node.explain()
- if (extraneous)
- expl.extraneous = true
- else {
- expl.dev = dev
- expl.optional = optional
- expl.devOptional = devOptional
- expl.peer = peer
- expl.bundled = inBundle
+ async explain (args) {
+ if (!args.length)
+ throw this.usage
+
+ const arb = new Arborist({ path: this.npm.prefix, ...this.npm.flatOptions })
+ const tree = await arb.loadActual()
+
+ const nodes = new Set()
+ for (const arg of args) {
+ for (const node of this.getNodes(tree, arg))
+ nodes.add(node)
}
- expls.push(expl)
- }
+ if (nodes.size === 0)
+ throw `No dependencies found matching ${args.join(', ')}`
- if (npm.flatOptions.json)
- output(JSON.stringify(expls, null, 2))
- else {
- output(expls.map(expl => {
- return explainNode(expl, Infinity, npm.color)
- }).join('\n\n'))
+ const expls = []
+ for (const node of nodes) {
+ const { extraneous, dev, optional, devOptional, peer, inBundle } = node
+ const expl = node.explain()
+ if (extraneous)
+ expl.extraneous = true
+ else {
+ expl.dev = dev
+ expl.optional = optional
+ expl.devOptional = devOptional
+ expl.peer = peer
+ expl.bundled = inBundle
+ }
+ expls.push(expl)
+ }
+
+ if (this.npm.flatOptions.json)
+ output(JSON.stringify(expls, null, 2))
+ else {
+ output(expls.map(expl => {
+ return explainNode(expl, Infinity, this.npm.color)
+ }).join('\n\n'))
+ }
}
-}
-const getNodes = (tree, arg) => {
- // if it's just a name, return packages by that name
- const { validForOldPackages: valid } = validName(arg)
- if (valid)
- return tree.inventory.query('name', arg)
+ getNodes (tree, arg) {
+ // if it's just a name, return packages by that name
+ const { validForOldPackages: valid } = validName(arg)
+ if (valid)
+ return tree.inventory.query('name', arg)
- // if it's a location, get that node
- const maybeLoc = arg.replace(/\\/g, '/').replace(/\/+$/, '')
- const nodeByLoc = tree.inventory.get(maybeLoc)
- if (nodeByLoc)
- return [nodeByLoc]
+ // if it's a location, get that node
+ const maybeLoc = arg.replace(/\\/g, '/').replace(/\/+$/, '')
+ const nodeByLoc = tree.inventory.get(maybeLoc)
+ if (nodeByLoc)
+ return [nodeByLoc]
- // maybe a path to a node_modules folder
- const maybePath = relative(npm.prefix, resolve(maybeLoc))
- .replace(/\\/g, '/').replace(/\/+$/, '')
- const nodeByPath = tree.inventory.get(maybePath)
- if (nodeByPath)
- return [nodeByPath]
+ // maybe a path to a node_modules folder
+ const maybePath = relative(this.npm.prefix, resolve(maybeLoc))
+ .replace(/\\/g, '/').replace(/\/+$/, '')
+ const nodeByPath = tree.inventory.get(maybePath)
+ if (nodeByPath)
+ return [nodeByPath]
- // otherwise, try to select all matching nodes
- try {
- return getNodesByVersion(tree, arg)
- } catch (er) {
- return []
+ // otherwise, try to select all matching nodes
+ try {
+ return this.getNodesByVersion(tree, arg)
+ } catch (er) {
+ return []
+ }
}
-}
-const getNodesByVersion = (tree, arg) => {
- const spec = npa(arg, npm.prefix)
- if (spec.type !== 'version' && spec.type !== 'range')
- return []
+ getNodesByVersion (tree, arg) {
+ const spec = npa(arg, this.npm.prefix)
+ if (spec.type !== 'version' && spec.type !== 'range')
+ return []
- return tree.inventory.filter(node => {
- return node.package.name === spec.name &&
- semver.satisfies(node.package.version, spec.rawSpec)
- })
+ return tree.inventory.filter(node => {
+ return node.package.name === spec.name &&
+ semver.satisfies(node.package.version, spec.rawSpec)
+ })
+ }
}
-
-module.exports = Object.assign(cmd, { usage, completion })
+module.exports = Explain
diff --git a/deps/npm/lib/explore.js b/deps/npm/lib/explore.js
index e9b09707ec63bc..fdfe6e1bcf7c8f 100644
--- a/deps/npm/lib/explore.js
+++ b/deps/npm/lib/explore.js
@@ -1,69 +1,82 @@
// npm explore [@]
// open a subshell to the package folder.
-const usageUtil = require('./utils/usage.js')
-const completion = require('./utils/completion/installed-shallow.js')
-const usage = usageUtil('explore', 'npm explore [ -- ]')
const rpj = require('read-package-json-fast')
-
-const cmd = (args, cb) => explore(args).then(() => cb()).catch(cb)
-
-const output = require('./utils/output.js')
-const npm = require('./npm.js')
-
const runScript = require('@npmcli/run-script')
const { join, resolve, relative } = require('path')
+const completion = require('./utils/completion/installed-shallow.js')
+const output = require('./utils/output.js')
+const usageUtil = require('./utils/usage.js')
-const explore = async args => {
- if (args.length < 1 || !args[0])
- throw usage
+class Explore {
+ constructor (npm) {
+ this.npm = npm
+ }
- const pkgname = args.shift()
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('explore', 'npm explore [ -- ]')
+ }
- // detect and prevent any .. shenanigans
- const path = join(npm.dir, join('/', pkgname))
- if (relative(path, npm.dir) === '')
- throw usage
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ async completion (opts) {
+ return completion(this.npm, opts)
+ }
- // run as if running a script named '_explore', which we set to either
- // the set of arguments, or the shell config, and let @npmcli/run-script
- // handle all the escaping and PATH setup stuff.
+ exec (args, cb) {
+ this.explore(args).then(() => cb()).catch(cb)
+ }
- const pkg = await rpj(resolve(path, 'package.json')).catch(er => {
- npm.log.error('explore', `It doesn't look like ${pkgname} is installed.`)
- throw er
- })
+ async explore (args) {
+ if (args.length < 1 || !args[0])
+ throw this.usage
- const { shell } = npm.flatOptions
- pkg.scripts = {
- ...(pkg.scripts || {}),
- _explore: args.join(' ').trim() || shell,
- }
+ const pkgname = args.shift()
+
+ // detect and prevent any .. shenanigans
+ const path = join(this.npm.dir, join('/', pkgname))
+ if (relative(path, this.npm.dir) === '')
+ throw this.usage
- if (!args.length)
- output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`)
- npm.log.disableProgress()
- try {
- return await runScript({
- ...npm.flatOptions,
- pkg,
- banner: false,
- path,
- stdioString: true,
- event: '_explore',
- stdio: 'inherit',
- }).catch(er => {
- process.exitCode = typeof er.code === 'number' && er.code !== 0 ? er.code
- : 1
- // if it's not an exit error, or non-interactive, throw it
- const isProcExit = er.message === 'command failed' &&
- (typeof er.code === 'number' || /^SIG/.test(er.signal || ''))
- if (args.length || !isProcExit)
- throw er
+ // run as if running a script named '_explore', which we set to either
+ // the set of arguments, or the shell config, and let @npmcli/run-script
+ // handle all the escaping and PATH setup stuff.
+
+ const pkg = await rpj(resolve(path, 'package.json')).catch(er => {
+ this.npm.log.error('explore', `It doesn't look like ${pkgname} is installed.`)
+ throw er
})
- } finally {
- npm.log.enableProgress()
+
+ const { shell } = this.npm.flatOptions
+ pkg.scripts = {
+ ...(pkg.scripts || {}),
+ _explore: args.join(' ').trim() || shell,
+ }
+
+ if (!args.length)
+ output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`)
+ this.npm.log.disableProgress()
+ try {
+ return await runScript({
+ ...this.npm.flatOptions,
+ pkg,
+ banner: false,
+ path,
+ stdioString: true,
+ event: '_explore',
+ stdio: 'inherit',
+ }).catch(er => {
+ process.exitCode = typeof er.code === 'number' && er.code !== 0 ? er.code
+ : 1
+ // if it's not an exit error, or non-interactive, throw it
+ const isProcExit = er.message === 'command failed' &&
+ (typeof er.code === 'number' || /^SIG/.test(er.signal || ''))
+ if (args.length || !isProcExit)
+ throw er
+ })
+ } finally {
+ this.npm.log.enableProgress()
+ }
}
}
-
-module.exports = Object.assign(cmd, { completion, usage })
+module.exports = Explore
diff --git a/deps/npm/lib/find-dupes.js b/deps/npm/lib/find-dupes.js
index 19e7ea6a7c8cc5..5061be9cc381a8 100644
--- a/deps/npm/lib/find-dupes.js
+++ b/deps/npm/lib/find-dupes.js
@@ -1,8 +1,19 @@
// dedupe duplicated packages, or find them in the tree
-const dedupe = require('./dedupe.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil('find-dupes', 'npm find-dupes')
-const cmd = (args, cb) => dedupe({ dryRun: true }, cb)
+class FindDupes {
+ constructor (npm) {
+ this.npm = npm
+ }
-module.exports = Object.assign(cmd, { usage })
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil('find-dupes', 'npm find-dupes')
+ }
+
+ exec (args, cb) {
+ this.npm.config.set('dry-run', true)
+ this.npm.commands.dedupe([], cb)
+ }
+}
+module.exports = FindDupes
diff --git a/deps/npm/lib/fund.js b/deps/npm/lib/fund.js
index 41dd48c4653429..1e9724266401f3 100644
--- a/deps/npm/lib/fund.js
+++ b/deps/npm/lib/fund.js
@@ -11,200 +11,210 @@ const {
isValidFunding,
} = require('libnpmfund')
-const npm = require('./npm.js')
const completion = require('./utils/completion/installed-deep.js')
const output = require('./utils/output.js')
const openUrl = require('./utils/open-url.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil(
- 'fund',
- 'npm fund',
- 'npm fund [--json] [--browser] [--unicode] [[<@scope>/] [--which=]'
-)
-
-const cmd = (args, cb) => fund(args).then(() => cb()).catch(cb)
-
-function printJSON (fundingInfo) {
- return JSON.stringify(fundingInfo, null, 2)
-}
-
const getPrintableName = ({ name, version }) => {
const printableVersion = version ? `@${version}` : ''
return `${name}${printableVersion}`
}
-function printHuman (fundingInfo, { color, unicode }) {
- const seenUrls = new Map()
-
- const tree = obj =>
- archy(obj, '', { unicode })
-
- const result = depth({
- tree: fundingInfo,
-
- // composes human readable package name
- // and creates a new archy item for readable output
- visit: ({ name, version, funding }) => {
- const [fundingSource] = []
- .concat(normalizeFunding(funding))
- .filter(isValidFunding)
- const { url } = fundingSource || {}
- const pkgRef = getPrintableName({ name, version })
- let item = {
- label: pkgRef,
- }
-
- if (url) {
- item.label = tree({
- label: color ? chalk.bgBlack.white(url) : url,
- nodes: [pkgRef],
- }).trim()
-
- // stacks all packages together under the same item
- if (seenUrls.has(url)) {
- item = seenUrls.get(url)
- item.label += `, ${pkgRef}`
- return null
- } else
- seenUrls.set(url, item)
- }
-
- return item
- },
-
- // puts child nodes back into returned archy
- // output while also filtering out missing items
- leave: (item, children) => {
- if (item)
- item.nodes = children.filter(Boolean)
-
- return item
- },
-
- // turns tree-like object return by libnpmfund
- // into children to be properly read by treeverse
- getChildren: (node) =>
- Object.keys(node.dependencies || {})
- .map(key => ({
- name: key,
- ...node.dependencies[key],
- })),
- })
-
- const res = tree(result)
- return color ? chalk.reset(res) : res
-}
+class Fund {
+ constructor (npm) {
+ this.npm = npm
+ }
-async function openFundingUrl ({ path, tree, spec, fundingSourceNumber }) {
- const arg = npa(spec, path)
- const retrievePackageMetadata = () => {
- if (arg.type === 'directory') {
- if (tree.path === arg.fetchSpec) {
- // matches cwd, e.g: npm fund .
- return tree.package
- } else {
- // matches any file path within current arborist inventory
- for (const item of tree.inventory.values()) {
- if (item.path === arg.fetchSpec)
- return item.package
- }
- }
- } else {
- // tries to retrieve a package from arborist inventory
- // by matching resulted package name from the provided spec
- const [item] = [...tree.inventory.query('name', arg.name)]
- .filter(i => semver.valid(i.package.version))
- .sort((a, b) => semver.rcompare(a.package.version, b.package.version))
-
- if (item)
- return item.package
- }
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil(
+ 'fund',
+ 'npm fund',
+ 'npm fund [--json] [--browser] [--unicode] [[<@scope>/] [--which=]'
+ )
}
- const { funding } = retrievePackageMetadata() ||
- await pacote.manifest(arg, npm.flatOptions).catch(() => ({}))
-
- const validSources = []
- .concat(normalizeFunding(funding))
- .filter(isValidFunding)
-
- const matchesValidSource =
- validSources.length === 1 ||
- (fundingSourceNumber > 0 && fundingSourceNumber <= validSources.length)
-
- if (matchesValidSource) {
- const index = fundingSourceNumber ? fundingSourceNumber - 1 : 0
- const { type, url } = validSources[index]
- const typePrefix = type ? `${type} funding` : 'Funding'
- const msg = `${typePrefix} available at the following URL`
- return new Promise((resolve, reject) =>
- openUrl(url, msg, err => err
- ? reject(err)
- : resolve()
- ))
- } else if (validSources.length && !(fundingSourceNumber >= 1)) {
- validSources.forEach(({ type, url }, i) => {
- const typePrefix = type ? `${type} funding` : 'Funding'
- const msg = `${typePrefix} available at the following URL`
- output(`${i + 1}: ${msg}: ${url}`)
- })
- output('Run `npm fund [<@scope>/] --which=1`, for example, to open the first funding URL listed in that package')
- } else {
- const noFundingError = new Error(`No valid funding method available for: ${spec}`)
- noFundingError.code = 'ENOFUND'
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ async completion (opts) {
+ return completion(this.npm, opts)
+ }
- throw noFundingError
+ exec (args, cb) {
+ this.fund(args).then(() => cb()).catch(cb)
}
-}
-const fund = async (args) => {
- const opts = npm.flatOptions
- const spec = args[0]
- const numberArg = opts.which
+ async fund (args) {
+ const opts = this.npm.flatOptions
+ const spec = args[0]
+ const numberArg = opts.which
- const fundingSourceNumber = numberArg && parseInt(numberArg, 10)
+ const fundingSourceNumber = numberArg && parseInt(numberArg, 10)
- const badFundingSourceNumber =
- numberArg !== undefined &&
+ const badFundingSourceNumber =
+ numberArg !== undefined &&
(String(fundingSourceNumber) !== numberArg || fundingSourceNumber < 1)
- if (badFundingSourceNumber) {
- const err = new Error('`npm fund [<@scope>/] [--which=fundingSourceNumber]` must be given a positive integer')
- err.code = 'EFUNDNUMBER'
- throw err
+ if (badFundingSourceNumber) {
+ const err = new Error('`npm fund [<@scope>/] [--which=fundingSourceNumber]` must be given a positive integer')
+ err.code = 'EFUNDNUMBER'
+ throw err
+ }
+
+ if (opts.global) {
+ const err = new Error('`npm fund` does not support global packages')
+ err.code = 'EFUNDGLOBAL'
+ throw err
+ }
+
+ const where = this.npm.prefix
+ const arb = new Arborist({ ...opts, path: where })
+ const tree = await arb.loadActual()
+
+ if (spec) {
+ await this.openFundingUrl({
+ path: where,
+ tree,
+ spec,
+ fundingSourceNumber,
+ })
+ return
+ }
+
+ const print = opts.json
+ ? this.printJSON
+ : this.printHuman
+
+ output(
+ print(
+ getFundingInfo(tree),
+ opts
+ )
+ )
}
- if (opts.global) {
- const err = new Error('`npm fund` does not support global packages')
- err.code = 'EFUNDGLOBAL'
- throw err
+ printJSON (fundingInfo) {
+ return JSON.stringify(fundingInfo, null, 2)
}
- const where = npm.prefix
- const arb = new Arborist({ ...opts, path: where })
- const tree = await arb.loadActual()
+ printHuman (fundingInfo, { color, unicode }) {
+ const seenUrls = new Map()
+
+ const tree = obj =>
+ archy(obj, '', { unicode })
+
+ const result = depth({
+ tree: fundingInfo,
+
+ // composes human readable package name
+ // and creates a new archy item for readable output
+ visit: ({ name, version, funding }) => {
+ const [fundingSource] = []
+ .concat(normalizeFunding(funding))
+ .filter(isValidFunding)
+ const { url } = fundingSource || {}
+ const pkgRef = getPrintableName({ name, version })
+ let item = {
+ label: pkgRef,
+ }
+
+ if (url) {
+ item.label = tree({
+ label: color ? chalk.bgBlack.white(url) : url,
+ nodes: [pkgRef],
+ }).trim()
+
+ // stacks all packages together under the same item
+ if (seenUrls.has(url)) {
+ item = seenUrls.get(url)
+ item.label += `, ${pkgRef}`
+ return null
+ } else
+ seenUrls.set(url, item)
+ }
- if (spec) {
- await openFundingUrl({
- path: where,
- tree,
- spec,
- fundingSourceNumber,
+ return item
+ },
+
+ // puts child nodes back into returned archy
+ // output while also filtering out missing items
+ leave: (item, children) => {
+ if (item)
+ item.nodes = children.filter(Boolean)
+
+ return item
+ },
+
+ // turns tree-like object return by libnpmfund
+ // into children to be properly read by treeverse
+ getChildren: (node) =>
+ Object.keys(node.dependencies || {})
+ .map(key => ({
+ name: key,
+ ...node.dependencies[key],
+ })),
})
- return
+
+ const res = tree(result)
+ return color ? chalk.reset(res) : res
}
- const print = opts.json
- ? printJSON
- : printHuman
+ async openFundingUrl ({ path, tree, spec, fundingSourceNumber }) {
+ const arg = npa(spec, path)
+ const retrievePackageMetadata = () => {
+ if (arg.type === 'directory') {
+ if (tree.path === arg.fetchSpec) {
+ // matches cwd, e.g: npm fund .
+ return tree.package
+ } else {
+ // matches any file path within current arborist inventory
+ for (const item of tree.inventory.values()) {
+ if (item.path === arg.fetchSpec)
+ return item.package
+ }
+ }
+ } else {
+ // tries to retrieve a package from arborist inventory
+ // by matching resulted package name from the provided spec
+ const [item] = [...tree.inventory.query('name', arg.name)]
+ .filter(i => semver.valid(i.package.version))
+ .sort((a, b) => semver.rcompare(a.package.version, b.package.version))
+
+ if (item)
+ return item.package
+ }
+ }
+
+ const { funding } = retrievePackageMetadata() ||
+ await pacote.manifest(arg, this.npm.flatOptions).catch(() => ({}))
- output(
- print(
- getFundingInfo(tree),
- opts
- )
- )
-}
+ const validSources = []
+ .concat(normalizeFunding(funding))
+ .filter(isValidFunding)
+
+ const matchesValidSource =
+ validSources.length === 1 ||
+ (fundingSourceNumber > 0 && fundingSourceNumber <= validSources.length)
+
+ if (matchesValidSource) {
+ const index = fundingSourceNumber ? fundingSourceNumber - 1 : 0
+ const { type, url } = validSources[index]
+ const typePrefix = type ? `${type} funding` : 'Funding'
+ const msg = `${typePrefix} available at the following URL`
+ return openUrl(this.npm, url, msg)
+ } else if (validSources.length && !(fundingSourceNumber >= 1)) {
+ validSources.forEach(({ type, url }, i) => {
+ const typePrefix = type ? `${type} funding` : 'Funding'
+ const msg = `${typePrefix} available at the following URL`
+ output(`${i + 1}: ${msg}: ${url}`)
+ })
+ output('Run `npm fund [<@scope>/] --which=1`, for example, to open the first funding URL listed in that package')
+ } else {
+ const noFundingError = new Error(`No valid funding method available for: ${spec}`)
+ noFundingError.code = 'ENOFUND'
-module.exports = Object.assign(cmd, { usage, completion })
+ throw noFundingError
+ }
+ }
+}
+module.exports = Fund
diff --git a/deps/npm/lib/get.js b/deps/npm/lib/get.js
index 8a416027d7fbaa..a5b2f5514473d8 100644
--- a/deps/npm/lib/get.js
+++ b/deps/npm/lib/get.js
@@ -1,15 +1,25 @@
-const npm = require('./npm.js')
-const config = require('./config.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil(
- 'get',
- 'npm get [ ...] (See `npm config`)'
-)
+class Get {
+ constructor (npm) {
+ this.npm = npm
+ }
-const completion = config.completion
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil(
+ 'get',
+ 'npm get [ ...] (See `npm config`)'
+ )
+ }
-const cmd = (args, cb) =>
- npm.commands.config(['get'].concat(args), cb)
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ async completion (opts) {
+ return this.npm.commands.config.completion(opts)
+ }
-module.exports = Object.assign(cmd, { usage, completion })
+ exec (args, cb) {
+ this.npm.commands.config(['get'].concat(args), cb)
+ }
+}
+module.exports = Get
diff --git a/deps/npm/lib/help-search.js b/deps/npm/lib/help-search.js
index b1847350480439..ed2bc23b9109df 100644
--- a/deps/npm/lib/help-search.js
+++ b/deps/npm/lib/help-search.js
@@ -1,203 +1,211 @@
const fs = require('fs')
const path = require('path')
-const npm = require('./npm.js')
const color = require('ansicolors')
const output = require('./utils/output.js')
const usageUtil = require('./utils/usage.js')
+const npmUsage = require('./utils/npm-usage.js')
const { promisify } = require('util')
const glob = promisify(require('glob'))
const readFile = promisify(fs.readFile)
const didYouMean = require('./utils/did-you-mean.js')
const { cmdList } = require('./utils/cmd-list.js')
-const usage = usageUtil('help-search', 'npm help-search ')
-
-const npmUsage = require('./utils/npm-usage.js')
+class HelpSearch {
+ constructor (npm) {
+ this.npm = npm
+ }
-const cmd = (args, cb) => helpSearch(args).then(() => cb()).catch(cb)
+ get usage () {
+ return usageUtil('help-search', 'npm help-search ')
+ }
-const helpSearch = async args => {
- if (!args.length)
- throw usage
+ exec (args, cb) {
+ this.helpSearch(args).then(() => cb()).catch(cb)
+ }
- const docPath = path.resolve(__dirname, '..', 'docs/content')
+ async helpSearch (args) {
+ if (!args.length)
+ throw this.usage
+
+ const docPath = path.resolve(__dirname, '..', 'docs/content')
+
+ const files = await glob(`${docPath}/*/*.md`)
+ const data = await this.readFiles(files)
+ const results = await this.searchFiles(args, data, files)
+ // if only one result, then just show that help section.
+ if (results.length === 1) {
+ return this.npm.commands.help([path.basename(results[0].file, '.md')], er => {
+ if (er)
+ throw er
+ })
+ }
- const files = await glob(`${docPath}/*/*.md`)
- const data = await readFiles(files)
- const results = await searchFiles(args, data, files)
- // if only one result, then just show that help section.
- if (results.length === 1) {
- return npm.commands.help([path.basename(results[0].file, '.md')], er => {
- if (er)
- throw er
- })
+ const formatted = this.formatResults(args, results)
+ if (!formatted.trim())
+ npmUsage(this.npm, false)
+ else {
+ output(formatted)
+ output(didYouMean(args[0], cmdList))
+ }
}
- const formatted = formatResults(args, results)
- if (!formatted.trim())
- npmUsage(false)
- else {
- output(formatted)
- output(didYouMean(args[0], cmdList))
+ async readFiles (files) {
+ const res = {}
+ await Promise.all(files.map(async file => {
+ res[file] = (await readFile(file, 'utf8'))
+ .replace(/^---\n(.*\n)*?---\n/, '').trim()
+ }))
+ return 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
-}
+ async searchFiles (args, data, files) {
+ const results = []
+ for (const [file, content] of Object.entries(data)) {
+ const lowerCase = content.toLowerCase()
+ // skip if no matches at all
+ if (!args.some(a => lowerCase.includes(a.toLowerCase())))
+ continue
+
+ 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.
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i]
+ const nextLine = lines[i + 1]
+ let match = false
+ if (nextLine) {
+ match = args.some(a =>
+ nextLine.toLowerCase().includes(a.toLowerCase()))
+ if (match) {
+ // skip over the next line, and the line after it.
+ i += 2
+ continue
+ }
+ }
+
+ match = args.some(a => line.toLowerCase().includes(a.toLowerCase()))
-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
- if (!args.some(a => lowerCase.includes(a.toLowerCase())))
- continue
-
- 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.
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i]
- const nextLine = lines[i + 1]
- let match = false
- if (nextLine) {
- match = args.some(a => nextLine.toLowerCase().includes(a.toLowerCase()))
if (match) {
- // skip over the next line, and the line after it.
- i += 2
+ // skip over the next line
+ i++
continue
}
- }
- match = args.some(a => line.toLowerCase().includes(a.toLowerCase()))
-
- if (match) {
- // skip over the next line
- i++
- continue
+ lines[i] = null
}
- lines[i] = null
- }
-
- // now squish any string of nulls into a single null
- const pruned = lines.reduce((l, r) => {
- if (!(r === null && l[l.length - 1] === null))
- l.push(r)
+ // now squish any string of nulls into a single null
+ const pruned = lines.reduce((l, r) => {
+ if (!(r === null && l[l.length - 1] === null))
+ l.push(r)
- return l
- }, [])
+ return l
+ }, [])
- if (pruned[pruned.length - 1] === null)
- pruned.pop()
+ if (pruned[pruned.length - 1] === null)
+ pruned.pop()
- if (pruned[0] === null)
- pruned.shift()
+ if (pruned[0] === null)
+ pruned.shift()
- // 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
+ // 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
+ if (hit > 0) {
+ found[arg] = (found[arg] || 0) + hit
+ totalHits += hit
+ }
}
}
+
+ const cmd = 'npm help ' +
+ path.basename(file, '.md').replace(/^npm-/, '')
+ results.push({
+ file,
+ cmd,
+ lines: pruned,
+ found: Object.keys(found),
+ hits: found,
+ totalHits,
+ })
}
- const cmd = 'npm help ' +
- path.basename(file, '.md').replace(/^npm-/, '')
- results.push({
- file,
- cmd,
- lines: pruned,
- found: Object.keys(found),
- hits: found,
- totalHits,
- })
+ // sort results by number of results found, then by number of hits
+ // then by number of matching lines
+
+ // coverage is ignored here because the contents of results are
+ // nondeterministic due to either glob or readFiles or Object.entries
+ return results.sort(/* istanbul ignore next */ (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)
}
- // sort results by number of results found, then by number of hits
- // then by number of matching lines
-
- // coverage is ignored here because the contents of results are
- // nondeterministic due to either glob or readFiles or Object.entries
- return results.sort(/* istanbul ignore next */ (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)
-}
-
-const formatResults = (args, results) => {
- const cols = Math.min(process.stdout.columns || Infinity, 80) + 1
+ formatResults (args, results) {
+ const cols = Math.min(process.stdout.columns || Infinity, 80) + 1
- 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(' ')
+ 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(' ')
- out.push(' '.repeat((Math.max(1, cols - out.join(' ').length - r.length - 1))))
- out.push(r)
+ out.push(' '.repeat((Math.max(1, cols - out.join(' ').length - r.length - 1))))
+ out.push(r)
- if (!npm.flatOptions.long)
- return out.join('')
+ if (!this.npm.flatOptions.long)
+ return out.join('')
- out.unshift('\n\n')
- out.push('\n')
- out.push('-'.repeat(cols - 1) + '\n')
- res.lines.forEach((line, i) => {
- if (line === null || i > 3)
- return
+ 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
+ if (!this.npm.color) {
+ out.push(line + '\n')
+ return
}
- }
- out.push(hilitLine.join('') + '\n')
- })
+ 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 out.join('')
- }).join('\n')
+ return out.join('')
+ }).join('\n')
- const finalOut = results.length && !npm.flatOptions.long
- ? 'Top hits for ' + (args.map(JSON.stringify).join(' ')) + '\n' +
+ const finalOut = results.length && !this.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
+ : out
- return finalOut.trim()
+ return finalOut.trim()
+ }
}
-
-module.exports = Object.assign(cmd, { usage })
+module.exports = HelpSearch
diff --git a/deps/npm/lib/help.js b/deps/npm/lib/help.js
index 6f215c76c1ead0..d7897326f31185 100644
--- a/deps/npm/lib/help.js
+++ b/deps/npm/lib/help.js
@@ -1,191 +1,224 @@
-
-module.exports = help
-
-help.completion = async (opts) => {
- if (opts.conf.argv.remain.length > 2)
- return []
- const g = path.resolve(__dirname, '../man/man[0-9]/*.[0-9]')
- const files = await new Promise((resolve, reject) => {
- glob(g, function (er, files) {
- if (er)
- return reject(er)
- resolve(files)
- })
- })
-
- return Object.keys(files.reduce(function (acc, file) {
- file = path.basename(file).replace(/\.[0-9]+$/, '')
- file = file.replace(/^npm-/, '')
- acc[file] = true
- return acc
- }, { help: true }))
-}
-
const npmUsage = require('./utils/npm-usage.js')
const { spawn } = require('child_process')
const path = require('path')
-const npm = require('./npm.js')
const log = require('npmlog')
-const openUrl = require('./utils/open-url')
+const openUrl = require('./utils/open-url.js')
const glob = require('glob')
const output = require('./utils/output.js')
const usage = require('./utils/usage.js')
-help.usage = usage('help', 'npm help []')
-
-function help (args, cb) {
- const argv = npm.config.parsedArgv.cooked
-
- let argnum = 0
- if (args.length === 2 && ~~args[0])
- argnum = ~~args.shift()
-
- // npm help foo bar baz: search topics
- if (args.length > 1 && args[0])
- return npm.commands['help-search'](args, cb)
+class Help {
+ constructor (npm) {
+ this.npm = npm
+ }
- const affordances = {
- 'find-dupes': 'dedupe',
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usage('help', 'npm help []')
}
- let section = affordances[args[0]] || npm.deref(args[0]) || args[0]
- // npm help : show basic usage
- if (!section) {
- npmUsage(argv[0] === 'help')
- return cb()
+ async completion (opts) {
+ if (opts.conf.argv.remain.length > 2)
+ return []
+ const g = path.resolve(__dirname, '../man/man[0-9]/*.[0-9]')
+ const files = await new Promise((resolve, reject) => {
+ glob(g, function (er, files) {
+ if (er)
+ return reject(er)
+ resolve(files)
+ })
+ })
+
+ return Object.keys(files.reduce(function (acc, file) {
+ file = path.basename(file).replace(/\.[0-9]+$/, '')
+ file = file.replace(/^npm-/, '')
+ acc[file] = true
+ return acc
+ }, { help: true }))
}
- // npm -h: show command usage
- if (npm.config.get('usage') &&
- npm.commands[section] &&
- npm.commands[section].usage) {
- npm.config.set('loglevel', 'silent')
- log.level = 'silent'
- output(npm.commands[section].usage)
- return cb()
+ exec (args, cb) {
+ this.help(args).then(() => cb()).catch(cb)
}
- let pref = [1, 5, 7]
- if (argnum)
- pref = [argnum].concat(pref.filter(n => n !== argnum))
-
- // npm help : Try to find the path
- const manroot = path.resolve(__dirname, '..', 'man')
-
- // legacy
- if (section === 'global')
- section = 'folders'
- else if (section.match(/.*json/))
- section = section.replace('.json', '-json')
-
- // find either /section.n or /npm-section.n
- // The glob is used in the glob. The regexp is used much
- // further down. Globs and regexps are different
- const compextglob = '.+(gz|bz2|lzma|[FYzZ]|xz)'
- const compextre = '\\.(gz|bz2|lzma|[FYzZ]|xz)$'
- const f = '+(npm-' + section + '|' + section + ').[0-9]?(' + compextglob + ')'
- return glob(manroot + '/*/' + f, (er, mans) => {
- if (er)
- return cb(er)
-
- if (!mans.length)
- return npm.commands['help-search'](args, cb)
-
- mans = mans.map((man) => {
- const ext = path.extname(man)
- if (man.match(new RegExp(compextre)))
- man = path.basename(man, ext)
-
- return man
+ async help (args) {
+ const argv = this.npm.config.parsedArgv.cooked
+
+ let argnum = 0
+ if (args.length === 2 && ~~args[0])
+ argnum = ~~args.shift()
+
+ // npm help foo bar baz: search topics
+ if (args.length > 1 && args[0])
+ return this.helpSearch(args)
+
+ const affordances = {
+ 'find-dupes': 'dedupe',
+ }
+ let section = affordances[args[0]] || this.npm.deref(args[0]) || args[0]
+
+ // npm help : show basic usage
+ if (!section) {
+ npmUsage(this.npm, argv[0] === 'help')
+ return
+ }
+
+ // npm -h: show command usage
+ if (this.npm.config.get('usage') &&
+ this.npm.commands[section] &&
+ this.npm.commands[section].usage) {
+ this.npm.config.set('loglevel', 'silent')
+ log.level = 'silent'
+ output(this.npm.commands[section].usage)
+ return
+ }
+
+ let pref = [1, 5, 7]
+ if (argnum)
+ pref = [argnum].concat(pref.filter(n => n !== argnum))
+
+ // npm help : Try to find the path
+ const manroot = path.resolve(__dirname, '..', 'man')
+
+ // legacy
+ if (section === 'global')
+ section = 'folders'
+ else if (section.match(/.*json/))
+ section = section.replace('.json', '-json')
+
+ // find either /section.n or /npm-section.n
+ // The glob is used in the glob. The regexp is used much
+ // further down. Globs and regexps are different
+ const compextglob = '.+(gz|bz2|lzma|[FYzZ]|xz)'
+ const compextre = '\\.(gz|bz2|lzma|[FYzZ]|xz)$'
+ const f = '+(npm-' + section + '|' + section + ').[0-9]?(' + compextglob + ')'
+ return new Promise((resolve, reject) => {
+ glob(manroot + '/*/' + f, async (er, mans) => {
+ if (er)
+ return reject(er)
+
+ if (!mans.length) {
+ this.helpSearch(args).then(resolve).catch(reject)
+ return
+ }
+
+ mans = mans.map((man) => {
+ const ext = path.extname(man)
+ if (man.match(new RegExp(compextre)))
+ man = path.basename(man, ext)
+
+ return man
+ })
+
+ this.viewMan(this.pickMan(mans, pref), (err) => {
+ if (err)
+ return reject(err)
+ return resolve()
+ })
+ })
})
+ }
- viewMan(pickMan(mans, pref), cb)
- })
-}
-
-function pickMan (mans, pref_) {
- const nre = /([0-9]+)$/
- const pref = {}
- pref_.forEach((sect, i) => pref[sect] = i)
- mans = mans.sort((a, b) => {
- const an = a.match(nre)[1]
- const bn = b.match(nre)[1]
- return an === bn ? (a > b ? -1 : 1)
- : pref[an] < pref[bn] ? -1
- : 1
- })
- return mans[0]
-}
+ helpSearch (args) {
+ return new Promise((resolve, reject) => {
+ this.npm.commands['help-search'](args, (err) => {
+ // This would only error if args was empty, which it never is
+ /* istanbul ignore next */
+ if (err)
+ return reject(err)
-function viewMan (man, cb) {
- const nre = /([0-9]+)$/
- const num = man.match(nre)[1]
- const section = path.basename(man, '.' + num)
-
- // at this point, we know that the specified man page exists
- const manpath = path.join(__dirname, '..', 'man')
- const env = {}
- Object.keys(process.env).forEach(function (i) {
- env[i] = process.env[i]
- })
- env.MANPATH = manpath
- const viewer = npm.config.get('viewer')
-
- const opts = {
- env,
- stdio: 'inherit',
+ resolve()
+ })
+ })
}
- let bin = 'man'
- const args = []
- switch (viewer) {
- case 'woman':
- bin = 'emacsclient'
- args.push('-e', `(woman-find-file '${man}')`)
- break
-
- case 'browser':
- bin = false
- try {
- const url = htmlMan(man)
- openUrl(url, 'help available at the following URL', cb)
- } catch (err) {
- return cb(err)
- }
- break
-
- default:
- args.push(num, section)
- break
+ pickMan (mans, pref_) {
+ const nre = /([0-9]+)$/
+ const pref = {}
+ pref_.forEach((sect, i) => pref[sect] = i)
+ mans = mans.sort((a, b) => {
+ const an = a.match(nre)[1]
+ const bn = b.match(nre)[1]
+ return an === bn ? (a > b ? -1 : 1)
+ : pref[an] < pref[bn] ? -1
+ : 1
+ })
+ return mans[0]
}
- if (bin) {
- const proc = spawn(bin, args, opts)
- proc.on('exit', (code) => {
- if (code)
- return cb(new Error(`help process exited with code: ${code}`))
+ viewMan (man, cb) {
+ const nre = /([0-9]+)$/
+ const num = man.match(nre)[1]
+ const section = path.basename(man, '.' + num)
- return cb()
+ // at this point, we know that the specified man page exists
+ const manpath = path.join(__dirname, '..', 'man')
+ const env = {}
+ Object.keys(process.env).forEach(function (i) {
+ env[i] = process.env[i]
})
+ env.MANPATH = manpath
+ const viewer = this.npm.config.get('viewer')
+
+ const opts = {
+ env,
+ stdio: 'inherit',
+ }
+
+ let bin = 'man'
+ const args = []
+ switch (viewer) {
+ case 'woman':
+ bin = 'emacsclient'
+ args.push('-e', `(woman-find-file '${man}')`)
+ break
+
+ case 'browser':
+ bin = false
+ try {
+ const url = this.htmlMan(man)
+ openUrl(this.npm, url, 'help available at the following URL').then(
+ () => cb()
+ ).catch(cb)
+ } catch (err) {
+ cb(err)
+ }
+ break
+
+ default:
+ args.push(num, section)
+ break
+ }
+
+ if (bin) {
+ const proc = spawn(bin, args, opts)
+ proc.on('exit', (code) => {
+ if (code)
+ return cb(new Error(`help process exited with code: ${code}`))
+
+ return cb()
+ })
+ }
}
-}
-function htmlMan (man) {
- let sect = +man.match(/([0-9]+)$/)[1]
- const f = path.basename(man).replace(/[.]([0-9]+)$/, '')
- switch (sect) {
- case 1:
- sect = 'commands'
- break
- case 5:
- sect = 'configuring-npm'
- break
- case 7:
- sect = 'using-npm'
- break
- default:
- throw new Error('invalid man section: ' + sect)
+ htmlMan (man) {
+ let sect = +man.match(/([0-9]+)$/)[1]
+ const f = path.basename(man).replace(/[.]([0-9]+)$/, '')
+ switch (sect) {
+ case 1:
+ sect = 'commands'
+ break
+ case 5:
+ sect = 'configuring-npm'
+ break
+ case 7:
+ sect = 'using-npm'
+ break
+ default:
+ throw new Error('invalid man section: ' + sect)
+ }
+ return 'file://' + path.resolve(__dirname, '..', 'docs', 'output', sect, f + '.html')
}
- return 'file://' + path.resolve(__dirname, '..', 'docs', 'output', sect, f + '.html')
}
+module.exports = Help
diff --git a/deps/npm/lib/hook.js b/deps/npm/lib/hook.js
index 7d69ccbf2aa4c1..312f542d7cff61 100644
--- a/deps/npm/lib/hook.js
+++ b/deps/npm/lib/hook.js
@@ -1,53 +1,62 @@
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 usageUtil = require('./utils/usage.js')
-const usage = usageUtil('hook', [
- 'npm hook add [--type=]',
- 'npm hook ls [pkg]',
- 'npm hook rm ',
- 'npm hook update ',
-].join('\n'))
-const cmd = (args, cb) => hook(args).then(() => cb()).catch(cb)
+class Hook {
+ constructor (npm) {
+ this.npm = npm
+ }
+
+ get usage () {
+ return usageUtil('hook', [
+ 'npm hook add [--type=]',
+ 'npm hook ls [pkg]',
+ 'npm hook rm ',
+ 'npm hook update ',
+ ].join('\n'))
+ }
+
+ exec (args, cb) {
+ this.hook(args).then(() => cb()).catch(cb)
+ }
-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
+ async hook (args) {
+ return otplease(this.npm.flatOptions, (opts) => {
+ switch (args[0]) {
+ case 'add':
+ return this.add(args[1], args[2], args[3], opts)
+ case 'ls':
+ return this.ls(args[1], opts)
+ case 'rm':
+ return this.rm(args[1], opts)
+ case 'update':
+ case 'up':
+ return this.update(args[1], args[2], args[3], opts)
+ default:
+ throw this.usage
+ }
+ })
}
-})
-const add = (pkg, uri, secret, opts) => {
- hookApi.add(pkg, uri, secret, opts).then(hook => {
+ async add (pkg, uri, secret, opts) {
+ const hook = await hookApi.add(pkg, uri, secret, opts)
if (opts.json)
output(JSON.stringify(hook, null, 2))
else if (opts.parseable) {
output(Object.keys(hook).join('\t'))
output(Object.keys(hook).map(k => hook[k]).join('\t'))
} else if (!opts.silent && opts.loglevel !== 'silent') {
- output(`+ ${hookName(hook)} ${
+ output(`+ ${this.hookName(hook)} ${
opts.unicode ? ' ➜ ' : ' -> '
} ${hook.endpoint}`)
}
- })
-}
+ }
-const ls = (pkg, opts) => {
- return hookApi.ls({ ...opts, package: pkg }).then(hooks => {
+ async ls (pkg, opts) {
+ const hooks = await hookApi.ls({ ...opts, package: pkg })
if (opts.json)
output(JSON.stringify(hooks, null, 2))
else if (opts.parseable) {
@@ -67,7 +76,7 @@ const ls = (pkg, opts) => {
hooks.forEach((hook) => {
table.push([
{ rowSpan: 2, content: hook.id },
- hookName(hook),
+ this.hookName(hook),
hook.endpoint,
])
if (hook.last_delivery) {
@@ -83,46 +92,43 @@ const ls = (pkg, opts) => {
})
output(table.toString())
}
- })
-}
+ }
-const rm = (id, opts) => {
- return hookApi.rm(id, opts).then(hook => {
+ async rm (id, opts) {
+ const hook = await hookApi.rm(id, opts)
if (opts.json)
output(JSON.stringify(hook, null, 2))
else if (opts.parseable) {
output(Object.keys(hook).join('\t'))
output(Object.keys(hook).map(k => hook[k]).join('\t'))
} else if (!opts.silent && opts.loglevel !== 'silent') {
- output(`- ${hookName(hook)} ${
+ output(`- ${this.hookName(hook)} ${
opts.unicode ? ' ✘ ' : ' X '
} ${hook.endpoint}`)
}
- })
-}
+ }
-const update = (id, uri, secret, opts) => {
- return hookApi.update(id, uri, secret, opts).then(hook => {
+ async update (id, uri, secret, opts) {
+ const hook = await hookApi.update(id, uri, secret, opts)
if (opts.json)
output(JSON.stringify(hook, null, 2))
else if (opts.parseable) {
output(Object.keys(hook).join('\t'))
output(Object.keys(hook).map(k => hook[k]).join('\t'))
} else if (!opts.silent && opts.loglevel !== 'silent') {
- output(`+ ${hookName(hook)} ${
+ output(`+ ${this.hookName(hook)} ${
opts.unicode ? ' ➜ ' : ' -> '
} ${hook.endpoint}`)
}
- })
-}
+ }
-const hookName = (hook) => {
- let target = hook.name
- if (hook.type === 'scope')
- target = '@' + target
- if (hook.type === 'owner')
- target = '~' + target
- return target
+ 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 })
+module.exports = Hook
diff --git a/deps/npm/lib/init.js b/deps/npm/lib/init.js
index a029779f89638f..af97a9614e368c 100644
--- a/deps/npm/lib/init.js
+++ b/deps/npm/lib/init.js
@@ -1,88 +1,97 @@
const initJson = require('init-package-json')
const npa = require('npm-package-arg')
-const npm = require('./npm.js')
const usageUtil = require('./utils/usage.js')
const output = require('./utils/output.js')
-const usage = usageUtil(
- 'init',
- '\nnpm init [--force|-f|--yes|-y|--scope]' +
- '\nnpm init <@scope> (same as `npx <@scope>/create`)' +
- '\nnpm init [<@scope>/] (same as `npx [<@scope>/]create-`)'
-)
-
-const cmd = (args, cb) => init(args).then(() => cb()).catch(cb)
+class Init {
+ constructor (npm) {
+ this.npm = npm
+ }
-const init = async args => {
- // the new npx style way
- if (args.length) {
- const initerName = args[0]
- let packageName = initerName
- if (/^@[^/]+$/.test(initerName))
- packageName = initerName + '/create'
- else {
- const req = npa(initerName)
- if (req.type === 'git' && req.hosted) {
- const { user, project } = req.hosted
- packageName = initerName
- .replace(user + '/' + project, user + '/create-' + project)
- } else if (req.registry) {
- packageName = req.name.replace(/^(@[^/]+\/)?/, '$1create-')
- if (req.rawSpec)
- packageName += '@' + req.rawSpec
- } else {
- throw Object.assign(new Error(
- 'Unrecognized initializer: ' + initerName +
- '\nFor more package binary executing power check out `npx`:' +
- '\nhttps://www.npmjs.com/package/npx'
- ), { code: 'EUNSUPPORTED' })
- }
- }
- npm.config.set('package', [])
- const newArgs = [packageName, ...args.slice(1)]
- return new Promise((res, rej) => {
- npm.commands.exec(newArgs, er => er ? rej(er) : res())
- })
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil(
+ 'init',
+ '\nnpm init [--force|-f|--yes|-y|--scope]' +
+ '\nnpm init <@scope> (same as `npx <@scope>/create`)' +
+ '\nnpm init [<@scope>/] (same as `npx [<@scope>/]create-`)'
+ )
}
- // the old way
- const dir = process.cwd()
- npm.log.pause()
- npm.log.disableProgress()
- const initFile = npm.config.get('init-module')
- if (!npm.flatOptions.yes && !npm.flatOptions.force) {
- output([
- 'This utility will walk you through creating a package.json file.',
- 'It only covers the most common items, and tries to guess sensible defaults.',
- '',
- 'See `npm help init` for definitive documentation on these fields',
- 'and exactly what they do.',
- '',
- 'Use `npm install ` afterwards to install a package and',
- 'save it as a dependency in the package.json file.',
- '',
- 'Press ^C at any time to quit.',
- ].join('\n'))
+ exec (args, cb) {
+ this.init(args).then(() => cb()).catch(cb)
}
- // XXX promisify init-package-json
- await new Promise((res, rej) => {
- initJson(dir, initFile, npm.config, (er, data) => {
- npm.log.resume()
- npm.log.enableProgress()
- npm.log.silly('package data', data)
- if (er && er.message === 'canceled') {
- npm.log.warn('init', 'canceled')
- return res()
- }
- if (er)
- rej(er)
+
+ async init (args) {
+ // the new npx style way
+ if (args.length) {
+ const initerName = args[0]
+ let packageName = initerName
+ if (/^@[^/]+$/.test(initerName))
+ packageName = initerName + '/create'
else {
- npm.log.info('init', 'written successfully')
- res(data)
+ const req = npa(initerName)
+ if (req.type === 'git' && req.hosted) {
+ const { user, project } = req.hosted
+ packageName = initerName
+ .replace(user + '/' + project, user + '/create-' + project)
+ } else if (req.registry) {
+ packageName = req.name.replace(/^(@[^/]+\/)?/, '$1create-')
+ if (req.rawSpec)
+ packageName += '@' + req.rawSpec
+ } else {
+ throw Object.assign(new Error(
+ 'Unrecognized initializer: ' + initerName +
+ '\nFor more package binary executing power check out `npx`:' +
+ '\nhttps://www.npmjs.com/package/npx'
+ ), { code: 'EUNSUPPORTED' })
+ }
}
+ this.npm.config.set('package', [])
+ const newArgs = [packageName, ...args.slice(1)]
+ return new Promise((res, rej) => {
+ this.npm.commands.exec(newArgs, er => er ? rej(er) : res())
+ })
+ }
+
+ // the old way
+ const dir = process.cwd()
+ this.npm.log.pause()
+ this.npm.log.disableProgress()
+ const initFile = this.npm.config.get('init-module')
+ if (!this.npm.flatOptions.yes && !this.npm.flatOptions.force) {
+ output([
+ 'This utility will walk you through creating a package.json file.',
+ 'It only covers the most common items, and tries to guess sensible defaults.',
+ '',
+ 'See `npm help init` for definitive documentation on these fields',
+ 'and exactly what they do.',
+ '',
+ 'Use `npm install ` afterwards to install a package and',
+ 'save it as a dependency in the package.json file.',
+ '',
+ 'Press ^C at any time to quit.',
+ ].join('\n'))
+ }
+ // XXX promisify init-package-json
+ await new Promise((res, rej) => {
+ initJson(dir, initFile, this.npm.config, (er, data) => {
+ this.npm.log.resume()
+ this.npm.log.enableProgress()
+ this.npm.log.silly('package data', data)
+ if (er && er.message === 'canceled') {
+ this.npm.log.warn('init', 'canceled')
+ return res()
+ }
+ if (er)
+ rej(er)
+ else {
+ this.npm.log.info('init', 'written successfully')
+ res(data)
+ }
+ })
})
- })
+ }
}
-
-module.exports = Object.assign(cmd, { usage })
+module.exports = Init
diff --git a/deps/npm/lib/install-ci-test.js b/deps/npm/lib/install-ci-test.js
index 52c41c413a64cc..d1740999d4b67d 100644
--- a/deps/npm/lib/install-ci-test.js
+++ b/deps/npm/lib/install-ci-test.js
@@ -1,19 +1,27 @@
// npm install-ci-test
// Runs `npm ci` and then runs `npm test`
-const ci = require('./ci.js')
-const test = require('./test.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil(
- 'install-ci-test',
- 'npm install-ci-test [args]' +
- '\nSame args as `npm ci`'
-)
+class InstallCITest {
+ constructor (npm) {
+ this.npm = npm
+ }
-const completion = ci.completion
+ get usage () {
+ return usageUtil(
+ 'install-ci-test',
+ 'npm install-ci-test [args]' +
+ '\nSame args as `npm ci`'
+ )
+ }
-const ciTest = (args, cb) =>
- ci(args, er => er ? cb(er) : test([], cb))
-
-module.exports = Object.assign(ciTest, { usage, completion })
+ exec (args, cb) {
+ this.npm.commands.ci(args, (er) => {
+ if (er)
+ return cb(er)
+ this.npm.commands.test([], cb)
+ })
+ }
+}
+module.exports = InstallCITest
diff --git a/deps/npm/lib/install-test.js b/deps/npm/lib/install-test.js
index 9593361e320b8e..487f8da00b6d3b 100644
--- a/deps/npm/lib/install-test.js
+++ b/deps/npm/lib/install-test.js
@@ -1,19 +1,31 @@
// npm install-test
// Runs `npm install` and then runs `npm test`
-const install = require('./install.js')
-const test = require('./test.js')
const usageUtil = require('./utils/usage.js')
-const usage = usageUtil(
- 'install-test',
- 'npm install-test [args]' +
- '\nSame args as `npm install`'
-)
+class InstallTest {
+ constructor (npm) {
+ this.npm = npm
+ }
-const completion = install.completion
+ get usage () {
+ return usageUtil(
+ 'install-test',
+ 'npm install-test [args]' +
+ '\nSame args as `npm install`'
+ )
+ }
-const installTest = (args, cb) =>
- install(args, er => er ? cb(er) : test([], cb))
+ async completion (opts) {
+ return this.npm.commands.install.completion(opts)
+ }
-module.exports = Object.assign(installTest, { usage, completion })
+ exec (args, cb) {
+ this.npm.commands.install(args, (er) => {
+ if (er)
+ return cb(er)
+ this.npm.commands.test([], cb)
+ })
+ }
+}
+module.exports = InstallTest
diff --git a/deps/npm/lib/install.js b/deps/npm/lib/install.js
index 5f0137db1ceacb..d7fd384d5bd6f0 100644
--- a/deps/npm/lib/install.js
+++ b/deps/npm/lib/install.js
@@ -3,7 +3,6 @@
const fs = require('fs')
const util = require('util')
const readdir = util.promisify(fs.readdir)
-const npm = require('./npm.js')
const usageUtil = require('./utils/usage.js')
const reifyFinish = require('./utils/reify-finish.js')
const log = require('npmlog')
@@ -11,133 +10,143 @@ const { resolve, join } = require('path')
const Arborist = require('@npmcli/arborist')
const runScript = require('@npmcli/run-script')
-const cmd = async (args, cb) => install(args).then(() => cb()).catch(cb)
-
-const install = async args => {
- // the /path/to/node_modules/..
- const globalTop = resolve(npm.globalDir, '..')
- const { ignoreScripts, global: isGlobalInstall } = npm.flatOptions
- const where = isGlobalInstall ? globalTop : npm.prefix
-
- // don't try to install the prefix into itself
- args = args.filter(a => resolve(a) !== npm.prefix)
-
- // `npm i -g` => "install this package globally"
- if (where === globalTop && !args.length)
- args = ['.']
-
- // TODO: Add warnings for other deprecated flags? or remove this one?
- if (npm.config.get('dev'))
- log.warn('install', 'Usage of the `--dev` option is deprecated. Use `--include=dev` instead.')
-
- const arb = new Arborist({
- ...npm.flatOptions,
- path: where,
- })
+class Install {
+ constructor (npm) {
+ this.npm = npm
+ }
- await arb.reify({
- ...npm.flatOptions,
- add: args,
- })
- if (!args.length && !isGlobalInstall && !ignoreScripts) {
- const { scriptShell } = npm.flatOptions
- const scripts = [
- 'preinstall',
+ /* istanbul ignore next - see test/lib/load-all-commands.js */
+ get usage () {
+ return usageUtil(
'install',
- 'postinstall',
- 'prepublish', // XXX should we remove this finally??
- 'preprepare',
- 'prepare',
- 'postprepare',
- ]
- for (const event of scripts) {
- await runScript({
- path: where,
- args: [],
- scriptShell,
- stdio: 'inherit',
- stdioString: true,
- banner: log.level !== 'silent',
- event,
- })
- }
+ 'npm install (with no args, in package dir)' +
+ '\nnpm install [<@scope>/]' +
+ '\nnpm install [<@scope>/]@' +
+ '\nnpm install [<@scope>/]@' +
+ '\nnpm install [<@scope>/]@' +
+ '\nnpm install @npm: