diff options
author | npm team <ops+robot@npmjs.com> | 2021-12-02 22:04:46 +0000 |
---|---|---|
committer | Rich Trott <rtrott@gmail.com> | 2021-12-05 08:31:02 -0800 |
commit | b323cec78f713bc113be7f6030d787804a9af5a0 (patch) | |
tree | 1605ce209f7625877e5e2de629299d63dbd3f0b3 /deps/npm | |
parent | b9f81ad1ae49f96dc585b0399320ce8c075e907f (diff) | |
download | node-new-b323cec78f713bc113be7f6030d787804a9af5a0.tar.gz |
deps: upgrade npm to 8.2.0
PR-URL: https://github.com/nodejs/node/pull/41065
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'deps/npm')
287 files changed, 5105 insertions, 5604 deletions
diff --git a/deps/npm/docs/content/using-npm/config.md b/deps/npm/docs/content/using-npm/config.md index a5017e61db..fe197e344d 100644 --- a/deps/npm/docs/content/using-npm/config.md +++ b/deps/npm/docs/content/using-npm/config.md @@ -1014,8 +1014,8 @@ Ideal if all users are on npm version 7 and higher. * Type: "silent", "error", "warn", "notice", "http", "timing", "info", "verbose", or "silly" -What level of logs to report. On failure, *all* logs are written to -`npm-debug.log` in the current working directory. +What level of logs to report. All logs are written to a debug log, with the +path to that file printed if the execution of a command fails. Any logs of a higher level than the setting are shown. The default is "notice". @@ -1387,7 +1387,7 @@ Save installed packages to a package.json file as `optionalDependencies`. * Default: false * Type: Boolean -Save installed packages. to a package.json file as `peerDependencies` +Save installed packages to a package.json file as `peerDependencies` <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> diff --git a/deps/npm/docs/content/using-npm/logging.md b/deps/npm/docs/content/using-npm/logging.md new file mode 100644 index 0000000000..b7c5e89977 --- /dev/null +++ b/deps/npm/docs/content/using-npm/logging.md @@ -0,0 +1,60 @@ +--- +title: Logging +section: 7 +description: Why, What & How we Log +--- + +### Description + +The `npm` CLI has various mechanisms for showing different levels of information back to end-users for certain commands, configurations & environments. + +### Setting Log Levels + +#### `loglevel` + +`loglevel` is a global argument/config that can be set to determine the type of information to be displayed. + +The default value of `loglevel` is `"notice"` but there are several levels/types of logs available, including: + +- `"silent"` +- `"error"` +- `"warn"` +- `"notice"` +- `"http"` +- `"timing"` +- `"info"` +- `"verbose"` +- `"silly"` + +All logs pertaining to a level proceeding the current setting will be shown. + +All logs are written to a debug log, with the path to that file printed if the execution of a command fails. + +##### Aliases + +The log levels listed above have various corresponding aliases, including: + +- `-d`: `--loglevel info` +- `--dd`: `--loglevel verbose` +- `--verbose`: `--loglevel verbose` +- `--ddd`: `--loglevel silly` +- `-q`: `--loglevel warn` +- `--quiet`: `--loglevel warn` +- `-s`: `--loglevel silent` +- `--silent`: `--loglevel silent` + +#### `foreground-scripts` + +The `npm` CLI began hiding the output of lifecycle scripts for `npm install` as of `v7`. Notably, this means you will not see logs/output from packages that may be using "install scripts" to display information back to you or from your own project's scripts defined in `package.json`. If you'd like to change this behavior & log this output you can set `foreground-scripts` to `true`. + +### Registry Response Headers + +#### `npm-notice` + +The `npm` CLI reads from & logs any `npm-notice` headers that are returned from the configured registry. This mechanism can be used by third-party registries to provide useful information when network-dependent requests occur. + +This header is not cached, and will not be logged if the request is served from the cache. + +### See also + +* [config](/using-npm/config) diff --git a/deps/npm/docs/content/using-npm/scripts.md b/deps/npm/docs/content/using-npm/scripts.md index fba37c2860..737cef3f43 100644 --- a/deps/npm/docs/content/using-npm/scripts.md +++ b/deps/npm/docs/content/using-npm/scripts.md @@ -259,7 +259,7 @@ package.json file, then your package scripts would have the in your code with `process.env.npm_package_name` and `process.env.npm_package_version`, and so on for other fields. -See [`package-json.md`](/configuring-npm/package-json) for more on package configs. +See [`package.json`](/configuring-npm/package-json) for more on package configs. #### current lifecycle event diff --git a/deps/npm/docs/content/using-npm/workspaces.md b/deps/npm/docs/content/using-npm/workspaces.md index fc29907225..c2ecce5ef4 100644 --- a/deps/npm/docs/content/using-npm/workspaces.md +++ b/deps/npm/docs/content/using-npm/workspaces.md @@ -8,7 +8,7 @@ description: Working with workspaces **Workspaces** is a generic term that refers to the set of features in the npm cli that provides support to managing multiple packages from your local -files system from within a singular top-level, root package. +file system from within a singular top-level, root package. This set of features makes up for a much more streamlined workflow handling linked packages from the local file system. Automating the linking process diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index e344845a34..9fd0fb148a 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -160,7 +160,7 @@ tree at all, use <a href="../commands/npm-explain.html"><code>npm explain</code> the results to only the paths to the packages named. Note that nested packages will <em>also</em> show the paths to the specified packages. For example, running <code>npm ls promzard</code> in npm's source tree will show:</p> -<pre lang="bash"><code>npm@8.1.4 /path/to/npm +<pre lang="bash"><code>npm@8.2.0 /path/to/npm └─┬ init-package-json@0.0.4 └── promzard@0.1.5 </code></pre> diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html index dd111c40be..8f1c16a442 100644 --- a/deps/npm/docs/output/commands/npm.html +++ b/deps/npm/docs/output/commands/npm.html @@ -149,7 +149,7 @@ npm command-line interface <pre lang="bash"><code>npm <command> [args] </code></pre> <h3 id="version">Version</h3> -<p>8.1.4</p> +<p>8.2.0</p> <h3 id="description">Description</h3> <p>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/config.html b/deps/npm/docs/output/using-npm/config.html index 639ef624bc..f3db847b48 100644 --- a/deps/npm/docs/output/using-npm/config.html +++ b/deps/npm/docs/output/using-npm/config.html @@ -962,8 +962,8 @@ Ideal if all users are on npm version 7 and higher.</p> <li>Type: "silent", "error", "warn", "notice", "http", "timing", "info", "verbose", or "silly"</li> </ul> -<p>What level of logs to report. On failure, <em>all</em> logs are written to -<code>npm-debug.log</code> in the current working directory.</p> +<p>What level of logs to report. All logs are written to a debug log, with the +path to that file printed if the execution of a command fails.</p> <p>Any logs of a higher level than the setting are shown. The default is "notice".</p> <p>See also the <code>foreground-scripts</code> config.</p> @@ -1259,7 +1259,7 @@ rather than using npm's default semver range operator.</p> <li>Default: false</li> <li>Type: Boolean</li> </ul> -<p>Save installed packages. to a package.json file as <code>peerDependencies</code></p> +<p>Save installed packages to a package.json file as <code>peerDependencies</code></p> <!-- raw HTML omitted --> <!-- raw HTML omitted --> <h4 id="save-prefix"><code>save-prefix</code></h4> diff --git a/deps/npm/docs/output/using-npm/logging.html b/deps/npm/docs/output/using-npm/logging.html new file mode 100644 index 0000000000..d4b9760967 --- /dev/null +++ b/deps/npm/docs/output/using-npm/logging.html @@ -0,0 +1,203 @@ +<!DOCTYPE html><html><head> +<meta charset="utf-8"> +<title>Logging</title> +<style> +body { + background-color: #ffffff; + color: #24292e; + + margin: 0; + + line-height: 1.5; + + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +} +#rainbar { + height: 10px; + background-image: linear-gradient(139deg, #fb8817, #ff4b01, #c12127, #e02aff); +} + +a { + text-decoration: none; + color: #0366d6; +} +a:hover { + text-decoration: underline; +} + +pre { + margin: 1em 0px; + padding: 1em; + border: solid 1px #e1e4e8; + border-radius: 6px; + + display: block; + overflow: auto; + + white-space: pre; + + background-color: #f6f8fa; + color: #393a34; +} +code { + font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 85%; + padding: 0.2em 0.4em; + background-color: #f6f8fa; + color: #393a34; +} +pre > code { + padding: 0; + background-color: inherit; + color: inherit; +} +h1, h2, h3 { + font-weight: 600; +} + +#logobar { + background-color: #333333; + margin: 0 auto; + padding: 1em 4em; +} +#logobar .logo { + float: left; +} +#logobar .title { + font-weight: 600; + color: #dddddd; + float: left; + margin: 5px 0 0 1em; +} +#logobar:after { + content: ""; + display: block; + clear: both; +} + +#content { + margin: 0 auto; + padding: 0 4em; +} + +#table_of_contents > h2 { + font-size: 1.17em; +} +#table_of_contents ul:first-child { + border: solid 1px #e1e4e8; + border-radius: 6px; + padding: 1em; + background-color: #f6f8fa; + color: #393a34; +} +#table_of_contents ul { + list-style-type: none; + padding-left: 1.5em; +} +#table_of_contents li { + font-size: 0.9em; +} +#table_of_contents li a { + color: #000000; +} + +header.title { + border-bottom: solid 1px #e1e4e8; +} +header.title > h1 { + margin-bottom: 0.25em; +} +header.title > .description { + display: block; + margin-bottom: 0.5em; + line-height: 1; +} + +footer#edit { + border-top: solid 1px #e1e4e8; + margin: 3em 0 4em 0; + padding-top: 2em; +} +</style> +</head> +<body> +<div id="banner"> +<div id="rainbar"></div> +<div id="logobar"> +<svg class="logo" role="img" height="32" width="32" viewBox="0 0 700 700"> +<polygon fill="#cb0000" points="0,700 700,700 700,0 0,0"></polygon> +<polygon fill="#ffffff" points="150,550 350,550 350,250 450,250 450,550 550,550 550,150 150,150"></polygon> +</svg> +<div class="title"> +npm command-line interface +</div> +</div> +</div> + +<section id="content"> +<header class="title"> +<h1 id="logging">Logging</h1> +<span class="description">Why, What & How we Log</span> +</header> + +<section id="table_of_contents"> +<h2 id="table-of-contents">Table of contents</h2> +<div id="_table_of_contents"><ul><li><a href="#description">Description</a></li><li><a href="#setting-log-levels">Setting Log Levels</a></li><ul><li><a href="#loglevel"><code>loglevel</code></a></li><ul><li><a href="#aliases">Aliases</a></li></ul><li><a href="#foreground-scripts"><code>foreground-scripts</code></a></li></ul><li><a href="#registry-response-headers">Registry Response Headers</a></li><ul><li><a href="#npm-notice"><code>npm-notice</code></a></li></ul><li><a href="#see-also">See also</a></li></ul></div> +</section> + +<div id="_content"><h3 id="description">Description</h3> +<p>The <code>npm</code> CLI has various mechanisms for showing different levels of information back to end-users for certain commands, configurations & environments.</p> +<h3 id="setting-log-levels">Setting Log Levels</h3> +<h4 id="loglevel"><code>loglevel</code></h4> +<p><code>loglevel</code> is a global argument/config that can be set to determine the type of information to be displayed.</p> +<p>The default value of <code>loglevel</code> is <code>"notice"</code> but there are several levels/types of logs available, including:</p> +<ul> +<li><code>"silent"</code></li> +<li><code>"error"</code></li> +<li><code>"warn"</code></li> +<li><code>"notice"</code></li> +<li><code>"http"</code></li> +<li><code>"timing"</code></li> +<li><code>"info"</code></li> +<li><code>"verbose"</code></li> +<li><code>"silly"</code></li> +</ul> +<p>All logs pertaining to a level proceeding the current setting will be shown.</p> +<p>All logs are written to a debug log, with the path to that file printed if the execution of a command fails.</p> +<h5 id="aliases">Aliases</h5> +<p>The log levels listed above have various corresponding aliases, including:</p> +<ul> +<li><code>-d</code>: <code>--loglevel info</code></li> +<li><code>--dd</code>: <code>--loglevel verbose</code></li> +<li><code>--verbose</code>: <code>--loglevel verbose</code></li> +<li><code>--ddd</code>: <code>--loglevel silly</code></li> +<li><code>-q</code>: <code>--loglevel warn</code></li> +<li><code>--quiet</code>: <code>--loglevel warn</code></li> +<li><code>-s</code>: <code>--loglevel silent</code></li> +<li><code>--silent</code>: <code>--loglevel silent</code></li> +</ul> +<h4 id="foreground-scripts"><code>foreground-scripts</code></h4> +<p>The <code>npm</code> CLI began hiding the output of lifecycle scripts for <code>npm install</code> as of <code>v7</code>. Notably, this means you will not see logs/output from packages that may be using "install scripts" to display information back to you or from your own project's scripts defined in <code>package.json</code>. If you'd like to change this behavior & log this output you can set <code>foreground-scripts</code> to <code>true</code>.</p> +<h3 id="registry-response-headers">Registry Response Headers</h3> +<h4 id="npm-notice"><code>npm-notice</code></h4> +<p>The <code>npm</code> CLI reads from & logs any <code>npm-notice</code> headers that are returned from the configured registry. This mechanism can be used by third-party registries to provide useful information when network-dependent requests occur.</p> +<p>This header is not cached, and will not be logged if the request is served from the cache.</p> +<h3 id="see-also">See also</h3> +<ul> +<li><a href="../using-npm/config.html">config</a></li> +</ul> +</div> + +<footer id="edit"> +<a href="https://github.com/npm/cli/edit/latest/docs/content/using-npm/logging.md"> +<svg role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentcolor" style="vertical-align: text-bottom; margin-right: 0.3em;"> +<path fill-rule="evenodd" d="M11.013 1.427a1.75 1.75 0 012.474 0l1.086 1.086a1.75 1.75 0 010 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 01-.927-.928l.929-3.25a1.75 1.75 0 01.445-.758l8.61-8.61zm1.414 1.06a.25.25 0 00-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 000-.354l-1.086-1.086zM11.189 6.25L9.75 4.81l-6.286 6.287a.25.25 0 00-.064.108l-.558 1.953 1.953-.558a.249.249 0 00.108-.064l6.286-6.286z"></path> +</svg> +Edit this page on GitHub +</a> +</footer> +</section> + + + +</body></html>
\ No newline at end of file diff --git a/deps/npm/docs/output/using-npm/scripts.html b/deps/npm/docs/output/using-npm/scripts.html index 3a51b05707..19082719ef 100644 --- a/deps/npm/docs/output/using-npm/scripts.html +++ b/deps/npm/docs/output/using-npm/scripts.html @@ -380,7 +380,7 @@ package.json file, then your package scripts would have the <code>npm_package_version</code> set to "1.2.5". You can access these variables in your code with <code>process.env.npm_package_name</code> and <code>process.env.npm_package_version</code>, and so on for other fields.</p> -<p>See <a href="../configuring-npm/package-json.html"><code>package-json.md</code></a> for more on package configs.</p> +<p>See <a href="../configuring-npm/package-json.html"><code>package.json</code></a> for more on package configs.</p> <h4 id="current-lifecycle-event">current lifecycle event</h4> <p>Lastly, the <code>npm_lifecycle_event</code> environment variable is set to whichever stage of the cycle is being executed. So, you could have a diff --git a/deps/npm/docs/output/using-npm/workspaces.html b/deps/npm/docs/output/using-npm/workspaces.html index 6f5a23e749..42f10e5f3d 100644 --- a/deps/npm/docs/output/using-npm/workspaces.html +++ b/deps/npm/docs/output/using-npm/workspaces.html @@ -148,7 +148,7 @@ npm command-line interface <div id="_content"><h3 id="description">Description</h3> <p><strong>Workspaces</strong> is a generic term that refers to the set of features in the npm cli that provides support to managing multiple packages from your local -files system from within a singular top-level, root package.</p> +file system from within a singular top-level, root package.</p> <p>This set of features makes up for a much more streamlined workflow handling linked packages from the local file system. Automating the linking process as part of <code>npm install</code> and avoiding manually having to use <code>npm link</code> in diff --git a/deps/npm/lib/auth/legacy.js b/deps/npm/lib/auth/legacy.js index 2da82e361d..d1401ce14b 100644 --- a/deps/npm/lib/auth/legacy.js +++ b/deps/npm/lib/auth/legacy.js @@ -1,15 +1,12 @@ -const log = require('npmlog') const profile = require('npm-profile') - +const log = require('../utils/log-shim') const openUrl = require('../utils/open-url.js') const read = require('../utils/read-user-info.js') const loginPrompter = async (creds) => { - const opts = { log: log } - - creds.username = await read.username('Username:', creds.username, opts) + creds.username = await read.username('Username:', creds.username) creds.password = await read.password('Password:', creds.password) - creds.email = await read.email('Email: (this IS public) ', creds.email, opts) + creds.email = await read.email('Email: (this IS public) ', creds.email) return creds } @@ -19,7 +16,7 @@ const login = async (npm, opts) => { const requestOTP = async () => { const otp = await read.otp( - 'Enter one-time password from your authenticator app: ' + 'Enter one-time password: ' ) return profile.loginCouch( diff --git a/deps/npm/lib/auth/sso.js b/deps/npm/lib/auth/sso.js index 6fcfc30e5d..795eb8972a 100644 --- a/deps/npm/lib/auth/sso.js +++ b/deps/npm/lib/auth/sso.js @@ -7,10 +7,9 @@ // CLI, we can remove this, and fold the lib/auth/legacy.js back into // lib/adduser.js -const log = require('npmlog') const profile = require('npm-profile') const npmFetch = require('npm-registry-fetch') - +const log = require('../utils/log-shim') const openUrl = require('../utils/open-url.js') const otplease = require('../utils/otplease.js') diff --git a/deps/npm/lib/cli.js b/deps/npm/lib/cli.js index 9dcd9d04d2..3d0c32d4be 100644 --- a/deps/npm/lib/cli.js +++ b/deps/npm/lib/cli.js @@ -4,20 +4,23 @@ module.exports = async process => { // leak any private CLI configs to other programs process.title = 'npm' - const { checkForBrokenNode, checkForUnsupportedNode } = require('../lib/utils/unsupported.js') - + // We used to differentiate between known broken and unsupported + // versions of node and attempt to only log unsupported but still run. + // After we dropped node 10 support, we can use new features + // (like static, private, etc) which will only give vague syntax errors, + // so now both broken and unsupported use console, but only broken + // will process.exit. It is important to now perform *both* of these + // checks as early as possible so the user gets the error message. + const { checkForBrokenNode, checkForUnsupportedNode } = require('./utils/unsupported.js') checkForBrokenNode() - - const log = require('npmlog') - // pause it here so it can unpause when we've loaded the configs - // and know what loglevel we should be printing. - log.pause() - checkForUnsupportedNode() - const Npm = require('../lib/npm.js') + const exitHandler = require('./utils/exit-handler.js') + process.on('uncaughtException', exitHandler) + process.on('unhandledRejection', exitHandler) + + const Npm = require('./npm.js') const npm = new Npm() - const exitHandler = require('../lib/utils/exit-handler.js') exitHandler.setNpm(npm) // if npm is called as "npmg" or "npm_g", then @@ -26,16 +29,14 @@ module.exports = async process => { process.argv.splice(1, 1, 'npm', '-g') } - const replaceInfo = require('../lib/utils/replace-info.js') + const log = require('./utils/log-shim.js') + const replaceInfo = require('./utils/replace-info.js') log.verbose('cli', replaceInfo(process.argv)) log.info('using', 'npm@%s', npm.version) log.info('using', 'node@%s', process.version) - process.on('uncaughtException', exitHandler) - process.on('unhandledRejection', exitHandler) - - const updateNotifier = require('../lib/utils/update-notifier.js') + const updateNotifier = require('./utils/update-notifier.js') let cmd // now actually fire up npm and run the command. @@ -63,7 +64,7 @@ module.exports = async process => { } await npm.exec(cmd, npm.argv) - exitHandler() + return exitHandler() } catch (err) { if (err.code === 'EUNKNOWNCOMMAND') { const didYouMean = require('./utils/did-you-mean.js') diff --git a/deps/npm/lib/commands/adduser.js b/deps/npm/lib/commands/adduser.js index 6cd6d3001c..1cf70fffbf 100644 --- a/deps/npm/lib/commands/adduser.js +++ b/deps/npm/lib/commands/adduser.js @@ -1,4 +1,4 @@ -const log = require('npmlog') +const log = require('../utils/log-shim.js') const replaceInfo = require('../utils/replace-info.js') const BaseCommand = require('../base-command.js') const authTypes = { @@ -31,6 +31,7 @@ class AddUser extends BaseCommand { creds, registry, scope, + log, }) await this.updateConfig({ diff --git a/deps/npm/lib/commands/bin.js b/deps/npm/lib/commands/bin.js index 8f5ae0cc52..bb700d45a8 100644 --- a/deps/npm/lib/commands/bin.js +++ b/deps/npm/lib/commands/bin.js @@ -10,6 +10,7 @@ class Bin extends BaseCommand { const b = this.npm.bin this.npm.output(b) if (this.npm.config.get('global') && !envPath.includes(b)) { + // XXX: does this need to be console? console.error('(not in PATH env variable)') } } diff --git a/deps/npm/lib/commands/bugs.js b/deps/npm/lib/commands/bugs.js index 8ca8188ccd..5dfd1eb918 100644 --- a/deps/npm/lib/commands/bugs.js +++ b/deps/npm/lib/commands/bugs.js @@ -1,5 +1,5 @@ -const log = require('npmlog') const pacote = require('pacote') +const log = require('../utils/log-shim') const openUrl = require('../utils/open-url.js') const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js') const BaseCommand = require('../base-command.js') diff --git a/deps/npm/lib/commands/cache.js b/deps/npm/lib/commands/cache.js index b1c045bbfa..ecb34cb891 100644 --- a/deps/npm/lib/commands/cache.js +++ b/deps/npm/lib/commands/cache.js @@ -1,6 +1,5 @@ const cacache = require('cacache') const { promisify } = require('util') -const log = require('npmlog') const pacote = require('pacote') const path = require('path') const rimraf = promisify(require('rimraf')) @@ -9,6 +8,7 @@ const BaseCommand = require('../base-command.js') const npa = require('npm-package-arg') const jsonParse = require('json-parse-even-better-errors') const localeCompare = require('@isaacs/string-locale-compare')('en') +const log = require('../utils/log-shim') const searchCachePackage = async (path, spec, cacheKeys) => { const parsed = npa(spec) @@ -141,7 +141,7 @@ class Cache extends BaseCommand { try { entry = await cacache.get(cachePath, key) } catch (err) { - this.npm.log.warn(`Not Found: ${key}`) + log.warn(`Not Found: ${key}`) break } this.npm.output(`Deleted: ${key}`) diff --git a/deps/npm/lib/commands/ci.js b/deps/npm/lib/commands/ci.js index e928a01d15..2c2f8da866 100644 --- a/deps/npm/lib/commands/ci.js +++ b/deps/npm/lib/commands/ci.js @@ -5,8 +5,7 @@ const reifyFinish = require('../utils/reify-finish.js') const runScript = require('@npmcli/run-script') const fs = require('fs') const readdir = util.promisify(fs.readdir) - -const log = require('npmlog') +const log = require('../utils/log-shim.js') const removeNodeModules = async where => { const rimrafOpts = { glob: false } @@ -39,7 +38,7 @@ class CI extends ArboristWorkspaceCmd { const opts = { ...this.npm.flatOptions, path: where, - log: this.npm.log, + log, save: false, // npm ci should never modify the lockfile or package.json workspaces: this.workspaceNames, } diff --git a/deps/npm/lib/commands/config.js b/deps/npm/lib/commands/config.js index 0cdcd576f5..eb1d570c6e 100644 --- a/deps/npm/lib/commands/config.js +++ b/deps/npm/lib/commands/config.js @@ -11,6 +11,7 @@ const { spawn } = require('child_process') const { EOL } = require('os') const ini = require('ini') const localeCompare = require('@isaacs/string-locale-compare')('en') +const log = require('../utils/log-shim.js') // take an array of `[key, value, k2=v2, k3, v3, ...]` and turn into // { key: value, k2: v2, k3: v3 } @@ -87,12 +88,12 @@ class Config extends BaseCommand { } async execWorkspaces (args, filters) { - this.npm.log.warn('config', 'This command does not support workspaces.') + log.warn('config', 'This command does not support workspaces.') return this.exec(args) } async exec ([action, ...args]) { - this.npm.log.disableProgress() + log.disableProgress() try { switch (action) { case 'set': @@ -117,7 +118,7 @@ class Config extends BaseCommand { throw this.usageError() } } finally { - this.npm.log.enableProgress() + log.enableProgress() } } @@ -128,10 +129,10 @@ class Config extends BaseCommand { const where = this.npm.flatOptions.location for (const [key, val] of Object.entries(keyValues(args))) { - this.npm.log.info('config', 'set %j %j', key, val) + 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') + log.warn('config', 'omitting invalid config values') } } diff --git a/deps/npm/lib/commands/dedupe.js b/deps/npm/lib/commands/dedupe.js index e1eafbe3bc..cc4b119d09 100644 --- a/deps/npm/lib/commands/dedupe.js +++ b/deps/npm/lib/commands/dedupe.js @@ -1,6 +1,7 @@ // dedupe duplicated packages, or find them in the tree const Arborist = require('@npmcli/arborist') const reifyFinish = require('../utils/reify-finish.js') +const log = require('../utils/log-shim.js') const ArboristWorkspaceCmd = require('../arborist-cmd.js') @@ -32,7 +33,7 @@ class Dedupe extends ArboristWorkspaceCmd { const where = this.npm.prefix const opts = { ...this.npm.flatOptions, - log: this.npm.log, + log, path: where, dryRun, workspaces: this.workspaceNames, diff --git a/deps/npm/lib/commands/diff.js b/deps/npm/lib/commands/diff.js index 3134f502ea..d737a58dc4 100644 --- a/deps/npm/lib/commands/diff.js +++ b/deps/npm/lib/commands/diff.js @@ -1,13 +1,11 @@ const { resolve } = require('path') - const semver = require('semver') const libnpmdiff = require('libnpmdiff') const npa = require('npm-package-arg') const Arborist = require('@npmcli/arborist') -const npmlog = require('npmlog') const pacote = require('pacote') const pickManifest = require('npm-pick-manifest') - +const log = require('../utils/log-shim') const readPackageName = require('../utils/read-package-name.js') const BaseCommand = require('../base-command.js') @@ -57,7 +55,7 @@ class Diff extends BaseCommand { } const [a, b] = await this.retrieveSpecs(specs) - npmlog.info('diff', { src: a, dst: b }) + log.info('diff', { src: a, dst: b }) const res = await libnpmdiff([a, b], { ...this.npm.flatOptions, @@ -83,7 +81,7 @@ class Diff extends BaseCommand { try { name = await readPackageName(this.prefix) } catch (e) { - npmlog.verbose('diff', 'could not read project dir package.json') + log.verbose('diff', 'could not read project dir package.json') } if (!name) { @@ -116,7 +114,7 @@ class Diff extends BaseCommand { try { pkgName = await readPackageName(this.prefix) } catch (e) { - npmlog.verbose('diff', 'could not read project dir package.json') + log.verbose('diff', 'could not read project dir package.json') noPackageJson = true } @@ -154,7 +152,7 @@ class Diff extends BaseCommand { actualTree.inventory.query('name', spec.name) .values().next().value } catch (e) { - npmlog.verbose('diff', 'failed to load actual install tree') + log.verbose('diff', 'failed to load actual install tree') } if (!node || !node.name || !node.package || !node.package.version) { @@ -227,7 +225,7 @@ class Diff extends BaseCommand { try { pkgName = await readPackageName(this.prefix) } catch (e) { - npmlog.verbose('diff', 'could not read project dir package.json') + log.verbose('diff', 'could not read project dir package.json') } if (!pkgName) { @@ -261,7 +259,7 @@ class Diff extends BaseCommand { const arb = new Arborist(opts) actualTree = await arb.loadActual(opts) } catch (e) { - npmlog.verbose('diff', 'failed to load actual install tree') + log.verbose('diff', 'failed to load actual install tree') } return specs.map(i => { diff --git a/deps/npm/lib/commands/dist-tag.js b/deps/npm/lib/commands/dist-tag.js index fa79b293c5..bf2dffe912 100644 --- a/deps/npm/lib/commands/dist-tag.js +++ b/deps/npm/lib/commands/dist-tag.js @@ -1,8 +1,7 @@ -const log = require('npmlog') const npa = require('npm-package-arg') const regFetch = require('npm-registry-fetch') const semver = require('semver') - +const log = require('../utils/log-shim') const otplease = require('../utils/otplease.js') const readPackageName = require('../utils/read-package-name.js') const BaseCommand = require('../base-command.js') diff --git a/deps/npm/lib/commands/docs.js b/deps/npm/lib/commands/docs.js index 9aba242057..19cd735642 100644 --- a/deps/npm/lib/commands/docs.js +++ b/deps/npm/lib/commands/docs.js @@ -1,8 +1,7 @@ -const log = require('npmlog') const pacote = require('pacote') const openUrl = require('../utils/open-url.js') const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js') - +const log = require('../utils/log-shim') const BaseCommand = require('../base-command.js') class Docs extends BaseCommand { static description = 'Open documentation for a package in a web browser' diff --git a/deps/npm/lib/commands/doctor.js b/deps/npm/lib/commands/doctor.js index 6b8878b6f4..47a522eb67 100644 --- a/deps/npm/lib/commands/doctor.js +++ b/deps/npm/lib/commands/doctor.js @@ -8,6 +8,7 @@ const pacote = require('pacote') const { resolve } = require('path') const semver = require('semver') const { promisify } = require('util') +const log = require('../utils/log-shim.js') const ansiTrim = require('../utils/ansi-trim.js') const isWindows = require('../utils/is-windows.js') const ping = require('../utils/ping.js') @@ -42,7 +43,7 @@ class Doctor extends BaseCommand { static params = ['registry'] async exec (args) { - this.npm.log.info('Running checkup') + log.info('Running checkup') // each message is [title, ok, message] const messages = [] @@ -124,7 +125,7 @@ class Doctor extends BaseCommand { stringLength: s => ansiTrim(s).length, } - const silent = this.npm.log.levels[this.npm.log.level] > this.npm.log.levels.error + const silent = log.levels[log.level] > log.levels.error if (!silent) { this.npm.output(table(outTable, tableOpts)) if (!allOk) { @@ -137,7 +138,7 @@ class Doctor extends BaseCommand { } async checkPing () { - const tracker = this.npm.log.newItem('checkPing', 1) + const tracker = log.newItem('checkPing', 1) tracker.info('checkPing', 'Pinging registry') try { await ping(this.npm.flatOptions) @@ -154,7 +155,7 @@ class Doctor extends BaseCommand { } async getLatestNpmVersion () { - const tracker = this.npm.log.newItem('getLatestNpmVersion', 1) + const tracker = log.newItem('getLatestNpmVersion', 1) tracker.info('getLatestNpmVersion', 'Getting npm package information') try { const latest = (await pacote.manifest('npm@latest', this.npm.flatOptions)).version @@ -173,7 +174,7 @@ class Doctor extends BaseCommand { const current = process.version const currentRange = `^${current}` const url = 'https://nodejs.org/dist/index.json' - const tracker = this.npm.log.newItem('getLatestNodejsVersion', 1) + const tracker = log.newItem('getLatestNodejsVersion', 1) tracker.info('getLatestNodejsVersion', 'Getting Node.js release information') try { const res = await fetch(url, { method: 'GET', ...this.npm.flatOptions }) @@ -207,7 +208,7 @@ class Doctor extends BaseCommand { let ok = true - const tracker = this.npm.log.newItem(root, 1) + const tracker = log.newItem(root, 1) try { const uid = process.getuid() @@ -269,7 +270,7 @@ class Doctor extends BaseCommand { } async getGitPath () { - const tracker = this.npm.log.newItem('getGitPath', 1) + const tracker = log.newItem('getGitPath', 1) tracker.info('getGitPath', 'Finding git in your PATH') try { return await which('git').catch(er => { @@ -282,7 +283,7 @@ class Doctor extends BaseCommand { } async verifyCachedFiles () { - const tracker = this.npm.log.newItem('verifyCachedFiles', 1) + const tracker = log.newItem('verifyCachedFiles', 1) tracker.info('verifyCachedFiles', 'Verifying the npm cache') try { const stats = await cacache.verify(this.npm.flatOptions.cache) diff --git a/deps/npm/lib/commands/exec.js b/deps/npm/lib/commands/exec.js index 515ac910f8..61a6d96595 100644 --- a/deps/npm/lib/commands/exec.js +++ b/deps/npm/lib/commands/exec.js @@ -1,6 +1,7 @@ const libexec = require('libnpmexec') const BaseCommand = require('../base-command.js') const getLocationMsg = require('../exec/get-workspace-location-msg.js') +const log = require('../utils/log-shim') // it's like this: // @@ -59,7 +60,6 @@ class Exec extends BaseCommand { const { flatOptions, localBin, - log, globalBin, } = this.npm const output = (...outputArgs) => this.npm.output(...outputArgs) diff --git a/deps/npm/lib/commands/explore.js b/deps/npm/lib/commands/explore.js index f94fff01c4..90e6af69fe 100644 --- a/deps/npm/lib/commands/explore.js +++ b/deps/npm/lib/commands/explore.js @@ -4,6 +4,7 @@ const rpj = require('read-package-json-fast') const runScript = require('@npmcli/run-script') const { join, resolve, relative } = require('path') +const log = require('../utils/log-shim.js') const completion = require('../utils/completion/installed-shallow.js') const BaseCommand = require('../base-command.js') @@ -37,7 +38,7 @@ class Explore extends BaseCommand { // 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.`) + log.error('explore', `It doesn't look like ${pkgname} is installed.`) throw er }) @@ -50,7 +51,7 @@ class Explore extends BaseCommand { if (!args.length) { this.npm.output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`) } - this.npm.log.disableProgress() + log.disableProgress() try { return await runScript({ ...this.npm.flatOptions, @@ -71,7 +72,7 @@ class Explore extends BaseCommand { } }) } finally { - this.npm.log.enableProgress() + log.enableProgress() } } } diff --git a/deps/npm/lib/commands/fund.js b/deps/npm/lib/commands/fund.js index 81c6d9a1b0..47a51c33a6 100644 --- a/deps/npm/lib/commands/fund.js +++ b/deps/npm/lib/commands/fund.js @@ -5,6 +5,7 @@ const pacote = require('pacote') const semver = require('semver') const npa = require('npm-package-arg') const { depth } = require('treeverse') +const log = require('../utils/log-shim.js') const { readTree: getFundingInfo, normalizeFunding, isValidFunding } = require('libnpmfund') const completion = require('../utils/completion/installed-deep.js') @@ -68,7 +69,7 @@ class Fund extends ArboristWorkspaceCmd { // TODO: add !workspacesEnabled option handling to libnpmfund const fundingInfo = getFundingInfo(tree, { ...this.flatOptions, - log: this.npm.log, + log, workspaces: this.workspaceNames, }) diff --git a/deps/npm/lib/commands/init.js b/deps/npm/lib/commands/init.js index eaca2716ee..7e8a8f7a5c 100644 --- a/deps/npm/lib/commands/init.js +++ b/deps/npm/lib/commands/init.js @@ -7,6 +7,7 @@ const rpj = require('read-package-json-fast') const libexec = require('libnpmexec') const mapWorkspaces = require('@npmcli/map-workspaces') const PackageJson = require('@npmcli/package-json') +const log = require('../utils/log-shim.js') const getLocationMsg = require('../exec/get-workspace-location-msg.js') const BaseCommand = require('../base-command.js') @@ -94,7 +95,6 @@ class Init extends BaseCommand { const { flatOptions, localBin, - log, globalBin, } = this.npm // this function is definitely called. But because of coverage map stuff @@ -125,8 +125,8 @@ class Init extends BaseCommand { } async template (path = process.cwd()) { - this.npm.log.pause() - this.npm.log.disableProgress() + log.pause() + log.disableProgress() const initFile = this.npm.config.get('init-module') if (!this.npm.config.get('yes') && !this.npm.config.get('force')) { @@ -147,17 +147,17 @@ class Init extends BaseCommand { // XXX promisify init-package-json await new Promise((res, rej) => { initJson(path, initFile, this.npm.config, (er, data) => { - this.npm.log.resume() - this.npm.log.enableProgress() - this.npm.log.silly('package data', data) + log.resume() + log.enableProgress() + log.silly('package data', data) if (er && er.message === 'canceled') { - this.npm.log.warn('init', 'canceled') + log.warn('init', 'canceled') return res() } if (er) { rej(er) } else { - this.npm.log.info('init', 'written successfully') + log.info('init', 'written successfully') res(data) } }) diff --git a/deps/npm/lib/commands/install.js b/deps/npm/lib/commands/install.js index 02ccb57248..a92a5edc5e 100644 --- a/deps/npm/lib/commands/install.js +++ b/deps/npm/lib/commands/install.js @@ -3,7 +3,7 @@ const fs = require('fs') const util = require('util') const readdir = util.promisify(fs.readdir) const reifyFinish = require('../utils/reify-finish.js') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const { resolve, join } = require('path') const Arborist = require('@npmcli/arborist') const runScript = require('@npmcli/run-script') @@ -118,7 +118,7 @@ class Install extends ArboristWorkspaceCmd { checks.checkEngine(npmManifest, npmManifest.version, process.version) } catch (e) { if (forced) { - this.npm.log.warn( + log.warn( 'install', /* eslint-disable-next-line max-len */ `Forcing global npm install with incompatible version ${npmManifest.version} into node ${process.version}` @@ -147,7 +147,7 @@ class Install extends ArboristWorkspaceCmd { const opts = { ...this.npm.flatOptions, - log: this.npm.log, + log, auditLevel: null, path: where, add: args, diff --git a/deps/npm/lib/commands/link.js b/deps/npm/lib/commands/link.js index 8755af6f68..e8e2c6b349 100644 --- a/deps/npm/lib/commands/link.js +++ b/deps/npm/lib/commands/link.js @@ -7,6 +7,7 @@ const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') const rpj = require('read-package-json-fast') const semver = require('semver') +const log = require('../utils/log-shim.js') const reifyFinish = require('../utils/reify-finish.js') @@ -68,7 +69,7 @@ class Link extends ArboristWorkspaceCmd { const globalOpts = { ...this.npm.flatOptions, path: globalTop, - log: this.npm.log, + log, global: true, prune: false, } @@ -117,7 +118,7 @@ class Link extends ArboristWorkspaceCmd { const localArb = new Arborist({ ...this.npm.flatOptions, prune: false, - log: this.npm.log, + log, path: this.npm.prefix, save, }) @@ -125,7 +126,7 @@ class Link extends ArboristWorkspaceCmd { ...this.npm.flatOptions, prune: false, path: this.npm.prefix, - log: this.npm.log, + log, add: names.map(l => `file:${resolve(globalTop, 'node_modules', l)}`), save, workspaces: this.workspaceNames, @@ -142,12 +143,12 @@ class Link extends ArboristWorkspaceCmd { const arb = new Arborist({ ...this.npm.flatOptions, path: globalTop, - log: this.npm.log, + log, global: true, }) await arb.reify({ add, - log: this.npm.log, + log, }) await reifyFinish(this.npm, arb) } diff --git a/deps/npm/lib/commands/logout.js b/deps/npm/lib/commands/logout.js index e17b2b8790..4e6bab9859 100644 --- a/deps/npm/lib/commands/logout.js +++ b/deps/npm/lib/commands/logout.js @@ -1,6 +1,6 @@ -const log = require('npmlog') const getAuth = require('npm-registry-fetch/auth.js') const npmFetch = require('npm-registry-fetch') +const log = require('../utils/log-shim') const BaseCommand = require('../base-command.js') class Logout extends BaseCommand { diff --git a/deps/npm/lib/commands/owner.js b/deps/npm/lib/commands/owner.js index 8f0b1f1eff..c027ad6464 100644 --- a/deps/npm/lib/commands/owner.js +++ b/deps/npm/lib/commands/owner.js @@ -1,8 +1,7 @@ -const log = require('npmlog') const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') const pacote = require('pacote') - +const log = require('../utils/log-shim') const otplease = require('../utils/otplease.js') const readLocalPkgName = require('../utils/read-package-name.js') const BaseCommand = require('../base-command.js') diff --git a/deps/npm/lib/commands/pack.js b/deps/npm/lib/commands/pack.js index d84dde86e8..0719fa3b85 100644 --- a/deps/npm/lib/commands/pack.js +++ b/deps/npm/lib/commands/pack.js @@ -1,14 +1,11 @@ const util = require('util') -const log = require('npmlog') const pacote = require('pacote') const libpack = require('libnpmpack') const npa = require('npm-package-arg') const path = require('path') - +const log = require('../utils/log-shim') const { getContents, logTar } = require('../utils/tar.js') - const writeFile = util.promisify(require('fs').writeFile) - const BaseCommand = require('../base-command.js') class Pack extends BaseCommand { @@ -70,7 +67,7 @@ class Pack extends BaseCommand { } for (const tar of tarballs) { - logTar(tar, { log, unicode }) + logTar(tar, { unicode }) this.npm.output(tar.filename.replace(/^@/, '').replace(/\//, '-')) } } @@ -82,7 +79,7 @@ class Pack extends BaseCommand { const useWorkspaces = args.length === 0 || args.includes('.') if (!useWorkspaces) { - this.npm.log.warn('Ignoring workspaces for specified package(s)') + log.warn('Ignoring workspaces for specified package(s)') return this.exec(args) } diff --git a/deps/npm/lib/commands/ping.js b/deps/npm/lib/commands/ping.js index a049d24127..993e029d45 100644 --- a/deps/npm/lib/commands/ping.js +++ b/deps/npm/lib/commands/ping.js @@ -1,4 +1,4 @@ -const log = require('npmlog') +const log = require('../utils/log-shim') const pingUtil = require('../utils/ping.js') const BaseCommand = require('../base-command.js') diff --git a/deps/npm/lib/commands/profile.js b/deps/npm/lib/commands/profile.js index 0939013cc2..1250ed7d1c 100644 --- a/deps/npm/lib/commands/profile.js +++ b/deps/npm/lib/commands/profile.js @@ -1,7 +1,7 @@ const inspect = require('util').inspect const { URL } = require('url') const ansistyles = require('ansistyles') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const npmProfile = require('npm-profile') const qrcodeTerminal = require('qrcode-terminal') const Table = require('cli-table3') @@ -321,7 +321,7 @@ class Profile extends BaseCommand { } else if (userInfo && userInfo.tfa) { if (!conf.otp) { conf.otp = await readUserInfo.otp( - 'Enter one-time password from your authenticator app: ' + 'Enter one-time password: ' ) } } @@ -386,7 +386,7 @@ class Profile extends BaseCommand { const password = await readUserInfo.password() if (!conf.otp) { - const msg = 'Enter one-time password from your authenticator app: ' + const msg = 'Enter one-time password: ' conf.otp = await readUserInfo.otp(msg) } diff --git a/deps/npm/lib/commands/prune.js b/deps/npm/lib/commands/prune.js index 403575e024..5831df6285 100644 --- a/deps/npm/lib/commands/prune.js +++ b/deps/npm/lib/commands/prune.js @@ -1,5 +1,6 @@ // prune extraneous packages const Arborist = require('@npmcli/arborist') +const log = require('../utils/log-shim.js') const reifyFinish = require('../utils/reify-finish.js') const ArboristWorkspaceCmd = require('../arborist-cmd.js') @@ -14,7 +15,7 @@ class Prune extends ArboristWorkspaceCmd { const opts = { ...this.npm.flatOptions, path: where, - log: this.npm.log, + log, workspaces: this.workspaceNames, } const arb = new Arborist(opts) diff --git a/deps/npm/lib/commands/publish.js b/deps/npm/lib/commands/publish.js index 88ddcae7bb..ad538668b6 100644 --- a/deps/npm/lib/commands/publish.js +++ b/deps/npm/lib/commands/publish.js @@ -1,5 +1,5 @@ const util = require('util') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const semver = require('semver') const pack = require('libnpmpack') const libpub = require('libnpmpublish').publish @@ -94,10 +94,10 @@ class Publish extends BaseCommand { flatten(manifest.publishConfig, opts) } - // note that logTar calls npmlog.notice(), so if we ARE in silent mode, + // note that logTar calls log.notice(), so if we ARE in silent mode, // this will do nothing, but we still want it in the debuglog if it fails. if (!json) { - logTar(pkgContents, { log, unicode }) + logTar(pkgContents, { unicode }) } if (!dryRun) { diff --git a/deps/npm/lib/commands/repo.js b/deps/npm/lib/commands/repo.js index cc68e85650..8ac4178f26 100644 --- a/deps/npm/lib/commands/repo.js +++ b/deps/npm/lib/commands/repo.js @@ -1,7 +1,6 @@ -const log = require('npmlog') const pacote = require('pacote') const { URL } = require('url') - +const log = require('../utils/log-shim') const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js') const openUrl = require('../utils/open-url.js') diff --git a/deps/npm/lib/commands/run-script.js b/deps/npm/lib/commands/run-script.js index 37140c8c53..cd877e0b3d 100644 --- a/deps/npm/lib/commands/run-script.js +++ b/deps/npm/lib/commands/run-script.js @@ -3,7 +3,7 @@ const chalk = require('chalk') const runScript = require('@npmcli/run-script') const { isServerPackage } = runScript const rpj = require('read-package-json-fast') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const didYouMean = require('../utils/did-you-mean.js') const isWindowsShell = require('../utils/is-windows-shell.js') diff --git a/deps/npm/lib/commands/search.js b/deps/npm/lib/commands/search.js index ff533ebbd1..bdeeffe816 100644 --- a/deps/npm/lib/commands/search.js +++ b/deps/npm/lib/commands/search.js @@ -1,7 +1,7 @@ const Minipass = require('minipass') const Pipeline = require('minipass-pipeline') const libSearch = require('libnpmsearch') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const formatPackageStream = require('../search/format-package-stream.js') const packageFilter = require('../search/package-filter.js') diff --git a/deps/npm/lib/commands/set-script.js b/deps/npm/lib/commands/set-script.js index 58fd2726db..7c73ff01b9 100644 --- a/deps/npm/lib/commands/set-script.js +++ b/deps/npm/lib/commands/set-script.js @@ -1,7 +1,7 @@ const { resolve } = require('path') -const log = require('npmlog') const rpj = require('read-package-json-fast') const PackageJson = require('@npmcli/package-json') +const log = require('../utils/log-shim') const BaseCommand = require('../base-command.js') class SetScript extends BaseCommand { diff --git a/deps/npm/lib/commands/shrinkwrap.js b/deps/npm/lib/commands/shrinkwrap.js index dfb3c8e381..05e3f6d278 100644 --- a/deps/npm/lib/commands/shrinkwrap.js +++ b/deps/npm/lib/commands/shrinkwrap.js @@ -1,8 +1,7 @@ const { resolve, basename } = require('path') const { unlink } = require('fs').promises const Arborist = require('@npmcli/arborist') -const log = require('npmlog') - +const log = require('../utils/log-shim') const BaseCommand = require('../base-command.js') class Shrinkwrap extends BaseCommand { static description = 'Lock down dependency versions for publication' diff --git a/deps/npm/lib/commands/star.js b/deps/npm/lib/commands/star.js index 1bbd25efda..ec11605899 100644 --- a/deps/npm/lib/commands/star.js +++ b/deps/npm/lib/commands/star.js @@ -1,7 +1,6 @@ const fetch = require('npm-registry-fetch') -const log = require('npmlog') const npa = require('npm-package-arg') - +const log = require('../utils/log-shim') const getIdentity = require('../utils/get-identity') const BaseCommand = require('../base-command.js') diff --git a/deps/npm/lib/commands/stars.js b/deps/npm/lib/commands/stars.js index 1260655d07..f45ec846dc 100644 --- a/deps/npm/lib/commands/stars.js +++ b/deps/npm/lib/commands/stars.js @@ -1,6 +1,5 @@ -const log = require('npmlog') const fetch = require('npm-registry-fetch') - +const log = require('../utils/log-shim') const getIdentity = require('../utils/get-identity.js') const BaseCommand = require('../base-command.js') diff --git a/deps/npm/lib/commands/token.js b/deps/npm/lib/commands/token.js index db23742038..df80f1afec 100644 --- a/deps/npm/lib/commands/token.js +++ b/deps/npm/lib/commands/token.js @@ -1,7 +1,7 @@ const Table = require('cli-table3') const ansistyles = require('ansistyles') const { v4: isCidrV4, v6: isCidrV6 } = require('is-cidr') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const profile = require('npm-profile') const otplease = require('../utils/otplease.js') diff --git a/deps/npm/lib/commands/uninstall.js b/deps/npm/lib/commands/uninstall.js index dba45e127a..b40c59bda4 100644 --- a/deps/npm/lib/commands/uninstall.js +++ b/deps/npm/lib/commands/uninstall.js @@ -1,4 +1,5 @@ const { resolve } = require('path') +const log = require('../utils/log-shim.js') const Arborist = require('@npmcli/arborist') const rpj = require('read-package-json-fast') @@ -48,7 +49,7 @@ class Uninstall extends ArboristWorkspaceCmd { const opts = { ...this.npm.flatOptions, path, - log: this.npm.log, + log, rm: args, workspaces: this.workspaceNames, } diff --git a/deps/npm/lib/commands/unpublish.js b/deps/npm/lib/commands/unpublish.js index 3636dc58a6..578890025d 100644 --- a/deps/npm/lib/commands/unpublish.js +++ b/deps/npm/lib/commands/unpublish.js @@ -5,7 +5,7 @@ const libaccess = require('libnpmaccess') const npmFetch = require('npm-registry-fetch') const libunpub = require('libnpmpublish').unpublish const readJson = util.promisify(require('read-package-json')) - +const log = require('../utils/log-shim') const otplease = require('../utils/otplease.js') const getIdentity = require('../utils/get-identity.js') @@ -66,8 +66,8 @@ class Unpublish extends BaseCommand { let pkgName let pkgVersion - this.npm.log.silly('unpublish', 'args[0]', args[0]) - this.npm.log.silly('unpublish', 'spec', spec) + log.silly('unpublish', 'args[0]', args[0]) + log.silly('unpublish', 'spec', spec) if ((!spec || !spec.rawSpec) && !force) { throw this.usageError( @@ -92,7 +92,7 @@ class Unpublish extends BaseCommand { } } - this.npm.log.verbose('unpublish', manifest) + log.verbose('unpublish', manifest) const { name, version, publishConfig } = manifest const pkgJsonSpec = npa.resolve(name, version) diff --git a/deps/npm/lib/commands/update.js b/deps/npm/lib/commands/update.js index 4bb74990be..a8bbc4c969 100644 --- a/deps/npm/lib/commands/update.js +++ b/deps/npm/lib/commands/update.js @@ -1,7 +1,7 @@ const path = require('path') const Arborist = require('@npmcli/arborist') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const reifyFinish = require('../utils/reify-finish.js') const completion = require('../utils/completion/installed-deep.js') @@ -47,7 +47,7 @@ class Update extends ArboristWorkspaceCmd { const arb = new Arborist({ ...this.npm.flatOptions, - log: this.npm.log, + log, path: where, workspaces: this.workspaceNames, }) diff --git a/deps/npm/lib/commands/view.js b/deps/npm/lib/commands/view.js index 105ebc16df..4f7464ddd7 100644 --- a/deps/npm/lib/commands/view.js +++ b/deps/npm/lib/commands/view.js @@ -4,7 +4,7 @@ const color = require('ansicolors') const columns = require('cli-columns') const fs = require('fs') const jsonParse = require('json-parse-even-better-errors') -const log = require('npmlog') +const log = require('../utils/log-shim.js') const npa = require('npm-package-arg') const { resolve } = require('path') const formatBytes = require('../utils/format-bytes.js') @@ -139,7 +139,7 @@ class View extends BaseCommand { const local = /^\.@/.test(pkg) || pkg === '.' if (!local) { - this.npm.log.warn('Ignoring workspaces for specified package(s)') + log.warn('Ignoring workspaces for specified package(s)') return this.exec([pkg, ...args]) } let wholePackument = false diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index ecc7f0a7de..4d22b531a4 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -1,34 +1,10 @@ const EventEmitter = require('events') const { resolve, dirname } = require('path') const Config = require('@npmcli/config') -const log = require('npmlog') // Patch the global fs module here at the app level require('graceful-fs').gracefulify(require('fs')) -// TODO make this only ever load once (or unload) in tests -const procLogListener = require('./utils/proc-log-listener.js') - -// Timers in progress -const timers = new Map() -// Finished timers -const timings = {} - -const processOnTimeHandler = name => { - timers.set(name, Date.now()) -} - -const processOnTimeEndHandler = name => { - if (timers.has(name)) { - const ms = Date.now() - timers.get(name) - log.timing(name, `Completed in ${ms}ms`) - timings[name] = ms - timers.delete(name) - } else { - log.silly('timing', "Tried to end timer that doesn't exist:", name) - } -} - const { definitions, flatten, shorthands } = require('./utils/config/index.js') const { shellouts } = require('./utils/cmd-list.js') const usage = require('./utils/npm-usage.js') @@ -36,9 +12,11 @@ const usage = require('./utils/npm-usage.js') const which = require('which') const deref = require('./utils/deref-command.js') -const setupLog = require('./utils/setup-log.js') -const cleanUpLogFiles = require('./utils/cleanup-log-files.js') -const getProjectScope = require('./utils/get-project-scope.js') +const LogFile = require('./utils/log-file.js') +const Timers = require('./utils/timers.js') +const Display = require('./utils/display.js') +const log = require('./utils/log-shim') +const replaceInfo = require('./utils/replace-info.js') let warnedNonDashArg = false const _load = Symbol('_load') @@ -51,21 +29,30 @@ class Npm extends EventEmitter { return pkg.version } + #unloaded = false + #timers = null + #logFile = null + #display = null + constructor () { super() - this.started = Date.now() this.command = null - this.timings = timings - this.timers = timers - process.on('time', processOnTimeHandler) - process.on('timeEnd', processOnTimeEndHandler) - procLogListener() - process.emit('time', 'npm') + this.#logFile = new LogFile() + this.#display = new Display() + this.#timers = new Timers({ + start: 'npm', + listener: (name, ms) => { + const args = ['timing', name, `Completed in ${ms}ms`] + this.#logFile.log(...args) + this.#display.log(...args) + }, + }) this.config = new Config({ npmPath: dirname(__dirname), definitions, flatten, shorthands, + log, }) this[_title] = process.title this.updateNotification = null @@ -118,7 +105,7 @@ class Npm extends EventEmitter { .filter(arg => /^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(arg)) .forEach(arg => { warnedNonDashArg = true - this.log.error( + log.error( 'arg', 'Argument starts with non-ascii dash, this is probably invalid:', arg @@ -165,14 +152,13 @@ class Npm extends EventEmitter { async load () { if (!this.loadPromise) { process.emit('time', 'npm:load') - this.log.pause() this.loadPromise = new Promise((resolve, reject) => { this[_load]() .catch(er => er) .then(er => { this.loadErr = er if (!er && this.config.get('force')) { - this.log.warn('using --force', 'Recommended protections disabled.') + log.warn('using --force', 'Recommended protections disabled.') } process.emit('timeEnd', 'npm:load') @@ -190,6 +176,34 @@ class Npm extends EventEmitter { return this.config.loaded } + // This gets called at the end of the exit handler and + // during any tests to cleanup all of our listeners + // Everything in here should be synchronous + unload () { + // Track if we've already unloaded so we dont + // write multiple timing files. This is only an + // issue in tests right now since we unload + // in both tap teardowns and the exit handler + if (this.#unloaded) { + return + } + this.#timers.off() + this.#display.off() + this.#logFile.off() + if (this.loaded && this.config.get('timing')) { + this.#timers.writeFile({ + command: process.argv.slice(2), + // We used to only ever report a single log file + // so to be backwards compatible report the last logfile + // XXX: remove this in npm 9 or just keep it forever + logfile: this.logFiles[this.logFiles.length - 1], + logfiles: this.logFiles, + version: this.version, + }) + } + this.#unloaded = true + } + get title () { return this[_title] } @@ -204,12 +218,12 @@ class Npm extends EventEmitter { let node try { node = which.sync(process.argv[0]) - } catch (_) { + } catch { // TODO should we throw here? } process.emit('timeEnd', 'npm:load:whichnode') if (node && node.toUpperCase() !== process.execPath.toUpperCase()) { - this.log.verbose('node symlink', node) + log.verbose('node symlink', node) process.execPath = node this.config.execPath = node } @@ -229,19 +243,35 @@ class Npm extends EventEmitter { const tokrev = deref(this.argv[0]) === 'token' && this.argv[1] === 'revoke' this.title = tokrev ? 'npm token revoke' + (this.argv[2] ? ' ***' : '') - : ['npm', ...this.argv].join(' ') + : replaceInfo(['npm', ...this.argv].join(' ')) process.emit('timeEnd', 'npm:load:setTitle') - process.emit('time', 'npm:load:setupLog') - setupLog(this.config) - process.emit('timeEnd', 'npm:load:setupLog') + process.emit('time', 'npm:load:display') + this.#display.load({ + // Use logColor since that is based on stderr + color: this.logColor, + progress: this.flatOptions.progress, + timing: this.config.get('timing'), + loglevel: this.config.get('loglevel'), + unicode: this.config.get('unicode'), + heading: this.config.get('heading'), + }) + process.emit('timeEnd', 'npm:load:display') process.env.COLOR = this.color ? '1' : '0' - process.emit('time', 'npm:load:cleanupLog') - cleanUpLogFiles(this.cache, this.config.get('logs-max'), this.log.warn) - process.emit('timeEnd', 'npm:load:cleanupLog') + process.emit('time', 'npm:load:logFile') + this.#logFile.load({ + dir: resolve(this.cache, '_logs'), + logsMax: this.config.get('logs-max'), + }) + log.verbose('logfile', this.#logFile.files[0]) + process.emit('timeEnd', 'npm:load:logFile') - this.log.resume() + process.emit('time', 'npm:load:timers') + this.#timers.load({ + dir: this.cache, + }) + process.emit('timeEnd', 'npm:load:timers') process.emit('time', 'npm:load:configScope') const configScope = this.config.get('scope') @@ -249,10 +279,6 @@ class Npm extends EventEmitter { this.config.set('scope', `@${configScope}`, this.config.find('scope')) } process.emit('timeEnd', 'npm:load:configScope') - - process.emit('time', 'npm:load:projectScope') - this.projectScope = this.config.get('scope') || getProjectScope(this.prefix) - process.emit('timeEnd', 'npm:load:projectScope') } get flatOptions () { @@ -263,18 +289,35 @@ class Npm extends EventEmitter { return flat } + // color and logColor are a special derived values that takes into + // consideration not only the config, but whether or not we are operating + // in a tty with the associated output (stdout/stderr) get color () { - // This is a special derived value that takes into consideration not only - // the config, but whether or not we are operating in a tty. return this.flatOptions.color } + get logColor () { + return this.flatOptions.logColor + } + get lockfileVersion () { return 2 } - get log () { - return log + get unfinishedTimers () { + return this.#timers.unfinished + } + + get finishedTimers () { + return this.#timers.finished + } + + get started () { + return this.#timers.started + } + + get logFiles () { + return this.#logFile.files } get cache () { @@ -352,9 +395,10 @@ class Npm extends EventEmitter { // output to stdout in a progress bar compatible way output (...msg) { - this.log.clearProgress() + log.clearProgress() + // eslint-disable-next-line no-console console.log(...msg) - this.log.showProgress() + log.showProgress() } } module.exports = Npm diff --git a/deps/npm/lib/utils/audit-error.js b/deps/npm/lib/utils/audit-error.js index b4ab26fd0c..7feccc739b 100644 --- a/deps/npm/lib/utils/audit-error.js +++ b/deps/npm/lib/utils/audit-error.js @@ -1,3 +1,5 @@ +const log = require('./log-shim') + // print an error or just nothing if the audit report has an error // this is called by the audit command, and by the reify-output util // prints a JSON version of the error if it's --json @@ -15,7 +17,7 @@ const auditError = (npm, report) => { const { error } = report // ok, we care about it, then - npm.log.warn('audit', error.message) + log.warn('audit', error.message) const { body: errBody } = error const body = Buffer.isBuffer(errBody) ? errBody.toString() : errBody if (npm.flatOptions.json) { diff --git a/deps/npm/lib/utils/cleanup-log-files.js b/deps/npm/lib/utils/cleanup-log-files.js deleted file mode 100644 index 8fb0fa1550..0000000000 --- a/deps/npm/lib/utils/cleanup-log-files.js +++ /dev/null @@ -1,35 +0,0 @@ -// module to clean out the old log files in cache/_logs -// this is a best-effort attempt. if a rm fails, we just -// log a message about it and move on. We do return a -// Promise that succeeds when we've tried to delete everything, -// just for the benefit of testing this function properly. - -const { resolve } = require('path') -const rimraf = require('rimraf') -const glob = require('glob') -module.exports = (cache, max, warn) => { - return new Promise(done => { - glob(resolve(cache, '_logs', '*-debug.log'), (er, files) => { - if (er) { - return done() - } - - let pending = files.length - max - if (pending <= 0) { - return done() - } - - for (let i = 0; i < files.length - max; i++) { - rimraf(files[i], er => { - if (er) { - warn('log', 'failed to remove log file', files[i]) - } - - if (--pending === 0) { - done() - } - }) - } - }) - }) -} diff --git a/deps/npm/lib/utils/config/definitions.js b/deps/npm/lib/utils/config/definitions.js index b47a46de85..ac8a4e2f67 100644 --- a/deps/npm/lib/utils/config/definitions.js +++ b/deps/npm/lib/utils/config/definitions.js @@ -472,7 +472,10 @@ define('color', { flatten (key, obj, flatOptions) { flatOptions.color = !obj.color ? false : obj.color === 'always' ? true - : process.stdout.isTTY + : !!process.stdout.isTTY + flatOptions.logColor = !obj.color ? false + : obj.color === 'always' ? true + : !!process.stderr.isTTY }, }) @@ -1211,8 +1214,8 @@ define('loglevel', { 'silly', ], description: ` - What level of logs to report. On failure, *all* logs are written to - \`npm-debug.log\` in the current working directory. + What level of logs to report. All logs are written to a debug log, + with the path to that file printed if the execution of a command fails. Any logs of a higher level than the setting are shown. The default is "notice". @@ -1533,6 +1536,10 @@ define('progress', { Set to \`false\` to suppress the progress bar. `, + flatten (key, obj, flatOptions) { + flatOptions.progress = !obj.progress ? false + : !!process.stderr.isTTY && process.env.TERM !== 'dumb' + }, }) define('proxy', { @@ -1681,7 +1688,7 @@ define('save-peer', { default: false, type: Boolean, description: ` - Save installed packages. to a package.json file as \`peerDependencies\` + Save installed packages to a package.json file as \`peerDependencies\` `, flatten (key, obj, flatOptions) { if (!obj[key]) { @@ -1782,7 +1789,10 @@ define('scope', { `, flatten (key, obj, flatOptions) { const value = obj[key] - flatOptions.projectScope = value && !/^@/.test(value) ? `@${value}` : value + const scope = value && !/^@/.test(value) ? `@${value}` : value + flatOptions.scope = scope + // projectScope is kept for compatibility with npm-registry-fetch + flatOptions.projectScope = scope }, }) diff --git a/deps/npm/lib/utils/deref-command.js b/deps/npm/lib/utils/deref-command.js index dd89fb5a4f..0a3c8c90bc 100644 --- a/deps/npm/lib/utils/deref-command.js +++ b/deps/npm/lib/utils/deref-command.js @@ -1,6 +1,6 @@ // de-reference abbreviations and shorthands into canonical command name -const { aliases, cmdList, plumbing } = require('../utils/cmd-list.js') +const { aliases, cmdList, plumbing } = require('./cmd-list.js') const aliasNames = Object.keys(aliases) const fullList = cmdList.concat(aliasNames).filter(c => !plumbing.includes(c)) const abbrev = require('abbrev') diff --git a/deps/npm/lib/utils/display.js b/deps/npm/lib/utils/display.js new file mode 100644 index 0000000000..aae51e8806 --- /dev/null +++ b/deps/npm/lib/utils/display.js @@ -0,0 +1,119 @@ +const { inspect } = require('util') +const npmlog = require('npmlog') +const log = require('./log-shim.js') +const { explain } = require('./explain-eresolve.js') + +const _logHandler = Symbol('logHandler') +const _eresolveWarn = Symbol('eresolveWarn') +const _log = Symbol('log') +const _npmlog = Symbol('npmlog') + +class Display { + constructor () { + // pause by default until config is loaded + this.on() + log.pause() + } + + on () { + process.on('log', this[_logHandler]) + } + + off () { + process.off('log', this[_logHandler]) + // Unbalanced calls to enable/disable progress + // will leave change listeners on the tracker + // This pretty much only happens in tests but + // this removes the event emitter listener warnings + log.tracker.removeAllListeners() + } + + load (config) { + const { + color, + timing, + loglevel, + unicode, + progress, + heading = 'npm', + } = config + + // XXX: decouple timing from loglevel + if (timing && loglevel === 'notice') { + log.level = 'timing' + } else { + log.level = loglevel + } + + log.heading = heading + + if (color) { + log.enableColor() + } else { + log.disableColor() + } + + if (unicode) { + log.enableUnicode() + } else { + log.disableUnicode() + } + + // if it's more than error, don't show progress + const silent = log.levels[log.level] > log.levels.error + if (progress && !silent) { + log.enableProgress() + } else { + log.disableProgress() + } + + // Resume displaying logs now that we have config + log.resume() + } + + log (...args) { + this[_logHandler](...args) + } + + [_logHandler] = (level, ...args) => { + try { + this[_log](level, ...args) + } catch (ex) { + try { + // if it crashed once, it might again! + this[_npmlog]('verbose', `attempt to log ${inspect(args)} crashed`, ex) + } catch (ex2) { + // eslint-disable-next-line no-console + console.error(`attempt to log ${inspect(args)} crashed`, ex, ex2) + } + } + } + + [_log] (...args) { + return this[_eresolveWarn](...args) || this[_npmlog](...args) + } + + // Explicitly call these on npmlog and not log shim + // This is the final place we should call npmlog before removing it. + [_npmlog] (level, ...args) { + npmlog[level](...args) + } + + // Also (and this is a really inexcusable kludge), we patch the + // log.warn() method so that when we see a peerDep override + // explanation from Arborist, we can replace the object with a + // highly abbreviated explanation of what's being overridden. + [_eresolveWarn] (level, heading, message, expl) { + if (level === 'warn' && + heading === 'ERESOLVE' && + expl && typeof expl === 'object' + ) { + this[_npmlog](level, heading, message) + this[_npmlog](level, '', explain(expl, log.useColor(), 2)) + // Return true to short circuit other log in chain + return true + } + } +} + +module.exports = Display diff --git a/deps/npm/lib/utils/error-message.js b/deps/npm/lib/utils/error-message.js index 48ad4676f4..4d584346d0 100644 --- a/deps/npm/lib/utils/error-message.js +++ b/deps/npm/lib/utils/error-message.js @@ -1,9 +1,9 @@ const { format } = require('util') const { resolve } = require('path') const nameValidator = require('validate-npm-package-name') -const npmlog = require('npmlog') const replaceInfo = require('./replace-info.js') const { report } = require('./explain-eresolve.js') +const log = require('./log-shim') module.exports = (er, npm) => { const short = [] @@ -20,7 +20,10 @@ module.exports = (er, npm) => { case 'ERESOLVE': short.push(['ERESOLVE', er.message]) detail.push(['', '']) - detail.push(['', report(er, npm.color, resolve(npm.cache, 'eresolve-report.txt'))]) + // XXX(display): error messages are logged so we use the logColor since that is based + // on stderr. This should be handled solely by the display layer so it could also be + // printed to stdout if necessary. + detail.push(['', report(er, !!npm.logColor, resolve(npm.cache, 'eresolve-report.txt'))]) break case 'ENOLOCK': { @@ -61,7 +64,7 @@ module.exports = (er, npm) => { if (!isWindows && (isCachePath || isCacheDest)) { // user probably doesn't need this, but still add it to the debug log - npmlog.verbose(er.stack) + log.verbose(er.stack) short.push([ '', [ diff --git a/deps/npm/lib/utils/exit-handler.js b/deps/npm/lib/utils/exit-handler.js index 5b2811468e..3243466242 100644 --- a/deps/npm/lib/utils/exit-handler.js +++ b/deps/npm/lib/utils/exit-handler.js @@ -1,119 +1,108 @@ const os = require('os') -const path = require('path') -const writeFileAtomic = require('write-file-atomic') -const mkdirp = require('mkdirp-infer-owner') -const fs = require('graceful-fs') +const log = require('./log-shim.js') const errorMessage = require('./error-message.js') const replaceInfo = require('./replace-info.js') -let exitHandlerCalled = false -let logFileName -let npm // set by the cli -let wroteLogFile = false - -const getLogFile = () => { - // we call this multiple times, so we need to treat it as a singleton because - // the date is part of the name - if (!logFileName) { - logFileName = path.resolve( - npm.config.get('cache'), - '_logs', - new Date().toISOString().replace(/[.:]/g, '_') + '-debug.log' - ) - } +const messageText = msg => msg.map(line => line.slice(1).join(' ')).join('\n') - return logFileName -} +let npm = null // set by the cli +let exitHandlerCalled = false +let showLogFileMessage = false process.on('exit', code => { + log.disableProgress() + // process.emit is synchronous, so the timeEnd handler will run before the // unfinished timer check below process.emit('timeEnd', 'npm') - npm.log.disableProgress() - for (const [name, timers] of npm.timers) { - npm.log.verbose('unfinished npm timer', name, timers) - } - if (npm.config.loaded && npm.config.get('timing')) { - try { - const file = path.resolve(npm.config.get('cache'), '_timing.json') - const dir = path.dirname(npm.config.get('cache')) - mkdirp.sync(dir) - - fs.appendFileSync( - file, - JSON.stringify({ - command: process.argv.slice(2), - logfile: getLogFile(), - version: npm.version, - ...npm.timings, - }) + '\n' - ) - - const st = fs.lstatSync(path.dirname(npm.config.get('cache'))) - fs.chownSync(dir, st.uid, st.gid) - fs.chownSync(file, st.uid, st.gid) - } catch (ex) { - // ignore + const hasNpm = !!npm + const hasLoadedNpm = hasNpm && npm.config.loaded + + // Unfinished timers can be read before config load + if (hasNpm) { + for (const [name, timer] of npm.unfinishedTimers) { + log.verbose('unfinished npm timer', name, timer) } } if (!code) { - npm.log.info('ok') + log.info('ok') } else { - npm.log.verbose('code', code) + log.verbose('code', code) } if (!exitHandlerCalled) { process.exitCode = code || 1 - npm.log.error('', 'Exit handler never called!') + log.error('', 'Exit handler never called!') console.error('') - npm.log.error('', 'This is an error with npm itself. Please report this error at:') - npm.log.error('', ' <https://github.com/npm/cli/issues>') - // TODO this doesn't have an npm.config.loaded guard - writeLogFile() + log.error('', 'This is an error with npm itself. Please report this error at:') + log.error('', ' <https://github.com/npm/cli/issues>') + showLogFileMessage = true } - // In timing mode we always write the log file - if (npm.config.loaded && npm.config.get('timing') && !wroteLogFile) { - writeLogFile() + + // In timing mode we always show the log file message + if (hasLoadedNpm && npm.config.get('timing')) { + showLogFileMessage = true } - if (wroteLogFile) { + + // npm must be loaded to know where the log file was written + if (showLogFileMessage && hasLoadedNpm) { // just a line break - if (npm.log.levels[npm.log.level] <= npm.log.levels.error) { + if (log.levels[log.level] <= log.levels.error) { console.error('') } - npm.log.error( + log.error( '', - ['A complete log of this run can be found in:', ' ' + getLogFile()].join('\n') + [ + 'A complete log of this run can be found in:', + ...npm.logFiles.map(f => ' ' + f), + ].join('\n') ) } + // This removes any listeners npm setup and writes files if necessary + // This is mostly used for tests to avoid max listener warnings + if (hasLoadedNpm) { + npm.unload() + } + // these are needed for the tests to have a clean slate in each test case exitHandlerCalled = false - wroteLogFile = false + showLogFileMessage = false }) const exitHandler = err => { - npm.log.disableProgress() - if (!npm.config.loaded) { + exitHandlerCalled = true + + log.disableProgress() + + const hasNpm = !!npm + const hasLoadedNpm = hasNpm && npm.config.loaded + + if (!hasNpm) { + err = err || new Error('Exit prior to setting npm in exit handler') + console.error(err.stack || err.message) + return process.exit(1) + } + + if (!hasLoadedNpm) { err = err || new Error('Exit prior to config file resolving.') console.error(err.stack || err.message) } // only show the notification if it finished. if (typeof npm.updateNotification === 'string') { - const { level } = npm.log - npm.log.level = 'notice' - npm.log.notice('', npm.updateNotification) - npm.log.level = level + const { level } = log + log.level = 'notice' + log.notice('', npm.updateNotification) + log.level = level } - exitHandlerCalled = true - let exitCode - let noLog + let noLogMessage if (err) { exitCode = 1 @@ -125,13 +114,13 @@ const exitHandler = err => { const quietShellout = isShellout && typeof err.code === 'number' && err.code if (quietShellout) { exitCode = err.code - noLog = true + noLogMessage = true } else if (typeof err === 'string') { - noLog = true - npm.log.error('', err) + log.error('', err) + noLogMessage = true } else if (!(err instanceof Error)) { - noLog = true - npm.log.error('weird error', err) + log.error('weird error', err) + noLogMessage = true } else { if (!err.code) { const matchErrorCode = err.message.match(/^(?:Error: )?(E[A-Z]+)/) @@ -141,31 +130,30 @@ const exitHandler = err => { for (const k of ['type', 'stack', 'statusCode', 'pkgid']) { const v = err[k] if (v) { - npm.log.verbose(k, replaceInfo(v)) + log.verbose(k, replaceInfo(v)) } } - npm.log.verbose('cwd', process.cwd()) - const args = replaceInfo(process.argv) - npm.log.verbose('', os.type() + ' ' + os.release()) - npm.log.verbose('argv', args.map(JSON.stringify).join(' ')) - npm.log.verbose('node', process.version) - npm.log.verbose('npm ', 'v' + npm.version) + log.verbose('cwd', process.cwd()) + log.verbose('', os.type() + ' ' + os.release()) + log.verbose('argv', args.map(JSON.stringify).join(' ')) + log.verbose('node', process.version) + log.verbose('npm ', 'v' + npm.version) for (const k of ['code', 'syscall', 'file', 'path', 'dest', 'errno']) { const v = err[k] if (v) { - npm.log.error(k, v) + log.error(k, v) } } const msg = errorMessage(err, npm) for (const errline of [...msg.summary, ...msg.detail]) { - npm.log.error(...errline) + log.error(...errline) } - if (npm.config.loaded && npm.config.get('json')) { + if (hasLoadedNpm && npm.config.get('json')) { const error = { error: { code: err.code, @@ -183,17 +171,12 @@ const exitHandler = err => { } } } - npm.log.verbose('exit', exitCode || 0) - if (npm.log.level === 'silent') { - noLog = true - } + log.verbose('exit', exitCode || 0) - // noLog is true if there was an error, including if config wasn't loaded, so - // this doesn't need a config.loaded guard - if (exitCode && !noLog) { - writeLogFile() - } + showLogFileMessage = log.level === 'silent' || noLogMessage + ? false + : !!exitCode // explicitly call process.exit now so we don't hang on things like the // update notifier, also flush stdout beforehand because process.exit doesn't @@ -201,42 +184,6 @@ const exitHandler = err => { process.stdout.write('', () => process.exit(exitCode)) } -const messageText = msg => msg.map(line => line.slice(1).join(' ')).join('\n') - -const writeLogFile = () => { - try { - let logOutput = '' - npm.log.record.forEach(m => { - const p = [m.id, m.level] - if (m.prefix) { - p.push(m.prefix) - } - const pref = p.join(' ') - - m.message - .trim() - .split(/\r?\n/) - .map(line => (pref + ' ' + line).trim()) - .forEach(line => { - logOutput += line + os.EOL - }) - }) - - const file = getLogFile() - const dir = path.dirname(file) - mkdirp.sync(dir) - writeFileAtomic.sync(file, logOutput) - - const st = fs.lstatSync(path.dirname(npm.config.get('cache'))) - fs.chownSync(dir, st.uid, st.gid) - fs.chownSync(file, st.uid, st.gid) - - // truncate once it's been written. - npm.log.record.length = 0 - wroteLogFile = true - } catch (ex) {} -} - module.exports = exitHandler module.exports.setNpm = n => { npm = n diff --git a/deps/npm/lib/utils/get-project-scope.js b/deps/npm/lib/utils/get-project-scope.js deleted file mode 100644 index dc1b4deba3..0000000000 --- a/deps/npm/lib/utils/get-project-scope.js +++ /dev/null @@ -1,19 +0,0 @@ -const { resolve } = require('path') -module.exports = prefix => { - try { - const { name } = require(resolve(prefix, 'package.json')) - if (!name || typeof name !== 'string') { - return '' - } - - const split = name.split('/') - if (split.length < 2) { - return '' - } - - const scope = split[0] - return /^@/.test(scope) ? scope : '' - } catch (er) { - return '' - } -} diff --git a/deps/npm/lib/utils/log-file.js b/deps/npm/lib/utils/log-file.js new file mode 100644 index 0000000000..b37fd23e07 --- /dev/null +++ b/deps/npm/lib/utils/log-file.js @@ -0,0 +1,245 @@ +const os = require('os') +const path = require('path') +const { format, promisify } = require('util') +const rimraf = promisify(require('rimraf')) +const glob = promisify(require('glob')) +const MiniPass = require('minipass') +const fsMiniPass = require('fs-minipass') +const log = require('./log-shim') +const withChownSync = require('./with-chown-sync') + +const _logHandler = Symbol('logHandler') +const _formatLogItem = Symbol('formatLogItem') +const _getLogFilePath = Symbol('getLogFilePath') +const _openLogFile = Symbol('openLogFile') +const _cleanLogs = Symbol('cleanlogs') +const _endStream = Symbol('endStream') +const _isBuffered = Symbol('isBuffered') + +class LogFiles { + // If we write multiple log files we want them all to have the same + // identifier for sorting and matching purposes + #logId = null + + // Default to a plain minipass stream so we can buffer + // initial writes before we know the cache location + #logStream = null + + // We cap log files at a certain number of log events per file. + // Note that each log event can write more than one line to the + // file. Then we rotate log files once this number of events is reached + #MAX_LOGS_PER_FILE = null + + // Now that we write logs continuously we need to have a backstop + // here for infinite loops that still log. This is also partially handled + // by the config.get('max-files') option, but this is a failsafe to + // prevent runaway log file creation + #MAX_LOG_FILES_PER_PROCESS = null + + #fileLogCount = 0 + #totalLogCount = 0 + #dir = null + #logsMax = null + #files = [] + + constructor ({ + maxLogsPerFile = 50_000, + maxFilesPerProcess = 5, + } = {}) { + this.#logId = LogFiles.logId(new Date()) + this.#MAX_LOGS_PER_FILE = maxLogsPerFile + this.#MAX_LOG_FILES_PER_PROCESS = maxFilesPerProcess + this.on() + } + + static logId (d) { + return d.toISOString().replace(/[.:]/g, '_') + } + + static fileName (prefix, suffix) { + return `${prefix}-debug-${suffix}.log` + } + + static format (count, level, title, ...args) { + let prefix = `${count} ${level}` + if (title) { + prefix += ` ${title}` + } + + return format(...args) + .split(/\r?\n/) + .reduce((lines, line) => + lines += prefix + (line ? ' ' : '') + line + os.EOL, + '' + ) + } + + on () { + this.#logStream = new MiniPass() + process.on('log', this[_logHandler]) + } + + off () { + process.off('log', this[_logHandler]) + this[_endStream]() + } + + load ({ dir, logsMax } = {}) { + this.#dir = dir + this.#logsMax = logsMax + + // Log stream has already ended + if (!this.#logStream) { + return + } + // Pipe our initial stream to our new file stream and + // set that as the new log logstream for future writes + const initialFile = this[_openLogFile]() + if (initialFile) { + this.#logStream = this.#logStream.pipe(initialFile) + } + + // Kickoff cleaning process. This is async but it wont delete + // our next log file since it deletes oldest first. Return the + // result so it can be awaited in tests + return this[_cleanLogs]() + } + + log (...args) { + this[_logHandler](...args) + } + + get files () { + return this.#files + } + + get [_isBuffered] () { + return this.#logStream instanceof MiniPass + } + + [_endStream] (output) { + if (this.#logStream) { + this.#logStream.end(output) + this.#logStream = null + } + } + + [_logHandler] = (level, ...args) => { + // Ignore pause and resume events since we + // write everything to the log file + if (level === 'pause' || level === 'resume') { + return + } + + // If the stream is ended then do nothing + if (!this.#logStream) { + return + } + + const logOutput = this[_formatLogItem](level, ...args) + + if (this[_isBuffered]) { + // Cant do anything but buffer the output if we dont + // have a file stream yet + this.#logStream.write(logOutput) + return + } + + // Open a new log file if we've written too many logs to this one + if (this.#fileLogCount >= this.#MAX_LOGS_PER_FILE) { + // Write last chunk to the file and close it + this[_endStream](logOutput) + if (this.#files.length >= this.#MAX_LOG_FILES_PER_PROCESS) { + // but if its way too many then we just stop listening + this.off() + } else { + // otherwise we are ready for a new file for the next event + this.#logStream = this[_openLogFile]() + } + } else { + this.#logStream.write(logOutput) + } + } + + [_formatLogItem] (...args) { + this.#fileLogCount += 1 + return LogFiles.format(this.#totalLogCount++, ...args) + } + + [_getLogFilePath] (prefix, suffix) { + return path.resolve(this.#dir, LogFiles.fileName(prefix, suffix)) + } + + [_openLogFile] () { + // Count in filename will be 0 indexed + const count = this.#files.length + + // Pad with zeros so that our log files are always sorted properly + // We never want to write files ending in `-9.log` and `-10.log` because + // log file cleaning is done by deleting the oldest so in this example + // `-10.log` would be deleted next + const countDigits = this.#MAX_LOG_FILES_PER_PROCESS.toString().length + + try { + const logStream = withChownSync( + this[_getLogFilePath](this.#logId, count.toString().padStart(countDigits, '0')), + // Some effort was made to make the async, but we need to write logs + // during process.on('exit') which has to be synchronous. So in order + // to never drop log messages, it is easiest to make it sync all the time + // and this was measured to be about 1.5% slower for 40k lines of output + (f) => new fsMiniPass.WriteStreamSync(f, { flags: 'a' }) + ) + if (count > 0) { + // Reset file log count if we are opening + // after our first file + this.#fileLogCount = 0 + } + this.#files.push(logStream.path) + return logStream + } catch (e) { + // XXX: do something here for errors? + // log to display only? + return null + } + } + + async [_cleanLogs] () { + // module to clean out the old log files + // this is a best-effort attempt. if a rm fails, we just + // log a message about it and move on. We do return a + // Promise that succeeds when we've tried to delete everything, + // just for the benefit of testing this function properly. + + if (typeof this.#logsMax !== 'number') { + return + } + + // Add 1 to account for the current log file and make + // minimum config 0 so current log file is never deleted + // XXX: we should make a separate documented option to + // disable log file writing + const max = Math.max(this.#logsMax, 0) + 1 + try { + const files = await glob(this[_getLogFilePath]('*', '*')) + const toDelete = files.length - max + + if (toDelete <= 0) { + return + } + + log.silly('logfile', `start cleaning logs, removing ${toDelete} files`) + + for (const file of files.slice(0, toDelete)) { + try { + await rimraf(file) + } catch (e) { + log.warn('logfile', 'error removing log file', file, e) + } + } + } catch (e) { + log.warn('logfile', 'error cleaning log files', e) + } + } +} + +module.exports = LogFiles diff --git a/deps/npm/lib/utils/log-shim.js b/deps/npm/lib/utils/log-shim.js new file mode 100644 index 0000000000..9d5a36d967 --- /dev/null +++ b/deps/npm/lib/utils/log-shim.js @@ -0,0 +1,59 @@ +const NPMLOG = require('npmlog') +const PROCLOG = require('proc-log') + +// Sets getter and optionally a setter +// otherwise setting should throw +const accessors = (obj, set) => (k) => ({ + get: () => obj[k], + set: set ? (v) => (obj[k] = v) : () => { + throw new Error(`Cant set ${k}`) + }, +}) + +// Set the value to a bound function on the object +const value = (obj) => (k) => ({ + value: (...args) => obj[k].apply(obj, args), +}) + +const properties = { + // npmlog getters/setters + level: accessors(NPMLOG, true), + heading: accessors(NPMLOG, true), + levels: accessors(NPMLOG), + gauge: accessors(NPMLOG), + stream: accessors(NPMLOG), + tracker: accessors(NPMLOG), + progressEnabled: accessors(NPMLOG), + // npmlog methods + useColor: value(NPMLOG), + enableColor: value(NPMLOG), + disableColor: value(NPMLOG), + enableUnicode: value(NPMLOG), + disableUnicode: value(NPMLOG), + enableProgress: value(NPMLOG), + disableProgress: value(NPMLOG), + clearProgress: value(NPMLOG), + showProgress: value(NPMLOG), + newItem: value(NPMLOG), + newGroup: value(NPMLOG), + // proclog methods + notice: value(PROCLOG), + error: value(PROCLOG), + warn: value(PROCLOG), + info: value(PROCLOG), + verbose: value(PROCLOG), + http: value(PROCLOG), + silly: value(PROCLOG), + pause: value(PROCLOG), + resume: value(PROCLOG), +} + +const descriptors = Object.entries(properties).reduce((acc, [k, v]) => { + acc[k] = { enumerable: true, ...v(k) } + return acc +}, {}) + +// Create an object with the allowed properties rom npm log and all +// the logging methods from proc log +// XXX: this should go away and requires of this should be replaced with proc-log + new display +module.exports = Object.freeze(Object.defineProperties({}, descriptors)) diff --git a/deps/npm/lib/utils/proc-log-listener.js b/deps/npm/lib/utils/proc-log-listener.js deleted file mode 100644 index 2cfe94ecb0..0000000000 --- a/deps/npm/lib/utils/proc-log-listener.js +++ /dev/null @@ -1,22 +0,0 @@ -const log = require('npmlog') -const { inspect } = require('util') -module.exports = () => { - process.on('log', (level, ...args) => { - try { - log[level](...args) - } catch (ex) { - try { - // if it crashed once, it might again! - log.verbose(`attempt to log ${inspect([level, ...args])} crashed`, ex) - } catch (ex2) { - console.error(`attempt to log ${inspect([level, ...args])} crashed`, ex) - } - } - }) -} - -// for tests -/* istanbul ignore next */ -module.exports.reset = () => { - process.removeAllListeners('log') -} diff --git a/deps/npm/lib/utils/pulse-till-done.js b/deps/npm/lib/utils/pulse-till-done.js index a88b8aacd8..2229414147 100644 --- a/deps/npm/lib/utils/pulse-till-done.js +++ b/deps/npm/lib/utils/pulse-till-done.js @@ -1,4 +1,4 @@ -const log = require('npmlog') +const log = require('./log-shim.js') let pulseTimer = null const withPromise = async (promise) => { diff --git a/deps/npm/lib/utils/read-user-info.js b/deps/npm/lib/utils/read-user-info.js index 993aa886f6..ac24396c6a 100644 --- a/deps/npm/lib/utils/read-user-info.js +++ b/deps/npm/lib/utils/read-user-info.js @@ -1,7 +1,7 @@ const { promisify } = require('util') const readAsync = promisify(require('read')) const userValidate = require('npm-user-validate') -const log = require('npmlog') +const log = require('./log-shim.js') exports.otp = readOTP exports.password = readPassword @@ -40,30 +40,30 @@ function readPassword (msg = passwordPrompt, password, isRetry) { .then((password) => readPassword(msg, password, true)) } -function readUsername (msg = usernamePrompt, username, opts = {}, isRetry) { +function readUsername (msg = usernamePrompt, username, isRetry) { if (isRetry && username) { const error = userValidate.username(username) if (error) { - opts.log && opts.log.warn(error.message) + log.warn(error.message) } else { return Promise.resolve(username.trim()) } } return read({ prompt: msg, default: username || '' }) - .then((username) => readUsername(msg, username, opts, true)) + .then((username) => readUsername(msg, username, true)) } -function readEmail (msg = emailPrompt, email, opts = {}, isRetry) { +function readEmail (msg = emailPrompt, email, isRetry) { if (isRetry && email) { const error = userValidate.email(email) if (error) { - opts.log && opts.log.warn(error.message) + log.warn(error.message) } else { return email.trim() } } return read({ prompt: msg, default: email || '' }) - .then((username) => readEmail(msg, username, opts, true)) + .then((username) => readEmail(msg, username, true)) } diff --git a/deps/npm/lib/utils/reify-output.js b/deps/npm/lib/utils/reify-output.js index 7741b72200..b4114c1b2f 100644 --- a/deps/npm/lib/utils/reify-output.js +++ b/deps/npm/lib/utils/reify-output.js @@ -9,7 +9,7 @@ // found 37 vulnerabilities (5 low, 7 moderate, 25 high) // run `npm audit fix` to fix them, or `npm audit` for details -const log = require('npmlog') +const log = require('./log-shim.js') const { depth } = require('treeverse') const ms = require('ms') const auditReport = require('npm-audit-report') diff --git a/deps/npm/lib/utils/setup-log.js b/deps/npm/lib/utils/setup-log.js deleted file mode 100644 index 05ca38c828..0000000000 --- a/deps/npm/lib/utils/setup-log.js +++ /dev/null @@ -1,66 +0,0 @@ -// module to set the appropriate log settings based on configs -// returns a boolean to say whether we should enable color on -// stdout or not. -// -// Also (and this is a really inexcusable kludge), we patch the -// log.warn() method so that when we see a peerDep override -// explanation from Arborist, we can replace the object with a -// highly abbreviated explanation of what's being overridden. -const log = require('npmlog') -const { explain } = require('./explain-eresolve.js') - -module.exports = (config) => { - const color = config.get('color') - - const { warn } = log - - const stdoutTTY = process.stdout.isTTY - const stderrTTY = process.stderr.isTTY - const dumbTerm = process.env.TERM === 'dumb' - const stderrNotDumb = stderrTTY && !dumbTerm - // this logic is duplicated in the config 'color' flattener - const enableColorStderr = color === 'always' ? true - : color === false ? false - : stderrTTY - - const enableColorStdout = color === 'always' ? true - : color === false ? false - : stdoutTTY - - log.warn = (heading, ...args) => { - if (heading === 'ERESOLVE' && args[1] && typeof args[1] === 'object') { - warn(heading, args[0]) - return warn('', explain(args[1], enableColorStdout, 2)) - } - return warn(heading, ...args) - } - - if (config.get('timing') && config.get('loglevel') === 'notice') { - log.level = 'timing' - } else { - log.level = config.get('loglevel') - } - - log.heading = config.get('heading') || 'npm' - - if (enableColorStderr) { - log.enableColor() - } else { - log.disableColor() - } - - if (config.get('unicode')) { - log.enableUnicode() - } else { - log.disableUnicode() - } - - // if it's more than error, don't show progress - const quiet = log.levels[log.level] > log.levels.error - - if (config.get('progress') && stderrNotDumb && !quiet) { - log.enableProgress() - } else { - log.disableProgress() - } -} diff --git a/deps/npm/lib/utils/tar.js b/deps/npm/lib/utils/tar.js index 26e7a98df6..2f2773c6d4 100644 --- a/deps/npm/lib/utils/tar.js +++ b/deps/npm/lib/utils/tar.js @@ -1,6 +1,6 @@ const tar = require('tar') const ssri = require('ssri') -const npmlog = require('npmlog') +const log = require('./log-shim') const formatBytes = require('./format-bytes.js') const columnify = require('columnify') const localeCompare = require('@isaacs/string-locale-compare')('en', { @@ -9,7 +9,7 @@ const localeCompare = require('@isaacs/string-locale-compare')('en', { }) const logTar = (tarball, opts = {}) => { - const { unicode = false, log = npmlog } = opts + const { unicode = false } = opts log.notice('') log.notice('', `${unicode ? '📦 ' : 'package:'} ${tarball.name}@${tarball.version}`) log.notice('=== Tarball Contents ===') diff --git a/deps/npm/lib/utils/timers.js b/deps/npm/lib/utils/timers.js new file mode 100644 index 0000000000..acff29eb05 --- /dev/null +++ b/deps/npm/lib/utils/timers.js @@ -0,0 +1,111 @@ +const EE = require('events') +const path = require('path') +const fs = require('graceful-fs') +const log = require('./log-shim') +const withChownSync = require('./with-chown-sync.js') + +const _timeListener = Symbol('timeListener') +const _timeEndListener = Symbol('timeEndListener') +const _init = Symbol('init') + +// This is an event emiiter but on/off +// only listen on a single internal event that gets +// emitted whenever a timer ends +class Timers extends EE { + #unfinished = new Map() + #finished = {} + #onTimeEnd = Symbol('onTimeEnd') + #dir = null + #initialListener = null + #initialTimer = null + + constructor ({ listener = null, start = 'npm' } = {}) { + super() + this.#initialListener = listener + this.#initialTimer = start + this[_init]() + } + + get unfinished () { + return this.#unfinished + } + + get finished () { + return this.#finished + } + + [_init] () { + this.on() + if (this.#initialListener) { + this.on(this.#initialListener) + } + process.emit('time', this.#initialTimer) + this.started = this.#unfinished.get(this.#initialTimer) + } + + on (listener) { + if (listener) { + super.on(this.#onTimeEnd, listener) + } else { + process.on('time', this[_timeListener]) + process.on('timeEnd', this[_timeEndListener]) + } + } + + off (listener) { + if (listener) { + super.off(this.#onTimeEnd, listener) + } else { + this.removeAllListeners(this.#onTimeEnd) + process.off('time', this[_timeListener]) + process.off('timeEnd', this[_timeEndListener]) + } + } + + load ({ dir }) { + this.#dir = dir + } + + writeFile (fileData) { + try { + const globalStart = this.started + const globalEnd = this.#finished.npm || Date.now() + const content = { + ...fileData, + ...this.#finished, + // add any unfinished timers with their relative start/end + unfinished: [...this.#unfinished.entries()].reduce((acc, [name, start]) => { + acc[name] = [start - globalStart, globalEnd - globalStart] + return acc + }, {}), + } + withChownSync( + path.resolve(this.#dir, '_timing.json'), + (f) => + // we append line delimited json to this file...forever + // XXX: should we also write a process specific timing file? + // with similar rules to the debug log (max files, etc) + fs.appendFileSync(f, JSON.stringify(content) + '\n') + ) + } catch (e) { + log.warn('timing', 'could not write timing file', e) + } + } + + [_timeListener] = (name) => { + this.#unfinished.set(name, Date.now()) + } + + [_timeEndListener] = (name) => { + if (this.#unfinished.has(name)) { + const ms = Date.now() - this.#unfinished.get(name) + this.#finished[name] = ms + this.#unfinished.delete(name) + this.emit(this.#onTimeEnd, name, ms) + } else { + log.silly('timing', "Tried to end timer that doesn't exist:", name) + } + } +} + +module.exports = Timers diff --git a/deps/npm/lib/utils/unsupported.js b/deps/npm/lib/utils/unsupported.js index 5f6a341a83..75aad5e780 100644 --- a/deps/npm/lib/utils/unsupported.js +++ b/deps/npm/lib/utils/unsupported.js @@ -1,7 +1,14 @@ +/* eslint-disable no-console */ const semver = require('semver') const supported = require('../../package.json').engines.node const knownBroken = '<6.2.0 || 9 <9.3.0' +// Keep this file compatible with all practical versions of node +// so we dont get syntax errors when trying to give the users +// a nice error message. Don't use our log handler because +// if we encounter a syntax error early on, that will never +// get displayed to the user. + const checkVersion = exports.checkVersion = version => { const versionNoPrerelease = version.replace(/-.*$/, '') return { @@ -24,10 +31,9 @@ exports.checkForBrokenNode = () => { exports.checkForUnsupportedNode = () => { const nodejs = checkVersion(process.version) if (nodejs.unsupported) { - const log = require('npmlog') - log.warn('npm', 'npm does not support Node.js ' + process.version) - log.warn('npm', 'You should probably upgrade to a newer version of node as we') - log.warn('npm', "can't make any promises that npm will work with this version.") - log.warn('npm', 'You can find the latest version at https://nodejs.org/') + console.error('npm does not support Node.js ' + process.version) + console.error('You should probably upgrade to a newer version of node as we') + console.error("can't make any promises that npm will work with this version.") + console.error('You can find the latest version at https://nodejs.org/') } } diff --git a/deps/npm/lib/utils/update-notifier.js b/deps/npm/lib/utils/update-notifier.js index 2b45d54c81..44b6a5433c 100644 --- a/deps/npm/lib/utils/update-notifier.js +++ b/deps/npm/lib/utils/update-notifier.js @@ -10,6 +10,7 @@ const { promisify } = require('util') const stat = promisify(require('fs').stat) const writeFile = promisify(require('fs').writeFile) const { resolve } = require('path') +const log = require('./log-shim.js') const isGlobalNpmUpdate = npm => { return npm.flatOptions.global && @@ -61,7 +62,7 @@ const updateNotifier = async (npm, spec = 'latest') => { // if they're currently using a prerelease, nudge to the next prerelease // otherwise, nudge to latest. - const useColor = npm.log.useColor() + const useColor = log.useColor() const mani = await pacote.manifest(`npm@${spec}`, { // always prefer latest, even if doing --tag=whatever on the cmd diff --git a/deps/npm/lib/utils/usage.js b/deps/npm/lib/utils/usage.js index e23e50c51c..39eaa45e41 100644 --- a/deps/npm/lib/utils/usage.js +++ b/deps/npm/lib/utils/usage.js @@ -1,4 +1,4 @@ -const aliases = require('../utils/cmd-list').aliases +const aliases = require('./cmd-list').aliases module.exports = function usage (cmd, txt, opt) { const post = Object.keys(aliases).reduce(function (p, c) { diff --git a/deps/npm/lib/utils/with-chown-sync.js b/deps/npm/lib/utils/with-chown-sync.js new file mode 100644 index 0000000000..481b5696dd --- /dev/null +++ b/deps/npm/lib/utils/with-chown-sync.js @@ -0,0 +1,13 @@ +const mkdirp = require('mkdirp-infer-owner') +const fs = require('graceful-fs') +const path = require('path') + +module.exports = (file, method) => { + const dir = path.dirname(file) + mkdirp.sync(dir) + const result = method(file) + const st = fs.lstatSync(dir) + fs.chownSync(dir, st.uid, st.gid) + fs.chownSync(file, st.uid, st.gid) + return result +} diff --git a/deps/npm/man/man1/npm-access.1 b/deps/npm/man/man1/npm-access.1 index 6ee369df5a..e6786f2a04 100644 --- a/deps/npm/man/man1/npm-access.1 +++ b/deps/npm/man/man1/npm-access.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ACCESS" "1" "November 2021" "" "" +.TH "NPM\-ACCESS" "1" "December 2021" "" "" .SH "NAME" \fBnpm-access\fR \- Set access level on published packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-adduser.1 b/deps/npm/man/man1/npm-adduser.1 index 10d035f753..859088196e 100644 --- a/deps/npm/man/man1/npm-adduser.1 +++ b/deps/npm/man/man1/npm-adduser.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ADDUSER" "1" "November 2021" "" "" +.TH "NPM\-ADDUSER" "1" "December 2021" "" "" .SH "NAME" \fBnpm-adduser\fR \- Add a registry user account .SS Synopsis diff --git a/deps/npm/man/man1/npm-audit.1 b/deps/npm/man/man1/npm-audit.1 index 4f2c25c675..9279f1f6e8 100644 --- a/deps/npm/man/man1/npm-audit.1 +++ b/deps/npm/man/man1/npm-audit.1 @@ -1,4 +1,4 @@ -.TH "NPM\-AUDIT" "1" "November 2021" "" "" +.TH "NPM\-AUDIT" "1" "December 2021" "" "" .SH "NAME" \fBnpm-audit\fR \- Run a security audit .SS Synopsis diff --git a/deps/npm/man/man1/npm-bin.1 b/deps/npm/man/man1/npm-bin.1 index 927373bc4b..fa1abc087e 100644 --- a/deps/npm/man/man1/npm-bin.1 +++ b/deps/npm/man/man1/npm-bin.1 @@ -1,4 +1,4 @@ -.TH "NPM\-BIN" "1" "November 2021" "" "" +.TH "NPM\-BIN" "1" "December 2021" "" "" .SH "NAME" \fBnpm-bin\fR \- Display npm bin folder .SS Synopsis diff --git a/deps/npm/man/man1/npm-bugs.1 b/deps/npm/man/man1/npm-bugs.1 index 2356611d4c..857b78727a 100644 --- a/deps/npm/man/man1/npm-bugs.1 +++ b/deps/npm/man/man1/npm-bugs.1 @@ -1,4 +1,4 @@ -.TH "NPM\-BUGS" "1" "November 2021" "" "" +.TH "NPM\-BUGS" "1" "December 2021" "" "" .SH "NAME" \fBnpm-bugs\fR \- Report bugs for a package in a web browser .SS Synopsis diff --git a/deps/npm/man/man1/npm-cache.1 b/deps/npm/man/man1/npm-cache.1 index 1f93ecf7e5..0ae5e8251e 100644 --- a/deps/npm/man/man1/npm-cache.1 +++ b/deps/npm/man/man1/npm-cache.1 @@ -1,4 +1,4 @@ -.TH "NPM\-CACHE" "1" "November 2021" "" "" +.TH "NPM\-CACHE" "1" "December 2021" "" "" .SH "NAME" \fBnpm-cache\fR \- Manipulates packages cache .SS Synopsis diff --git a/deps/npm/man/man1/npm-ci.1 b/deps/npm/man/man1/npm-ci.1 index 9e9951fbbf..fdd6edbdc0 100644 --- a/deps/npm/man/man1/npm-ci.1 +++ b/deps/npm/man/man1/npm-ci.1 @@ -1,4 +1,4 @@ -.TH "NPM\-CI" "1" "November 2021" "" "" +.TH "NPM\-CI" "1" "December 2021" "" "" .SH "NAME" \fBnpm-ci\fR \- Install a project with a clean slate .SS Synopsis diff --git a/deps/npm/man/man1/npm-completion.1 b/deps/npm/man/man1/npm-completion.1 index c79b8b0d88..93b7785ec9 100644 --- a/deps/npm/man/man1/npm-completion.1 +++ b/deps/npm/man/man1/npm-completion.1 @@ -1,4 +1,4 @@ -.TH "NPM\-COMPLETION" "1" "November 2021" "" "" +.TH "NPM\-COMPLETION" "1" "December 2021" "" "" .SH "NAME" \fBnpm-completion\fR \- Tab Completion for npm .SS Synopsis diff --git a/deps/npm/man/man1/npm-config.1 b/deps/npm/man/man1/npm-config.1 index 87b2e4082b..8b667c03d9 100644 --- a/deps/npm/man/man1/npm-config.1 +++ b/deps/npm/man/man1/npm-config.1 @@ -1,4 +1,4 @@ -.TH "NPM\-CONFIG" "1" "November 2021" "" "" +.TH "NPM\-CONFIG" "1" "December 2021" "" "" .SH "NAME" \fBnpm-config\fR \- Manage the npm configuration files .SS Synopsis diff --git a/deps/npm/man/man1/npm-dedupe.1 b/deps/npm/man/man1/npm-dedupe.1 index e619784485..dff883b827 100644 --- a/deps/npm/man/man1/npm-dedupe.1 +++ b/deps/npm/man/man1/npm-dedupe.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DEDUPE" "1" "November 2021" "" "" +.TH "NPM\-DEDUPE" "1" "December 2021" "" "" .SH "NAME" \fBnpm-dedupe\fR \- Reduce duplication in the package tree .SS Synopsis diff --git a/deps/npm/man/man1/npm-deprecate.1 b/deps/npm/man/man1/npm-deprecate.1 index a4eb24c0be..f83b46a156 100644 --- a/deps/npm/man/man1/npm-deprecate.1 +++ b/deps/npm/man/man1/npm-deprecate.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DEPRECATE" "1" "November 2021" "" "" +.TH "NPM\-DEPRECATE" "1" "December 2021" "" "" .SH "NAME" \fBnpm-deprecate\fR \- Deprecate a version of a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-diff.1 b/deps/npm/man/man1/npm-diff.1 index 74e801df1e..e730b597a6 100644 --- a/deps/npm/man/man1/npm-diff.1 +++ b/deps/npm/man/man1/npm-diff.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DIFF" "1" "November 2021" "" "" +.TH "NPM\-DIFF" "1" "December 2021" "" "" .SH "NAME" \fBnpm-diff\fR \- The registry diff command .SS Synopsis diff --git a/deps/npm/man/man1/npm-dist-tag.1 b/deps/npm/man/man1/npm-dist-tag.1 index 5d52da1d13..e2bd3c0e28 100644 --- a/deps/npm/man/man1/npm-dist-tag.1 +++ b/deps/npm/man/man1/npm-dist-tag.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DIST\-TAG" "1" "November 2021" "" "" +.TH "NPM\-DIST\-TAG" "1" "December 2021" "" "" .SH "NAME" \fBnpm-dist-tag\fR \- Modify package distribution tags .SS Synopsis diff --git a/deps/npm/man/man1/npm-docs.1 b/deps/npm/man/man1/npm-docs.1 index edbeef32a4..d0f2ce82c2 100644 --- a/deps/npm/man/man1/npm-docs.1 +++ b/deps/npm/man/man1/npm-docs.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DOCS" "1" "November 2021" "" "" +.TH "NPM\-DOCS" "1" "December 2021" "" "" .SH "NAME" \fBnpm-docs\fR \- Open documentation for a package in a web browser .SS Synopsis diff --git a/deps/npm/man/man1/npm-doctor.1 b/deps/npm/man/man1/npm-doctor.1 index 9c371ff0cc..3b863eddab 100644 --- a/deps/npm/man/man1/npm-doctor.1 +++ b/deps/npm/man/man1/npm-doctor.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DOCTOR" "1" "November 2021" "" "" +.TH "NPM\-DOCTOR" "1" "December 2021" "" "" .SH "NAME" \fBnpm-doctor\fR \- Check your npm environment .SS Synopsis diff --git a/deps/npm/man/man1/npm-edit.1 b/deps/npm/man/man1/npm-edit.1 index b8b0404eb5..4d3bf1711d 100644 --- a/deps/npm/man/man1/npm-edit.1 +++ b/deps/npm/man/man1/npm-edit.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EDIT" "1" "November 2021" "" "" +.TH "NPM\-EDIT" "1" "December 2021" "" "" .SH "NAME" \fBnpm-edit\fR \- Edit an installed package .SS Synopsis diff --git a/deps/npm/man/man1/npm-exec.1 b/deps/npm/man/man1/npm-exec.1 index 6d6100c15d..545d799306 100644 --- a/deps/npm/man/man1/npm-exec.1 +++ b/deps/npm/man/man1/npm-exec.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EXEC" "1" "November 2021" "" "" +.TH "NPM\-EXEC" "1" "December 2021" "" "" .SH "NAME" \fBnpm-exec\fR \- Run a command from a local or remote npm package .SS Synopsis diff --git a/deps/npm/man/man1/npm-explain.1 b/deps/npm/man/man1/npm-explain.1 index 239c988cf5..91a66ff3f5 100644 --- a/deps/npm/man/man1/npm-explain.1 +++ b/deps/npm/man/man1/npm-explain.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EXPLAIN" "1" "November 2021" "" "" +.TH "NPM\-EXPLAIN" "1" "December 2021" "" "" .SH "NAME" \fBnpm-explain\fR \- Explain installed packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-explore.1 b/deps/npm/man/man1/npm-explore.1 index 8f0097241d..79e4e5a7df 100644 --- a/deps/npm/man/man1/npm-explore.1 +++ b/deps/npm/man/man1/npm-explore.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EXPLORE" "1" "November 2021" "" "" +.TH "NPM\-EXPLORE" "1" "December 2021" "" "" .SH "NAME" \fBnpm-explore\fR \- Browse an installed package .SS Synopsis diff --git a/deps/npm/man/man1/npm-find-dupes.1 b/deps/npm/man/man1/npm-find-dupes.1 index 49fff29263..bd157ab7fd 100644 --- a/deps/npm/man/man1/npm-find-dupes.1 +++ b/deps/npm/man/man1/npm-find-dupes.1 @@ -1,4 +1,4 @@ -.TH "NPM\-FIND\-DUPES" "1" "November 2021" "" "" +.TH "NPM\-FIND\-DUPES" "1" "December 2021" "" "" .SH "NAME" \fBnpm-find-dupes\fR \- Find duplication in the package tree .SS Synopsis diff --git a/deps/npm/man/man1/npm-fund.1 b/deps/npm/man/man1/npm-fund.1 index de01552c76..488dd168c6 100644 --- a/deps/npm/man/man1/npm-fund.1 +++ b/deps/npm/man/man1/npm-fund.1 @@ -1,4 +1,4 @@ -.TH "NPM\-FUND" "1" "November 2021" "" "" +.TH "NPM\-FUND" "1" "December 2021" "" "" .SH "NAME" \fBnpm-fund\fR \- Retrieve funding information .SS Synopsis diff --git a/deps/npm/man/man1/npm-help-search.1 b/deps/npm/man/man1/npm-help-search.1 index 12ee237f06..8566e38185 100644 --- a/deps/npm/man/man1/npm-help-search.1 +++ b/deps/npm/man/man1/npm-help-search.1 @@ -1,4 +1,4 @@ -.TH "NPM\-HELP\-SEARCH" "1" "November 2021" "" "" +.TH "NPM\-HELP\-SEARCH" "1" "December 2021" "" "" .SH "NAME" \fBnpm-help-search\fR \- Search npm help documentation .SS Synopsis diff --git a/deps/npm/man/man1/npm-help.1 b/deps/npm/man/man1/npm-help.1 index aa62e72ac0..260a253fed 100644 --- a/deps/npm/man/man1/npm-help.1 +++ b/deps/npm/man/man1/npm-help.1 @@ -1,4 +1,4 @@ -.TH "NPM\-HELP" "1" "November 2021" "" "" +.TH "NPM\-HELP" "1" "December 2021" "" "" .SH "NAME" \fBnpm-help\fR \- Get help on npm .SS Synopsis diff --git a/deps/npm/man/man1/npm-hook.1 b/deps/npm/man/man1/npm-hook.1 index 8ebd352d87..609604155b 100644 --- a/deps/npm/man/man1/npm-hook.1 +++ b/deps/npm/man/man1/npm-hook.1 @@ -1,4 +1,4 @@ -.TH "NPM\-HOOK" "1" "November 2021" "" "" +.TH "NPM\-HOOK" "1" "December 2021" "" "" .SH "NAME" \fBnpm-hook\fR \- Manage registry hooks .SS Synopsis diff --git a/deps/npm/man/man1/npm-init.1 b/deps/npm/man/man1/npm-init.1 index 65108e2c07..8119ff10fd 100644 --- a/deps/npm/man/man1/npm-init.1 +++ b/deps/npm/man/man1/npm-init.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INIT" "1" "November 2021" "" "" +.TH "NPM\-INIT" "1" "December 2021" "" "" .SH "NAME" \fBnpm-init\fR \- Create a package\.json file .SS Synopsis diff --git a/deps/npm/man/man1/npm-install-ci-test.1 b/deps/npm/man/man1/npm-install-ci-test.1 index df9f22e7da..5b2e09cf1c 100644 --- a/deps/npm/man/man1/npm-install-ci-test.1 +++ b/deps/npm/man/man1/npm-install-ci-test.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INSTALL\-CI\-TEST" "1" "November 2021" "" "" +.TH "NPM\-INSTALL\-CI\-TEST" "1" "December 2021" "" "" .SH "NAME" \fBnpm-install-ci-test\fR \- Install a project with a clean slate and run tests .SS Synopsis diff --git a/deps/npm/man/man1/npm-install-test.1 b/deps/npm/man/man1/npm-install-test.1 index 7250721f6d..451ae94e87 100644 --- a/deps/npm/man/man1/npm-install-test.1 +++ b/deps/npm/man/man1/npm-install-test.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INSTALL\-TEST" "1" "November 2021" "" "" +.TH "NPM\-INSTALL\-TEST" "1" "December 2021" "" "" .SH "NAME" \fBnpm-install-test\fR \- Install package(s) and run tests .SS Synopsis diff --git a/deps/npm/man/man1/npm-install.1 b/deps/npm/man/man1/npm-install.1 index 7f0c422ded..cf93650b30 100644 --- a/deps/npm/man/man1/npm-install.1 +++ b/deps/npm/man/man1/npm-install.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INSTALL" "1" "November 2021" "" "" +.TH "NPM\-INSTALL" "1" "December 2021" "" "" .SH "NAME" \fBnpm-install\fR \- Install a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-link.1 b/deps/npm/man/man1/npm-link.1 index 83700438ce..b15ac7bce6 100644 --- a/deps/npm/man/man1/npm-link.1 +++ b/deps/npm/man/man1/npm-link.1 @@ -1,4 +1,4 @@ -.TH "NPM\-LINK" "1" "November 2021" "" "" +.TH "NPM\-LINK" "1" "December 2021" "" "" .SH "NAME" \fBnpm-link\fR \- Symlink a package folder .SS Synopsis diff --git a/deps/npm/man/man1/npm-logout.1 b/deps/npm/man/man1/npm-logout.1 index a9f0ebe55e..17534e845f 100644 --- a/deps/npm/man/man1/npm-logout.1 +++ b/deps/npm/man/man1/npm-logout.1 @@ -1,4 +1,4 @@ -.TH "NPM\-LOGOUT" "1" "November 2021" "" "" +.TH "NPM\-LOGOUT" "1" "December 2021" "" "" .SH "NAME" \fBnpm-logout\fR \- Log out of the registry .SS Synopsis diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1 index 784b338ec9..5320cc51fb 100644 --- a/deps/npm/man/man1/npm-ls.1 +++ b/deps/npm/man/man1/npm-ls.1 @@ -1,4 +1,4 @@ -.TH "NPM\-LS" "1" "November 2021" "" "" +.TH "NPM\-LS" "1" "December 2021" "" "" .SH "NAME" \fBnpm-ls\fR \- List installed packages .SS Synopsis @@ -26,7 +26,7 @@ example, running \fBnpm ls promzard\fP in npm's source tree will show: .P .RS 2 .nf -npm@8\.1\.4 /path/to/npm +npm@8\.2\.0 /path/to/npm └─┬ init\-package\-json@0\.0\.4 └── promzard@0\.1\.5 .fi diff --git a/deps/npm/man/man1/npm-org.1 b/deps/npm/man/man1/npm-org.1 index c92d90a759..3ca826bd6c 100644 --- a/deps/npm/man/man1/npm-org.1 +++ b/deps/npm/man/man1/npm-org.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ORG" "1" "November 2021" "" "" +.TH "NPM\-ORG" "1" "December 2021" "" "" .SH "NAME" \fBnpm-org\fR \- Manage orgs .SS Synopsis diff --git a/deps/npm/man/man1/npm-outdated.1 b/deps/npm/man/man1/npm-outdated.1 index 6477c2ea0d..e596e77c34 100644 --- a/deps/npm/man/man1/npm-outdated.1 +++ b/deps/npm/man/man1/npm-outdated.1 @@ -1,4 +1,4 @@ -.TH "NPM\-OUTDATED" "1" "November 2021" "" "" +.TH "NPM\-OUTDATED" "1" "December 2021" "" "" .SH "NAME" \fBnpm-outdated\fR \- Check for outdated packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-owner.1 b/deps/npm/man/man1/npm-owner.1 index a7d6b45b74..289d67a668 100644 --- a/deps/npm/man/man1/npm-owner.1 +++ b/deps/npm/man/man1/npm-owner.1 @@ -1,4 +1,4 @@ -.TH "NPM\-OWNER" "1" "November 2021" "" "" +.TH "NPM\-OWNER" "1" "December 2021" "" "" .SH "NAME" \fBnpm-owner\fR \- Manage package owners .SS Synopsis diff --git a/deps/npm/man/man1/npm-pack.1 b/deps/npm/man/man1/npm-pack.1 index 13bc733666..42ab2fa74f 100644 --- a/deps/npm/man/man1/npm-pack.1 +++ b/deps/npm/man/man1/npm-pack.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PACK" "1" "November 2021" "" "" +.TH "NPM\-PACK" "1" "December 2021" "" "" .SH "NAME" \fBnpm-pack\fR \- Create a tarball from a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-ping.1 b/deps/npm/man/man1/npm-ping.1 index 75db070280..885cbd837d 100644 --- a/deps/npm/man/man1/npm-ping.1 +++ b/deps/npm/man/man1/npm-ping.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PING" "1" "November 2021" "" "" +.TH "NPM\-PING" "1" "December 2021" "" "" .SH "NAME" \fBnpm-ping\fR \- Ping npm registry .SS Synopsis diff --git a/deps/npm/man/man1/npm-pkg.1 b/deps/npm/man/man1/npm-pkg.1 index aaa37abe84..dcb6a8bb4d 100644 --- a/deps/npm/man/man1/npm-pkg.1 +++ b/deps/npm/man/man1/npm-pkg.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PKG" "1" "November 2021" "" "" +.TH "NPM\-PKG" "1" "December 2021" "" "" .SH "NAME" \fBnpm-pkg\fR \- Manages your package\.json .SS Synopsis diff --git a/deps/npm/man/man1/npm-prefix.1 b/deps/npm/man/man1/npm-prefix.1 index f986f28c75..259b85e7ee 100644 --- a/deps/npm/man/man1/npm-prefix.1 +++ b/deps/npm/man/man1/npm-prefix.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PREFIX" "1" "November 2021" "" "" +.TH "NPM\-PREFIX" "1" "December 2021" "" "" .SH "NAME" \fBnpm-prefix\fR \- Display prefix .SS Synopsis diff --git a/deps/npm/man/man1/npm-profile.1 b/deps/npm/man/man1/npm-profile.1 index e3a365ecd1..176afb69c2 100644 --- a/deps/npm/man/man1/npm-profile.1 +++ b/deps/npm/man/man1/npm-profile.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PROFILE" "1" "November 2021" "" "" +.TH "NPM\-PROFILE" "1" "December 2021" "" "" .SH "NAME" \fBnpm-profile\fR \- Change settings on your registry profile .SS Synopsis diff --git a/deps/npm/man/man1/npm-prune.1 b/deps/npm/man/man1/npm-prune.1 index 4fb47b337b..54204593ff 100644 --- a/deps/npm/man/man1/npm-prune.1 +++ b/deps/npm/man/man1/npm-prune.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PRUNE" "1" "November 2021" "" "" +.TH "NPM\-PRUNE" "1" "December 2021" "" "" .SH "NAME" \fBnpm-prune\fR \- Remove extraneous packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-publish.1 b/deps/npm/man/man1/npm-publish.1 index 6657ee20e5..ca9a3041bf 100644 --- a/deps/npm/man/man1/npm-publish.1 +++ b/deps/npm/man/man1/npm-publish.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PUBLISH" "1" "November 2021" "" "" +.TH "NPM\-PUBLISH" "1" "December 2021" "" "" .SH "NAME" \fBnpm-publish\fR \- Publish a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-rebuild.1 b/deps/npm/man/man1/npm-rebuild.1 index 1f5ecab8dd..5b0e96d04b 100644 --- a/deps/npm/man/man1/npm-rebuild.1 +++ b/deps/npm/man/man1/npm-rebuild.1 @@ -1,4 +1,4 @@ -.TH "NPM\-REBUILD" "1" "November 2021" "" "" +.TH "NPM\-REBUILD" "1" "December 2021" "" "" .SH "NAME" \fBnpm-rebuild\fR \- Rebuild a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-repo.1 b/deps/npm/man/man1/npm-repo.1 index e763152ac8..178816429a 100644 --- a/deps/npm/man/man1/npm-repo.1 +++ b/deps/npm/man/man1/npm-repo.1 @@ -1,4 +1,4 @@ -.TH "NPM\-REPO" "1" "November 2021" "" "" +.TH "NPM\-REPO" "1" "December 2021" "" "" .SH "NAME" \fBnpm-repo\fR \- Open package repository page in the browser .SS Synopsis diff --git a/deps/npm/man/man1/npm-restart.1 b/deps/npm/man/man1/npm-restart.1 index d113d2fdb6..37060c2b6f 100644 --- a/deps/npm/man/man1/npm-restart.1 +++ b/deps/npm/man/man1/npm-restart.1 @@ -1,4 +1,4 @@ -.TH "NPM\-RESTART" "1" "November 2021" "" "" +.TH "NPM\-RESTART" "1" "December 2021" "" "" .SH "NAME" \fBnpm-restart\fR \- Restart a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-root.1 b/deps/npm/man/man1/npm-root.1 index 24b6a36e23..9ac47bbeb3 100644 --- a/deps/npm/man/man1/npm-root.1 +++ b/deps/npm/man/man1/npm-root.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ROOT" "1" "November 2021" "" "" +.TH "NPM\-ROOT" "1" "December 2021" "" "" .SH "NAME" \fBnpm-root\fR \- Display npm root .SS Synopsis diff --git a/deps/npm/man/man1/npm-run-script.1 b/deps/npm/man/man1/npm-run-script.1 index da566d33f2..22b80dbf02 100644 --- a/deps/npm/man/man1/npm-run-script.1 +++ b/deps/npm/man/man1/npm-run-script.1 @@ -1,4 +1,4 @@ -.TH "NPM\-RUN\-SCRIPT" "1" "November 2021" "" "" +.TH "NPM\-RUN\-SCRIPT" "1" "December 2021" "" "" .SH "NAME" \fBnpm-run-script\fR \- Run arbitrary package scripts .SS Synopsis diff --git a/deps/npm/man/man1/npm-search.1 b/deps/npm/man/man1/npm-search.1 index 281ad48c3f..5b16ae5bab 100644 --- a/deps/npm/man/man1/npm-search.1 +++ b/deps/npm/man/man1/npm-search.1 @@ -1,4 +1,4 @@ -.TH "NPM\-SEARCH" "1" "November 2021" "" "" +.TH "NPM\-SEARCH" "1" "December 2021" "" "" .SH "NAME" \fBnpm-search\fR \- Search for packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-set-script.1 b/deps/npm/man/man1/npm-set-script.1 index 453a2ccec6..960d5d81fa 100644 --- a/deps/npm/man/man1/npm-set-script.1 +++ b/deps/npm/man/man1/npm-set-script.1 @@ -1,4 +1,4 @@ -.TH "NPM\-SET\-SCRIPT" "1" "November 2021" "" "" +.TH "NPM\-SET\-SCRIPT" "1" "December 2021" "" "" .SH "NAME" \fBnpm-set-script\fR \- Set tasks in the scripts section of package\.json .SS Synopsis diff --git a/deps/npm/man/man1/npm-shrinkwrap.1 b/deps/npm/man/man1/npm-shrinkwrap.1 index 793c13d6d7..166ec5da10 100644 --- a/deps/npm/man/man1/npm-shrinkwrap.1 +++ b/deps/npm/man/man1/npm-shrinkwrap.1 @@ -1,4 +1,4 @@ -.TH "NPM\-SHRINKWRAP" "1" "November 2021" "" "" +.TH "NPM\-SHRINKWRAP" "1" "December 2021" "" "" .SH "NAME" \fBnpm-shrinkwrap\fR \- Lock down dependency versions for publication .SS Synopsis diff --git a/deps/npm/man/man1/npm-star.1 b/deps/npm/man/man1/npm-star.1 index ed2cb43004..7b580abec8 100644 --- a/deps/npm/man/man1/npm-star.1 +++ b/deps/npm/man/man1/npm-star.1 @@ -1,4 +1,4 @@ -.TH "NPM\-STAR" "1" "November 2021" "" "" +.TH "NPM\-STAR" "1" "December 2021" "" "" .SH "NAME" \fBnpm-star\fR \- Mark your favorite packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-stars.1 b/deps/npm/man/man1/npm-stars.1 index 93221b69d1..3cf9bdc96e 100644 --- a/deps/npm/man/man1/npm-stars.1 +++ b/deps/npm/man/man1/npm-stars.1 @@ -1,4 +1,4 @@ -.TH "NPM\-STARS" "1" "November 2021" "" "" +.TH "NPM\-STARS" "1" "December 2021" "" "" .SH "NAME" \fBnpm-stars\fR \- View packages marked as favorites .SS Synopsis diff --git a/deps/npm/man/man1/npm-start.1 b/deps/npm/man/man1/npm-start.1 index ca5d0490ed..66b9a935ff 100644 --- a/deps/npm/man/man1/npm-start.1 +++ b/deps/npm/man/man1/npm-start.1 @@ -1,4 +1,4 @@ -.TH "NPM\-START" "1" "November 2021" "" "" +.TH "NPM\-START" "1" "December 2021" "" "" .SH "NAME" \fBnpm-start\fR \- Start a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-stop.1 b/deps/npm/man/man1/npm-stop.1 index ff301333aa..daf293986b 100644 --- a/deps/npm/man/man1/npm-stop.1 +++ b/deps/npm/man/man1/npm-stop.1 @@ -1,4 +1,4 @@ -.TH "NPM\-STOP" "1" "November 2021" "" "" +.TH "NPM\-STOP" "1" "December 2021" "" "" .SH "NAME" \fBnpm-stop\fR \- Stop a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-team.1 b/deps/npm/man/man1/npm-team.1 index 97e06883db..a75060f1b2 100644 --- a/deps/npm/man/man1/npm-team.1 +++ b/deps/npm/man/man1/npm-team.1 @@ -1,4 +1,4 @@ -.TH "NPM\-TEAM" "1" "November 2021" "" "" +.TH "NPM\-TEAM" "1" "December 2021" "" "" .SH "NAME" \fBnpm-team\fR \- Manage organization teams and team memberships .SS Synopsis diff --git a/deps/npm/man/man1/npm-test.1 b/deps/npm/man/man1/npm-test.1 index abff79323a..44e0d716c8 100644 --- a/deps/npm/man/man1/npm-test.1 +++ b/deps/npm/man/man1/npm-test.1 @@ -1,4 +1,4 @@ -.TH "NPM\-TEST" "1" "November 2021" "" "" +.TH "NPM\-TEST" "1" "December 2021" "" "" .SH "NAME" \fBnpm-test\fR \- Test a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-token.1 b/deps/npm/man/man1/npm-token.1 index 99476c0ce1..a1ff1bc883 100644 --- a/deps/npm/man/man1/npm-token.1 +++ b/deps/npm/man/man1/npm-token.1 @@ -1,4 +1,4 @@ -.TH "NPM\-TOKEN" "1" "November 2021" "" "" +.TH "NPM\-TOKEN" "1" "December 2021" "" "" .SH "NAME" \fBnpm-token\fR \- Manage your authentication tokens .SS Synopsis diff --git a/deps/npm/man/man1/npm-uninstall.1 b/deps/npm/man/man1/npm-uninstall.1 index 16af51f32e..f1015a4174 100644 --- a/deps/npm/man/man1/npm-uninstall.1 +++ b/deps/npm/man/man1/npm-uninstall.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UNINSTALL" "1" "November 2021" "" "" +.TH "NPM\-UNINSTALL" "1" "December 2021" "" "" .SH "NAME" \fBnpm-uninstall\fR \- Remove a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-unpublish.1 b/deps/npm/man/man1/npm-unpublish.1 index 8d3b3e0298..052d7ef4c4 100644 --- a/deps/npm/man/man1/npm-unpublish.1 +++ b/deps/npm/man/man1/npm-unpublish.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UNPUBLISH" "1" "November 2021" "" "" +.TH "NPM\-UNPUBLISH" "1" "December 2021" "" "" .SH "NAME" \fBnpm-unpublish\fR \- Remove a package from the registry .SS Synopsis diff --git a/deps/npm/man/man1/npm-unstar.1 b/deps/npm/man/man1/npm-unstar.1 index c61a8a5bd5..ef9fe6e386 100644 --- a/deps/npm/man/man1/npm-unstar.1 +++ b/deps/npm/man/man1/npm-unstar.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UNSTAR" "1" "November 2021" "" "" +.TH "NPM\-UNSTAR" "1" "December 2021" "" "" .SH "NAME" \fBnpm-unstar\fR \- Remove an item from your favorite packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-update.1 b/deps/npm/man/man1/npm-update.1 index 800b69de2d..4188dda6b1 100644 --- a/deps/npm/man/man1/npm-update.1 +++ b/deps/npm/man/man1/npm-update.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UPDATE" "1" "November 2021" "" "" +.TH "NPM\-UPDATE" "1" "December 2021" "" "" .SH "NAME" \fBnpm-update\fR \- Update packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-version.1 b/deps/npm/man/man1/npm-version.1 index ebe993deb5..73fcf0bdfa 100644 --- a/deps/npm/man/man1/npm-version.1 +++ b/deps/npm/man/man1/npm-version.1 @@ -1,4 +1,4 @@ -.TH "NPM\-VERSION" "1" "November 2021" "" "" +.TH "NPM\-VERSION" "1" "December 2021" "" "" .SH "NAME" \fBnpm-version\fR \- Bump a package version .SS Synopsis diff --git a/deps/npm/man/man1/npm-view.1 b/deps/npm/man/man1/npm-view.1 index 5af03df4b3..4ff00fa934 100644 --- a/deps/npm/man/man1/npm-view.1 +++ b/deps/npm/man/man1/npm-view.1 @@ -1,4 +1,4 @@ -.TH "NPM\-VIEW" "1" "November 2021" "" "" +.TH "NPM\-VIEW" "1" "December 2021" "" "" .SH "NAME" \fBnpm-view\fR \- View registry info .SS Synopsis diff --git a/deps/npm/man/man1/npm-whoami.1 b/deps/npm/man/man1/npm-whoami.1 index e3c7524455..bd3aea36aa 100644 --- a/deps/npm/man/man1/npm-whoami.1 +++ b/deps/npm/man/man1/npm-whoami.1 @@ -1,4 +1,4 @@ -.TH "NPM\-WHOAMI" "1" "November 2021" "" "" +.TH "NPM\-WHOAMI" "1" "December 2021" "" "" .SH "NAME" \fBnpm-whoami\fR \- Display npm username .SS Synopsis diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1 index 5bd83235ff..bddb695d55 100644 --- a/deps/npm/man/man1/npm.1 +++ b/deps/npm/man/man1/npm.1 @@ -1,4 +1,4 @@ -.TH "NPM" "1" "November 2021" "" "" +.TH "NPM" "1" "December 2021" "" "" .SH "NAME" \fBnpm\fR \- javascript package manager .SS Synopsis @@ -10,7 +10,7 @@ npm <command> [args] .RE .SS Version .P -8\.1\.4 +8\.2\.0 .SS Description .P npm is the package manager for the Node JavaScript platform\. It puts diff --git a/deps/npm/man/man1/npx.1 b/deps/npm/man/man1/npx.1 index 46c9be0529..f210e94f09 100644 --- a/deps/npm/man/man1/npx.1 +++ b/deps/npm/man/man1/npx.1 @@ -1,4 +1,4 @@ -.TH "NPX" "1" "November 2021" "" "" +.TH "NPX" "1" "December 2021" "" "" .SH "NAME" \fBnpx\fR \- Run a command from a local or remote npm package .SS Synopsis diff --git a/deps/npm/man/man5/folders.5 b/deps/npm/man/man5/folders.5 index 859e3b38bf..7b0161242f 100644 --- a/deps/npm/man/man5/folders.5 +++ b/deps/npm/man/man5/folders.5 @@ -1,4 +1,4 @@ -.TH "FOLDERS" "5" "November 2021" "" "" +.TH "FOLDERS" "5" "December 2021" "" "" .SH "NAME" \fBfolders\fR \- Folder Structures Used by npm .SS Description diff --git a/deps/npm/man/man5/install.5 b/deps/npm/man/man5/install.5 index 99a90dcaaf..1879e6557f 100644 --- a/deps/npm/man/man5/install.5 +++ b/deps/npm/man/man5/install.5 @@ -1,4 +1,4 @@ -.TH "INSTALL" "5" "November 2021" "" "" +.TH "INSTALL" "5" "December 2021" "" "" .SH "NAME" \fBinstall\fR \- Download and install node and npm .SS Description diff --git a/deps/npm/man/man5/npm-shrinkwrap-json.5 b/deps/npm/man/man5/npm-shrinkwrap-json.5 index 9fdb54c6b1..05f6cf4fd8 100644 --- a/deps/npm/man/man5/npm-shrinkwrap-json.5 +++ b/deps/npm/man/man5/npm-shrinkwrap-json.5 @@ -1,4 +1,4 @@ -.TH "NPM\-SHRINKWRAP\.JSON" "5" "November 2021" "" "" +.TH "NPM\-SHRINKWRAP\.JSON" "5" "December 2021" "" "" .SH "NAME" \fBnpm-shrinkwrap.json\fR \- A publishable lockfile .SS Description diff --git a/deps/npm/man/man5/npmrc.5 b/deps/npm/man/man5/npmrc.5 index 60c03a8c14..33f011e795 100644 --- a/deps/npm/man/man5/npmrc.5 +++ b/deps/npm/man/man5/npmrc.5 @@ -1,4 +1,4 @@ -.TH "NPMRC" "5" "November 2021" "" "" +.TH "NPMRC" "5" "December 2021" "" "" .SH "NAME" \fBnpmrc\fR \- The npm config files .SS Description diff --git a/deps/npm/man/man5/package-json.5 b/deps/npm/man/man5/package-json.5 index 857d564953..6f38ff876b 100644 --- a/deps/npm/man/man5/package-json.5 +++ b/deps/npm/man/man5/package-json.5 @@ -1,4 +1,4 @@ -.TH "PACKAGE\.JSON" "5" "November 2021" "" "" +.TH "PACKAGE\.JSON" "5" "December 2021" "" "" .SH "NAME" \fBpackage.json\fR \- Specifics of npm's package\.json handling .SS Description diff --git a/deps/npm/man/man5/package-lock-json.5 b/deps/npm/man/man5/package-lock-json.5 index 8544d70b71..22cccd59d3 100644 --- a/deps/npm/man/man5/package-lock-json.5 +++ b/deps/npm/man/man5/package-lock-json.5 @@ -1,4 +1,4 @@ -.TH "PACKAGE\-LOCK\.JSON" "5" "November 2021" "" "" +.TH "PACKAGE\-LOCK\.JSON" "5" "December 2021" "" "" .SH "NAME" \fBpackage-lock.json\fR \- A manifestation of the manifest .SS Description diff --git a/deps/npm/man/man7/config.7 b/deps/npm/man/man7/config.7 index 2157f70cce..c366ec1bef 100644 --- a/deps/npm/man/man7/config.7 +++ b/deps/npm/man/man7/config.7 @@ -1,4 +1,4 @@ -.TH "CONFIG" "7" "November 2021" "" "" +.TH "CONFIG" "7" "December 2021" "" "" .SH "NAME" \fBconfig\fR \- More than you probably want to know about npm configuration .SS Description @@ -1286,8 +1286,8 @@ Type: "silent", "error", "warn", "notice", "http", "timing", "info", .RE .P -What level of logs to report\. On failure, \fIall\fR logs are written to -\fBnpm\-debug\.log\fP in the current working directory\. +What level of logs to report\. All logs are written to a debug log, with the +path to that file printed if the execution of a command fails\. .P Any logs of a higher level than the setting are shown\. The default is "notice"\. @@ -1752,7 +1752,7 @@ Type: Boolean .RE .P -Save installed packages\. to a package\.json file as \fBpeerDependencies\fP +Save installed packages to a package\.json file as \fBpeerDependencies\fP <!\-\- automatically generated, do not edit manually \-\-> <!\-\- see lib/utils/config/definitions\.js \-\-> diff --git a/deps/npm/man/man7/developers.7 b/deps/npm/man/man7/developers.7 index 9461ca9fc8..017beab9da 100644 --- a/deps/npm/man/man7/developers.7 +++ b/deps/npm/man/man7/developers.7 @@ -1,4 +1,4 @@ -.TH "DEVELOPERS" "7" "November 2021" "" "" +.TH "DEVELOPERS" "7" "December 2021" "" "" .SH "NAME" \fBdevelopers\fR \- Developer Guide .SS Description diff --git a/deps/npm/man/man7/logging.7 b/deps/npm/man/man7/logging.7 new file mode 100644 index 0000000000..9098c38849 --- /dev/null +++ b/deps/npm/man/man7/logging.7 @@ -0,0 +1,74 @@ +.TH "LOGGING" "7" "December 2021" "" "" +.SH "NAME" +\fBLogging\fR \- Why, What & How we Log +.SS Description +.P +The \fBnpm\fP CLI has various mechanisms for showing different levels of information back to end\-users for certain commands, configurations & environments\. +.SS Setting Log Levels +.SS \fBloglevel\fP +.P +\fBloglevel\fP is a global argument/config that can be set to determine the type of information to be displayed\. +.P +The default value of \fBloglevel\fP is \fB"notice"\fP but there are several levels/types of logs available, including: +.RS 0 +.IP \(bu 2 +\fB"silent"\fP +.IP \(bu 2 +\fB"error"\fP +.IP \(bu 2 +\fB"warn"\fP +.IP \(bu 2 +\fB"notice"\fP +.IP \(bu 2 +\fB"http"\fP +.IP \(bu 2 +\fB"timing"\fP +.IP \(bu 2 +\fB"info"\fP +.IP \(bu 2 +\fB"verbose"\fP +.IP \(bu 2 +\fB"silly"\fP + +.RE +.P +All logs pertaining to a level proceeding the current setting will be shown\. +.P +All logs are written to a debug log, with the path to that file printed if the execution of a command fails\. +.SS Aliases +.P +The log levels listed above have various corresponding aliases, including: +.RS 0 +.IP \(bu 2 +\fB\-d\fP: \fB\-\-loglevel info\fP +.IP \(bu 2 +\fB\-\-dd\fP: \fB\-\-loglevel verbose\fP +.IP \(bu 2 +\fB\-\-verbose\fP: \fB\-\-loglevel verbose\fP +.IP \(bu 2 +\fB\-\-ddd\fP: \fB\-\-loglevel silly\fP +.IP \(bu 2 +\fB\-q\fP: \fB\-\-loglevel warn\fP +.IP \(bu 2 +\fB\-\-quiet\fP: \fB\-\-loglevel warn\fP +.IP \(bu 2 +\fB\-s\fP: \fB\-\-loglevel silent\fP +.IP \(bu 2 +\fB\-\-silent\fP: \fB\-\-loglevel silent\fP + +.RE +.SS \fBforeground\-scripts\fP +.P +The \fBnpm\fP CLI began hiding the output of lifecycle scripts for \fBnpm install\fP as of \fBv7\fP\|\. Notably, this means you will not see logs/output from packages that may be using "install scripts" to display information back to you or from your own project's scripts defined in \fBpackage\.json\fP\|\. If you'd like to change this behavior & log this output you can set \fBforeground\-scripts\fP to \fBtrue\fP\|\. +.SS Registry Response Headers +.SS \fBnpm\-notice\fP +.P +The \fBnpm\fP CLI reads from & logs any \fBnpm\-notice\fP headers that are returned from the configured registry\. This mechanism can be used by third\-party registries to provide useful information when network\-dependent requests occur\. +.P +This header is not cached, and will not be logged if the request is served from the cache\. +.SS See also +.RS 0 +.IP \(bu 2 +npm help config + +.RE diff --git a/deps/npm/man/man7/orgs.7 b/deps/npm/man/man7/orgs.7 index a6664a1dac..32941be2f6 100644 --- a/deps/npm/man/man7/orgs.7 +++ b/deps/npm/man/man7/orgs.7 @@ -1,4 +1,4 @@ -.TH "ORGS" "7" "November 2021" "" "" +.TH "ORGS" "7" "December 2021" "" "" .SH "NAME" \fBorgs\fR \- Working with Teams & Orgs .SS Description diff --git a/deps/npm/man/man7/registry.7 b/deps/npm/man/man7/registry.7 index 6b46806bf0..3f5a28edcd 100644 --- a/deps/npm/man/man7/registry.7 +++ b/deps/npm/man/man7/registry.7 @@ -1,4 +1,4 @@ -.TH "REGISTRY" "7" "November 2021" "" "" +.TH "REGISTRY" "7" "December 2021" "" "" .SH "NAME" \fBregistry\fR \- The JavaScript Package Registry .SS Description diff --git a/deps/npm/man/man7/removal.7 b/deps/npm/man/man7/removal.7 index 24d66dfa92..daf2873184 100644 --- a/deps/npm/man/man7/removal.7 +++ b/deps/npm/man/man7/removal.7 @@ -1,4 +1,4 @@ -.TH "REMOVAL" "7" "November 2021" "" "" +.TH "REMOVAL" "7" "December 2021" "" "" .SH "NAME" \fBremoval\fR \- Cleaning the Slate .SS Synopsis diff --git a/deps/npm/man/man7/scope.7 b/deps/npm/man/man7/scope.7 index f5fa03206b..d4702277a7 100644 --- a/deps/npm/man/man7/scope.7 +++ b/deps/npm/man/man7/scope.7 @@ -1,4 +1,4 @@ -.TH "SCOPE" "7" "November 2021" "" "" +.TH "SCOPE" "7" "December 2021" "" "" .SH "NAME" \fBscope\fR \- Scoped packages .SS Description diff --git a/deps/npm/man/man7/scripts.7 b/deps/npm/man/man7/scripts.7 index 9d1659eeee..2c121b1f4a 100644 --- a/deps/npm/man/man7/scripts.7 +++ b/deps/npm/man/man7/scripts.7 @@ -1,4 +1,4 @@ -.TH "SCRIPTS" "7" "November 2021" "" "" +.TH "SCRIPTS" "7" "December 2021" "" "" .SH "NAME" \fBscripts\fR \- How npm handles the "scripts" field .SS Description @@ -351,7 +351,7 @@ package\.json file, then your package scripts would have the in your code with \fBprocess\.env\.npm_package_name\fP and \fBprocess\.env\.npm_package_version\fP, and so on for other fields\. .P -See npm help \fBpackage\-json\.md\fP for more on package configs\. +See npm help \fBpackage\.json\fP for more on package configs\. .SS current lifecycle event .P Lastly, the \fBnpm_lifecycle_event\fP environment variable is set to diff --git a/deps/npm/man/man7/workspaces.7 b/deps/npm/man/man7/workspaces.7 index c72ae28b11..c809092741 100644 --- a/deps/npm/man/man7/workspaces.7 +++ b/deps/npm/man/man7/workspaces.7 @@ -1,11 +1,11 @@ -.TH "WORKSPACES" "7" "November 2021" "" "" +.TH "WORKSPACES" "7" "December 2021" "" "" .SH "NAME" \fBworkspaces\fR \- Working with workspaces .SS Description .P \fBWorkspaces\fR is a generic term that refers to the set of features in the npm cli that provides support to managing multiple packages from your local -files system from within a singular top\-level, root package\. +file system from within a singular top\-level, root package\. .P This set of features makes up for a much more streamlined workflow handling linked packages from the local file system\. Automating the linking process diff --git a/deps/npm/node_modules/@npmcli/config/lib/index.js b/deps/npm/node_modules/@npmcli/config/lib/index.js index 724ce14c38..e52f7a14f7 100644 --- a/deps/npm/node_modules/@npmcli/config/lib/index.js +++ b/deps/npm/node_modules/@npmcli/config/lib/index.js @@ -497,15 +497,17 @@ class Config { } async loadProjectConfig () { + // the localPrefix can be set by the CLI config, but otherwise is + // found by walking up the folder tree. either way, we load it before + // we return to make sure localPrefix is set + await this.loadLocalPrefix() + if (this[_get]('global') === true || this[_get]('location') === 'global') { this.data.get('project').source = '(global mode enabled, ignored)' this.sources.set(this.data.get('project').source, 'project') return } - // the localPrefix can be set by the CLI config, but otherwise is - // found by walking up the folder tree - await this.loadLocalPrefix() const projectFile = resolve(this.localPrefix, '.npmrc') // if we're in the ~ directory, and there happens to be a node_modules // folder (which is not TOO uncommon, it turns out), then we can end diff --git a/deps/npm/node_modules/@npmcli/config/package.json b/deps/npm/node_modules/@npmcli/config/package.json index f36d8f7b11..299202ec2d 100644 --- a/deps/npm/node_modules/@npmcli/config/package.json +++ b/deps/npm/node_modules/@npmcli/config/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/config", - "version": "2.3.1", + "version": "2.3.2", "files": [ "lib" ], diff --git a/deps/npm/node_modules/are-we-there-yet/package.json b/deps/npm/node_modules/are-we-there-yet/package.json index d3901a86d6..5714e09c3b 100644 --- a/deps/npm/node_modules/are-we-there-yet/package.json +++ b/deps/npm/node_modules/are-we-there-yet/package.json @@ -1,6 +1,6 @@ { "name": "are-we-there-yet", - "version": "1.1.6", + "version": "2.0.0", "description": "Keep track of the overall completion of many disparate processes", "main": "lib/index.js", "scripts": { diff --git a/deps/npm/node_modules/code-point-at/index.js b/deps/npm/node_modules/code-point-at/index.js deleted file mode 100644 index 0432fe6a30..0000000000 --- a/deps/npm/node_modules/code-point-at/index.js +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable babel/new-cap, xo/throw-new-error */ -'use strict'; -module.exports = function (str, pos) { - if (str === null || str === undefined) { - throw TypeError(); - } - - str = String(str); - - var size = str.length; - var i = pos ? Number(pos) : 0; - - if (Number.isNaN(i)) { - i = 0; - } - - if (i < 0 || i >= size) { - return undefined; - } - - var first = str.charCodeAt(i); - - if (first >= 0xD800 && first <= 0xDBFF && size > i + 1) { - var second = str.charCodeAt(i + 1); - - if (second >= 0xDC00 && second <= 0xDFFF) { - return ((first - 0xD800) * 0x400) + second - 0xDC00 + 0x10000; - } - } - - return first; -}; diff --git a/deps/npm/node_modules/code-point-at/license b/deps/npm/node_modules/code-point-at/license deleted file mode 100644 index 654d0bfe94..0000000000 --- a/deps/npm/node_modules/code-point-at/license +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/deps/npm/node_modules/code-point-at/package.json b/deps/npm/node_modules/code-point-at/package.json deleted file mode 100644 index c5907a5078..0000000000 --- a/deps/npm/node_modules/code-point-at/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "code-point-at", - "version": "1.1.0", - "description": "ES2015 `String#codePointAt()` ponyfill", - "license": "MIT", - "repository": "sindresorhus/code-point-at", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "xo && ava" - }, - "files": [ - "index.js" - ], - "keywords": [ - "es2015", - "ponyfill", - "polyfill", - "shim", - "string", - "str", - "code", - "point", - "at", - "codepoint", - "unicode" - ], - "devDependencies": { - "ava": "*", - "xo": "^0.16.0" - } -} diff --git a/deps/npm/node_modules/code-point-at/readme.md b/deps/npm/node_modules/code-point-at/readme.md deleted file mode 100644 index 4c97730e69..0000000000 --- a/deps/npm/node_modules/code-point-at/readme.md +++ /dev/null @@ -1,32 +0,0 @@ -# code-point-at [![Build Status](https://travis-ci.org/sindresorhus/code-point-at.svg?branch=master)](https://travis-ci.org/sindresorhus/code-point-at) - -> ES2015 [`String#codePointAt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) [ponyfill](https://ponyfill.com) - - -## Install - -``` -$ npm install --save code-point-at -``` - - -## Usage - -```js -var codePointAt = require('code-point-at'); - -codePointAt('🐴'); -//=> 128052 - -codePointAt('abc', 2); -//=> 99 -``` - -## API - -### codePointAt(input, [position]) - - -## License - -MIT © [Sindre Sorhus](https://sindresorhus.com) diff --git a/deps/npm/node_modules/node-gyp/CHANGELOG.md b/deps/npm/node_modules/node-gyp/CHANGELOG.md index e5d1a4d065..1e54fd69a6 100644 --- a/deps/npm/node_modules/node-gyp/CHANGELOG.md +++ b/deps/npm/node_modules/node-gyp/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +### [8.4.1](https://www.github.com/nodejs/node-gyp/compare/v8.4.0...v8.4.1) (2021-11-19) + + +### Bug Fixes + +* windows command missing space ([#2553](https://www.github.com/nodejs/node-gyp/issues/2553)) ([cc37b88](https://www.github.com/nodejs/node-gyp/commit/cc37b880690706d3c5d04d5a68c76c392a0a23ed)) + + +### Doc + +* fix typo in powershell node-gyp update ([787cf7f](https://www.github.com/nodejs/node-gyp/commit/787cf7f8e5ddd5039e02b64ace6b7b15e06fe0a4)) + + +### Core + +* npmlog@6.0.0 ([8083f6b](https://www.github.com/nodejs/node-gyp/commit/8083f6b855bd7f3326af04c5f5269fc28d7f2508)) + ## [8.4.0](https://www.github.com/nodejs/node-gyp/compare/v8.3.0...v8.4.0) (2021-11-05) diff --git a/deps/npm/node_modules/node-gyp/docs/Updating-npm-bundled-node-gyp.md b/deps/npm/node_modules/node-gyp/docs/Updating-npm-bundled-node-gyp.md index 01ad5642b2..0777687c22 100644 --- a/deps/npm/node_modules/node-gyp/docs/Updating-npm-bundled-node-gyp.md +++ b/deps/npm/node_modules/node-gyp/docs/Updating-npm-bundled-node-gyp.md @@ -27,13 +27,13 @@ npm config set node_gyp $(npm prefix -g)/lib/node_modules/node-gyp/bin/node-gyp. ### Windows Command Prompt ``` npm install --global node-gyp@latest -for /f "delims=" %P in ('npm prefix -g') do npm config set node_gyp"%P\node_modules\node-gyp\bin\node-gyp.js" +for /f "delims=" %P in ('npm prefix -g') do npm config set node_gyp "%P\node_modules\node-gyp\bin\node-gyp.js" ``` ### Powershell ``` npm install --global node-gyp@latest -npm prefix -g | % {npm config set node_gyp "$_\node_modules\node-gyp\bin\node-gypjs"} +npm prefix -g | % {npm config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"} ``` ## Undo diff --git a/deps/npm/node_modules/node-gyp/node_modules/aproba/LICENSE b/deps/npm/node_modules/node-gyp/node_modules/aproba/LICENSE deleted file mode 100644 index 2a4982dc40..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/aproba/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (c) 2015, Rebecca Turner <me@re-becca.org> - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/deps/npm/node_modules/node-gyp/node_modules/aproba/index.js b/deps/npm/node_modules/node-gyp/node_modules/aproba/index.js deleted file mode 100644 index 6f3f797c09..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/aproba/index.js +++ /dev/null @@ -1,105 +0,0 @@ -'use strict' - -function isArguments (thingy) { - return thingy != null && typeof thingy === 'object' && thingy.hasOwnProperty('callee') -} - -var types = { - '*': {label: 'any', check: function () { return true }}, - A: {label: 'array', check: function (thingy) { return Array.isArray(thingy) || isArguments(thingy) }}, - S: {label: 'string', check: function (thingy) { return typeof thingy === 'string' }}, - N: {label: 'number', check: function (thingy) { return typeof thingy === 'number' }}, - F: {label: 'function', check: function (thingy) { return typeof thingy === 'function' }}, - O: {label: 'object', check: function (thingy) { return typeof thingy === 'object' && thingy != null && !types.A.check(thingy) && !types.E.check(thingy) }}, - B: {label: 'boolean', check: function (thingy) { return typeof thingy === 'boolean' }}, - E: {label: 'error', check: function (thingy) { return thingy instanceof Error }}, - Z: {label: 'null', check: function (thingy) { return thingy == null }} -} - -function addSchema (schema, arity) { - var group = arity[schema.length] = arity[schema.length] || [] - if (group.indexOf(schema) === -1) group.push(schema) -} - -var validate = module.exports = function (rawSchemas, args) { - if (arguments.length !== 2) throw wrongNumberOfArgs(['SA'], arguments.length) - if (!rawSchemas) throw missingRequiredArg(0, 'rawSchemas') - if (!args) throw missingRequiredArg(1, 'args') - if (!types.S.check(rawSchemas)) throw invalidType(0, ['string'], rawSchemas) - if (!types.A.check(args)) throw invalidType(1, ['array'], args) - var schemas = rawSchemas.split('|') - var arity = {} - - schemas.forEach(function (schema) { - for (var ii = 0; ii < schema.length; ++ii) { - var type = schema[ii] - if (!types[type]) throw unknownType(ii, type) - } - if (/E.*E/.test(schema)) throw moreThanOneError(schema) - addSchema(schema, arity) - if (/E/.test(schema)) { - addSchema(schema.replace(/E.*$/, 'E'), arity) - addSchema(schema.replace(/E/, 'Z'), arity) - if (schema.length === 1) addSchema('', arity) - } - }) - var matching = arity[args.length] - if (!matching) { - throw wrongNumberOfArgs(Object.keys(arity), args.length) - } - for (var ii = 0; ii < args.length; ++ii) { - var newMatching = matching.filter(function (schema) { - var type = schema[ii] - var typeCheck = types[type].check - return typeCheck(args[ii]) - }) - if (!newMatching.length) { - var labels = matching.map(function (schema) { - return types[schema[ii]].label - }).filter(function (schema) { return schema != null }) - throw invalidType(ii, labels, args[ii]) - } - matching = newMatching - } -} - -function missingRequiredArg (num) { - return newException('EMISSINGARG', 'Missing required argument #' + (num + 1)) -} - -function unknownType (num, type) { - return newException('EUNKNOWNTYPE', 'Unknown type ' + type + ' in argument #' + (num + 1)) -} - -function invalidType (num, expectedTypes, value) { - var valueType - Object.keys(types).forEach(function (typeCode) { - if (types[typeCode].check(value)) valueType = types[typeCode].label - }) - return newException('EINVALIDTYPE', 'Argument #' + (num + 1) + ': Expected ' + - englishList(expectedTypes) + ' but got ' + valueType) -} - -function englishList (list) { - return list.join(', ').replace(/, ([^,]+)$/, ' or $1') -} - -function wrongNumberOfArgs (expected, got) { - var english = englishList(expected) - var args = expected.every(function (ex) { return ex.length === 1 }) - ? 'argument' - : 'arguments' - return newException('EWRONGARGCOUNT', 'Expected ' + english + ' ' + args + ' but got ' + got) -} - -function moreThanOneError (schema) { - return newException('ETOOMANYERRORTYPES', - 'Only one error type per argument signature is allowed, more than one found in "' + schema + '"') -} - -function newException (code, msg) { - var e = new Error(msg) - e.code = code - if (Error.captureStackTrace) Error.captureStackTrace(e, validate) - return e -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/aproba/package.json b/deps/npm/node_modules/node-gyp/node_modules/aproba/package.json deleted file mode 100644 index f008787bc2..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/aproba/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "aproba", - "version": "1.2.0", - "description": "A ridiculously light-weight argument validator (now browser friendly)", - "main": "index.js", - "directories": { - "test": "test" - }, - "dependencies": {}, - "devDependencies": { - "standard": "^10.0.3", - "tap": "^10.0.2" - }, - "files": [ - "index.js" - ], - "scripts": { - "test": "standard && tap -j3 test/*.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/iarna/aproba" - }, - "keywords": [ - "argument", - "validate" - ], - "author": "Rebecca Turner <me@re-becca.org>", - "license": "ISC", - "bugs": { - "url": "https://github.com/iarna/aproba/issues" - }, - "homepage": "https://github.com/iarna/aproba" -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/LICENSE b/deps/npm/node_modules/node-gyp/node_modules/gauge/LICENSE deleted file mode 100644 index e756052969..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (c) 2014, Rebecca Turner <me@re-becca.org> - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/base-theme.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/base-theme.js deleted file mode 100644 index 0b67638e02..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/base-theme.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict' -var spin = require('./spin.js') -var progressBar = require('./progress-bar.js') - -module.exports = { - activityIndicator: function (values, theme, width) { - if (values.spun == null) return - return spin(theme, values.spun) - }, - progressbar: function (values, theme, width) { - if (values.completed == null) return - return progressBar(theme, width, values.completed) - } -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/error.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/error.js deleted file mode 100644 index d9914ba533..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/error.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict' -var util = require('util') - -var User = exports.User = function User (msg) { - var err = new Error(msg) - Error.captureStackTrace(err, User) - err.code = 'EGAUGE' - return err -} - -exports.MissingTemplateValue = function MissingTemplateValue (item, values) { - var err = new User(util.format('Missing template value "%s"', item.type)) - Error.captureStackTrace(err, MissingTemplateValue) - err.template = item - err.values = values - return err -} - -exports.Internal = function Internal (msg) { - var err = new Error(msg) - Error.captureStackTrace(err, Internal) - err.code = 'EGAUGEINTERNAL' - return err -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/has-color.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/has-color.js deleted file mode 100644 index e283a256f2..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/has-color.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' - -module.exports = isWin32() || isColorTerm() - -function isWin32 () { - return process.platform === 'win32' -} - -function isColorTerm () { - var termHasColor = /^screen|^xterm|^vt100|color|ansi|cygwin|linux/i - return !!process.env.COLORTERM || termHasColor.test(process.env.TERM) -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/index.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/index.js deleted file mode 100644 index c55324008c..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/index.js +++ /dev/null @@ -1,233 +0,0 @@ -'use strict' -var Plumbing = require('./plumbing.js') -var hasUnicode = require('has-unicode') -var hasColor = require('./has-color.js') -var onExit = require('signal-exit') -var defaultThemes = require('./themes') -var setInterval = require('./set-interval.js') -var process = require('./process.js') -var setImmediate = require('./set-immediate') - -module.exports = Gauge - -function callWith (obj, method) { - return function () { - return method.call(obj) - } -} - -function Gauge (arg1, arg2) { - var options, writeTo - if (arg1 && arg1.write) { - writeTo = arg1 - options = arg2 || {} - } else if (arg2 && arg2.write) { - writeTo = arg2 - options = arg1 || {} - } else { - writeTo = process.stderr - options = arg1 || arg2 || {} - } - - this._status = { - spun: 0, - section: '', - subsection: '' - } - this._paused = false // are we paused for back pressure? - this._disabled = true // are all progress bar updates disabled? - this._showing = false // do we WANT the progress bar on screen - this._onScreen = false // IS the progress bar on screen - this._needsRedraw = false // should we print something at next tick? - this._hideCursor = options.hideCursor == null ? true : options.hideCursor - this._fixedFramerate = options.fixedFramerate == null - ? !(/^v0\.8\./.test(process.version)) - : options.fixedFramerate - this._lastUpdateAt = null - this._updateInterval = options.updateInterval == null ? 50 : options.updateInterval - - this._themes = options.themes || defaultThemes - this._theme = options.theme - var theme = this._computeTheme(options.theme) - var template = options.template || [ - {type: 'progressbar', length: 20}, - {type: 'activityIndicator', kerning: 1, length: 1}, - {type: 'section', kerning: 1, default: ''}, - {type: 'subsection', kerning: 1, default: ''} - ] - this.setWriteTo(writeTo, options.tty) - var PlumbingClass = options.Plumbing || Plumbing - this._gauge = new PlumbingClass(theme, template, this.getWidth()) - - this._$$doRedraw = callWith(this, this._doRedraw) - this._$$handleSizeChange = callWith(this, this._handleSizeChange) - - this._cleanupOnExit = options.cleanupOnExit == null || options.cleanupOnExit - this._removeOnExit = null - - if (options.enabled || (options.enabled == null && this._tty && this._tty.isTTY)) { - this.enable() - } else { - this.disable() - } -} -Gauge.prototype = {} - -Gauge.prototype.isEnabled = function () { - return !this._disabled -} - -Gauge.prototype.setTemplate = function (template) { - this._gauge.setTemplate(template) - if (this._showing) this._requestRedraw() -} - -Gauge.prototype._computeTheme = function (theme) { - if (!theme) theme = {} - if (typeof theme === 'string') { - theme = this._themes.getTheme(theme) - } else if (theme && (Object.keys(theme).length === 0 || theme.hasUnicode != null || theme.hasColor != null)) { - var useUnicode = theme.hasUnicode == null ? hasUnicode() : theme.hasUnicode - var useColor = theme.hasColor == null ? hasColor : theme.hasColor - theme = this._themes.getDefault({hasUnicode: useUnicode, hasColor: useColor, platform: theme.platform}) - } - return theme -} - -Gauge.prototype.setThemeset = function (themes) { - this._themes = themes - this.setTheme(this._theme) -} - -Gauge.prototype.setTheme = function (theme) { - this._gauge.setTheme(this._computeTheme(theme)) - if (this._showing) this._requestRedraw() - this._theme = theme -} - -Gauge.prototype._requestRedraw = function () { - this._needsRedraw = true - if (!this._fixedFramerate) this._doRedraw() -} - -Gauge.prototype.getWidth = function () { - return ((this._tty && this._tty.columns) || 80) - 1 -} - -Gauge.prototype.setWriteTo = function (writeTo, tty) { - var enabled = !this._disabled - if (enabled) this.disable() - this._writeTo = writeTo - this._tty = tty || - (writeTo === process.stderr && process.stdout.isTTY && process.stdout) || - (writeTo.isTTY && writeTo) || - this._tty - if (this._gauge) this._gauge.setWidth(this.getWidth()) - if (enabled) this.enable() -} - -Gauge.prototype.enable = function () { - if (!this._disabled) return - this._disabled = false - if (this._tty) this._enableEvents() - if (this._showing) this.show() -} - -Gauge.prototype.disable = function () { - if (this._disabled) return - if (this._showing) { - this._lastUpdateAt = null - this._showing = false - this._doRedraw() - this._showing = true - } - this._disabled = true - if (this._tty) this._disableEvents() -} - -Gauge.prototype._enableEvents = function () { - if (this._cleanupOnExit) { - this._removeOnExit = onExit(callWith(this, this.disable)) - } - this._tty.on('resize', this._$$handleSizeChange) - if (this._fixedFramerate) { - this.redrawTracker = setInterval(this._$$doRedraw, this._updateInterval) - if (this.redrawTracker.unref) this.redrawTracker.unref() - } -} - -Gauge.prototype._disableEvents = function () { - this._tty.removeListener('resize', this._$$handleSizeChange) - if (this._fixedFramerate) clearInterval(this.redrawTracker) - if (this._removeOnExit) this._removeOnExit() -} - -Gauge.prototype.hide = function (cb) { - if (this._disabled) return cb && process.nextTick(cb) - if (!this._showing) return cb && process.nextTick(cb) - this._showing = false - this._doRedraw() - cb && setImmediate(cb) -} - -Gauge.prototype.show = function (section, completed) { - this._showing = true - if (typeof section === 'string') { - this._status.section = section - } else if (typeof section === 'object') { - var sectionKeys = Object.keys(section) - for (var ii = 0; ii < sectionKeys.length; ++ii) { - var key = sectionKeys[ii] - this._status[key] = section[key] - } - } - if (completed != null) this._status.completed = completed - if (this._disabled) return - this._requestRedraw() -} - -Gauge.prototype.pulse = function (subsection) { - this._status.subsection = subsection || '' - this._status.spun ++ - if (this._disabled) return - if (!this._showing) return - this._requestRedraw() -} - -Gauge.prototype._handleSizeChange = function () { - this._gauge.setWidth(this._tty.columns - 1) - this._requestRedraw() -} - -Gauge.prototype._doRedraw = function () { - if (this._disabled || this._paused) return - if (!this._fixedFramerate) { - var now = Date.now() - if (this._lastUpdateAt && now - this._lastUpdateAt < this._updateInterval) return - this._lastUpdateAt = now - } - if (!this._showing && this._onScreen) { - this._onScreen = false - var result = this._gauge.hide() - if (this._hideCursor) { - result += this._gauge.showCursor() - } - return this._writeTo.write(result) - } - if (!this._showing && !this._onScreen) return - if (this._showing && !this._onScreen) { - this._onScreen = true - this._needsRedraw = true - if (this._hideCursor) { - this._writeTo.write(this._gauge.hideCursor()) - } - } - if (!this._needsRedraw) return - if (!this._writeTo.write(this._gauge.show(this._status))) { - this._paused = true - this._writeTo.on('drain', callWith(this, function () { - this._paused = false - this._doRedraw() - })) - } -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/package.json b/deps/npm/node_modules/node-gyp/node_modules/gauge/package.json deleted file mode 100644 index 4882cff839..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "gauge", - "version": "2.7.4", - "description": "A terminal based horizontal guage", - "main": "index.js", - "scripts": { - "test": "standard && tap test/*.js --coverage", - "prepublish": "rm -f *~" - }, - "repository": { - "type": "git", - "url": "https://github.com/iarna/gauge" - }, - "keywords": [ - "progressbar", - "progress", - "gauge" - ], - "author": "Rebecca Turner <me@re-becca.org>", - "license": "ISC", - "bugs": { - "url": "https://github.com/iarna/gauge/issues" - }, - "homepage": "https://github.com/iarna/gauge", - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "devDependencies": { - "readable-stream": "^2.0.6", - "require-inject": "^1.4.0", - "standard": "^7.1.2", - "tap": "^5.7.2", - "through2": "^2.0.0" - }, - "files": [ - "base-theme.js", - "CHANGELOG.md", - "error.js", - "has-color.js", - "index.js", - "LICENSE", - "package.json", - "plumbing.js", - "process.js", - "progress-bar.js", - "README.md", - "render-template.js", - "set-immediate.js", - "set-interval.js", - "spin.js", - "template-item.js", - "theme-set.js", - "themes.js", - "wide-truncate.js" - ] -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/plumbing.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/plumbing.js deleted file mode 100644 index 1afb4af6d5..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/plumbing.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict' -var consoleControl = require('console-control-strings') -var renderTemplate = require('./render-template.js') -var validate = require('aproba') - -var Plumbing = module.exports = function (theme, template, width) { - if (!width) width = 80 - validate('OAN', [theme, template, width]) - this.showing = false - this.theme = theme - this.width = width - this.template = template -} -Plumbing.prototype = {} - -Plumbing.prototype.setTheme = function (theme) { - validate('O', [theme]) - this.theme = theme -} - -Plumbing.prototype.setTemplate = function (template) { - validate('A', [template]) - this.template = template -} - -Plumbing.prototype.setWidth = function (width) { - validate('N', [width]) - this.width = width -} - -Plumbing.prototype.hide = function () { - return consoleControl.gotoSOL() + consoleControl.eraseLine() -} - -Plumbing.prototype.hideCursor = consoleControl.hideCursor - -Plumbing.prototype.showCursor = consoleControl.showCursor - -Plumbing.prototype.show = function (status) { - var values = Object.create(this.theme) - for (var key in status) { - values[key] = status[key] - } - - return renderTemplate(this.width, this.template, values).trim() + - consoleControl.color('reset') + - consoleControl.eraseLine() + consoleControl.gotoSOL() -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/process.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/process.js deleted file mode 100644 index 05e85694d7..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/process.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict' -// this exists so we can replace it during testing -module.exports = process diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/progress-bar.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/progress-bar.js deleted file mode 100644 index 7f8dd68be2..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/progress-bar.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict' -var validate = require('aproba') -var renderTemplate = require('./render-template.js') -var wideTruncate = require('./wide-truncate') -var stringWidth = require('string-width') - -module.exports = function (theme, width, completed) { - validate('ONN', [theme, width, completed]) - if (completed < 0) completed = 0 - if (completed > 1) completed = 1 - if (width <= 0) return '' - var sofar = Math.round(width * completed) - var rest = width - sofar - var template = [ - {type: 'complete', value: repeat(theme.complete, sofar), length: sofar}, - {type: 'remaining', value: repeat(theme.remaining, rest), length: rest} - ] - return renderTemplate(width, template, theme) -} - -// lodash's way of repeating -function repeat (string, width) { - var result = '' - var n = width - do { - if (n % 2) { - result += string - } - n = Math.floor(n / 2) - /*eslint no-self-assign: 0*/ - string += string - } while (n && stringWidth(result) < width) - - return wideTruncate(result, width) -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/render-template.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/render-template.js deleted file mode 100644 index 3261bfbe6f..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/render-template.js +++ /dev/null @@ -1,181 +0,0 @@ -'use strict' -var align = require('wide-align') -var validate = require('aproba') -var objectAssign = require('object-assign') -var wideTruncate = require('./wide-truncate') -var error = require('./error') -var TemplateItem = require('./template-item') - -function renderValueWithValues (values) { - return function (item) { - return renderValue(item, values) - } -} - -var renderTemplate = module.exports = function (width, template, values) { - var items = prepareItems(width, template, values) - var rendered = items.map(renderValueWithValues(values)).join('') - return align.left(wideTruncate(rendered, width), width) -} - -function preType (item) { - var cappedTypeName = item.type[0].toUpperCase() + item.type.slice(1) - return 'pre' + cappedTypeName -} - -function postType (item) { - var cappedTypeName = item.type[0].toUpperCase() + item.type.slice(1) - return 'post' + cappedTypeName -} - -function hasPreOrPost (item, values) { - if (!item.type) return - return values[preType(item)] || values[postType(item)] -} - -function generatePreAndPost (baseItem, parentValues) { - var item = objectAssign({}, baseItem) - var values = Object.create(parentValues) - var template = [] - var pre = preType(item) - var post = postType(item) - if (values[pre]) { - template.push({value: values[pre]}) - values[pre] = null - } - item.minLength = null - item.length = null - item.maxLength = null - template.push(item) - values[item.type] = values[item.type] - if (values[post]) { - template.push({value: values[post]}) - values[post] = null - } - return function ($1, $2, length) { - return renderTemplate(length, template, values) - } -} - -function prepareItems (width, template, values) { - function cloneAndObjectify (item, index, arr) { - var cloned = new TemplateItem(item, width) - var type = cloned.type - if (cloned.value == null) { - if (!(type in values)) { - if (cloned.default == null) { - throw new error.MissingTemplateValue(cloned, values) - } else { - cloned.value = cloned.default - } - } else { - cloned.value = values[type] - } - } - if (cloned.value == null || cloned.value === '') return null - cloned.index = index - cloned.first = index === 0 - cloned.last = index === arr.length - 1 - if (hasPreOrPost(cloned, values)) cloned.value = generatePreAndPost(cloned, values) - return cloned - } - - var output = template.map(cloneAndObjectify).filter(function (item) { return item != null }) - - var outputLength = 0 - var remainingSpace = width - var variableCount = output.length - - function consumeSpace (length) { - if (length > remainingSpace) length = remainingSpace - outputLength += length - remainingSpace -= length - } - - function finishSizing (item, length) { - if (item.finished) throw new error.Internal('Tried to finish template item that was already finished') - if (length === Infinity) throw new error.Internal('Length of template item cannot be infinity') - if (length != null) item.length = length - item.minLength = null - item.maxLength = null - --variableCount - item.finished = true - if (item.length == null) item.length = item.getBaseLength() - if (item.length == null) throw new error.Internal('Finished template items must have a length') - consumeSpace(item.getLength()) - } - - output.forEach(function (item) { - if (!item.kerning) return - var prevPadRight = item.first ? 0 : output[item.index - 1].padRight - if (!item.first && prevPadRight < item.kerning) item.padLeft = item.kerning - prevPadRight - if (!item.last) item.padRight = item.kerning - }) - - // Finish any that have a fixed (literal or intuited) length - output.forEach(function (item) { - if (item.getBaseLength() == null) return - finishSizing(item) - }) - - var resized = 0 - var resizing - var hunkSize - do { - resizing = false - hunkSize = Math.round(remainingSpace / variableCount) - output.forEach(function (item) { - if (item.finished) return - if (!item.maxLength) return - if (item.getMaxLength() < hunkSize) { - finishSizing(item, item.maxLength) - resizing = true - } - }) - } while (resizing && resized++ < output.length) - if (resizing) throw new error.Internal('Resize loop iterated too many times while determining maxLength') - - resized = 0 - do { - resizing = false - hunkSize = Math.round(remainingSpace / variableCount) - output.forEach(function (item) { - if (item.finished) return - if (!item.minLength) return - if (item.getMinLength() >= hunkSize) { - finishSizing(item, item.minLength) - resizing = true - } - }) - } while (resizing && resized++ < output.length) - if (resizing) throw new error.Internal('Resize loop iterated too many times while determining minLength') - - hunkSize = Math.round(remainingSpace / variableCount) - output.forEach(function (item) { - if (item.finished) return - finishSizing(item, hunkSize) - }) - - return output -} - -function renderFunction (item, values, length) { - validate('OON', arguments) - if (item.type) { - return item.value(values, values[item.type + 'Theme'] || {}, length) - } else { - return item.value(values, {}, length) - } -} - -function renderValue (item, values) { - var length = item.getBaseLength() - var value = typeof item.value === 'function' ? renderFunction(item, values, length) : item.value - if (value == null || value === '') return '' - var alignWith = align[item.align] || align.left - var leftPadding = item.padLeft ? align.left('', item.padLeft) : '' - var rightPadding = item.padRight ? align.right('', item.padRight) : '' - var truncated = wideTruncate(String(value), length) - var aligned = alignWith(truncated, length) - return leftPadding + aligned + rightPadding -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/set-immediate.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/set-immediate.js deleted file mode 100644 index 6650a485c4..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/set-immediate.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' -var process = require('./process') -try { - module.exports = setImmediate -} catch (ex) { - module.exports = process.nextTick -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/set-interval.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/set-interval.js deleted file mode 100644 index 576198793c..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/set-interval.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict' -// this exists so we can replace it during testing -module.exports = setInterval diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/spin.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/spin.js deleted file mode 100644 index 34142ee31a..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/spin.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict' - -module.exports = function spin (spinstr, spun) { - return spinstr[spun % spinstr.length] -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/template-item.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/template-item.js deleted file mode 100644 index 4f02fefaa2..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/template-item.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict' -var stringWidth = require('string-width') - -module.exports = TemplateItem - -function isPercent (num) { - if (typeof num !== 'string') return false - return num.slice(-1) === '%' -} - -function percent (num) { - return Number(num.slice(0, -1)) / 100 -} - -function TemplateItem (values, outputLength) { - this.overallOutputLength = outputLength - this.finished = false - this.type = null - this.value = null - this.length = null - this.maxLength = null - this.minLength = null - this.kerning = null - this.align = 'left' - this.padLeft = 0 - this.padRight = 0 - this.index = null - this.first = null - this.last = null - if (typeof values === 'string') { - this.value = values - } else { - for (var prop in values) this[prop] = values[prop] - } - // Realize percents - if (isPercent(this.length)) { - this.length = Math.round(this.overallOutputLength * percent(this.length)) - } - if (isPercent(this.minLength)) { - this.minLength = Math.round(this.overallOutputLength * percent(this.minLength)) - } - if (isPercent(this.maxLength)) { - this.maxLength = Math.round(this.overallOutputLength * percent(this.maxLength)) - } - return this -} - -TemplateItem.prototype = {} - -TemplateItem.prototype.getBaseLength = function () { - var length = this.length - if (length == null && typeof this.value === 'string' && this.maxLength == null && this.minLength == null) { - length = stringWidth(this.value) - } - return length -} - -TemplateItem.prototype.getLength = function () { - var length = this.getBaseLength() - if (length == null) return null - return length + this.padLeft + this.padRight -} - -TemplateItem.prototype.getMaxLength = function () { - if (this.maxLength == null) return null - return this.maxLength + this.padLeft + this.padRight -} - -TemplateItem.prototype.getMinLength = function () { - if (this.minLength == null) return null - return this.minLength + this.padLeft + this.padRight -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/theme-set.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/theme-set.js deleted file mode 100644 index c022d61cf1..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/theme-set.js +++ /dev/null @@ -1,114 +0,0 @@ -'use strict' -var objectAssign = require('object-assign') - -module.exports = function () { - return ThemeSetProto.newThemeSet() -} - -var ThemeSetProto = {} - -ThemeSetProto.baseTheme = require('./base-theme.js') - -ThemeSetProto.newTheme = function (parent, theme) { - if (!theme) { - theme = parent - parent = this.baseTheme - } - return objectAssign({}, parent, theme) -} - -ThemeSetProto.getThemeNames = function () { - return Object.keys(this.themes) -} - -ThemeSetProto.addTheme = function (name, parent, theme) { - this.themes[name] = this.newTheme(parent, theme) -} - -ThemeSetProto.addToAllThemes = function (theme) { - var themes = this.themes - Object.keys(themes).forEach(function (name) { - objectAssign(themes[name], theme) - }) - objectAssign(this.baseTheme, theme) -} - -ThemeSetProto.getTheme = function (name) { - if (!this.themes[name]) throw this.newMissingThemeError(name) - return this.themes[name] -} - -ThemeSetProto.setDefault = function (opts, name) { - if (name == null) { - name = opts - opts = {} - } - var platform = opts.platform == null ? 'fallback' : opts.platform - var hasUnicode = !!opts.hasUnicode - var hasColor = !!opts.hasColor - if (!this.defaults[platform]) this.defaults[platform] = {true: {}, false: {}} - this.defaults[platform][hasUnicode][hasColor] = name -} - -ThemeSetProto.getDefault = function (opts) { - if (!opts) opts = {} - var platformName = opts.platform || process.platform - var platform = this.defaults[platformName] || this.defaults.fallback - var hasUnicode = !!opts.hasUnicode - var hasColor = !!opts.hasColor - if (!platform) throw this.newMissingDefaultThemeError(platformName, hasUnicode, hasColor) - if (!platform[hasUnicode][hasColor]) { - if (hasUnicode && hasColor && platform[!hasUnicode][hasColor]) { - hasUnicode = false - } else if (hasUnicode && hasColor && platform[hasUnicode][!hasColor]) { - hasColor = false - } else if (hasUnicode && hasColor && platform[!hasUnicode][!hasColor]) { - hasUnicode = false - hasColor = false - } else if (hasUnicode && !hasColor && platform[!hasUnicode][hasColor]) { - hasUnicode = false - } else if (!hasUnicode && hasColor && platform[hasUnicode][!hasColor]) { - hasColor = false - } else if (platform === this.defaults.fallback) { - throw this.newMissingDefaultThemeError(platformName, hasUnicode, hasColor) - } - } - if (platform[hasUnicode][hasColor]) { - return this.getTheme(platform[hasUnicode][hasColor]) - } else { - return this.getDefault(objectAssign({}, opts, {platform: 'fallback'})) - } -} - -ThemeSetProto.newMissingThemeError = function newMissingThemeError (name) { - var err = new Error('Could not find a gauge theme named "' + name + '"') - Error.captureStackTrace.call(err, newMissingThemeError) - err.theme = name - err.code = 'EMISSINGTHEME' - return err -} - -ThemeSetProto.newMissingDefaultThemeError = function newMissingDefaultThemeError (platformName, hasUnicode, hasColor) { - var err = new Error( - 'Could not find a gauge theme for your platform/unicode/color use combo:\n' + - ' platform = ' + platformName + '\n' + - ' hasUnicode = ' + hasUnicode + '\n' + - ' hasColor = ' + hasColor) - Error.captureStackTrace.call(err, newMissingDefaultThemeError) - err.platform = platformName - err.hasUnicode = hasUnicode - err.hasColor = hasColor - err.code = 'EMISSINGTHEME' - return err -} - -ThemeSetProto.newThemeSet = function () { - var themeset = function (opts) { - return themeset.getDefault(opts) - } - return objectAssign(themeset, ThemeSetProto, { - themes: objectAssign({}, this.themes), - baseTheme: objectAssign({}, this.baseTheme), - defaults: JSON.parse(JSON.stringify(this.defaults || {})) - }) -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/themes.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/themes.js deleted file mode 100644 index eb5a4f5b5e..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/themes.js +++ /dev/null @@ -1,54 +0,0 @@ -'use strict' -var consoleControl = require('console-control-strings') -var ThemeSet = require('./theme-set.js') - -var themes = module.exports = new ThemeSet() - -themes.addTheme('ASCII', { - preProgressbar: '[', - postProgressbar: ']', - progressbarTheme: { - complete: '#', - remaining: '.' - }, - activityIndicatorTheme: '-\\|/', - preSubsection: '>' -}) - -themes.addTheme('colorASCII', themes.getTheme('ASCII'), { - progressbarTheme: { - preComplete: consoleControl.color('inverse'), - complete: ' ', - postComplete: consoleControl.color('stopInverse'), - preRemaining: consoleControl.color('brightBlack'), - remaining: '.', - postRemaining: consoleControl.color('reset') - } -}) - -themes.addTheme('brailleSpinner', { - preProgressbar: '⸨', - postProgressbar: '⸩', - progressbarTheme: { - complete: '░', - remaining: '⠂' - }, - activityIndicatorTheme: '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏', - preSubsection: '>' -}) - -themes.addTheme('colorBrailleSpinner', themes.getTheme('brailleSpinner'), { - progressbarTheme: { - preComplete: consoleControl.color('inverse'), - complete: ' ', - postComplete: consoleControl.color('stopInverse'), - preRemaining: consoleControl.color('brightBlack'), - remaining: '░', - postRemaining: consoleControl.color('reset') - } -}) - -themes.setDefault({}, 'ASCII') -themes.setDefault({hasColor: true}, 'colorASCII') -themes.setDefault({platform: 'darwin', hasUnicode: true}, 'brailleSpinner') -themes.setDefault({platform: 'darwin', hasUnicode: true, hasColor: true}, 'colorBrailleSpinner') diff --git a/deps/npm/node_modules/node-gyp/node_modules/gauge/wide-truncate.js b/deps/npm/node_modules/node-gyp/node_modules/gauge/wide-truncate.js deleted file mode 100644 index c531bc491f..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/gauge/wide-truncate.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict' -var stringWidth = require('string-width') -var stripAnsi = require('strip-ansi') - -module.exports = wideTruncate - -function wideTruncate (str, target) { - if (stringWidth(str) === 0) return str - if (target <= 0) return '' - if (stringWidth(str) <= target) return str - - // We compute the number of bytes of ansi sequences here and add - // that to our initial truncation to ensure that we don't slice one - // that we want to keep in half. - var noAnsi = stripAnsi(str) - var ansiSize = str.length + noAnsi.length - var truncated = str.slice(0, target + ansiSize) - - // we have to shrink the result to account for our ansi sequence buffer - // (if an ansi sequence was truncated) and double width characters. - while (stringWidth(truncated) > target) { - truncated = truncated.slice(0, -1) - } - return truncated -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/index.js b/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/index.js deleted file mode 100644 index a7d3e3855f..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/index.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; -var numberIsNan = require('number-is-nan'); - -module.exports = function (x) { - if (numberIsNan(x)) { - return false; - } - - // https://github.com/nodejs/io.js/blob/cff7300a578be1b10001f2d967aaedc88aee6402/lib/readline.js#L1369 - - // code points are derived from: - // http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt - if (x >= 0x1100 && ( - x <= 0x115f || // Hangul Jamo - 0x2329 === x || // LEFT-POINTING ANGLE BRACKET - 0x232a === x || // RIGHT-POINTING ANGLE BRACKET - // CJK Radicals Supplement .. Enclosed CJK Letters and Months - (0x2e80 <= x && x <= 0x3247 && x !== 0x303f) || - // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A - 0x3250 <= x && x <= 0x4dbf || - // CJK Unified Ideographs .. Yi Radicals - 0x4e00 <= x && x <= 0xa4c6 || - // Hangul Jamo Extended-A - 0xa960 <= x && x <= 0xa97c || - // Hangul Syllables - 0xac00 <= x && x <= 0xd7a3 || - // CJK Compatibility Ideographs - 0xf900 <= x && x <= 0xfaff || - // Vertical Forms - 0xfe10 <= x && x <= 0xfe19 || - // CJK Compatibility Forms .. Small Form Variants - 0xfe30 <= x && x <= 0xfe6b || - // Halfwidth and Fullwidth Forms - 0xff01 <= x && x <= 0xff60 || - 0xffe0 <= x && x <= 0xffe6 || - // Kana Supplement - 0x1b000 <= x && x <= 0x1b001 || - // Enclosed Ideographic Supplement - 0x1f200 <= x && x <= 0x1f251 || - // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane - 0x20000 <= x && x <= 0x3fffd)) { - return true; - } - - return false; -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/license b/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/license deleted file mode 100644 index 654d0bfe94..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/license +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/package.json b/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/package.json deleted file mode 100644 index b678d40de7..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "is-fullwidth-code-point", - "version": "1.0.0", - "description": "Check if the character represented by a given Unicode code point is fullwidth", - "license": "MIT", - "repository": "sindresorhus/is-fullwidth-code-point", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "node test.js" - }, - "files": [ - "index.js" - ], - "keywords": [ - "fullwidth", - "full-width", - "full", - "width", - "unicode", - "character", - "char", - "string", - "str", - "codepoint", - "code", - "point", - "is", - "detect", - "check" - ], - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "devDependencies": { - "ava": "0.0.4", - "code-point-at": "^1.0.0" - } -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/npmlog/LICENSE b/deps/npm/node_modules/node-gyp/node_modules/npmlog/LICENSE deleted file mode 100644 index 19129e315f..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/npmlog/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/deps/npm/node_modules/node-gyp/node_modules/npmlog/log.js b/deps/npm/node_modules/node-gyp/node_modules/npmlog/log.js deleted file mode 100644 index 341f3313ab..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/npmlog/log.js +++ /dev/null @@ -1,309 +0,0 @@ -'use strict' -var Progress = require('are-we-there-yet') -var Gauge = require('gauge') -var EE = require('events').EventEmitter -var log = exports = module.exports = new EE() -var util = require('util') - -var setBlocking = require('set-blocking') -var consoleControl = require('console-control-strings') - -setBlocking(true) -var stream = process.stderr -Object.defineProperty(log, 'stream', { - set: function (newStream) { - stream = newStream - if (this.gauge) this.gauge.setWriteTo(stream, stream) - }, - get: function () { - return stream - } -}) - -// by default, decide based on tty-ness. -var colorEnabled -log.useColor = function () { - return colorEnabled != null ? colorEnabled : stream.isTTY -} - -log.enableColor = function () { - colorEnabled = true - this.gauge.setTheme({hasColor: colorEnabled, hasUnicode: unicodeEnabled}) -} -log.disableColor = function () { - colorEnabled = false - this.gauge.setTheme({hasColor: colorEnabled, hasUnicode: unicodeEnabled}) -} - -// default level -log.level = 'info' - -log.gauge = new Gauge(stream, { - enabled: false, // no progress bars unless asked - theme: {hasColor: log.useColor()}, - template: [ - {type: 'progressbar', length: 20}, - {type: 'activityIndicator', kerning: 1, length: 1}, - {type: 'section', default: ''}, - ':', - {type: 'logline', kerning: 1, default: ''} - ] -}) - -log.tracker = new Progress.TrackerGroup() - -// we track this separately as we may need to temporarily disable the -// display of the status bar for our own loggy purposes. -log.progressEnabled = log.gauge.isEnabled() - -var unicodeEnabled - -log.enableUnicode = function () { - unicodeEnabled = true - this.gauge.setTheme({hasColor: this.useColor(), hasUnicode: unicodeEnabled}) -} - -log.disableUnicode = function () { - unicodeEnabled = false - this.gauge.setTheme({hasColor: this.useColor(), hasUnicode: unicodeEnabled}) -} - -log.setGaugeThemeset = function (themes) { - this.gauge.setThemeset(themes) -} - -log.setGaugeTemplate = function (template) { - this.gauge.setTemplate(template) -} - -log.enableProgress = function () { - if (this.progressEnabled) return - this.progressEnabled = true - this.tracker.on('change', this.showProgress) - if (this._pause) return - this.gauge.enable() -} - -log.disableProgress = function () { - if (!this.progressEnabled) return - this.progressEnabled = false - this.tracker.removeListener('change', this.showProgress) - this.gauge.disable() -} - -var trackerConstructors = ['newGroup', 'newItem', 'newStream'] - -var mixinLog = function (tracker) { - // mixin the public methods from log into the tracker - // (except: conflicts and one's we handle specially) - Object.keys(log).forEach(function (P) { - if (P[0] === '_') return - if (trackerConstructors.filter(function (C) { return C === P }).length) return - if (tracker[P]) return - if (typeof log[P] !== 'function') return - var func = log[P] - tracker[P] = function () { - return func.apply(log, arguments) - } - }) - // if the new tracker is a group, make sure any subtrackers get - // mixed in too - if (tracker instanceof Progress.TrackerGroup) { - trackerConstructors.forEach(function (C) { - var func = tracker[C] - tracker[C] = function () { return mixinLog(func.apply(tracker, arguments)) } - }) - } - return tracker -} - -// Add tracker constructors to the top level log object -trackerConstructors.forEach(function (C) { - log[C] = function () { return mixinLog(this.tracker[C].apply(this.tracker, arguments)) } -}) - -log.clearProgress = function (cb) { - if (!this.progressEnabled) return cb && process.nextTick(cb) - this.gauge.hide(cb) -} - -log.showProgress = function (name, completed) { - if (!this.progressEnabled) return - var values = {} - if (name) values.section = name - var last = log.record[log.record.length - 1] - if (last) { - values.subsection = last.prefix - var disp = log.disp[last.level] || last.level - var logline = this._format(disp, log.style[last.level]) - if (last.prefix) logline += ' ' + this._format(last.prefix, this.prefixStyle) - logline += ' ' + last.message.split(/\r?\n/)[0] - values.logline = logline - } - values.completed = completed || this.tracker.completed() - this.gauge.show(values) -}.bind(log) // bind for use in tracker's on-change listener - -// temporarily stop emitting, but don't drop -log.pause = function () { - this._paused = true - if (this.progressEnabled) this.gauge.disable() -} - -log.resume = function () { - if (!this._paused) return - this._paused = false - - var b = this._buffer - this._buffer = [] - b.forEach(function (m) { - this.emitLog(m) - }, this) - if (this.progressEnabled) this.gauge.enable() -} - -log._buffer = [] - -var id = 0 -log.record = [] -log.maxRecordSize = 10000 -log.log = function (lvl, prefix, message) { - var l = this.levels[lvl] - if (l === undefined) { - return this.emit('error', new Error(util.format( - 'Undefined log level: %j', lvl))) - } - - var a = new Array(arguments.length - 2) - var stack = null - for (var i = 2; i < arguments.length; i++) { - var arg = a[i - 2] = arguments[i] - - // resolve stack traces to a plain string. - if (typeof arg === 'object' && arg && - (arg instanceof Error) && arg.stack) { - - Object.defineProperty(arg, 'stack', { - value: stack = arg.stack + '', - enumerable: true, - writable: true - }) - } - } - if (stack) a.unshift(stack + '\n') - message = util.format.apply(util, a) - - var m = { id: id++, - level: lvl, - prefix: String(prefix || ''), - message: message, - messageRaw: a } - - this.emit('log', m) - this.emit('log.' + lvl, m) - if (m.prefix) this.emit(m.prefix, m) - - this.record.push(m) - var mrs = this.maxRecordSize - var n = this.record.length - mrs - if (n > mrs / 10) { - var newSize = Math.floor(mrs * 0.9) - this.record = this.record.slice(-1 * newSize) - } - - this.emitLog(m) -}.bind(log) - -log.emitLog = function (m) { - if (this._paused) { - this._buffer.push(m) - return - } - if (this.progressEnabled) this.gauge.pulse(m.prefix) - var l = this.levels[m.level] - if (l === undefined) return - if (l < this.levels[this.level]) return - if (l > 0 && !isFinite(l)) return - - // If 'disp' is null or undefined, use the lvl as a default - // Allows: '', 0 as valid disp - var disp = log.disp[m.level] != null ? log.disp[m.level] : m.level - this.clearProgress() - m.message.split(/\r?\n/).forEach(function (line) { - if (this.heading) { - this.write(this.heading, this.headingStyle) - this.write(' ') - } - this.write(disp, log.style[m.level]) - var p = m.prefix || '' - if (p) this.write(' ') - this.write(p, this.prefixStyle) - this.write(' ' + line + '\n') - }, this) - this.showProgress() -} - -log._format = function (msg, style) { - if (!stream) return - - var output = '' - if (this.useColor()) { - style = style || {} - var settings = [] - if (style.fg) settings.push(style.fg) - if (style.bg) settings.push('bg' + style.bg[0].toUpperCase() + style.bg.slice(1)) - if (style.bold) settings.push('bold') - if (style.underline) settings.push('underline') - if (style.inverse) settings.push('inverse') - if (settings.length) output += consoleControl.color(settings) - if (style.beep) output += consoleControl.beep() - } - output += msg - if (this.useColor()) { - output += consoleControl.color('reset') - } - return output -} - -log.write = function (msg, style) { - if (!stream) return - - stream.write(this._format(msg, style)) -} - -log.addLevel = function (lvl, n, style, disp) { - // If 'disp' is null or undefined, use the lvl as a default - if (disp == null) disp = lvl - this.levels[lvl] = n - this.style[lvl] = style - if (!this[lvl]) { - this[lvl] = function () { - var a = new Array(arguments.length + 1) - a[0] = lvl - for (var i = 0; i < arguments.length; i++) { - a[i + 1] = arguments[i] - } - return this.log.apply(this, a) - }.bind(this) - } - this.disp[lvl] = disp -} - -log.prefixStyle = { fg: 'magenta' } -log.headingStyle = { fg: 'white', bg: 'black' } - -log.style = {} -log.levels = {} -log.disp = {} -log.addLevel('silly', -Infinity, { inverse: true }, 'sill') -log.addLevel('verbose', 1000, { fg: 'blue', bg: 'black' }, 'verb') -log.addLevel('info', 2000, { fg: 'green' }) -log.addLevel('timing', 2500, { fg: 'green', bg: 'black' }) -log.addLevel('http', 3000, { fg: 'green', bg: 'black' }) -log.addLevel('notice', 3500, { fg: 'blue', bg: 'black' }) -log.addLevel('warn', 4000, { fg: 'black', bg: 'yellow' }, 'WARN') -log.addLevel('error', 5000, { fg: 'red', bg: 'black' }, 'ERR!') -log.addLevel('silent', Infinity) - -// allow 'error' prefix -log.on('error', function () {}) diff --git a/deps/npm/node_modules/node-gyp/node_modules/npmlog/package.json b/deps/npm/node_modules/node-gyp/node_modules/npmlog/package.json deleted file mode 100644 index 7220f8e72a..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/npmlog/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)", - "name": "npmlog", - "description": "logger for npm", - "version": "4.1.2", - "repository": { - "type": "git", - "url": "https://github.com/npm/npmlog.git" - }, - "main": "log.js", - "files": [ - "log.js" - ], - "scripts": { - "test": "standard && tap test/*.js" - }, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - }, - "devDependencies": { - "standard": "~7.1.2", - "tap": "~5.7.3" - }, - "license": "ISC" -} diff --git a/deps/npm/node_modules/node-gyp/node_modules/string-width/index.js b/deps/npm/node_modules/node-gyp/node_modules/string-width/index.js deleted file mode 100644 index b9bec62440..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/string-width/index.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; -var stripAnsi = require('strip-ansi'); -var codePointAt = require('code-point-at'); -var isFullwidthCodePoint = require('is-fullwidth-code-point'); - -// https://github.com/nodejs/io.js/blob/cff7300a578be1b10001f2d967aaedc88aee6402/lib/readline.js#L1345 -module.exports = function (str) { - if (typeof str !== 'string' || str.length === 0) { - return 0; - } - - var width = 0; - - str = stripAnsi(str); - - for (var i = 0; i < str.length; i++) { - var code = codePointAt(str, i); - - // ignore control characters - if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) { - continue; - } - - // surrogates - if (code >= 0x10000) { - i++; - } - - if (isFullwidthCodePoint(code)) { - width += 2; - } else { - width++; - } - } - - return width; -}; diff --git a/deps/npm/node_modules/node-gyp/node_modules/string-width/license b/deps/npm/node_modules/node-gyp/node_modules/string-width/license deleted file mode 100644 index 654d0bfe94..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/string-width/license +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/deps/npm/node_modules/node-gyp/node_modules/string-width/package.json b/deps/npm/node_modules/node-gyp/node_modules/string-width/package.json deleted file mode 100644 index 5ba436166e..0000000000 --- a/deps/npm/node_modules/node-gyp/node_modules/string-width/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "string-width", - "version": "1.0.2", - "description": "Get the visual width of a string - the number of columns required to display it", - "license": "MIT", - "repository": "sindresorhus/string-width", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "xo && ava" - }, - "files": [ - "index.js" - ], - "keywords": [ - "string", - "str", - "character", - "char", - "unicode", - "width", - "visual", - "column", - "columns", - "fullwidth", - "full-width", - "full", - "ansi", - "escape", - "codes", - "cli", - "command-line", - "terminal", - "console", - "cjk", - "chinese", - "japanese", - "korean", - "fixed-width" - ], - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "devDependencies": { - "ava": "*", - "xo": "*" - } -} diff --git a/deps/npm/node_modules/node-gyp/package.json b/deps/npm/node_modules/node-gyp/package.json index ea06551817..fbeae5e20d 100644 --- a/deps/npm/node_modules/node-gyp/package.json +++ b/deps/npm/node_modules/node-gyp/package.json @@ -11,7 +11,7 @@ "bindings", "gyp" ], - "version": "8.4.0", + "version": "8.4.1", "installVersion": 9, "author": "Nathan Rajlich <nathan@tootallnate.net> (http://tootallnate.net)", "repository": { @@ -27,7 +27,7 @@ "graceful-fs": "^4.2.6", "make-fetch-happen": "^9.1.0", "nopt": "^5.0.0", - "npmlog": "^4.1.2", + "npmlog": "^6.0.0", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.2", diff --git a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/LICENSE.md b/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/LICENSE.md deleted file mode 100644 index 845be76f64..0000000000 --- a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/LICENSE.md +++ /dev/null @@ -1,18 +0,0 @@ -ISC License - -Copyright npm, Inc. - -Permission to use, copy, modify, and/or distribute this -software for any purpose with or without fee is hereby -granted, provided that the above copyright notice and this -permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND NPM DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO -EVENT SHALL NPM BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE -USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/index.js b/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/index.js deleted file mode 100644 index 57d8743fda..0000000000 --- a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/index.js +++ /dev/null @@ -1,4 +0,0 @@ -'use strict' -exports.TrackerGroup = require('./tracker-group.js') -exports.Tracker = require('./tracker.js') -exports.TrackerStream = require('./tracker-stream.js') diff --git a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-base.js b/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-base.js deleted file mode 100644 index 6f43687557..0000000000 --- a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-base.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict' -var EventEmitter = require('events').EventEmitter -var util = require('util') - -var trackerId = 0 -var TrackerBase = module.exports = function (name) { - EventEmitter.call(this) - this.id = ++trackerId - this.name = name -} -util.inherits(TrackerBase, EventEmitter) diff --git a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-group.js b/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-group.js deleted file mode 100644 index 9da13f8a7e..0000000000 --- a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-group.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict' -var util = require('util') -var TrackerBase = require('./tracker-base.js') -var Tracker = require('./tracker.js') -var TrackerStream = require('./tracker-stream.js') - -var TrackerGroup = module.exports = function (name) { - TrackerBase.call(this, name) - this.parentGroup = null - this.trackers = [] - this.completion = {} - this.weight = {} - this.totalWeight = 0 - this.finished = false - this.bubbleChange = bubbleChange(this) -} -util.inherits(TrackerGroup, TrackerBase) - -function bubbleChange (trackerGroup) { - return function (name, completed, tracker) { - trackerGroup.completion[tracker.id] = completed - if (trackerGroup.finished) { - return - } - trackerGroup.emit('change', name || trackerGroup.name, trackerGroup.completed(), trackerGroup) - } -} - -TrackerGroup.prototype.nameInTree = function () { - var names = [] - var from = this - while (from) { - names.unshift(from.name) - from = from.parentGroup - } - return names.join('/') -} - -TrackerGroup.prototype.addUnit = function (unit, weight) { - if (unit.addUnit) { - var toTest = this - while (toTest) { - if (unit === toTest) { - throw new Error( - 'Attempted to add tracker group ' + - unit.name + ' to tree that already includes it ' + - this.nameInTree(this)) - } - toTest = toTest.parentGroup - } - unit.parentGroup = this - } - this.weight[unit.id] = weight || 1 - this.totalWeight += this.weight[unit.id] - this.trackers.push(unit) - this.completion[unit.id] = unit.completed() - unit.on('change', this.bubbleChange) - if (!this.finished) { - this.emit('change', unit.name, this.completion[unit.id], unit) - } - return unit -} - -TrackerGroup.prototype.completed = function () { - if (this.trackers.length === 0) { - return 0 - } - var valPerWeight = 1 / this.totalWeight - var completed = 0 - for (var ii = 0; ii < this.trackers.length; ii++) { - var trackerId = this.trackers[ii].id - completed += - valPerWeight * this.weight[trackerId] * this.completion[trackerId] - } - return completed -} - -TrackerGroup.prototype.newGroup = function (name, weight) { - return this.addUnit(new TrackerGroup(name), weight) -} - -TrackerGroup.prototype.newItem = function (name, todo, weight) { - return this.addUnit(new Tracker(name, todo), weight) -} - -TrackerGroup.prototype.newStream = function (name, todo, weight) { - return this.addUnit(new TrackerStream(name, todo), weight) -} - -TrackerGroup.prototype.finish = function () { - this.finished = true - if (!this.trackers.length) { - this.addUnit(new Tracker(), 1, true) - } - for (var ii = 0; ii < this.trackers.length; ii++) { - var tracker = this.trackers[ii] - tracker.finish() - tracker.removeListener('change', this.bubbleChange) - } - this.emit('change', this.name, 1, this) -} - -var buffer = ' ' -TrackerGroup.prototype.debug = function (depth) { - depth = depth || 0 - var indent = depth ? buffer.substr(0, depth) : '' - var output = indent + (this.name || 'top') + ': ' + this.completed() + '\n' - this.trackers.forEach(function (tracker) { - if (tracker instanceof TrackerGroup) { - output += tracker.debug(depth + 1) - } else { - output += indent + ' ' + tracker.name + ': ' + tracker.completed() + '\n' - } - }) - return output -} diff --git a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-stream.js b/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-stream.js deleted file mode 100644 index e1cf850557..0000000000 --- a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker-stream.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' -var util = require('util') -var stream = require('readable-stream') -var delegate = require('delegates') -var Tracker = require('./tracker.js') - -var TrackerStream = module.exports = function (name, size, options) { - stream.Transform.call(this, options) - this.tracker = new Tracker(name, size) - this.name = name - this.id = this.tracker.id - this.tracker.on('change', delegateChange(this)) -} -util.inherits(TrackerStream, stream.Transform) - -function delegateChange (trackerStream) { - return function (name, completion, tracker) { - trackerStream.emit('change', name, completion, trackerStream) - } -} - -TrackerStream.prototype._transform = function (data, encoding, cb) { - this.tracker.completeWork(data.length ? data.length : 1) - this.push(data) - cb() -} - -TrackerStream.prototype._flush = function (cb) { - this.tracker.finish() - cb() -} - -delegate(TrackerStream.prototype, 'tracker') - .method('completed') - .method('addWork') - .method('finish') diff --git a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker.js b/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker.js deleted file mode 100644 index a8f8b3ba01..0000000000 --- a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/lib/tracker.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict' -var util = require('util') -var TrackerBase = require('./tracker-base.js') - -var Tracker = module.exports = function (name, todo) { - TrackerBase.call(this, name) - this.workDone = 0 - this.workTodo = todo || 0 -} -util.inherits(Tracker, TrackerBase) - -Tracker.prototype.completed = function () { - return this.workTodo === 0 ? 0 : this.workDone / this.workTodo -} - -Tracker.prototype.addWork = function (work) { - this.workTodo += work - this.emit('change', this.name, this.completed(), this) -} - -Tracker.prototype.completeWork = function (work) { - this.workDone += work - if (this.workDone > this.workTodo) { - this.workDone = this.workTodo - } - this.emit('change', this.name, this.completed(), this) -} - -Tracker.prototype.finish = function () { - this.workTodo = this.workDone = 1 - this.emit('change', this.name, 1, this) -} diff --git a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/package.json b/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/package.json deleted file mode 100644 index 5714e09c3b..0000000000 --- a/deps/npm/node_modules/npmlog/node_modules/are-we-there-yet/package.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "name": "are-we-there-yet", - "version": "2.0.0", - "description": "Keep track of the overall completion of many disparate processes", - "main": "lib/index.js", - "scripts": { - "test": "tap", - "npmclilint": "npmcli-lint", - "lint": "eslint '**/*.js'", - "lintfix": "npm run lint -- --fix", - "posttest": "npm run lint", - "postsnap": "npm run lintfix --", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "snap": "tap" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/are-we-there-yet.git" - }, - "author": "GitHub Inc.", - "license": "ISC", - "bugs": { - "url": "https://github.com/npm/are-we-there-yet/issues" - }, - "homepage": "https://github.com/npm/are-we-there-yet", - "devDependencies": { - "@npmcli/eslint-config": "^1.0.0", - "@npmcli/template-oss": "^1.0.2", - "eslint": "^7.32.0", - "eslint-plugin-node": "^11.1.0", - "tap": "^15.0.9" - }, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "files": [ - "bin", - "lib" - ], - "engines": { - "node": ">=10" - }, - "tap": { - "branches": 68, - "statements": 92, - "functions": 86, - "lines": 92 - }, - "templateVersion": "1.0.2" -} diff --git a/deps/npm/node_modules/number-is-nan/index.js b/deps/npm/node_modules/number-is-nan/index.js deleted file mode 100644 index 79be4b9cb8..0000000000 --- a/deps/npm/node_modules/number-is-nan/index.js +++ /dev/null @@ -1,4 +0,0 @@ -'use strict'; -module.exports = Number.isNaN || function (x) { - return x !== x; -}; diff --git a/deps/npm/node_modules/number-is-nan/license b/deps/npm/node_modules/number-is-nan/license deleted file mode 100644 index 654d0bfe94..0000000000 --- a/deps/npm/node_modules/number-is-nan/license +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/deps/npm/node_modules/number-is-nan/package.json b/deps/npm/node_modules/number-is-nan/package.json deleted file mode 100644 index d2f51d4b1d..0000000000 --- a/deps/npm/node_modules/number-is-nan/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "number-is-nan", - "version": "1.0.1", - "description": "ES2015 Number.isNaN() ponyfill", - "license": "MIT", - "repository": "sindresorhus/number-is-nan", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "ava" - }, - "files": [ - "index.js" - ], - "keywords": [ - "es2015", - "ecmascript", - "ponyfill", - "polyfill", - "shim", - "number", - "is", - "nan", - "not" - ], - "devDependencies": { - "ava": "*" - } -} diff --git a/deps/npm/node_modules/number-is-nan/readme.md b/deps/npm/node_modules/number-is-nan/readme.md deleted file mode 100644 index 2463508712..0000000000 --- a/deps/npm/node_modules/number-is-nan/readme.md +++ /dev/null @@ -1,28 +0,0 @@ -# number-is-nan [![Build Status](https://travis-ci.org/sindresorhus/number-is-nan.svg?branch=master)](https://travis-ci.org/sindresorhus/number-is-nan) - -> ES2015 [`Number.isNaN()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) [ponyfill](https://ponyfill.com) - - -## Install - -``` -$ npm install --save number-is-nan -``` - - -## Usage - -```js -var numberIsNan = require('number-is-nan'); - -numberIsNan(NaN); -//=> true - -numberIsNan('unicorn'); -//=> false -``` - - -## License - -MIT © [Sindre Sorhus](http://sindresorhus.com) diff --git a/deps/npm/package.json b/deps/npm/package.json index 43456fef9a..f9ba8cd3c8 100644 --- a/deps/npm/package.json +++ b/deps/npm/package.json @@ -1,5 +1,5 @@ { - "version": "8.1.4", + "version": "8.2.0", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -57,7 +57,7 @@ "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^4.0.5", "@npmcli/ci-detect": "^1.4.0", - "@npmcli/config": "^2.3.0", + "@npmcli/config": "^2.3.2", "@npmcli/map-workspaces": "^2.0.0", "@npmcli/package-json": "^1.0.1", "@npmcli/run-script": "^2.0.0", @@ -96,7 +96,7 @@ "mkdirp": "^1.0.4", "mkdirp-infer-owner": "^2.0.0", "ms": "^2.1.2", - "node-gyp": "^8.4.0", + "node-gyp": "^8.4.1", "nopt": "^5.0.0", "npm-audit-report": "^2.1.5", "npm-install-checks": "^4.0.0", @@ -109,6 +109,7 @@ "opener": "^1.5.2", "pacote": "^12.0.2", "parse-conflict-json": "^1.1.1", + "proc-log": "^1.0.0", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", "read-package-json": "^4.1.1", @@ -181,6 +182,7 @@ "opener", "pacote", "parse-conflict-json", + "proc-log", "qrcode-terminal", "read", "read-package-json", @@ -199,10 +201,10 @@ ], "devDependencies": { "@npmcli/eslint-config": "^2.0.0", - "eslint": "^8.2.0", + "eslint": "^8.3.0", "licensee": "^8.2.0", "spawk": "^1.7.1", - "tap": "^15.1.2" + "tap": "^15.1.5" }, "scripts": { "dumpconf": "env | grep npm | sort | uniq", diff --git a/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs index c7be15f0c7..12cd631045 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -9,6 +9,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna { "prefix": "{LOCALPREFIX}", "userconfig": "{HOME}/.npmrc", + "cache": "{NPMDIR}/test/lib/commands/tap-testdir-config-config-list---json-sandbox/cache", "json": true, "projectloaded": "yes", "userloaded": "yes", @@ -24,7 +25,6 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna "bin-links": true, "browser": null, "ca": null, - "cache": "{CACHE}", "cache-max": null, "cache-min": 0, "cafile": null, @@ -175,7 +175,7 @@ before = null bin-links = true browser = null ca = null -cache = "{CACHE}" +; cache = "{CACHE}" ; overridden by cli cache-max = null cache-min = 0 cafile = null @@ -324,6 +324,7 @@ projectloaded = "yes" ; "cli" config from command line options +cache = "{NPMDIR}/test/lib/commands/tap-testdir-config-config-list---long-sandbox/cache" long = true prefix = "{LOCALPREFIX}" userconfig = "{HOME}/.npmrc" @@ -332,6 +333,7 @@ userconfig = "{HOME}/.npmrc" exports[`test/lib/commands/config.js TAP config list > output matches snapshot 1`] = ` ; "cli" config from command line options +cache = "{NPMDIR}/test/lib/commands/tap-testdir-config-config-list-sandbox/cache" prefix = "{LOCALPREFIX}" userconfig = "{HOME}/.npmrc" diff --git a/deps/npm/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs index a0d5795776..ddc80a9350 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs @@ -16,7 +16,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile ancient > must }, "config": {}, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-ancient", + "name": "root", "lockfileVersion": 1, "requires": true }, @@ -36,10 +36,10 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile ancient upgrad } }, "config": { - "lockfileVersion": 3 + "lockfile-version": 3 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-ancient-upgrade", + "name": "root", "lockfileVersion": 3, "requires": true, "packages": {} @@ -61,7 +61,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing > mus }, "config": {}, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing", + "name": "root", "lockfileVersion": 2, "requires": true, "packages": {} @@ -82,10 +82,10 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing downg } }, "config": { - "lockfileVersion": 1 + "lockfile-version": 1 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing-downgrade", + "name": "root", "lockfileVersion": 1, "requires": true }, @@ -105,10 +105,10 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing upgra } }, "config": { - "lockfileVersion": 3 + "lockfile-version": 3 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing-upgrade", + "name": "root", "lockfileVersion": 3, "requires": true, "packages": {} @@ -124,7 +124,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with nothing ancient > must match s "localPrefix": {}, "config": {}, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-nothing-ancient", + "name": "root", "lockfileVersion": 2, "requires": true, "packages": {} @@ -139,10 +139,10 @@ exports[`test/lib/commands/shrinkwrap.js TAP with nothing ancient upgrade > must { "localPrefix": {}, "config": { - "lockfileVersion": 3 + "lockfile-version": 3 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-nothing-ancient-upgrade", + "name": "root", "lockfileVersion": 3, "requires": true, "packages": {} @@ -162,12 +162,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json ancient > }, "config": {}, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient", + "name": "root", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient" + "name": "root" } } }, @@ -185,15 +185,15 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json ancient up } }, "config": { - "lockfileVersion": 3 + "lockfile-version": 3 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient-upgrade", + "name": "root", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient-upgrade" + "name": "root" } } }, @@ -212,12 +212,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing > }, "config": {}, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing", + "name": "root", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing" + "name": "root" } } }, @@ -235,10 +235,10 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing d } }, "config": { - "lockfileVersion": 1 + "lockfile-version": 1 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-downgrade", + "name": "root", "lockfileVersion": 1, "requires": true }, @@ -256,15 +256,15 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing u } }, "config": { - "lockfileVersion": 3 + "lockfile-version": 3 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-upgrade", + "name": "root", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-upgrade" + "name": "root" } } }, @@ -283,12 +283,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json ancient > mu }, "config": {}, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient", + "name": "root", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient" + "name": "root" } } }, @@ -306,15 +306,15 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json ancient upgr } }, "config": { - "lockfileVersion": 3 + "lockfile-version": 3 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient-upgrade", + "name": "root", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient-upgrade" + "name": "root" } } }, @@ -333,12 +333,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing > m }, "config": {}, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing", + "name": "root", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing" + "name": "root" } } }, @@ -356,10 +356,10 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing dow } }, "config": { - "lockfileVersion": 1 + "lockfile-version": 1 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-downgrade", + "name": "root", "lockfileVersion": 1, "requires": true }, @@ -377,15 +377,15 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing upg } }, "config": { - "lockfileVersion": 3 + "lockfile-version": 3 }, "shrinkwrap": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-upgrade", + "name": "root", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-upgrade" + "name": "root" } } }, diff --git a/deps/npm/tap-snapshots/test/lib/commands/view.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/view.js.test.cjs index 10d38cb3f8..72d09b44e2 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/view.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/view.js.test.cjs @@ -82,7 +82,7 @@ dist dist-tags: [1m[32mlatest[39m[22m: 1.0.0 -published [33myesterday[39m +published {TIME} ago[39m ` exports[`test/lib/commands/view.js TAP should log info of package in current working dir specific version > must match snapshot 1`] = ` @@ -99,7 +99,7 @@ dist dist-tags: [1m[32mlatest[39m[22m: 1.0.0 -published [33myesterday[39m +published {TIME} ago[39m ` exports[`test/lib/commands/view.js TAP should log package info package from git > must match snapshot 1`] = ` @@ -302,7 +302,7 @@ dist dist-tags: [1m[32mlatest[39m[22m: 1.0.0 -published [33myesterday[39m +published {TIME} ago[39m ` exports[`test/lib/commands/view.js TAP should log package info package with semver range > must match snapshot 1`] = ` @@ -319,7 +319,7 @@ dist dist-tags: [1m[32mlatest[39m[22m: 1.0.0 -published [33myesterday[39m +published {TIME} ago[39m [4m[1m[32mblue[39m@[32m1.0.1[39m[22m[24m | [1m[31mProprietary[39m[22m | deps: [32mnone[39m | versions: [33m2[39m diff --git a/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index 8c85225f2f..84bb22ff0e 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -1087,8 +1087,8 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for logle * Type: "silent", "error", "warn", "notice", "http", "timing", "info", "verbose", or "silly" -What level of logs to report. On failure, *all* logs are written to -\`npm-debug.log\` in the current working directory. +What level of logs to report. All logs are written to a debug log, with the +path to that file printed if the execution of a command fails. Any logs of a higher level than the setting are shown. The default is "notice". @@ -1462,7 +1462,7 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for save- * Default: false * Type: Boolean -Save installed packages. to a package.json file as \`peerDependencies\` +Save installed packages to a package.json file as \`peerDependencies\` ` exports[`test/lib/utils/config/definitions.js TAP > config description for save-prefix 1`] = ` diff --git a/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index 1ebb336092..3db90f7679 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -888,8 +888,8 @@ Ideal if all users are on npm version 7 and higher. * Type: "silent", "error", "warn", "notice", "http", "timing", "info", "verbose", or "silly" -What level of logs to report. On failure, *all* logs are written to -\`npm-debug.log\` in the current working directory. +What level of logs to report. All logs are written to a debug log, with the +path to that file printed if the execution of a command fails. Any logs of a higher level than the setting are shown. The default is "notice". @@ -1261,7 +1261,7 @@ Save installed packages to a package.json file as \`optionalDependencies\`. * Default: false * Type: Boolean -Save installed packages. to a package.json file as \`peerDependencies\` +Save installed packages to a package.json file as \`peerDependencies\` <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> diff --git a/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs index f035285d70..069212cec3 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs @@ -255,7 +255,7 @@ Object { "summary": Array [ Array [ "notsup", - "Unsupported platform for lodash@1.0.0: wanted {\\"os\\":\\"!yours,mine\\",\\"arch\\":\\"x867,x5309\\"} (current: {\\"os\\":\\"posix\\",\\"arch\\":\\"x64\\"})", + "Unsupported platform for lodash@1.0.0: wanted {/"os/":/"!yours,mine/",/"arch/":/"x867,x5309/"} (current: {/"os/":/"posix/",/"arch/":/"x64/"})", ], ], } @@ -277,7 +277,7 @@ Object { "summary": Array [ Array [ "notsup", - "Unsupported platform for lodash@1.0.0: wanted {\\"os\\":\\"!yours\\",\\"arch\\":\\"x420\\"} (current: {\\"os\\":\\"posix\\",\\"arch\\":\\"x64\\"})", + "Unsupported platform for lodash@1.0.0: wanted {/"os/":/"!yours/",/"arch/":/"x420/"} (current: {/"os/":/"posix/",/"arch/":/"x64/"})", ], ], } @@ -394,7 +394,7 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "/some/cache/dir/dest", + "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-false-cacheDest-true-/cache/dest", "path": "/not/cache/dir/path", }, ], @@ -428,7 +428,7 @@ Object { Error: whoopsie { "code": "EACCES", "dest": "/not/cache/dir/dest", - "path": "/some/cache/dir/path", + "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-true-cacheDest-false-/cache/path", }, ], ], @@ -460,8 +460,8 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "/some/cache/dir/dest", - "path": "/some/cache/dir/path", + "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-true-cacheDest-true-/cache/dest", + "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-true-cacheDest-true-/cache/path", }, ], ], @@ -502,7 +502,12 @@ Object { ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":false,"loaded":true,"cachePath":false,"cacheDest":false} > must match snapshot 2`] = ` -Array [] +Array [ + Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", + ], +] ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":false,"loaded":true,"cachePath":false,"cacheDest":true} > must match snapshot 1`] = ` @@ -517,7 +522,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 867:5309 "/some/cache/dir" + sudo chown -R 867:5309 "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-true-/cache" ), ], ], @@ -527,6 +532,10 @@ Object { exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":false,"loaded":true,"cachePath":false,"cacheDest":true} > must match snapshot 2`] = ` Array [ Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", + ], + Array [ "dummy stack trace", ], ] @@ -544,7 +553,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 867:5309 "/some/cache/dir" + sudo chown -R 867:5309 "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-false-/cache" ), ], ], @@ -554,6 +563,10 @@ Object { exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":false,"loaded":true,"cachePath":true,"cacheDest":false} > must match snapshot 2`] = ` Array [ Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", + ], + Array [ "dummy stack trace", ], ] @@ -571,7 +584,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 867:5309 "/some/cache/dir" + sudo chown -R 867:5309 "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-true-/cache" ), ], ], @@ -581,6 +594,10 @@ Object { exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":false,"loaded":true,"cachePath":true,"cacheDest":true} > must match snapshot 2`] = ` Array [ Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", + ], + Array [ "dummy stack trace", ], ] @@ -642,7 +659,7 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "/some/cache/dir/dest", + "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-false-cacheDest-true-/cache/dest", "path": "/not/cache/dir/path", }, ], @@ -677,7 +694,7 @@ Object { Error: whoopsie { "code": "EACCES", "dest": "/not/cache/dir/dest", - "path": "/some/cache/dir/path", + "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-true-cacheDest-false-/cache/path", }, ], ], @@ -710,8 +727,8 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "/some/cache/dir/dest", - "path": "/some/cache/dir/path", + "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-true-cacheDest-true-/cache/dest", + "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-true-cacheDest-true-/cache/path", }, ], ], @@ -753,7 +770,12 @@ Object { ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":true,"loaded":true,"cachePath":false,"cacheDest":false} > must match snapshot 2`] = ` -Array [] +Array [ + Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", + ], +] ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":true,"loaded":true,"cachePath":false,"cacheDest":true} > must match snapshot 1`] = ` @@ -778,7 +800,7 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "/some/cache/dir/dest", + "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-true-/cache/dest", "path": "/not/cache/dir/path", }, ], @@ -787,7 +809,12 @@ Object { ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":true,"loaded":true,"cachePath":false,"cacheDest":true} > must match snapshot 2`] = ` -Array [] +Array [ + Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", + ], +] ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":true,"loaded":true,"cachePath":true,"cacheDest":false} > must match snapshot 1`] = ` @@ -813,7 +840,7 @@ Object { Error: whoopsie { "code": "EACCES", "dest": "/not/cache/dir/dest", - "path": "/some/cache/dir/path", + "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-false-/cache/path", }, ], ], @@ -821,7 +848,12 @@ Object { ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":true,"loaded":true,"cachePath":true,"cacheDest":false} > must match snapshot 2`] = ` -Array [] +Array [ + Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", + ], +] ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":true,"loaded":true,"cachePath":true,"cacheDest":true} > must match snapshot 1`] = ` @@ -846,8 +878,8 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "/some/cache/dir/dest", - "path": "/some/cache/dir/path", + "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/dest", + "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/path", }, ], ], @@ -855,7 +887,12 @@ Object { ` exports[`test/lib/utils/error-message.js TAP eacces/eperm {"windows":true,"loaded":true,"cachePath":true,"cacheDest":true} > must match snapshot 2`] = ` -Array [] +Array [ + Array [ + "logfile", + "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", + ], +] ` exports[`test/lib/utils/error-message.js TAP enoent without a file > must match snapshot 1`] = ` @@ -863,7 +900,7 @@ Object { "detail": Array [ Array [ "enoent", - "This is related to npm not being able to find a file.\\n", + "This is related to npm not being able to find a file./n", ], ], "summary": Array [ diff --git a/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs index eb383c104a..523aabca29 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs @@ -5,16 +5,56 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/utils/exit-handler.js TAP handles unknown error > should have expected log contents for unknown error 1`] = ` -24 verbose stack Error: ERROR -25 verbose cwd {CWD} -26 verbose Foo 1.0.0 -27 verbose argv "/node" "{CWD}/test/lib/utils/exit-handler.js" -28 verbose node v1.0.0 -29 verbose npm v1.0.0 -30 error code ERROR -31 error ERR ERROR -32 error ERR ERROR -33 verbose exit 1 +exports[`test/lib/utils/exit-handler.js TAP handles unknown error with logs and debug file > debug file contents 1`] = ` +0 timing npm:load:whichnode Completed in {TIME}ms +15 timing config:load Completed in {TIME}ms +16 timing npm:load:configload Completed in {TIME}ms +17 timing npm:load:setTitle Completed in {TIME}ms +19 timing npm:load:display Completed in {TIME}ms +20 verbose logfile {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log +21 timing npm:load:logFile Completed in {TIME}ms +22 timing npm:load:timers Completed in {TIME}ms +23 timing npm:load:configScope Completed in {TIME}ms +24 timing npm:load Completed in {TIME}ms +25 verbose stack Error: Unknown error +26 verbose cwd {CWD} +27 verbose Foo 1.0.0 +28 verbose argv "/node" "{CWD}/test/lib/utils/exit-handler.js" +29 verbose node v1.0.0 +30 verbose npm v1.0.0 +31 error code ECODE +32 error ERR SUMMARY Unknown error +33 error ERR DETAIL Unknown error +34 verbose exit 1 +35 timing npm Completed in {TIME}ms +36 verbose code 1 +37 error A complete log of this run can be found in: +37 error {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log +` +exports[`test/lib/utils/exit-handler.js TAP handles unknown error with logs and debug file > logs 1`] = ` +timing npm:load:whichnode Completed in {TIME}ms +timing config:load Completed in {TIME}ms +timing npm:load:configload Completed in {TIME}ms +timing npm:load:setTitle Completed in {TIME}ms +timing npm:load:display Completed in {TIME}ms +verbose logfile {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log +timing npm:load:logFile Completed in {TIME}ms +timing npm:load:timers Completed in {TIME}ms +timing npm:load:configScope Completed in {TIME}ms +timing npm:load Completed in {TIME}ms +verbose stack Error: Unknown error +verbose cwd {CWD} +verbose Foo 1.0.0 +verbose argv "/node" "{CWD}/test/lib/utils/exit-handler.js" +verbose node v1.0.0 +verbose npm v1.0.0 +error code ECODE +error ERR SUMMARY Unknown error +error ERR DETAIL Unknown error +verbose exit 1 +timing npm Completed in {TIME}ms +verbose code 1 +error A complete log of this run can be found in: + {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log ` diff --git a/deps/npm/tap-snapshots/test/lib/utils/log-file.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/log-file.js.test.cjs new file mode 100644 index 0000000000..ecce9eafcc --- /dev/null +++ b/deps/npm/tap-snapshots/test/lib/utils/log-file.js.test.cjs @@ -0,0 +1,68 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/lib/utils/log-file.js TAP snapshot > must match snapshot 1`] = ` +0 error no prefix +1 error prefix with prefix +2 error prefix 1 2 3 +3 verbose { obj: { with: { many: [Object] } } } +4 verbose {"obj":{"with":{"many":{"props":1}}}} +5 verbose { +5 verbose "obj": { +5 verbose "with": { +5 verbose "many": { +5 verbose "props": 1 +5 verbose } +5 verbose } +5 verbose } +5 verbose } +6 verbose [ 'test', 'with', 'an', 'array' ] +7 verbose ["test","with","an","array"] +8 verbose [ +8 verbose "test", +8 verbose "with", +8 verbose "an", +8 verbose "array" +8 verbose ] +9 verbose [ 'test', [ 'with', [ 'an', [Array] ] ] ] +10 verbose ["test",["with",["an",["array"]]]] +11 verbose [ +11 verbose "test", +11 verbose [ +11 verbose "with", +11 verbose [ +11 verbose "an", +11 verbose [ +11 verbose "array" +11 verbose ] +11 verbose ] +11 verbose ] +11 verbose ] +12 error pre has many errors Error: message +12 error pre at stack trace line 0 +12 error pre at stack trace line 1 +12 error pre at stack trace line 2 +12 error pre at stack trace line 3 +12 error pre at stack trace line 4 +12 error pre at stack trace line 5 +12 error pre at stack trace line 6 +12 error pre at stack trace line 7 +12 error pre at stack trace line 8 +12 error pre at stack trace line 9 Error: message2 +12 error pre at stack trace line 0 +12 error pre at stack trace line 1 +12 error pre at stack trace line 2 +12 error pre at stack trace line 3 +12 error pre at stack trace line 4 +12 error pre at stack trace line 5 +12 error pre at stack trace line 6 +12 error pre at stack trace line 7 +12 error pre at stack trace line 8 +12 error pre at stack trace line 9 +13 error nostack [Error: message] + +` diff --git a/deps/npm/test/fixtures/clean-snapshot.js b/deps/npm/test/fixtures/clean-snapshot.js new file mode 100644 index 0000000000..037155eea1 --- /dev/null +++ b/deps/npm/test/fixtures/clean-snapshot.js @@ -0,0 +1,19 @@ +// XXX: this also cleans quoted " in json snapshots +// ideally this could be avoided but its easier to just +// run this command inside cleanSnapshot +const normalizePath = (str) => str + .replace(/\r\n/g, '\n') // normalize line endings (for ini) + .replace(/[A-z]:\\/g, '\\') // turn windows roots to posix ones + .replace(/\\+/g, '/') // replace \ with / + +const cleanCwd = (path) => normalizePath(path) + .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') + +const cleanDate = (str) => + str.replace(/\d{4}-\d{2}-\d{2}T\d{2}[_:]\d{2}[_:]\d{2}[_:]\d{3}Z/g, '{DATE}') + +module.exports = { + normalizePath, + cleanCwd, + cleanDate, +} diff --git a/deps/npm/test/fixtures/mock-globals.js b/deps/npm/test/fixtures/mock-globals.js new file mode 100644 index 0000000000..29da2a48b0 --- /dev/null +++ b/deps/npm/test/fixtures/mock-globals.js @@ -0,0 +1,210 @@ +// An initial implementation for a feature that will hopefully exist in tap +// https://github.com/tapjs/node-tap/issues/789 +// This file is only used in tests but it is still tested itself. +// Hopefully it can be removed for a feature in tap in the future + +const sep = '.' +const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k) +const opd = (o, k) => Object.getOwnPropertyDescriptor(o, k) +const po = (o) => Object.getPrototypeOf(o) +const pojo = (o) => Object.prototype.toString.call(o) === '[object Object]' +const last = (arr) => arr[arr.length - 1] +const splitLast = (str) => str.split(new RegExp(`\\${sep}(?=[^${sep}]+$)`)) +const dupes = (arr) => arr.filter((k, i) => arr.indexOf(k) !== i) +const dupesStartsWith = (arr) => arr.filter((k1) => arr.some((k2) => k2.startsWith(k1 + sep))) + +// A weird getter that can look up keys on nested objects but also +// match keys with dots in their names, eg { 'process.env': { TERM: 'a' } } +// can be looked up with the key 'process.env.TERM' +const get = (obj, key, childKey = '') => { + if (has(obj, key)) { + return childKey ? get(obj[key], childKey) : obj[key] + } else if (key.includes(sep)) { + const [parentKey, prefix] = splitLast(key) + return get( + obj, + parentKey, + prefix + (childKey && sep + childKey) + ) + } +} + +// Map an object to an array of nested keys separated by dots +// { a: 1, b: { c: 2, d: [1] } } => ['a', 'b.c', 'b.d'] +const getKeys = (values, p = '', acc = []) => + Object.entries(values).reduce((memo, [k, value]) => { + const key = p ? [p, k].join(sep) : k + return pojo(value) ? getKeys(value, key, memo) : memo.concat(key) + }, acc) + +// Walk prototype chain to get first available descriptor. This is necessary +// to get the current property descriptor for things like `process.on`. +// Since `opd(process, 'on') === undefined` but if you +// walk up the prototype chain you get the original descriptor +// `opd(po(po(process)), 'on') === { value, ... }` +const protoDescriptor = (obj, key) => { + let descriptor + // i always wanted to assign variables in a while loop's condition + // i thought it would feel better than this + while (!(descriptor = opd(obj, key))) { + if (!(obj = po(obj))) { + break + } + } + return descriptor +} + +// Path can be different cases across platform so get the original case +// of the path before anything is changed +// XXX: other special cases to handle? +const specialCaseKeys = (() => { + const originalKeys = { + PATH: process.env.PATH ? 'PATH' : process.env.Path ? 'Path' : 'path', + } + return (key) => { + switch (key.toLowerCase()) { + case 'process.env.path': + return originalKeys.PATH + } + } +})() + +const _setGlobal = Symbol('setGlobal') +const _nextDescriptor = Symbol('nextDescriptor') + +class DescriptorStack { + #stack = [] + #global = null + #valueKey = null + #defaultDescriptor = { configurable: true, writable: true, enumerable: true } + #delete = () => ({ DELETE: true }) + #isDelete = (o) => o && o.DELETE === true + + constructor (key) { + const keys = splitLast(key) + this.#global = keys.length === 1 ? global : get(global, keys[0]) + this.#valueKey = specialCaseKeys(key) || last(keys) + // If the global object doesnt return a descriptor for the key + // then we mark it for deletion on teardown + this.#stack = [ + protoDescriptor(this.#global, this.#valueKey) || this.#delete(), + ] + } + + add (value) { + // This must be a unique object so we can find it later via indexOf + // That's why delete/nextDescriptor create new objects + const nextDescriptor = this[_nextDescriptor](value) + this.#stack.push(this[_setGlobal](nextDescriptor)) + + return () => { + const index = this.#stack.indexOf(nextDescriptor) + // If the stack doesnt contain the descriptor anymore + // than do nothing. This keeps the reset function indempotent + if (index > -1) { + // Resetting removes a descriptor from the stack + this.#stack.splice(index, 1) + // But we always reset to what is now the most recent in case + // resets are being called manually out of order + this[_setGlobal](last(this.#stack)) + } + } + } + + reset () { + // Everything could be reset manually so only + // teardown if we have an initial descriptor left + // and then delete the rest of the stack + if (this.#stack.length) { + this[_setGlobal](this.#stack[0]) + this.#stack.length = 0 + } + } + + [_setGlobal] (d) { + if (this.#isDelete(d)) { + delete this.#global[this.#valueKey] + } else { + Object.defineProperty(this.#global, this.#valueKey, d) + } + return d + } + + [_nextDescriptor] (value) { + if (value === undefined) { + return this.#delete() + } + const d = last(this.#stack) + return { + // If the previous descriptor was one to delete the property + // then use the default descriptor as the base + ...(this.#isDelete(d) ? this.#defaultDescriptor : d), + ...(d && d.get ? { get: () => value } : { value }), + } + } +} + +class MockGlobals { + #descriptors = {} + + register (globals, { replace = false } = {}) { + // Replace means dont merge in object values but replace them instead + // so we only get top level keys instead of walking the obj + const keys = replace ? Object.keys(globals) : getKeys(globals) + + // An error state where due to object mode there are multiple global + // values to be set with the same key + const duplicates = dupes(keys) + if (duplicates.length) { + throw new Error(`mockGlobals was called with duplicate keys: ${duplicates}`) + } + + // Another error where when in replace mode overlapping keys are set like + // process and process.stdout which would cause unexpected behavior + const overlapping = dupesStartsWith(keys) + if (overlapping.length) { + const message = overlapping + .map((k) => `${k} -> ${keys.filter((kk) => kk.startsWith(k + sep))}`) + throw new Error(`mockGlobals was called with overlapping keys: ${message}`) + } + + // Set each property passed in and return fns to reset them + // Return an object with each path as a key for manually resetting in each test + return keys.reduce((acc, key) => { + const desc = this.#descriptors[key] || (this.#descriptors[key] = new DescriptorStack(key)) + acc[key] = desc.add(get(globals, key)) + return acc + }, {}) + } + + teardown (key) { + if (!key) { + Object.values(this.#descriptors).forEach((d) => d.reset()) + return + } + this.#descriptors[key].reset() + } +} + +// Each test has one instance of MockGlobals so it can be called multiple times per test +// Its a weak map so that it can be garbage collected along with the tap tests without +// needing to explicitly call cache.delete +const cache = new WeakMap() + +module.exports = (t, globals, options) => { + let instance = cache.get(t) + if (!instance) { + instance = cache.set(t, new MockGlobals()).get(t) + // Teardown only needs to be initialized once. The instance + // will keep track of its own state during the test + t.teardown(() => instance.teardown()) + } + + return { + // Reset contains only the functions to reset the globals + // set by this function call + reset: instance.register(globals, options), + // Teardown will reset across all calls tied to this test + teardown: () => instance.teardown(), + } +} diff --git a/deps/npm/test/fixtures/mock-logs.js b/deps/npm/test/fixtures/mock-logs.js new file mode 100644 index 0000000000..80037c6ffa --- /dev/null +++ b/deps/npm/test/fixtures/mock-logs.js @@ -0,0 +1,71 @@ + +const NPMLOG = require('npmlog') +const { LEVELS } = require('proc-log') + +const merge = (...objs) => objs.reduce((acc, obj) => ({ ...acc, ...obj })) + +const mockLogs = (otherMocks = {}) => { + // Return mocks as an array with getters for each level + // that return an array of logged properties with the + // level removed. This is for convenience throughout tests + const logs = Object.defineProperties( + [], + ['timing', ...LEVELS].reduce((acc, level) => { + acc[level] = { + get () { + return this + .filter(([l]) => level === l) + .map(([l, ...args]) => args) + }, + } + return acc + }, {}) + ) + + // This returns an object with mocked versions of all necessary + // logging modules. It mocks them with methods that add logs + // to an array which it also returns. The reason it also returns + // the mocks is that in tests the same instance of these mocks + // should be passed to multiple calls to t.mock. + // XXX: this is messy and fragile and should be removed in favor + // of some other way to collect and filter logs across all tests + const logMocks = { + 'proc-log': merge( + { LEVELS }, + LEVELS.reduce((acc, l) => { + acc[l] = (...args) => { + // Re-emit log item for since the log file listens on these + process.emit('log', l, ...args) + // Dont add pause/resume events to the logs. Those aren't displayed + // and emitting them is tested in the display layer + if (l !== 'pause' && l !== 'resume') { + logs.push([l, ...args]) + } + } + return acc + }, {}), + otherMocks['proc-log'] + ), + // Object.assign is important here because we need to assign + // mocked properties directly to npmlog and then mock with that + // object. This is necessary so tests can still directly set + // `log.level = 'silent'` anywhere in the test and have that + // that reflected in the npmlog singleton. + // XXX: remove with npmlog + npmlog: Object.assign(NPMLOG, merge( + // no-op all npmlog methods by default so tests + // dont output anything to the terminal + Object.keys(NPMLOG.levels).reduce((acc, k) => { + acc[k] = () => {} + return acc + }, {}), + // except collect timing logs + { timing: (...args) => logs.push(['timing', ...args]) }, + otherMocks.npmlog + )), + } + + return { logs, logMocks } +} + +module.exports = mockLogs diff --git a/deps/npm/test/fixtures/mock-npm.js b/deps/npm/test/fixtures/mock-npm.js index a51ec3e5bb..7518855319 100644 --- a/deps/npm/test/fixtures/mock-npm.js +++ b/deps/npm/test/fixtures/mock-npm.js @@ -1,71 +1,126 @@ -const npmlog = require('npmlog') -const procLog = require('../../lib/utils/proc-log-listener.js') -procLog.reset() - -// In theory we shouldn't have to do this if all the tests were tearing down -// their listeners properly, we're still getting warnings even though -// perfStop() and procLog.reset() is in the teardown script. This silences the -// warnings for now -require('events').defaultMaxListeners = Infinity - -const realLog = {} -for (const level in npmlog.levels) { - realLog[level] = npmlog[level] -} - -const { title, execPath } = process +const os = require('os') +const fs = require('fs').promises +const path = require('path') +const mockLogs = require('./mock-logs') +const mockGlobals = require('./mock-globals') +const log = require('../../lib/utils/log-shim') -// Eventually this should default to having a prefix of an empty testdir, and -// awaiting npm.load() unless told not to (for npm tests for example). Ideally -// the prefix of an empty dir is inferred rather than explicitly set const RealMockNpm = (t, otherMocks = {}) => { - const mock = {} - mock.logs = [] - mock.outputs = [] - mock.joinedOutput = () => { - return mock.outputs.map(o => o.join(' ')).join('\n') + const mock = { + ...mockLogs(otherMocks), + outputs: [], + joinedOutput: () => mock.outputs.map(o => o.join(' ')).join('\n'), } - mock.filteredLogs = title => mock.logs.filter(([t]) => t === title).map(([, , msg]) => msg) - const Npm = t.mock('../../lib/npm.js', otherMocks) - class MockNpm extends Npm { - constructor () { - super() - for (const level in npmlog.levels) { - npmlog[level] = (...msg) => { - mock.logs.push([level, ...msg]) - - const l = npmlog.level - npmlog.level = 'silent' - realLog[level](...msg) - npmlog.level = l - } - } - // npm.js tests need this restored to actually test this function! - mock.npmOutput = this.output - this.output = (...msg) => mock.outputs.push(msg) + + const Npm = t.mock('../../lib/npm.js', { + ...otherMocks, + ...mock.logMocks, + }) + + mock.Npm = class MockNpm extends Npm { + // lib/npm.js tests needs this to actually test the function! + originalOutput (...args) { + super.output(...args) + } + + output (...args) { + mock.outputs.push(args) } } - mock.Npm = MockNpm - t.afterEach(() => { - mock.outputs.length = 0 - mock.logs.length = 0 + + return mock +} + +// Resolve some options to a function call with supplied args +const result = (fn, ...args) => typeof fn === 'function' ? fn(...args) : fn + +const LoadMockNpm = async (t, { + init = true, + load = init, + testdir = {}, + config = {}, + mocks = {}, + globals = null, +} = {}) => { + // Mock some globals with their original values so they get torn down + // back to the original at the end of the test since they are manipulated + // by npm itself + mockGlobals(t, { + process: { + title: process.title, + execPath: process.execPath, + env: { + npm_command: process.env.npm_command, + COLOR: process.env.COLOR, + }, + }, }) - t.teardown(() => { - process.removeAllListeners('time') - process.removeAllListeners('timeEnd') - npmlog.record.length = 0 - for (const level in npmlog.levels) { - npmlog[level] = realLog[level] - } - procLog.reset() - process.title = title - process.execPath = execPath - delete process.env.npm_command - delete process.env.COLOR + const { Npm, ...rest } = RealMockNpm(t, mocks) + + if (!init && load) { + throw new Error('cant `load` without `init`') + } + + const _level = log.level + t.teardown(() => log.level = _level) + + if (config.loglevel) { + // Set log level as early as possible since it is set + // on the npmlog singleton and shared across everything + log.level = config.loglevel + } + + const dir = t.testdir({ root: testdir, cache: {} }) + const prefix = path.join(dir, 'root') + const cache = path.join(dir, 'cache') + + // Set cache to testdir via env var so it is available when load is run + // XXX: remove this for a solution where cache argv is passed in + mockGlobals(t, { + 'process.env.npm_config_cache': cache, }) - return mock + if (globals) { + mockGlobals(t, result(globals, { prefix, cache })) + } + + const npm = init ? new Npm() : null + t.teardown(() => npm && npm.unload()) + + if (load) { + await npm.load() + for (const [k, v] of Object.entries(result(config, { npm, prefix, cache }))) { + npm.config.set(k, v) + } + if (config.loglevel) { + // Set global loglevel *again* since it possibly got reset during load + // XXX: remove with npmlog + log.level = config.loglevel + } + npm.prefix = prefix + npm.cache = cache + } + + return { + ...rest, + Npm, + npm, + prefix, + cache, + debugFile: async () => { + const readFiles = npm.logFiles.map(f => fs.readFile(f)) + const logFiles = await Promise.all(readFiles) + return logFiles + .flatMap((d) => d.toString().trim().split(os.EOL)) + .filter(Boolean) + .join('\n') + }, + timingFile: async () => { + const data = await fs.readFile(path.resolve(cache, '_timing.json'), 'utf8') + return JSON.parse(data) // XXX: this fails if multiple timings are written + }, + } } const realConfig = require('../../lib/utils/config') @@ -96,21 +151,6 @@ class MockNpm { set: (k, v) => config[k] = v, list: [{ ...realConfig.defaults, ...config }], } - if (!this.log) { - this.log = { - clearProgress: () => {}, - disableProgress: () => {}, - enableProgress: () => {}, - http: () => {}, - info: () => {}, - levels: [], - notice: () => {}, - pause: () => {}, - silly: () => {}, - verbose: () => {}, - warn: () => {}, - } - } } output (...msg) { @@ -127,5 +167,5 @@ const FakeMockNpm = (base = {}) => { module.exports = { fake: FakeMockNpm, - real: RealMockNpm, + load: LoadMockNpm, } diff --git a/deps/npm/test/fixtures/sandbox.js b/deps/npm/test/fixtures/sandbox.js index b012790fb5..701d9cea72 100644 --- a/deps/npm/test/fixtures/sandbox.js +++ b/deps/npm/test/fixtures/sandbox.js @@ -4,15 +4,12 @@ const { homedir, tmpdir } = require('os') const { dirname, join } = require('path') const { promisify } = require('util') const mkdirp = require('mkdirp-infer-owner') -const npmlog = require('npmlog') const rimraf = promisify(require('rimraf')) +const mockLogs = require('./mock-logs') const chain = new Map() const sandboxes = new Map() -// Disable lint errors for assigning to process global -/* global process:writable */ - // keep a reference to the real process const _process = process @@ -34,19 +31,6 @@ createHook({ }, }).enable() -for (const level in npmlog.levels) { - npmlog[`_${level}`] = npmlog[level] - npmlog[level] = (...args) => { - process._logs = process._logs || {} - process._logs[level] = process._logs[level] || [] - process._logs[level].push(args) - const _level = npmlog.level - npmlog.level = 'silent' - npmlog[`_${level}`](...args) - npmlog.level = _level - } -} - const _data = Symbol('sandbox.data') const _dirs = Symbol('sandbox.dirs') const _test = Symbol('sandbox.test') @@ -57,6 +41,7 @@ const _output = Symbol('sandbox.output') const _proxy = Symbol('sandbox.proxy') const _get = Symbol('sandbox.proxy.get') const _set = Symbol('sandbox.proxy.set') +const _logs = Symbol('sandbox.logs') // these config keys can be redacted widely const redactedDefaults = [ @@ -92,6 +77,7 @@ class Sandbox extends EventEmitter { global: options.global || join(tempDir, 'global'), home: options.home || join(tempDir, 'home'), project: options.project || join(tempDir, 'project'), + cache: options.cache || join(tempDir, 'cache'), } this[_proxy] = new Proxy(_process, { @@ -111,7 +97,7 @@ class Sandbox extends EventEmitter { } get logs () { - return this[_proxy]._logs + return this[_logs] } get global () { @@ -126,6 +112,10 @@ class Sandbox extends EventEmitter { return this[_dirs].project } + get cache () { + return this[_dirs].cache + } + get process () { return this[_proxy] } @@ -205,7 +195,9 @@ class Sandbox extends EventEmitter { if (this[_parent]) { sandboxes.delete(this[_parent]) } - + if (this[_npm]) { + this[_npm].unload() + } return rimraf(this[_dirs].temp).catch(() => null) } @@ -275,11 +267,17 @@ class Sandbox extends EventEmitter { '--prefix', this.project, '--userconfig', join(this.home, '.npmrc'), '--globalconfig', join(this.global, 'npmrc'), + '--cache', this.cache, command, ...argv, ] - const Npm = this[_test].mock('../../lib/npm.js', this[_mocks]) + const mockedLogs = mockLogs(this[_mocks]) + this[_logs] = mockedLogs.logs + const Npm = this[_test].mock('../../lib/npm.js', { + ...this[_mocks], + ...mockedLogs.logMocks, + }) this[_npm] = new Npm() this[_npm].output = (...args) => this[_output].push(args) await this[_npm].load() @@ -321,11 +319,17 @@ class Sandbox extends EventEmitter { '--prefix', this.project, '--userconfig', join(this.home, '.npmrc'), '--globalconfig', join(this.global, 'npmrc'), + '--cache', this.cache, command, ...argv, ] - const Npm = this[_test].mock('../../lib/npm.js', this[_mocks]) + const mockedLogs = mockLogs(this[_mocks]) + this[_logs] = mockedLogs.logs + const Npm = this[_test].mock('../../lib/npm.js', { + ...this[_mocks], + ...mockedLogs.logMocks, + }) this[_npm] = new Npm() this[_npm].output = (...args) => this[_output].push(args) await this[_npm].load() diff --git a/deps/npm/test/index.js b/deps/npm/test/index.js index 26db16e1f7..081c89cee9 100644 --- a/deps/npm/test/index.js +++ b/deps/npm/test/index.js @@ -1,16 +1,18 @@ const t = require('tap') const index = require.resolve('../index.js') const packageIndex = require.resolve('../') + t.equal(index, packageIndex, 'index is main package require() export') t.throws(() => require(index), { message: 'The programmatic API was removed in npm v8.0.0', }) t.test('loading as main module will load the cli', t => { + const cwd = t.testdir() const { spawn } = require('child_process') const LS = require('../lib/commands/ls.js') const ls = new LS({}) - const p = spawn(process.execPath, [index, 'ls', '-h']) + const p = spawn(process.execPath, [index, 'ls', '-h', '--cache', cwd]) const out = [] p.stdout.on('data', c => out.push(c)) p.on('close', (code, signal) => { diff --git a/deps/npm/test/lib/auth/legacy.js b/deps/npm/test/lib/auth/legacy.js index 7b61e9f6e9..0c23f8ba6b 100644 --- a/deps/npm/test/lib/auth/legacy.js +++ b/deps/npm/test/lib/auth/legacy.js @@ -6,7 +6,7 @@ const token = '24528a24f240' const profile = {} const read = {} const legacy = t.mock('../../../lib/auth/legacy.js', { - npmlog: { + 'proc-log': { info: (...msgs) => { log += msgs.join(' ') }, diff --git a/deps/npm/test/lib/auth/sso.js b/deps/npm/test/lib/auth/sso.js index d592205593..473c8cc241 100644 --- a/deps/npm/test/lib/auth/sso.js +++ b/deps/npm/test/lib/auth/sso.js @@ -11,7 +11,7 @@ const SSO_URL = 'https://registry.npmjs.org/{SSO_URL}' const profile = {} const npmFetch = {} const sso = t.mock('../../../lib/auth/sso.js', { - npmlog: { + 'proc-log': { info: (...msgs) => { log += msgs.join(' ') + '\n' }, diff --git a/deps/npm/test/lib/cli.js b/deps/npm/test/lib/cli.js index d762943b47..f02c57d8cf 100644 --- a/deps/npm/test/lib/cli.js +++ b/deps/npm/test/lib/cli.js @@ -1,176 +1,153 @@ const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm.js') - -const unsupportedMock = { - checkForBrokenNode: () => {}, - checkForUnsupportedNode: () => {}, -} - -let exitHandlerCalled = null -let exitHandlerNpm = null -let exitHandlerCb -const exitHandlerMock = (...args) => { - exitHandlerCalled = args - if (exitHandlerCb) { - exitHandlerCb() +const mockGlobals = require('../fixtures/mock-globals.js') +const { load: loadMockNpm } = require('../fixtures/mock-npm.js') + +const cliMock = async (t, mocks) => { + let exitHandlerArgs = null + let npm = null + const exitHandlerMock = (...args) => { + exitHandlerArgs = args + npm.unload() } -} -exitHandlerMock.setNpm = npm => { - exitHandlerNpm = npm -} - -const logs = [] -const npmlogMock = { - pause: () => logs.push('pause'), - verbose: (...msg) => logs.push(['verbose', ...msg]), - info: (...msg) => logs.push(['info', ...msg]), -} + exitHandlerMock.setNpm = _npm => npm = _npm -const cliMock = Npm => - t.mock('../../lib/cli.js', { + const { Npm, outputs, logMocks, logs } = await loadMockNpm(t, { mocks, init: false }) + const cli = t.mock('../../lib/cli.js', { '../../lib/npm.js': Npm, '../../lib/utils/update-notifier.js': async () => null, - '../../lib/utils/unsupported.js': unsupportedMock, + '../../lib/utils/unsupported.js': { + checkForBrokenNode: () => {}, + checkForUnsupportedNode: () => {}, + }, '../../lib/utils/exit-handler.js': exitHandlerMock, - npmlog: npmlogMock, + ...logMocks, }) -const processMock = proc => { - const mocked = { - ...process, - on: () => {}, - ...proc, + return { + Npm, + cli, + outputs, + exitHandlerCalled: () => exitHandlerArgs, + exitHandlerNpm: () => npm, + logs, } - // nopt looks at process directly - process.argv = mocked.argv - return mocked } -const { argv } = process - t.afterEach(() => { - logs.length = 0 - process.argv = argv - exitHandlerCalled = null - exitHandlerNpm = null + delete process.exitCode }) t.test('print the version, and treat npm_g as npm -g', async t => { - const proc = processMock({ - argv: ['node', 'npm_g', '-v'], - version: process.version, + mockGlobals(t, { + 'process.argv': ['node', 'npm_g', '-v'], }) - const { Npm, outputs } = mockNpm(t) - const cli = cliMock(Npm) - await cli(proc) + const { logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t) + await cli(process) - t.strictSame(proc.argv, ['node', 'npm', '-g', '-v'], 'npm process.argv was rewritten') t.strictSame(process.argv, ['node', 'npm', '-g', '-v'], 'system process.argv was rewritten') - t.strictSame(logs, [ - 'pause', - ['verbose', 'cli', proc.argv], - ['info', 'using', 'npm@%s', Npm.version], - ['info', 'using', 'node@%s', process.version], + t.strictSame(logs.verbose.filter(([p]) => p !== 'logfile'), [ + ['cli', process.argv], + ]) + t.strictSame(logs.info, [ + ['using', 'npm@%s', Npm.version], + ['using', 'node@%s', process.version], ]) t.strictSame(outputs, [[Npm.version]]) - t.strictSame(exitHandlerCalled, []) + t.strictSame(exitHandlerCalled(), []) }) t.test('calling with --versions calls npm version with no args', async t => { - t.plan(5) - const proc = processMock({ - argv: ['node', 'npm', 'install', 'or', 'whatever', '--versions'], + t.plan(6) + mockGlobals(t, { + 'process.argv': ['node', 'npm', 'install', 'or', 'whatever', '--versions'], }) - const { Npm, outputs } = mockNpm(t, { + const { logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t, { '../../lib/commands/version.js': class Version { async exec (args) { t.strictSame(args, []) } }, }) - const cli = cliMock(Npm) - await cli(proc) - t.equal(proc.title, 'npm') - t.strictSame(logs, [ - 'pause', - ['verbose', 'cli', proc.argv], - ['info', 'using', 'npm@%s', Npm.version], - ['info', 'using', 'node@%s', process.version], + + await cli(process) + t.equal(process.title, 'npm install or whatever') + t.strictSame(logs.verbose.filter(([p]) => p !== 'logfile'), [ + ['cli', process.argv], + ]) + t.strictSame(logs.info, [ + ['using', 'npm@%s', Npm.version], + ['using', 'node@%s', process.version], ]) t.strictSame(outputs, []) - t.strictSame(exitHandlerCalled, []) + t.strictSame(exitHandlerCalled(), []) }) t.test('logged argv is sanitized', async t => { - const proc = processMock({ - argv: [ + mockGlobals(t, { + 'process.argv': [ 'node', 'npm', 'version', 'https://username:password@npmjs.org/test_url_with_a_password', ], }) - const { Npm } = mockNpm(t, { + const { logs, cli, Npm } = await cliMock(t, { '../../lib/commands/version.js': class Version { async exec (args) {} }, }) - const cli = cliMock(Npm) - - await cli(proc) - t.equal(proc.title, 'npm') - t.strictSame(logs, [ - 'pause', + await cli(process) + t.ok(process.title.startsWith('npm version https://username:***@npmjs.org')) + t.strictSame(logs.verbose.filter(([p]) => p !== 'logfile'), [ [ - 'verbose', 'cli', ['node', 'npm', 'version', 'https://username:***@npmjs.org/test_url_with_a_password'], ], - ['info', 'using', 'npm@%s', Npm.version], - ['info', 'using', 'node@%s', process.version], + ]) + t.strictSame(logs.info, [ + ['using', 'npm@%s', Npm.version], + ['using', 'node@%s', process.version], ]) }) t.test('print usage if no params provided', async t => { - const proc = processMock({ - argv: ['node', 'npm'], + mockGlobals(t, { + 'process.argv': ['node', 'npm'], }) - const { Npm, outputs } = mockNpm(t) - const cli = cliMock(Npm) - await cli(proc) + const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t) + await cli(process) t.match(outputs[0][0], 'Usage:', 'outputs npm usage') - t.match(exitHandlerCalled, [], 'should call exitHandler with no args') - t.ok(exitHandlerNpm, 'exitHandler npm is set') - t.match(proc.exitCode, 1) + t.match(exitHandlerCalled(), [], 'should call exitHandler with no args') + t.ok(exitHandlerNpm(), 'exitHandler npm is set') + t.match(process.exitCode, 1) }) t.test('print usage if non-command param provided', async t => { - const proc = processMock({ - argv: ['node', 'npm', 'tset'], + mockGlobals(t, { + 'process.argv': ['node', 'npm', 'tset'], }) - const { Npm, outputs } = mockNpm(t) - const cli = cliMock(Npm) - await cli(proc) + const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t) + await cli(process) t.match(outputs[0][0], 'Unknown command: "tset"') t.match(outputs[0][0], 'Did you mean this?') - t.match(exitHandlerCalled, [], 'should call exitHandler with no args') - t.ok(exitHandlerNpm, 'exitHandler npm is set') - t.match(proc.exitCode, 1) + t.match(exitHandlerCalled(), [], 'should call exitHandler with no args') + t.ok(exitHandlerNpm(), 'exitHandler npm is set') + t.match(process.exitCode, 1) }) t.test('load error calls error handler', async t => { - const proc = processMock({ - argv: ['node', 'npm', 'asdf'], + mockGlobals(t, { + 'process.argv': ['node', 'npm', 'asdf'], }) const err = new Error('test load error') - const { Npm } = mockNpm(t, { + const { cli, exitHandlerCalled } = await cliMock(t, { '../../lib/utils/config/index.js': { definitions: null, flatten: null, @@ -182,7 +159,6 @@ t.test('load error calls error handler', async t => { } }, }) - const cli = cliMock(Npm) - await cli(proc) - t.strictSame(exitHandlerCalled, [err]) + await cli(process) + t.strictSame(exitHandlerCalled(), [err]) }) diff --git a/deps/npm/test/lib/commands/access.js b/deps/npm/test/lib/commands/access.js index fdf132aff9..298897e4f5 100644 --- a/deps/npm/test/lib/commands/access.js +++ b/deps/npm/test/lib/commands/access.js @@ -1,18 +1,9 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm.js') - -const { Npm } = mockNpm(t) -const npm = new Npm() - -const prefix = t.testdir({}) - -t.before(async () => { - await npm.load() - npm.prefix = prefix -}) +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') t.test('completion', async t => { + const { npm } = await loadMockNpm(t) const access = await npm.cmd('access') const testComp = (argv, expect) => { const res = access.completion({ conf: { argv: { remain: argv } } }) @@ -42,6 +33,7 @@ t.test('completion', async t => { }) t.test('subcommand required', async t => { + const { npm } = await loadMockNpm(t) const access = await npm.cmd('access') await t.rejects( npm.exec('access', []), @@ -50,6 +42,7 @@ t.test('subcommand required', async t => { }) t.test('unrecognized subcommand', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', ['blerg']), /Usage: blerg is not a recognized subcommand/, @@ -58,6 +51,7 @@ t.test('unrecognized subcommand', async t => { }) t.test('edit', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', ['edit', '@scoped/another']), /edit subcommand is not implemented yet/, @@ -66,15 +60,13 @@ t.test('edit', async t => { }) t.test('access public on unscoped package', async t => { - t.teardown(() => { - npm.prefix = prefix - }) - const testdir = t.testdir({ - 'package.json': JSON.stringify({ - name: 'npm-access-public-pkg', - }), + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'npm-access-public-pkg', + }), + }, }) - npm.prefix = testdir await t.rejects( npm.exec('access', ['public']), /Usage: This command is only available for scoped packages/, @@ -84,30 +76,30 @@ t.test('access public on unscoped package', async t => { t.test('access public on scoped package', async t => { t.plan(2) - const { Npm } = mockNpm(t, { - libnpmaccess: { - public: (pkg, { registry }) => { - t.equal(pkg, name, 'should use pkg name ref') - t.equal( - registry, - 'https://registry.npmjs.org/', - 'should forward correct options' - ) - return true + const name = '@scoped/npm-access-public-pkg' + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + public: (pkg, { registry }) => { + t.equal(pkg, name, 'should use pkg name ref') + t.equal( + registry, + 'https://registry.npmjs.org/', + 'should forward correct options' + ) + return true + }, }, }, + testdir: { + 'package.json': JSON.stringify({ name }), + }, }) - const npm = new Npm() - await npm.load() - const name = '@scoped/npm-access-public-pkg' - const testdir = t.testdir({ - 'package.json': JSON.stringify({ name }), - }) - npm.prefix = testdir await npm.exec('access', ['public']) }) t.test('access public on missing package.json', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', ['public']), /no package name passed to command and no package.json found/, @@ -116,14 +108,12 @@ t.test('access public on missing package.json', async t => { }) t.test('access public on invalid package.json', async t => { - t.teardown(() => { - npm.prefix = prefix - }) - const testdir = t.testdir({ - 'package.json': '{\n', - node_modules: {}, + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': '{\n', + node_modules: {}, + }, }) - npm.prefix = testdir await t.rejects( npm.exec('access', ['public']), { code: 'EJSONPARSE' }, @@ -132,15 +122,13 @@ t.test('access public on invalid package.json', async t => { }) t.test('access restricted on unscoped package', async t => { - t.teardown(() => { - npm.prefix = prefix - }) - const testdir = t.testdir({ - 'package.json': JSON.stringify({ - name: 'npm-access-restricted-pkg', - }), + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'npm-access-restricted-pkg', + }), + }, }) - npm.prefix = testdir await t.rejects( npm.exec('access', ['public']), /Usage: This command is only available for scoped packages/, @@ -150,30 +138,30 @@ t.test('access restricted on unscoped package', async t => { t.test('access restricted on scoped package', async t => { t.plan(2) - const { Npm } = mockNpm(t, { - libnpmaccess: { - restricted: (pkg, { registry }) => { - t.equal(pkg, name, 'should use pkg name ref') - t.equal( - registry, - 'https://registry.npmjs.org/', - 'should forward correct options' - ) - return true + const name = '@scoped/npm-access-restricted-pkg' + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + restricted: (pkg, { registry }) => { + t.equal(pkg, name, 'should use pkg name ref') + t.equal( + registry, + 'https://registry.npmjs.org/', + 'should forward correct options' + ) + return true + }, }, }, + testdir: { + 'package.json': JSON.stringify({ name }), + }, }) - const npm = new Npm() - await npm.load() - const name = '@scoped/npm-access-restricted-pkg' - const testdir = t.testdir({ - 'package.json': JSON.stringify({ name }), - }) - npm.prefix = testdir await npm.exec('access', ['restricted']) }) t.test('access restricted on missing package.json', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', ['restricted']), /no package name passed to command and no package.json found/, @@ -182,14 +170,12 @@ t.test('access restricted on missing package.json', async t => { }) t.test('access restricted on invalid package.json', async t => { - t.teardown(() => { - npm.prefix = prefix - }) - const testdir = t.testdir({ - 'package.json': '{\n', - node_modules: {}, + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': '{\n', + node_modules: {}, + }, }) - npm.prefix = testdir await t.rejects( npm.exec('access', ['restricted']), { code: 'EJSONPARSE' }, @@ -199,17 +185,18 @@ t.test('access restricted on invalid package.json', async t => { t.test('access grant read-only', async t => { t.plan(3) - const { Npm } = mockNpm(t, { - libnpmaccess: { - grant: (spec, team, permissions) => { - t.equal(spec, '@scoped/another', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - t.equal(permissions, 'read-only', 'should forward permissions') - return true + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + grant: (spec, team, permissions) => { + t.equal(spec, '@scoped/another', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + t.equal(permissions, 'read-only', 'should forward permissions') + return true + }, }, }, }) - const npm = new Npm() await npm.exec('access', [ 'grant', 'read-only', @@ -220,17 +207,18 @@ t.test('access grant read-only', async t => { t.test('access grant read-write', async t => { t.plan(3) - const { Npm } = mockNpm(t, { - libnpmaccess: { - grant: (spec, team, permissions) => { - t.equal(spec, '@scoped/another', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - t.equal(permissions, 'read-write', 'should forward permissions') - return true + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + grant: (spec, team, permissions) => { + t.equal(spec, '@scoped/another', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + t.equal(permissions, 'read-write', 'should forward permissions') + return true + }, }, }, }) - const npm = new Npm() await npm.exec('access', [ 'grant', 'read-write', @@ -241,24 +229,23 @@ t.test('access grant read-write', async t => { t.test('access grant current cwd', async t => { t.plan(3) - const testdir = t.testdir({ - 'package.json': JSON.stringify({ - name: 'yargs', - }), - }) - const { Npm } = mockNpm(t, { - libnpmaccess: { - grant: (spec, team, permissions) => { - t.equal(spec, 'yargs', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - t.equal(permissions, 'read-write', 'should forward permissions') - return true + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + grant: (spec, team, permissions) => { + t.equal(spec, 'yargs', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + t.equal(permissions, 'read-write', 'should forward permissions') + return true + }, }, }, + testdir: { + 'package.json': JSON.stringify({ + name: 'yargs', + }), + }, }) - const npm = new Npm() - await npm.load() - npm.prefix = testdir await npm.exec('access', [ 'grant', 'read-write', @@ -267,6 +254,7 @@ t.test('access grant current cwd', async t => { }) t.test('access grant others', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', [ 'grant', @@ -280,6 +268,7 @@ t.test('access grant others', async t => { }) t.test('access grant missing team args', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', [ 'grant', @@ -293,6 +282,7 @@ t.test('access grant missing team args', async t => { }) t.test('access grant malformed team arg', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', [ 'grant', @@ -307,36 +297,37 @@ t.test('access grant malformed team arg', async t => { t.test('access 2fa-required/2fa-not-required', async t => { t.plan(2) - const { Npm } = mockNpm(t, { - libnpmaccess: { - tfaRequired: (spec) => { - t.equal(spec, '@scope/pkg', 'should use expected spec') - return true - }, - tfaNotRequired: (spec) => { - t.equal(spec, 'unscoped-pkg', 'should use expected spec') - return true + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + tfaRequired: (spec) => { + t.equal(spec, '@scope/pkg', 'should use expected spec') + return true + }, + tfaNotRequired: (spec) => { + t.equal(spec, 'unscoped-pkg', 'should use expected spec') + return true + }, }, }, }) - const npm = new Npm() - await npm.exec('access', ['2fa-required', '@scope/pkg']) await npm.exec('access', ['2fa-not-required', 'unscoped-pkg']) }) t.test('access revoke', async t => { t.plan(2) - const { Npm } = mockNpm(t, { - libnpmaccess: { - revoke: (spec, team) => { - t.equal(spec, '@scoped/another', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - return true + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + revoke: (spec, team) => { + t.equal(spec, '@scoped/another', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + return true + }, }, }, }) - const npm = new Npm() await npm.exec('access', [ 'revoke', 'myorg:myteam', @@ -345,6 +336,7 @@ t.test('access revoke', async t => { }) t.test('access revoke missing team args', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', [ 'revoke', @@ -357,6 +349,7 @@ t.test('access revoke missing team args', async t => { }) t.test('access revoke malformed team arg', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( npm.exec('access', [ 'revoke', @@ -370,30 +363,32 @@ t.test('access revoke malformed team arg', async t => { t.test('npm access ls-packages with no team', async t => { t.plan(1) - const { Npm } = mockNpm(t, { - libnpmaccess: { - lsPackages: (entity) => { - t.equal(entity, 'foo', 'should use expected entity') - return {} + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + lsPackages: (entity) => { + t.equal(entity, 'foo', 'should use expected entity') + return {} + }, }, + '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), }, - '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), }) - const npm = new Npm() await npm.exec('access', ['ls-packages']) }) t.test('access ls-packages on team', async t => { t.plan(1) - const { Npm } = mockNpm(t, { - libnpmaccess: { - lsPackages: (entity) => { - t.equal(entity, 'myorg:myteam', 'should use expected entity') - return {} + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + lsPackages: (entity) => { + t.equal(entity, 'myorg:myteam', 'should use expected entity') + return {} + }, }, }, }) - const npm = new Npm() await npm.exec('access', [ 'ls-packages', 'myorg:myteam', @@ -402,36 +397,36 @@ t.test('access ls-packages on team', async t => { t.test('access ls-collaborators on current', async t => { t.plan(1) - const testdir = t.testdir({ - 'package.json': JSON.stringify({ - name: 'yargs', - }), - }) - const { Npm } = mockNpm(t, { - libnpmaccess: { - lsCollaborators: (spec) => { - t.equal(spec, 'yargs', 'should use expected spec') - return {} + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + lsCollaborators: (spec) => { + t.equal(spec, 'yargs', 'should use expected spec') + return {} + }, }, }, + testdir: { + 'package.json': JSON.stringify({ + name: 'yargs', + }), + }, }) - const npm = new Npm() - await npm.load() - npm.prefix = testdir await npm.exec('access', ['ls-collaborators']) }) t.test('access ls-collaborators on spec', async t => { t.plan(1) - const { Npm } = mockNpm(t, { - libnpmaccess: { - lsCollaborators: (spec) => { - t.equal(spec, 'yargs', 'should use expected spec') - return {} + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmaccess: { + lsCollaborators: (spec) => { + t.equal(spec, 'yargs', 'should use expected spec') + return {} + }, }, }, }) - const npm = new Npm() await npm.exec('access', [ 'ls-collaborators', 'yargs', diff --git a/deps/npm/test/lib/commands/adduser.js b/deps/npm/test/lib/commands/adduser.js index 71d79ea935..8a9358f9ab 100644 --- a/deps/npm/test/lib/commands/adduser.js +++ b/deps/npm/test/lib/commands/adduser.js @@ -20,6 +20,13 @@ const authDummy = (npm, options) => { throw new Error('did not pass full flatOptions to auth function') } + if (!options.log) { + // A quick to test to make sure a log gets passed to auth + // XXX: should be refactored with change to real mock npm + // https://github.com/npm/statusboard/issues/411 + throw new Error('pass log to auth') + } + return Promise.resolve({ message: 'success', newCreds: { @@ -71,6 +78,8 @@ const AddUser = t.mock('../../../lib/commands/adduser.js', { npmlog: { clearProgress: () => null, disableProgress: () => null, + }, + 'proc-log': { notice: (_, msg) => { registryOutput = msg }, diff --git a/deps/npm/test/lib/commands/audit.js b/deps/npm/test/lib/commands/audit.js index 3c87c76a8f..05f268d6bc 100644 --- a/deps/npm/test/lib/commands/audit.js +++ b/deps/npm/test/lib/commands/audit.js @@ -1,5 +1,5 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: _loadMockNpm } = require('../../fixtures/mock-npm') t.test('should audit using Arborist', async t => { let ARB_ARGS = null @@ -8,36 +8,35 @@ t.test('should audit using Arborist', async t => { let AUDIT_REPORT_CALLED = false let ARB_OBJ = null - const { Npm, outputs } = mockNpm(t, { - 'npm-audit-report': () => { - AUDIT_REPORT_CALLED = true - return { - report: 'there are vulnerabilities', - exitCode: 0, - } - }, - '@npmcli/arborist': function (args) { - ARB_ARGS = args - ARB_OBJ = this - this.audit = () => { - AUDIT_CALLED = true - this.auditReport = {} - } - }, - '../../lib/utils/reify-finish.js': (npm, arb) => { - if (arb !== ARB_OBJ) { - throw new Error('got wrong object passed to reify-output') - } + const loadMockNpm = (t) => _loadMockNpm(t, { + mocks: { + 'npm-audit-report': () => { + AUDIT_REPORT_CALLED = true + return { + report: 'there are vulnerabilities', + exitCode: 0, + } + }, + '@npmcli/arborist': function (args) { + ARB_ARGS = args + ARB_OBJ = this + this.audit = () => { + AUDIT_CALLED = true + this.auditReport = {} + } + }, + '../../lib/utils/reify-finish.js': (npm, arb) => { + if (arb !== ARB_OBJ) { + throw new Error('got wrong object passed to reify-output') + } - REIFY_FINISH_CALLED = true + REIFY_FINISH_CALLED = true + }, }, }) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir() - t.test('audit', async t => { + const { npm, outputs } = await loadMockNpm(t) await npm.exec('audit', []) t.match(ARB_ARGS, { audit: true, path: npm.prefix }) t.equal(AUDIT_CALLED, true, 'called audit') @@ -46,6 +45,7 @@ t.test('should audit using Arborist', async t => { }) t.test('audit fix', async t => { + const { npm } = await loadMockNpm(t) await npm.exec('audit', ['fix']) t.equal(REIFY_FINISH_CALLED, true, 'called reify output') }) @@ -53,69 +53,67 @@ t.test('should audit using Arborist', async t => { t.test('should audit - json', async t => { t.plan(1) - const { Npm } = mockNpm(t, { - 'npm-audit-report': (_, opts) => { - t.match(opts.reporter, 'json') - return { - report: 'there are vulnerabilities', - exitCode: 0, - } + const { npm } = await _loadMockNpm(t, { + mocks: { + 'npm-audit-report': (_, opts) => { + t.match(opts.reporter, 'json') + return { + report: 'there are vulnerabilities', + exitCode: 0, + } + }, + '@npmcli/arborist': function () { + this.audit = () => { + this.auditReport = {} + } + }, + '../../lib/utils/reify-output.js': () => {}, }, - '@npmcli/arborist': function () { - this.audit = () => { - this.auditReport = {} - } + config: { + json: true, }, - '../../lib/utils/reify-output.js': () => {}, }) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir() - npm.config.set('json', true) await npm.exec('audit', []) }) t.test('report endpoint error', async t => { - const { Npm, outputs, filteredLogs } = mockNpm(t, { - 'npm-audit-report': () => { - throw new Error('should not call audit report when there are errors') - }, - '@npmcli/arborist': function () { - this.audit = () => { - this.auditReport = { - error: { - message: 'hello, this didnt work', - method: 'POST', - uri: 'https://example.com/', - headers: { - head: ['ers'], + const loadMockNpm = (t, options) => _loadMockNpm(t, { + mocks: { + 'npm-audit-report': () => { + throw new Error('should not call audit report when there are errors') + }, + '@npmcli/arborist': function () { + this.audit = () => { + this.auditReport = { + error: { + message: 'hello, this didnt work', + method: 'POST', + uri: 'https://example.com/', + headers: { + head: ['ers'], + }, + statusCode: 420, + body: 'this is a string', }, - statusCode: 420, - body: 'this is a string', - // body: json ? { nope: 'lol' } : Buffer.from('i had a vuln but i eated it lol'), - }, + } } - } + }, + '../../lib/utils/reify-output.js': () => {}, }, - '../../lib/utils/reify-output.js': () => {}, + ...options, }) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir() - // npm.config.set('json', ) + t.test('json=false', async t => { + const { npm, outputs, logs } = await loadMockNpm(t, { config: { json: false } }) await t.rejects(npm.exec('audit', []), 'audit endpoint returned an error') - t.match(filteredLogs('warn'), ['hello, this didnt work']) + t.match(logs.warn, [['audit', 'hello, this didnt work']]) t.strictSame(outputs, [['this is a string']]) }) t.test('json=true', async t => { - t.teardown(() => { - npm.config.set('json', false) - }) - npm.config.set('json', true) + const { npm, outputs, logs } = await loadMockNpm(t, { config: { json: true } }) await t.rejects(npm.exec('audit', []), 'audit endpoint returned an error') - t.match(filteredLogs('warn'), ['hello, this didnt work']) + t.match(logs.warn, [['audit', 'hello, this didnt work']]) t.strictSame(outputs, [[ '{\n' + ' "message": "hello, this didnt work",\n' + @@ -135,8 +133,7 @@ t.test('report endpoint error', async t => { }) t.test('completion', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t) const audit = await npm.cmd('audit') t.test('fix', async t => { await t.resolveMatch( diff --git a/deps/npm/test/lib/commands/birthday.js b/deps/npm/test/lib/commands/birthday.js index 8c95dd57b2..9156d3df09 100644 --- a/deps/npm/test/lib/commands/birthday.js +++ b/deps/npm/test/lib/commands/birthday.js @@ -1,14 +1,15 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('birthday', async t => { t.plan(2) - const { Npm } = mockNpm(t, { - libnpmexec: ({ args, yes }) => { - t.ok(yes) - t.match(args, ['@npmcli/npm-birthday']) + const { npm } = await loadMockNpm(t, { + mocks: { + libnpmexec: ({ args, yes }) => { + t.ok(yes) + t.match(args, ['@npmcli/npm-birthday']) + }, }, }) - const npm = new Npm() await npm.exec('birthday', []) }) diff --git a/deps/npm/test/lib/commands/cache.js b/deps/npm/test/lib/commands/cache.js index 70a8ba1b20..fc92facff7 100644 --- a/deps/npm/test/lib/commands/cache.js +++ b/deps/npm/test/lib/commands/cache.js @@ -12,11 +12,6 @@ const rimraf = (path, cb) => { } let logOutput = [] -const npmlog = { - silly: (...args) => { - logOutput.push(['silly', ...args]) - }, -} let tarballStreamSpec = '' let tarballStreamOpts = {} @@ -141,9 +136,16 @@ const cacache = { const Cache = t.mock('../../../lib/commands/cache.js', { cacache, - npmlog, pacote, rimraf, + 'proc-log': { + silly: (...args) => { + logOutput.push(['silly', ...args]) + }, + warn: (...args) => { + logOutput.push(['warn', ...args]) + }, + }, }) const npm = mockNpm({ @@ -153,11 +155,6 @@ const npm = mockNpm({ output: (msg) => { outputOutput.push(msg) }, - log: { - warn: (...args) => { - logOutput.push(['warn', ...args]) - }, - }, }) const cache = new Cache(npm) diff --git a/deps/npm/test/lib/commands/ci.js b/deps/npm/test/lib/commands/ci.js index 1091f9125b..537d0784f8 100644 --- a/deps/npm/test/lib/commands/ci.js +++ b/deps/npm/test/lib/commands/ci.js @@ -159,7 +159,7 @@ t.test('should throw if package-lock.json or npm-shrinkwrap missing', async t => const CI = t.mock('../../../lib/commands/ci.js', { '@npmcli/run-script': opts => {}, '../../../lib/utils/reify-finish.js': async () => {}, - npmlog: { + 'proc-log': { verbose: () => { t.ok(true, 'log fn called') }, diff --git a/deps/npm/test/lib/commands/completion.js b/deps/npm/test/lib/commands/completion.js index 51212f06d8..dd571baf79 100644 --- a/deps/npm/test/lib/commands/completion.js +++ b/deps/npm/test/lib/commands/completion.js @@ -6,189 +6,153 @@ const completionScript = fs .readFileSync(path.resolve(__dirname, '../../../lib/utils/completion.sh'), { encoding: 'utf8' }) .replace(/^#!.*?\n/, '') -const { real: mockNpm } = require('../../fixtures/mock-npm') - -const { Npm, outputs } = mockNpm(t, { - '../../lib/utils/is-windows-shell.js': false, -}) -const npm = new Npm() +const { load: _loadMockNpm } = require('../../fixtures/mock-npm') +const mockGlobals = require('../../fixtures/mock-globals') + +const loadMockCompletion = async (t, o = {}) => { + const { globals, windows, ...options } = o + let resetGlobals = {} + if (globals) { + resetGlobals = mockGlobals(t, globals).reset + } + const res = await _loadMockNpm(t, { + mocks: { + '../../lib/utils/is-windows-shell.js': !!windows, + ...options.mocks, + }, + ...options, + }) + const completion = await res.npm.cmd('completion') + return { + resetGlobals, + completion, + ...res, + } +} + +const loadMockCompletionComp = async (t, word, line) => + loadMockCompletion(t, { + globals: { + 'process.env.COMP_CWORD': word, + 'process.env.COMP_LINE': line, + 'process.env.COMP_POINT': line.length, + }, + }) t.test('completion', async t => { - const completion = await npm.cmd('completion') t.test('completion completion', async t => { - const home = process.env.HOME - t.teardown(() => { - process.env.HOME = home - }) - - process.env.HOME = t.testdir({ - '.bashrc': '', - '.zshrc': '', + const { outputs, completion, prefix } = await loadMockCompletion(t, { + testdir: { + '.bashrc': 'aaa', + '.zshrc': 'aaa', + }, }) + mockGlobals(t, { 'process.env.HOME': prefix }) await completion.completion({ w: 2 }) t.matchSnapshot(outputs, 'both shells') }) t.test('completion completion no known shells', async t => { - const home = process.env.HOME - t.teardown(() => { - process.env.HOME = home - }) - - process.env.HOME = t.testdir() + const { outputs, completion, prefix } = await loadMockCompletion(t) + mockGlobals(t, { 'process.env.HOME': prefix }) await completion.completion({ w: 2 }) t.matchSnapshot(outputs, 'no responses') }) t.test('completion completion wrong word count', async t => { + const { outputs, completion } = await loadMockCompletion(t) + await completion.completion({ w: 3 }) t.matchSnapshot(outputs, 'no responses') }) t.test('dump script when completion is not being attempted', async t => { - const _write = process.stdout.write - const _on = process.stdout.on - t.teardown(() => { - process.stdout.write = _write - process.stdout.on = _on + let errorHandler, data + const { completion, resetGlobals } = await loadMockCompletion(t, { + globals: { + 'process.stdout.on': (event, handler) => { + errorHandler = handler + resetGlobals['process.stdout.on']() + }, + 'process.stdout.write': (chunk, callback) => { + data = chunk + process.nextTick(() => { + callback() + errorHandler({ errno: 'EPIPE' }) + }) + resetGlobals['process.stdout.write']() + }, + }, }) - let errorHandler - process.stdout.on = (event, handler) => { - errorHandler = handler - process.stdout.on = _on - } - - let data - process.stdout.write = (chunk, callback) => { - data = chunk - process.stdout.write = _write - process.nextTick(() => { - callback() - errorHandler({ errno: 'EPIPE' }) - }) - } - await completion.exec({}) - t.equal(data, completionScript, 'wrote the completion script') }) t.test('dump script exits correctly when EPIPE is emitted on stdout', async t => { - const _write = process.stdout.write - const _on = process.stdout.on - t.teardown(() => { - process.stdout.write = _write - process.stdout.on = _on + let errorHandler, data + const { completion, resetGlobals } = await loadMockCompletion(t, { + globals: { + 'process.stdout.on': (event, handler) => { + if (event === 'error') { + errorHandler = handler + } + resetGlobals['process.stdout.on']() + }, + 'process.stdout.write': (chunk, callback) => { + data = chunk + process.nextTick(() => { + errorHandler({ errno: 'EPIPE' }) + callback() + }) + resetGlobals['process.stdout.write']() + }, + }, }) - let errorHandler - process.stdout.on = (event, handler) => { - errorHandler = handler - process.stdout.on = _on - } - - let data - process.stdout.write = (chunk, callback) => { - data = chunk - process.stdout.write = _write - process.nextTick(() => { - errorHandler({ errno: 'EPIPE' }) - callback() - }) - } - await completion.exec({}) t.equal(data, completionScript, 'wrote the completion script') }) t.test('single command name', async t => { - process.env.COMP_CWORD = 1 - process.env.COMP_LINE = 'npm conf' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 1, 'npm conf') await completion.exec(['npm', 'conf']) t.matchSnapshot(outputs, 'single command name') }) t.test('multiple command names', async t => { - process.env.COMP_CWORD = 1 - process.env.COMP_LINE = 'npm a' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 1, 'npm a') await completion.exec(['npm', 'a']) t.matchSnapshot(outputs, 'multiple command names') }) t.test('completion of invalid command name does nothing', async t => { - process.env.COMP_CWORD = 1 - process.env.COMP_LINE = 'npm compute' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 1, 'npm compute') await completion.exec(['npm', 'compute']) t.matchSnapshot(outputs, 'no results') }) t.test('subcommand completion', async t => { - process.env.COMP_CWORD = 2 - process.env.COMP_LINE = 'npm access ' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm access ') await completion.exec(['npm', 'access', '']) t.matchSnapshot(outputs, 'subcommands') }) t.test('filtered subcommands', async t => { - process.env.COMP_CWORD = 2 - process.env.COMP_LINE = 'npm access p' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm access p') await completion.exec(['npm', 'access', 'p']) t.matchSnapshot(outputs, 'filtered subcommands') }) t.test('commands with no completion', async t => { - process.env.COMP_CWORD = 2 - process.env.COMP_LINE = 'npm adduser ' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm adduser ') // quotes around adduser are to ensure coverage when unescaping commands await completion.exec(['npm', "'adduser'", '']) @@ -196,63 +160,28 @@ t.test('completion', async t => { }) t.test('flags', async t => { - process.env.COMP_CWORD = 2 - process.env.COMP_LINE = 'npm install --v' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm install --v') await completion.exec(['npm', 'install', '--v']) - t.matchSnapshot(outputs, 'flags') }) t.test('--no- flags', async t => { - process.env.COMP_CWORD = 2 - process.env.COMP_LINE = 'npm install --no-v' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm install --no-v') await completion.exec(['npm', 'install', '--no-v']) - t.matchSnapshot(outputs, 'flags') }) t.test('double dashes escape from flag completion', async t => { - process.env.COMP_CWORD = 2 - process.env.COMP_LINE = 'npm -- install --' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm -- install --') await completion.exec(['npm', '--', 'install', '--']) - t.matchSnapshot(outputs, 'full command list') }) t.test('completion cannot complete options that take a value in mid-command', async t => { - process.env.COMP_CWORD = 2 - process.env.COMP_LINE = 'npm --registry install' - process.env.COMP_POINT = process.env.COMP_LINE.length - - t.teardown(() => { - delete process.env.COMP_CWORD - delete process.env.COMP_LINE - delete process.env.COMP_POINT - }) + const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm --registry install') await completion.exec(['npm', '--registry', 'install']) t.matchSnapshot(outputs, 'does not try to complete option arguments in the middle of a command') @@ -260,11 +189,7 @@ t.test('completion', async t => { }) t.test('windows without bash', async t => { - const { Npm, outputs } = mockNpm(t, { - '../../lib/utils/is-windows-shell.js': true, - }) - const npm = new Npm() - const completion = await npm.cmd('completion') + const { outputs, completion } = await loadMockCompletion(t, { windows: true }) await t.rejects( completion.exec({}), { code: 'ENOTSUP', message: /completion supported only in MINGW/ }, diff --git a/deps/npm/test/lib/commands/dedupe.js b/deps/npm/test/lib/commands/dedupe.js index 8fc0be0618..2e2fae2381 100644 --- a/deps/npm/test/lib/commands/dedupe.js +++ b/deps/npm/test/lib/commands/dedupe.js @@ -1,11 +1,12 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('should throw in global mode', async (t) => { - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.config.set('global', true) + const { npm } = await loadMockNpm(t, { + config: { + global: true, + }, + }) t.rejects( npm.exec('dedupe', []), { code: 'EDEDUPEGLOBAL' }, @@ -15,39 +16,41 @@ t.test('should throw in global mode', async (t) => { t.test('should remove dupes using Arborist', async (t) => { t.plan(5) - const { Npm } = mockNpm(t, { - '@npmcli/arborist': function (args) { - t.ok(args, 'gets options object') - t.ok(args.path, 'gets path option') - t.ok(args.dryRun, 'gets dryRun from user') - this.dedupe = () => { - t.ok(true, 'dedupe is called') - } + const { npm } = await loadMockNpm(t, { + mocks: { + '@npmcli/arborist': function (args) { + t.ok(args, 'gets options object') + t.ok(args.path, 'gets path option') + t.ok(args.dryRun, 'gets dryRun from user') + this.dedupe = () => { + t.ok(true, 'dedupe is called') + } + }, + '../../lib/utils/reify-finish.js': (npm, arb) => { + t.ok(arb, 'gets arborist tree') + }, }, - '../../lib/utils/reify-finish.js': (npm, arb) => { - t.ok(arb, 'gets arborist tree') + config: { + 'dry-run': 'true', }, }) - const npm = new Npm() - await npm.load() - npm.config.set('prefix', 'foo') - npm.config.set('dry-run', 'true') await npm.exec('dedupe', []) }) t.test('should remove dupes using Arborist - no arguments', async (t) => { t.plan(1) - const { Npm } = mockNpm(t, { - '@npmcli/arborist': function (args) { - t.ok(args.dryRun, 'gets dryRun from config') - this.dedupe = () => {} + const { npm } = await loadMockNpm(t, { + mocks: { + '@npmcli/arborist': function (args) { + t.ok(args.dryRun, 'gets dryRun from config') + this.dedupe = () => {} + }, + '../../lib/utils/reify-output.js': () => {}, + '../../lib/utils/reify-finish.js': () => {}, + }, + config: { + 'dry-run': true, }, - '../../lib/utils/reify-output.js': () => {}, - '../../lib/utils/reify-finish.js': () => {}, }) - const npm = new Npm() - await npm.load() - npm.config.set('prefix', 'foo') - npm.config.set('dry-run', true) await npm.exec('dedupe', []) }) diff --git a/deps/npm/test/lib/commands/diff.js b/deps/npm/test/lib/commands/diff.js index 811936fe6d..ed0702e378 100644 --- a/deps/npm/test/lib/commands/diff.js +++ b/deps/npm/test/lib/commands/diff.js @@ -31,7 +31,7 @@ const npm = mockNpm({ }) const mocks = { - npmlog: { info: noop, verbose: noop }, + 'proc-log': { info: noop, verbose: noop }, libnpmdiff: (...args) => libnpmdiff(...args), 'npm-registry-fetch': async () => ({}), '../../../lib/utils/usage.js': () => 'usage instructions', diff --git a/deps/npm/test/lib/commands/dist-tag.js b/deps/npm/test/lib/commands/dist-tag.js index 6b45dc1167..756a09d7de 100644 --- a/deps/npm/test/lib/commands/dist-tag.js +++ b/deps/npm/test/lib/commands/dist-tag.js @@ -61,7 +61,7 @@ const logger = (...msgs) => { } const DistTag = t.mock('../../../lib/commands/dist-tag.js', { - npmlog: { + 'proc-log': { error: logger, info: logger, verbose: logger, diff --git a/deps/npm/test/lib/commands/doctor.js b/deps/npm/test/lib/commands/doctor.js index e3ad5cc726..51b6111a0a 100644 --- a/deps/npm/test/lib/commands/doctor.js +++ b/deps/npm/test/lib/commands/doctor.js @@ -50,13 +50,13 @@ const logs = { info: [], } -const clearLogs = (obj = logs) => { +const clearLogs = () => { output.length = 0 - for (const key in obj) { - if (Array.isArray(obj[key])) { - obj[key].length = 0 + for (const key in logs) { + if (Array.isArray(logs[key])) { + logs[key].length = 0 } else { - delete obj[key] + delete logs[key] } } } @@ -65,13 +65,41 @@ const npm = { flatOptions: { registry: 'https://registry.npmjs.org/', }, - log: { + version: '7.1.0', + output: data => { + output.push(data) + }, +} + +let latestNpm = npm.version +const pacote = { + manifest: async () => { + return { version: latestNpm } + }, +} + +let verifyResponse = { verifiedCount: 1, verifiedContent: 1 } +const cacache = { + verify: async () => { + return verifyResponse + }, +} + +const mocks = { + '../../../lib/utils/is-windows.js': false, + '../../../lib/utils/ping.js': ping, + cacache, + pacote, + 'make-fetch-happen': fetch, + which, + 'proc-log': { info: msg => { logs.info.push(msg) }, + }, + npmlog: { newItem: name => { logs[name] = {} - return { info: (_, msg) => { if (!logs[name].info) { @@ -109,33 +137,11 @@ const npm = { error: 0, }, }, - version: '7.1.0', - output: data => { - output.push(data) - }, -} -let latestNpm = npm.version -const pacote = { - manifest: async () => { - return { version: latestNpm } - }, -} - -let verifyResponse = { verifiedCount: 1, verifiedContent: 1 } -const cacache = { - verify: async () => { - return verifyResponse - }, } const Doctor = t.mock('../../../lib/commands/doctor.js', { - '../../../lib/utils/is-windows.js': false, - '../../../lib/utils/ping.js': ping, - cacache, - pacote, - 'make-fetch-happen': fetch, - which, + ...mocks, }) const doctor = new Doctor(npm) @@ -205,7 +211,7 @@ t.test('node versions', t => { npm.globalDir = dir npm.localBin = dir npm.globalBin = dir - npm.log.level = 'info' + mocks.npmlog.level = 'info' st.teardown(() => { delete npm.cache @@ -214,7 +220,7 @@ t.test('node versions', t => { delete npm.globalDir delete npm.localBin delete npm.globalBin - npm.log.level = 'error' + mocks.npmlog.level = 'error' clearLogs() }) @@ -293,12 +299,8 @@ t.test('node versions', t => { vt.test('npm doctor skips some tests in windows', async st => { const WinDoctor = t.mock('../../../lib/commands/doctor.js', { + ...mocks, '../../../lib/utils/is-windows.js': true, - '../../../lib/utils/ping.js': ping, - cacache, - pacote, - 'make-fetch-happen': fetch, - which, }) const winDoctor = new WinDoctor(npm) @@ -592,12 +594,7 @@ t.test('node versions', t => { } const Doctor = t.mock('../../../lib/commands/doctor.js', { - '../../../lib/utils/is-windows.js': false, - '../../../lib/utils/ping.js': ping, - cacache, - pacote, - 'make-fetch-happen': fetch, - which, + ...mocks, fs, }) const doctor = new Doctor(npm) diff --git a/deps/npm/test/lib/commands/exec.js b/deps/npm/test/lib/commands/exec.js index 4ab26568f1..3c75c1d8d8 100644 --- a/deps/npm/test/lib/commands/exec.js +++ b/deps/npm/test/lib/commands/exec.js @@ -44,17 +44,6 @@ const npm = mockNpm({ localPrefix: 'local-prefix', localBin: 'local-bin', globalBin: 'global-bin', - log: { - disableProgress: () => { - PROGRESS_ENABLED = false - }, - enableProgress: () => { - PROGRESS_ENABLED = true - }, - warn: (...args) => { - LOG_WARN.push(args) - }, - }, }) const RUN_SCRIPTS = [] @@ -87,6 +76,23 @@ const PATH = require('../../../lib/utils/path.js') let CI_NAME = 'travis-ci' +const log = { + 'proc-log': { + warn: (...args) => { + LOG_WARN.push(args) + }, + }, + npmlog: { + disableProgress: () => { + PROGRESS_ENABLED = false + }, + enableProgress: () => { + PROGRESS_ENABLED = true + }, + clearProgress: () => {}, + }, +} + const mocks = { libnpmexec: t.mock('libnpmexec', { '@npmcli/arborist': Arborist, @@ -95,7 +101,9 @@ const mocks = { pacote, read, 'mkdirp-infer-owner': mkdirp, + ...log, }), + ...log, } const Exec = t.mock('../../../lib/commands/exec.js', mocks) const exec = new Exec(npm) diff --git a/deps/npm/test/lib/commands/explore.js b/deps/npm/test/lib/commands/explore.js index b2e7be2136..d1355d7671 100644 --- a/deps/npm/test/lib/commands/explore.js +++ b/deps/npm/test/lib/commands/explore.js @@ -51,14 +51,17 @@ const getExplore = (windows) => { path: require('path')[windows ? 'win32' : 'posix'], 'read-package-json-fast': mockRPJ, '@npmcli/run-script': mockRunScript, - }) - const npm = { - dir: windows ? 'c:\\npm\\dir' : '/npm/dir', - log: { + 'proc-log': { error: (...msg) => logs.push(msg), + warn: () => {}, + }, + npmlog: { disableProgress: () => {}, enableProgress: () => {}, }, + }) + const npm = { + dir: windows ? 'c:\\npm\\dir' : '/npm/dir', flatOptions: { shell: 'shell-command', }, diff --git a/deps/npm/test/lib/commands/find-dupes.js b/deps/npm/test/lib/commands/find-dupes.js index c1b9c71df5..06bd097b6c 100644 --- a/deps/npm/test/lib/commands/find-dupes.js +++ b/deps/npm/test/lib/commands/find-dupes.js @@ -1,27 +1,28 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('should run dedupe in dryRun mode', async (t) => { t.plan(5) - const { Npm } = mockNpm(t, { - '@npmcli/arborist': function (args) { - t.ok(args, 'gets options object') - t.ok(args.path, 'gets path option') - t.ok(args.dryRun, 'is called in dryRun mode') - this.dedupe = () => { - t.ok(true, 'dedupe is called') - } + const { npm } = await loadMockNpm(t, { + mocks: { + '@npmcli/arborist': function (args) { + t.ok(args, 'gets options object') + t.ok(args.path, 'gets path option') + t.ok(args.dryRun, 'is called in dryRun mode') + this.dedupe = () => { + t.ok(true, 'dedupe is called') + } + }, + '../../lib/utils/reify-finish.js': (npm, arb) => { + t.ok(arb, 'gets arborist tree') + }, }, - '../../lib/utils/reify-finish.js': (npm, arb) => { - t.ok(arb, 'gets arborist tree') + config: { + // explicitly set to false so we can be 100% sure it's always true when it + // hits arborist + 'dry-run': false, }, }) - const npm = new Npm() - await npm.load() - // explicitly set to false so we can be 100% sure it's always true when it - // hits arborist - npm.config.set('dry-run', false) - npm.config.set('prefix', 'foo') await npm.exec('find-dupes', []) }) diff --git a/deps/npm/test/lib/commands/get.js b/deps/npm/test/lib/commands/get.js index ba9e770e3e..597cccc3ff 100644 --- a/deps/npm/test/lib/commands/get.js +++ b/deps/npm/test/lib/commands/get.js @@ -1,12 +1,10 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('should retrieve values from config', async t => { - const { joinedOutput, Npm } = mockNpm(t) - const npm = new Npm() + const { joinedOutput, npm } = await loadMockNpm(t) const name = 'editor' const value = 'vigor' - await npm.load() npm.config.set(name, value) await npm.exec('get', [name]) t.equal( diff --git a/deps/npm/test/lib/commands/init.js b/deps/npm/test/lib/commands/init.js index 74b33168ad..215ebc5811 100644 --- a/deps/npm/test/lib/commands/init.js +++ b/deps/npm/test/lib/commands/init.js @@ -3,14 +3,6 @@ const fs = require('fs') const { resolve } = require('path') const { fake: mockNpm } = require('../../fixtures/mock-npm') -const npmLog = { - disableProgress: () => null, - enableProgress: () => null, - info: () => null, - pause: () => null, - resume: () => null, - silly: () => null, -} const config = { cache: 'bad-cache-dir', 'init-module': '~/.npm-init.js', @@ -23,10 +15,19 @@ const flatOptions = { const npm = mockNpm({ flatOptions, config, - log: npmLog, }) const mocks = { '../../../lib/utils/usage.js': () => 'usage instructions', + npmlog: { + disableProgress: () => null, + enableProgress: () => null, + }, + 'proc-log': { + info: () => null, + pause: () => null, + resume: () => null, + silly: () => null, + }, } const Init = t.mock('../../../lib/commands/init.js', mocks) const init = new Init(npm) @@ -37,7 +38,6 @@ const noop = () => {} t.afterEach(() => { config.yes = true config.package = undefined - npm.log = npmLog process.chdir(_cwd) console.log = _consolelog }) @@ -251,13 +251,15 @@ t.test('npm init cancel', async t => { 'init-package-json': (dir, initFile, config, cb) => cb( new Error('canceled') ), + 'proc-log': { + ...mocks['proc-log'], + warn: (title, msg) => { + t.equal(title, 'init', 'should have init title') + t.equal(msg, 'canceled', 'should log canceled') + }, + }, }) const init = new Init(npm) - npm.log = { ...npm.log } - npm.log.warn = (title, msg) => { - t.equal(title, 'init', 'should have init title') - t.equal(msg, 'canceled', 'should log canceled') - } process.chdir(npm.localPrefix) await init.exec([]) diff --git a/deps/npm/test/lib/commands/install.js b/deps/npm/test/lib/commands/install.js index 994684596a..d5db3af673 100644 --- a/deps/npm/test/lib/commands/install.js +++ b/deps/npm/test/lib/commands/install.js @@ -1,7 +1,10 @@ const t = require('tap') const path = require('path') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: _loadMockNpm } = require('../../fixtures/mock-npm') + +// Make less churn in the test to pass in mocks only signature +const loadMockNpm = (t, mocks) => _loadMockNpm(t, { mocks }) t.test('with args, dev=true', async t => { const SCRIPTS = [] @@ -9,7 +12,7 @@ t.test('with args, dev=true', async t => { let REIFY_CALLED = false let ARB_OBJ = null - const { Npm, filteredLogs } = mockNpm(t, { + const { npm, logs } = await loadMockNpm(t, { '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -27,8 +30,6 @@ t.test('with args, dev=true', async t => { }, }) - const npm = new Npm() - await npm.load() // This is here because CI calls tests with `--ignore-scripts`, which config // picks up from argv npm.config.set('ignore-scripts', false) @@ -41,8 +42,8 @@ t.test('with args, dev=true', async t => { await npm.exec('install', ['fizzbuzz']) t.match( - filteredLogs('warn'), - ['Usage of the `--dev` option is deprecated. Use `--include=dev` instead.'] + logs.warn, + [['install', 'Usage of the `--dev` option is deprecated. Use `--include=dev` instead.']] ) t.match( ARB_ARGS, @@ -59,7 +60,7 @@ t.test('without args', async t => { let REIFY_CALLED = false let ARB_OBJ = null - const { Npm } = mockNpm(t, { + const { npm } = await loadMockNpm(t, { '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -77,8 +78,6 @@ t.test('without args', async t => { }, }) - const npm = new Npm() - await npm.load() npm.prefix = path.resolve(t.testdir({})) npm.config.set('ignore-scripts', false) await npm.exec('install', []) @@ -98,7 +97,7 @@ t.test('without args', async t => { t.test('should ignore scripts with --ignore-scripts', async t => { const SCRIPTS = [] let REIFY_CALLED = false - const { Npm } = mockNpm(t, { + const { npm } = await loadMockNpm(t, { '../../lib/utils/reify-finish.js': async () => {}, '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) @@ -109,8 +108,6 @@ t.test('should ignore scripts with --ignore-scripts', async t => { } }, }) - const npm = new Npm() - await npm.load() npm.config.set('ignore-scripts', true) npm.prefix = path.resolve(t.testdir({})) await npm.exec('install', []) @@ -122,7 +119,7 @@ t.test('should install globally using Arborist', async t => { const SCRIPTS = [] let ARB_ARGS = null let REIFY_CALLED - const { Npm } = mockNpm(t, { + const { npm } = await loadMockNpm(t, { '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -134,8 +131,6 @@ t.test('should install globally using Arborist', async t => { } }, }) - const npm = new Npm() - await npm.load() npm.config.set('global', true) npm.globalPrefix = path.resolve(t.testdir({})) await npm.exec('install', []) @@ -148,7 +143,7 @@ t.test('should install globally using Arborist', async t => { }) t.test('npm i -g npm engines check success', async t => { - const { Npm } = mockNpm(t, { + const { npm } = await loadMockNpm(t, { '../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { this.reify = () => {} @@ -164,8 +159,6 @@ t.test('npm i -g npm engines check success', async t => { }, }, }) - const npm = new Npm() - await npm.load() npm.globalDir = t.testdir({}) npm.config.set('global', true) await npm.exec('install', ['npm']) @@ -173,7 +166,7 @@ t.test('npm i -g npm engines check success', async t => { }) t.test('npm i -g npm engines check failure', async t => { - const { Npm } = mockNpm(t, { + const { npm } = await loadMockNpm(t, { pacote: { manifest: () => { return { @@ -186,8 +179,6 @@ t.test('npm i -g npm engines check failure', async t => { }, }, }) - const npm = new Npm() - await npm.load() npm.globalDir = t.testdir({}) npm.config.set('global', true) await t.rejects( @@ -208,7 +199,7 @@ t.test('npm i -g npm engines check failure', async t => { }) t.test('npm i -g npm engines check failure forced override', async t => { - const { Npm } = mockNpm(t, { + const { npm } = await loadMockNpm(t, { '../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { this.reify = () => {} @@ -225,8 +216,6 @@ t.test('npm i -g npm engines check failure forced override', async t => { }, }, }) - const npm = new Npm() - await npm.load() npm.globalDir = t.testdir({}) npm.config.set('global', true) npm.config.set('force', true) @@ -235,7 +224,7 @@ t.test('npm i -g npm engines check failure forced override', async t => { }) t.test('npm i -g npm@version engines check failure', async t => { - const { Npm } = mockNpm(t, { + const { npm } = await loadMockNpm(t, { pacote: { manifest: () => { return { @@ -248,8 +237,6 @@ t.test('npm i -g npm@version engines check failure', async t => { }, }, }) - const npm = new Npm() - await npm.load() npm.globalDir = t.testdir({}) npm.config.set('global', true) await t.rejects( @@ -283,8 +270,7 @@ t.test('completion', async t => { }) t.test('completion to folder - has a match', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t, { load: false }) const install = await npm.cmd('install') process.chdir(testdir) const res = await install.completion({ partialWord: './ar' }) @@ -292,16 +278,14 @@ t.test('completion', async t => { }) t.test('completion to folder - invalid dir', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t, { load: false }) const install = await npm.cmd('install') const res = await install.completion({ partialWord: '/does/not/exist' }) t.strictSame(res, [], 'invalid dir: no matching') }) t.test('completion to folder - no matches', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t, { load: false }) const install = await npm.cmd('install') process.chdir(testdir) const res = await install.completion({ partialWord: './pa' }) @@ -309,8 +293,7 @@ t.test('completion', async t => { }) t.test('completion to folder - match is not a package', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t, { load: false }) const install = await npm.cmd('install') process.chdir(testdir) const res = await install.completion({ partialWord: './othe' }) @@ -318,8 +301,7 @@ t.test('completion', async t => { }) t.test('completion to url', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t, { load: false }) const install = await npm.cmd('install') process.chdir(testdir) const res = await install.completion({ partialWord: 'http://path/to/url' }) @@ -327,8 +309,7 @@ t.test('completion', async t => { }) t.test('no /', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t, { load: false }) const install = await npm.cmd('install') process.chdir(testdir) const res = await install.completion({ partialWord: 'toto' }) @@ -336,8 +317,7 @@ t.test('completion', async t => { }) t.test('only /', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await _loadMockNpm(t, { load: false }) const install = await npm.cmd('install') process.chdir(testdir) const res = await install.completion({ partialWord: '/' }) diff --git a/deps/npm/test/lib/commands/logout.js b/deps/npm/test/lib/commands/logout.js index 39ef86c843..ee01e7500d 100644 --- a/deps/npm/test/lib/commands/logout.js +++ b/deps/npm/test/lib/commands/logout.js @@ -10,45 +10,31 @@ const flatOptions = { scope: '', } const npm = mockNpm({ config, flatOptions }) - -const npmlog = {} - let result = null -const npmFetch = (url, opts) => { - result = { url, opts } -} -const mocks = { - npmlog, - 'npm-registry-fetch': npmFetch, +const mockLogout = (otherMocks) => { + const Logout = t.mock('../../../lib/commands/logout.js', { + 'npm-registry-fetch': (url, opts) => { + result = { url, opts } + }, + ...otherMocks, + }) + return new Logout(npm) } -const Logout = t.mock('../../../lib/commands/logout.js', mocks) -const logout = new Logout(npm) +t.afterEach(() => { + delete flatOptions.token + result = null + config.clearCredentialsByURI = null + config.delete = null + config.save = null +}) t.test('token logout', async t => { - t.teardown(() => { - delete flatOptions.token - result = null - mocks['npm-registry-fetch'] = null - config.clearCredentialsByURI = null - config.delete = null - config.save = null - npmlog.verbose = null - }) t.plan(5) flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/' - npmlog.verbose = (title, msg) => { - t.equal(title, 'logout', 'should have correcct log prefix') - t.equal( - msg, - 'clearing token for https://registry.npmjs.org/', - 'should log message with correct registry' - ) - } - npm.config.clearCredentialsByURI = registry => { t.equal( registry, @@ -61,6 +47,19 @@ t.test('token logout', async t => { t.equal(type, 'user', 'should save to user config') } + const logout = mockLogout({ + 'proc-log': { + verbose: (title, msg) => { + t.equal(title, 'logout', 'should have correcct log prefix') + t.equal( + msg, + 'clearing token for https://registry.npmjs.org/', + 'should log message with correct registry' + ) + }, + }, + }) + await logout.exec([]) t.same( @@ -87,12 +86,11 @@ t.test('token scoped logout', async t => { delete config['@myscope:registry'] delete flatOptions.scope result = null - mocks['npm-registry-fetch'] = null config.clearCredentialsByURI = null config.delete = null config.save = null - npmlog.verbose = null }) + t.plan(7) flatOptions['//diff-registry.npmjs.com/:_authToken'] = '@bar/' @@ -102,15 +100,6 @@ t.test('token scoped logout', async t => { flatOptions.scope = '@myscope' flatOptions['@myscope:registry'] = 'https://diff-registry.npmjs.com/' - npmlog.verbose = (title, msg) => { - t.equal(title, 'logout', 'should have correcct log prefix') - t.equal( - msg, - 'clearing token for https://diff-registry.npmjs.com/', - 'should log message with correct registry' - ) - } - npm.config.clearCredentialsByURI = registry => { t.equal( registry, @@ -128,6 +117,19 @@ t.test('token scoped logout', async t => { t.equal(type, 'user', 'should save to user config') } + const logout = mockLogout({ + 'proc-log': { + verbose: (title, msg) => { + t.equal(title, 'logout', 'should have correcct log prefix') + t.equal( + msg, + 'clearing token for https://diff-registry.npmjs.com/', + 'should log message with correct registry' + ) + }, + }, + }) + await logout.exec([]) t.same( @@ -154,29 +156,34 @@ t.test('user/pass logout', async t => { delete flatOptions['//registry.npmjs.org/:_password'] npm.config.clearCredentialsByURI = null npm.config.save = null - npmlog.verbose = null }) t.plan(2) flatOptions['//registry.npmjs.org/:username'] = 'foo' flatOptions['//registry.npmjs.org/:_password'] = 'bar' - npmlog.verbose = (title, msg) => { - t.equal(title, 'logout', 'should have correct log prefix') - t.equal( - msg, - 'clearing user credentials for https://registry.npmjs.org/', - 'should log message with correct registry' - ) - } - npm.config.clearCredentialsByURI = () => null npm.config.save = () => null + const logout = mockLogout({ + 'proc-log': { + verbose: (title, msg) => { + t.equal(title, 'logout', 'should have correct log prefix') + t.equal( + msg, + 'clearing user credentials for https://registry.npmjs.org/', + 'should log message with correct registry' + ) + }, + }, + }) + await logout.exec([]) }) t.test('missing credentials', async t => { + const logout = mockLogout() + await t.rejects( logout.exec([]), { @@ -191,11 +198,9 @@ t.test('ignore invalid scoped registry config', async t => { t.teardown(() => { delete flatOptions.token result = null - mocks['npm-registry-fetch'] = null config.clearCredentialsByURI = null config.delete = null config.save = null - npmlog.verbose = null }) t.plan(4) @@ -203,15 +208,6 @@ t.test('ignore invalid scoped registry config', async t => { config.scope = '@myscope' flatOptions['@myscope:registry'] = '' - npmlog.verbose = (title, msg) => { - t.equal(title, 'logout', 'should have correcct log prefix') - t.equal( - msg, - 'clearing token for https://registry.npmjs.org/', - 'should log message with correct registry' - ) - } - npm.config.clearCredentialsByURI = registry => { t.equal( registry, @@ -223,6 +219,19 @@ t.test('ignore invalid scoped registry config', async t => { npm.config.delete = () => null npm.config.save = () => null + const logout = mockLogout({ + 'proc-log': { + verbose: (title, msg) => { + t.equal(title, 'logout', 'should have correcct log prefix') + t.equal( + msg, + 'clearing token for https://registry.npmjs.org/', + 'should log message with correct registry' + ) + }, + }, + }) + await logout.exec([]) t.same( diff --git a/deps/npm/test/lib/commands/owner.js b/deps/npm/test/lib/commands/owner.js index 8645b349f8..b5d4d15842 100644 --- a/deps/npm/test/lib/commands/owner.js +++ b/deps/npm/test/lib/commands/owner.js @@ -14,11 +14,11 @@ const npm = mockNpm({ }) const npmFetch = { json: noop } -const npmlog = { error: noop, info: noop, verbose: noop } +const log = { error: noop, info: noop, verbose: noop } const pacote = { packument: noop } const mocks = { - npmlog, + 'proc-log': log, 'npm-registry-fetch': npmFetch, pacote, '../../../lib/utils/otplease.js': async (opts, fn) => fn({ otp: '123456', opts }), @@ -97,7 +97,7 @@ t.test('owner ls no args no cwd package', async t => { result = '' t.teardown(() => { result = '' - npmlog.error = noop + log.error = noop }) await t.rejects( @@ -114,14 +114,14 @@ t.test('owner ls fails to retrieve packument', async t => { pacote.packument = () => { throw new Error('ERR') } - npmlog.error = (title, msg, pkgName) => { + log.error = (title, msg, pkgName) => { t.equal(title, 'owner ls', 'should list npm owner ls title') t.equal(msg, "Couldn't get owner data", 'should use expected msg') t.equal(pkgName, '@npmcli/map-workspaces', 'should use pkg name') } t.teardown(() => { result = '' - npmlog.error = noop + log.error = noop pacote.packument = noop }) @@ -276,7 +276,7 @@ t.test('owner add <user> <pkg> already an owner', async t => { t.plan(2) result = '' - npmlog.info = (title, msg) => { + log.info = (title, msg) => { t.equal(title, 'owner add', 'should use expected title') t.equal( msg, @@ -304,7 +304,7 @@ t.test('owner add <user> <pkg> already an owner', async t => { } t.teardown(() => { result = '' - npmlog.info = noop + log.info = noop npmFetch.json = noop pacote.packument = noop }) @@ -385,7 +385,7 @@ t.test('owner add <user> <pkg> fails to retrieve user info', async t => { t.plan(3) result = '' - npmlog.error = (title, msg) => { + log.error = (title, msg) => { t.equal(title, 'owner mutate', 'should use expected title') t.equal(msg, 'Error getting user data for foo') } @@ -406,7 +406,7 @@ t.test('owner add <user> <pkg> fails to retrieve user info', async t => { }) t.teardown(() => { result = '' - npmlog.error = noop + log.error = noop npmFetch.json = noop pacote.packument = noop }) @@ -552,7 +552,7 @@ t.test('owner rm <user> <pkg> not a current owner', async t => { t.plan(2) result = '' - npmlog.info = (title, msg) => { + log.info = (title, msg) => { t.equal(title, 'owner rm', 'should log expected title') t.equal(msg, 'Not a package owner: foo', 'should log.info not a package owner msg') } @@ -578,7 +578,7 @@ t.test('owner rm <user> <pkg> not a current owner', async t => { } t.teardown(() => { result = '' - npmlog.info = noop + log.info = noop npmFetch.json = noop pacote.packument = noop }) diff --git a/deps/npm/test/lib/commands/pack.js b/deps/npm/test/lib/commands/pack.js index bc88772086..21057e2079 100644 --- a/deps/npm/test/lib/commands/pack.js +++ b/deps/npm/test/lib/commands/pack.js @@ -1,5 +1,5 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') const path = require('path') const fs = require('fs') @@ -9,33 +9,31 @@ t.afterEach(t => { }) t.test('should pack current directory with no arguments', async t => { - const { Npm, outputs, filteredLogs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-package', - version: '1.0.0', - }), + const { npm, outputs, logs } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'test-package', + version: '1.0.0', + }), + }, }) process.chdir(npm.prefix) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.strictSame(outputs, [[filename]]) - t.matchSnapshot(filteredLogs('notice'), 'logs pack contents') + t.matchSnapshot(logs.notice.map(([, m]) => m), 'logs pack contents') t.ok(fs.statSync(path.resolve(npm.prefix, filename))) }) t.test('follows pack-destination config', async t => { - const { Npm, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-package', - version: '1.0.0', - }), - 'tar-destination': {}, + const { npm, outputs } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'test-package', + version: '1.0.0', + }), + 'tar-destination': {}, + }, }) process.chdir(npm.prefix) npm.config.set('pack-destination', path.join(npm.prefix, 'tar-destination')) @@ -46,14 +44,13 @@ t.test('follows pack-destination config', async t => { }) t.test('should pack given directory for scoped package', async t => { - const { Npm, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: '@npm/test-package', - version: '1.0.0', - }), + const { npm, outputs } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: '@npm/test-package', + version: '1.0.0', + }), + }, }) process.chdir(npm.prefix) await npm.exec('pack', []) @@ -63,49 +60,46 @@ t.test('should pack given directory for scoped package', async t => { }) t.test('should log output as valid json', async t => { - const { Npm, outputs, filteredLogs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-package', - version: '1.0.0', - }), + const { npm, outputs, logs } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'test-package', + version: '1.0.0', + }), + }, }) process.chdir(npm.prefix) npm.config.set('json', true) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.matchSnapshot(outputs.map(JSON.parse), 'outputs as json') - t.matchSnapshot(filteredLogs('notice'), 'logs pack contents') + t.matchSnapshot(logs.notice.map(([, m]) => m), 'logs pack contents') t.ok(fs.statSync(path.resolve(npm.prefix, filename))) }) t.test('dry run', async t => { - const { Npm, outputs, filteredLogs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-package', - version: '1.0.0', - }), + const { npm, outputs, logs } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'test-package', + version: '1.0.0', + }), + }, }) npm.config.set('dry-run', true) process.chdir(npm.prefix) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.strictSame(outputs, [[filename]]) - t.matchSnapshot(filteredLogs('notice'), 'logs pack contents') + t.matchSnapshot(logs.notice.map(([, m]) => m), 'logs pack contents') t.throws(() => fs.statSync(path.resolve(npm.prefix, filename))) }) t.test('invalid packument', async t => { - const { Npm, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir({ - 'package.json': '{}', + const { npm, outputs } = await loadMockNpm(t, { + testdir: { + 'package.json': '{}', + }, }) process.chdir(npm.prefix) await t.rejects( @@ -116,52 +110,58 @@ t.test('invalid packument', async t => { }) t.test('workspaces', async t => { - const { Npm, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.prefix = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], + const loadWorkspaces = (t) => loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), + config: { + workspaces: true, }, }) - npm.config.set('workspaces', true) + t.test('all workspaces', async t => { + const { npm, outputs } = await loadWorkspaces(t) process.chdir(npm.prefix) await npm.exec('pack', []) t.strictSame(outputs, [['workspace-a-1.0.0.tgz'], ['workspace-b-1.0.0.tgz']]) }) t.test('all workspaces, `.` first arg', async t => { + const { npm, outputs } = await loadWorkspaces(t) process.chdir(npm.prefix) await npm.exec('pack', ['.']) t.strictSame(outputs, [['workspace-a-1.0.0.tgz'], ['workspace-b-1.0.0.tgz']]) }) t.test('one workspace', async t => { + const { npm, outputs } = await loadWorkspaces(t) process.chdir(npm.prefix) await npm.exec('pack', ['workspace-a']) t.strictSame(outputs, [['workspace-a-1.0.0.tgz']]) }) t.test('specific package', async t => { + const { npm, outputs } = await loadWorkspaces(t) process.chdir(npm.prefix) await npm.exec('pack', [npm.prefix]) t.strictSame(outputs, [['workspaces-test-1.0.0.tgz']]) diff --git a/deps/npm/test/lib/commands/ping.js b/deps/npm/test/lib/commands/ping.js index 7011c709b0..f808e0ac3b 100644 --- a/deps/npm/test/lib/commands/ping.js +++ b/deps/npm/test/lib/commands/ping.js @@ -11,7 +11,7 @@ t.test('pings', async t => { t.equal(spec.registry, registry, 'passes flatOptions') return {} }, - npmlog: { + 'proc-log': { notice: (type, spec) => { ++noticeCalls if (noticeCalls === 1) { @@ -45,7 +45,7 @@ t.test('pings and logs details', async t => { t.equal(spec.registry, registry, 'passes flatOptions') return details }, - npmlog: { + 'proc-log': { notice: (type, spec) => { ++noticeCalls if (noticeCalls === 1) { @@ -83,7 +83,7 @@ t.test('pings and returns json', async t => { t.equal(spec.registry, registry, 'passes flatOptions') return details }, - npmlog: { + 'proc-log': { notice: (type, spec) => { ++noticeCalls if (noticeCalls === 1) { diff --git a/deps/npm/test/lib/commands/prefix.js b/deps/npm/test/lib/commands/prefix.js index 6f059e73a7..e8295cf6a5 100644 --- a/deps/npm/test/lib/commands/prefix.js +++ b/deps/npm/test/lib/commands/prefix.js @@ -1,9 +1,8 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('prefix', async t => { - const { joinedOutput, Npm } = mockNpm(t) - const npm = new Npm() + const { joinedOutput, npm } = await loadMockNpm(t, { load: false }) await npm.exec('prefix', []) t.equal( joinedOutput(), diff --git a/deps/npm/test/lib/commands/profile.js b/deps/npm/test/lib/commands/profile.js index 6554ca89e4..3d55a37ddb 100644 --- a/deps/npm/test/lib/commands/profile.js +++ b/deps/npm/test/lib/commands/profile.js @@ -22,6 +22,8 @@ const mocks = { ansistyles: { bright: a => a }, npmlog: { gauge: { show () {} }, + }, + 'proc-log': { info () {}, notice () {}, warn () {}, @@ -489,23 +491,23 @@ t.test('profile set <key> <value>', t => { }, } - const npmlog = { - gauge: { - show () {}, - }, - warn (title, msg) { - t.equal(title, 'profile', 'should use expected profile') - t.equal( - msg, - 'Passwords do not match, please try again.', - 'should log password mismatch message' - ) - }, - } - const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, - npmlog, + npmlog: { + gauge: { + show () {}, + }, + }, + 'proc-log': { + warn (title, msg) { + t.equal(title, 'profile', 'should use expected profile') + t.equal( + msg, + 'Passwords do not match, please try again.', + 'should log password mismatch message' + ) + }, + }, 'npm-profile': npmProfile, '../../../lib/utils/read-user-info.js': readUserInfo, }) @@ -687,7 +689,7 @@ t.test('enable-2fa', t => { async otp (label) { t.equal( label, - 'Enter one-time password from your authenticator app: ', + 'Enter one-time password: ', 'should ask for otp confirmation' ) return '123456' @@ -1042,7 +1044,7 @@ t.test('disable-2fa', t => { async otp (label) { t.equal( label, - 'Enter one-time password from your authenticator app: ', + 'Enter one-time password: ', 'should ask for otp confirmation' ) return '1234' diff --git a/deps/npm/test/lib/commands/prune.js b/deps/npm/test/lib/commands/prune.js index 49d5ab9be3..a7f56547b1 100644 --- a/deps/npm/test/lib/commands/prune.js +++ b/deps/npm/test/lib/commands/prune.js @@ -1,20 +1,22 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('should prune using Arborist', async (t) => { t.plan(4) - const { Npm } = mockNpm(t, { - '@npmcli/arborist': function (args) { - t.ok(args, 'gets options object') - t.ok(args.path, 'gets path option') - this.prune = () => { - t.ok(true, 'prune is called') - } - }, - '../../lib/utils/reify-finish.js': (arb) => { - t.ok(arb, 'gets arborist tree') + const { npm } = await loadMockNpm(t, { + load: false, + mocks: { + '@npmcli/arborist': function (args) { + t.ok(args, 'gets options object') + t.ok(args.path, 'gets path option') + this.prune = () => { + t.ok(true, 'prune is called') + } + }, + '../../lib/utils/reify-finish.js': (arb) => { + t.ok(arb, 'gets arborist tree') + }, }, }) - const npm = new Npm() await npm.exec('prune', []) }) diff --git a/deps/npm/test/lib/commands/publish.js b/deps/npm/test/lib/commands/publish.js index 5f4fb40106..1178cd6ee1 100644 --- a/deps/npm/test/lib/commands/publish.js +++ b/deps/npm/test/lib/commands/publish.js @@ -1,13 +1,15 @@ const t = require('tap') const { fake: mockNpm } = require('../../fixtures/mock-npm') const fs = require('fs') +const log = require('../../../lib/utils/log-shim') // The way we set loglevel is kind of convoluted, and there is no way to affect // it from these tests, which only interact with lib/publish.js, which assumes // that the code that is requiring and calling lib/publish.js has already // taken care of the loglevel -const log = require('npmlog') -log.level = 'silent' +const _level = log.level +t.beforeEach(() => (log.level = 'silent')) +t.teardown(() => (log.level = _level)) t.cleanSnapshot = data => { return data.replace(/^ *"gitHead": .*$\n/gm, '') @@ -19,8 +21,6 @@ const defaults = Object.entries(definitions).reduce((defaults, [key, def]) => { return defaults }, {}) -t.afterEach(() => (log.level = 'silent')) - t.test( /* eslint-disable-next-line max-len */ 'should publish with libnpmpublish, passing through flatOptions and respecting publishConfig.registry', @@ -147,7 +147,7 @@ t.test('if loglevel=info and json, should not output package contents', async t id: 'someid', }), logTar: () => { - t.pass('logTar is called') + t.fail('logTar is not called in json mode') }, }, libnpmpublish: { @@ -188,7 +188,6 @@ t.test( ), }) - log.level = 'silent' const Publish = t.mock('../../../lib/commands/publish.js', { '../../../lib/utils/tar.js': { getContents: () => ({ @@ -681,9 +680,12 @@ t.test('private workspaces', async t => { } t.test('with color', async t => { + t.plan(4) + + log.level = 'info' const Publish = t.mock('../../../lib/commands/publish.js', { ...mocks, - npmlog: { + 'proc-log': { notice () {}, verbose () {}, warn (title, msg) { @@ -707,9 +709,12 @@ t.test('private workspaces', async t => { }) t.test('colorless', async t => { + t.plan(4) + + log.level = 'info' const Publish = t.mock('../../../lib/commands/publish.js', { ...mocks, - npmlog: { + 'proc-log': { notice () {}, verbose () {}, warn (title, msg) { @@ -730,6 +735,8 @@ t.test('private workspaces', async t => { }) t.test('unexpected error', async t => { + t.plan(1) + const Publish = t.mock('../../../lib/commands/publish.js', { ...mocks, libnpmpublish: { @@ -741,7 +748,7 @@ t.test('private workspaces', async t => { publishes.push(manifest) }, }, - npmlog: { + 'proc-log': { notice () {}, verbose () {}, }, @@ -755,6 +762,8 @@ t.test('private workspaces', async t => { }) t.test('runs correct lifecycle scripts', async t => { + t.plan(5) + const testDir = t.testdir({ 'package.json': JSON.stringify( { @@ -773,6 +782,7 @@ t.test('runs correct lifecycle scripts', async t => { }) const scripts = [] + log.level = 'info' const Publish = t.mock('../../../lib/commands/publish.js', { '@npmcli/run-script': args => { scripts.push(args) @@ -810,6 +820,8 @@ t.test('runs correct lifecycle scripts', async t => { }) t.test('does not run scripts on --ignore-scripts', async t => { + t.plan(4) + const testDir = t.testdir({ 'package.json': JSON.stringify( { @@ -821,6 +833,7 @@ t.test('does not run scripts on --ignore-scripts', async t => { ), }) + log.level = 'info' const Publish = t.mock('../../../lib/commands/publish.js', { '@npmcli/run-script': () => { t.fail('should not call run-script') diff --git a/deps/npm/test/lib/commands/repo.js b/deps/npm/test/lib/commands/repo.js index 4e61047b4e..93eb6d0311 100644 --- a/deps/npm/test/lib/commands/repo.js +++ b/deps/npm/test/lib/commands/repo.js @@ -1,8 +1,8 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm.js') -const { join, sep } = require('path') +const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js') +const { sep } = require('path') -const pkgDirs = t.testdir({ +const fixture = { 'package.json': JSON.stringify({ name: 'thispkg', version: '1.2.3', @@ -149,35 +149,36 @@ const pkgDirs = t.testdir({ }, }), }, - workspaces: { +} + +const workspaceFixture = { + 'package.json': JSON.stringify({ + name: 'workspaces-test', + version: '1.2.3-test', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + repository: 'https://github.com/npm/workspaces-test', + }), + 'workspace-a': { 'package.json': JSON.stringify({ - name: 'workspaces-test', - version: '1.2.3-test', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], - repository: 'https://github.com/npm/workspaces-test', + name: 'workspace-a', + version: '1.2.3-a', + repository: 'http://repo.workspace-a/', }), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.2.3-a', - repository: 'http://repo.workspace-a/', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.2.3-n', - repository: 'https://github.com/npm/workspace-b', - }), - }, - 'workspace-c': JSON.stringify({ - 'package.json': { - name: 'workspace-n', - version: '1.2.3-n', - }, + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.2.3-n', + repository: 'https://github.com/npm/workspace-b', }), }, -}) + 'workspace-c': JSON.stringify({ + 'package.json': { + name: 'workspace-n', + version: '1.2.3-n', + }, + }), +} // keep a tally of which urls got opened let opened = {} @@ -185,20 +186,18 @@ const openUrl = async (npm, url, errMsg) => { opened[url] = opened[url] || 0 opened[url]++ } - -const { Npm } = mockNpm(t, { - '../../lib/utils/open-url.js': openUrl, -}) -const npm = new Npm() - -t.before(async () => { - await npm.load() -}) - t.afterEach(() => opened = {}) -t.test('open repo urls', t => { - npm.localPrefix = pkgDirs +const loadMockNpm = async (t, prefix) => { + const res = await _loadMockNpm(t, { + mocks: { '../../lib/utils/open-url.js': openUrl }, + testdir: prefix, + }) + return res +} + +t.test('open repo urls', async t => { + const { npm } = await loadMockNpm(t, fixture) const expect = { hostedgit: 'https://github.com/foo/hostedgit', hostedgitat: 'https://github.com/foo/hostedgitat', @@ -239,8 +238,9 @@ t.test('open repo urls', t => { }) }) -t.test('fail if cannot figure out repo url', t => { - npm.localPrefix = pkgDirs +t.test('fail if cannot figure out repo url', async t => { + const { npm } = await loadMockNpm(t, fixture) + const cases = [ 'norepo', 'repoobbj-nourl', @@ -261,13 +261,13 @@ t.test('fail if cannot figure out repo url', t => { }) t.test('open default package if none specified', async t => { - npm.localPrefix = pkgDirs + const { npm } = await loadMockNpm(t, fixture) await npm.exec('repo', []) t.equal(opened['https://example.com/thispkg'], 1, 'opened expected url', { opened }) }) -t.test('workspaces', t => { - npm.localPrefix = join(pkgDirs, 'workspaces') +t.test('workspaces', async t => { + const { npm } = await loadMockNpm(t, workspaceFixture) t.afterEach(() => { npm.config.set('workspaces', null) @@ -311,5 +311,4 @@ t.test('workspaces', t => { ) t.match({}, opened, 'opened no repo urls') }) - t.end() }) diff --git a/deps/npm/test/lib/commands/restart.js b/deps/npm/test/lib/commands/restart.js index 608de0331d..7730f1a301 100644 --- a/deps/npm/test/lib/commands/restart.js +++ b/deps/npm/test/lib/commands/restart.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -12,24 +12,24 @@ t.teardown(() => { // pretty specific internals of runScript const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') -t.test('should run stop script from package.json', async t => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - restart: 'node ./test-restart.js', - }, - }), +t.test('should run restart script from package.json', async t => { + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + restart: 'node ./test-restart.js', + }, + }), + }, + config: { + loglevel: 'silent', + }, }) - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.log.level = 'silent' - npm.localPrefix = prefix - const [scriptShell] = makeSpawnArgs({ path: prefix }) + const [scriptShell] = makeSpawnArgs({ path: npm.prefix }) const script = spawk.spawn(scriptShell, (args) => { - t.ok(args.includes('node ./test-restart.js "foo"'), 'ran stop script with extra args') + t.ok(args.includes('node ./test-restart.js "foo"'), 'ran restart script with extra args') return true }) await npm.exec('restart', ['foo']) diff --git a/deps/npm/test/lib/commands/root.js b/deps/npm/test/lib/commands/root.js index 9871ddb25d..a886b30c3e 100644 --- a/deps/npm/test/lib/commands/root.js +++ b/deps/npm/test/lib/commands/root.js @@ -1,9 +1,8 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('prefix', async (t) => { - const { joinedOutput, Npm } = mockNpm(t) - const npm = new Npm() + const { joinedOutput, npm } = await loadMockNpm(t, { load: false }) await npm.exec('root', []) t.equal( joinedOutput(), diff --git a/deps/npm/test/lib/commands/run-script.js b/deps/npm/test/lib/commands/run-script.js index e421c655ef..ea0227cda0 100644 --- a/deps/npm/test/lib/commands/run-script.js +++ b/deps/npm/test/lib/commands/run-script.js @@ -31,13 +31,16 @@ const output = [] const npmlog = { disableProgress: () => null, level: 'warn', +} + +const log = { error: () => null, } t.afterEach(() => { npm.color = false npmlog.level = 'warn' - npmlog.error = () => null + log.error = () => null output.length = 0 RUN_SCRIPTS.length = 0 config['if-present'] = false @@ -56,6 +59,7 @@ const getRS = windows => { } ), npmlog, + 'proc-log': log, '../../../lib/utils/is-windows-shell.js': windows, }) return new RunScript(npm) @@ -758,7 +762,7 @@ t.test('workspaces', t => { t.test('missing scripts in all workspaces', async t => { const LOG = [] - npmlog.error = err => { + log.error = err => { LOG.push(String(err)) } await t.rejects( @@ -805,7 +809,7 @@ t.test('workspaces', t => { t.test('missing scripts in some workspaces', async t => { const LOG = [] - npmlog.error = err => { + log.error = err => { LOG.push(String(err)) } await runScript.execWorkspaces(['test'], ['a', 'b', 'c', 'd']) @@ -857,6 +861,7 @@ t.test('workspaces', t => { throw new Error('err') }, npmlog, + 'proc-log': log, '../../../lib/utils/is-windows-shell.js': false, }) const runScript = new RunScript(npm) @@ -875,6 +880,7 @@ t.test('workspaces', t => { RUN_SCRIPTS.push(opts) }, npmlog, + 'proc-log': log, '../../../lib/utils/is-windows-shell.js': false, }) const runScript = new RunScript(npm) diff --git a/deps/npm/test/lib/commands/set-script.js b/deps/npm/test/lib/commands/set-script.js index 592a2431c2..2c4fe57d68 100644 --- a/deps/npm/test/lib/commands/set-script.js +++ b/deps/npm/test/lib/commands/set-script.js @@ -10,7 +10,7 @@ const npm = mockNpm(flatOptions) const ERROR_OUTPUT = [] const WARN_OUTPUT = [] const SetScript = t.mock('../../../lib/commands/set-script.js', { - npmlog: { + 'proc-log': { error: (...args) => { ERROR_OUTPUT.push(args) }, diff --git a/deps/npm/test/lib/commands/set.js b/deps/npm/test/lib/commands/set.js index a57ea1a540..feeb901571 100644 --- a/deps/npm/test/lib/commands/set.js +++ b/deps/npm/test/lib/commands/set.js @@ -2,6 +2,7 @@ const t = require('tap') // can't run this until npm set can save to project level npmrc t.skip('npm set', async t => { + // XXX: convert to loadMockNpm const { real: mockNpm } = require('../../fixtures/mock-npm') const { joinedOutput, Npm } = mockNpm(t) const npm = new Npm() diff --git a/deps/npm/test/lib/commands/shrinkwrap.js b/deps/npm/test/lib/commands/shrinkwrap.js index db4021abd6..2b9e46c70c 100644 --- a/deps/npm/test/lib/commands/shrinkwrap.js +++ b/deps/npm/test/lib/commands/shrinkwrap.js @@ -1,7 +1,7 @@ const t = require('tap') const fs = require('fs') const { resolve } = require('path') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') // Attempt to parse json values in snapshots before // stringifying to remove escaped values like \\" @@ -13,7 +13,7 @@ t.formatSnapshot = obj => (k, v) => { try { return JSON.parse(v) - } catch (_) {} + } catch {} return v }, 2 @@ -23,33 +23,25 @@ t.formatSnapshot = obj => // and make some assertions that should always be true. Sets // the results on t.context for use in child tests const shrinkwrap = async (t, testdir = {}, config = {}, mocks = {}) => { - const { Npm, filteredLogs } = mockNpm(t, mocks) - const npm = new Npm() - await npm.load() - - npm.localPrefix = t.testdir(testdir) - if (config.lockfileVersion) { - npm.config.set('lockfile-version', config.lockfileVersion) - } - if (config.global) { - npm.config.set('global', config.global) - } + const { npm, logs } = await loadMockNpm(t, { + mocks, + config, + testdir, + }) await npm.exec('shrinkwrap', []) - const newFile = resolve(npm.localPrefix, 'npm-shrinkwrap.json') - const oldFile = resolve(npm.localPrefix, 'package-lock.json') - const notices = filteredLogs('notice') - const warnings = filteredLogs('warn') + const newFile = resolve(npm.prefix, 'npm-shrinkwrap.json') + const oldFile = resolve(npm.prefix, 'package-lock.json') t.notOk(fs.existsSync(oldFile), 'package-lock is always deleted') - t.same(warnings, [], 'no warnings') + t.same(logs.warn, [], 'no warnings') t.teardown(() => delete t.context) t.context = { localPrefix: testdir, config, shrinkwrap: JSON.parse(fs.readFileSync(newFile)), - logs: notices, + logs: logs.notice.map(([, m]) => m), } } @@ -58,8 +50,8 @@ const shrinkwrap = async (t, testdir = {}, config = {}, mocks = {}) => { const shrinkwrapMatrix = async (t, file, assertions) => { const ancient = JSON.stringify({ lockfileVersion: 1 }) const existing = JSON.stringify({ lockfileVersion: 2 }) - const upgrade = { lockfileVersion: 3 } - const downgrade = { lockfileVersion: 1 } + const upgrade = { 'lockfile-version': 3 } + const downgrade = { 'lockfile-version': 1 } let ancientDir = {} let existingDir = null diff --git a/deps/npm/test/lib/commands/star.js b/deps/npm/test/lib/commands/star.js index 13838bb105..9a49036422 100644 --- a/deps/npm/test/lib/commands/star.js +++ b/deps/npm/test/lib/commands/star.js @@ -15,9 +15,9 @@ const npm = mockNpm({ }, }) const npmFetch = { json: noop } -const npmlog = { error: noop, info: noop, verbose: noop } +const log = { error: noop, info: noop, verbose: noop } const mocks = { - npmlog, + 'proc-log': log, 'npm-registry-fetch': npmFetch, '../../../lib/utils/get-identity.js': async () => 'foo', '../../../lib/utils/usage.js': () => 'usage instructions', @@ -29,7 +29,7 @@ const star = new Star(npm) t.afterEach(() => { config.unicode = false config['star.unstar'] = false - npmlog.info = noop + log.info = noop result = '' }) @@ -53,7 +53,7 @@ t.test('star a package', async t => { : {} ), }) - npmlog.info = (title, msg, id) => { + log.info = (title, msg, id) => { t.equal(title, 'star', 'should use expected title') t.equal(msg, 'starring', 'should use expected msg') t.equal(id, pkgName, 'should use expected id') @@ -78,7 +78,7 @@ t.test('unstar a package', async t => { : { foo: true } ), }) - npmlog.info = (title, msg, id) => { + log.info = (title, msg, id) => { t.equal(title, 'unstar', 'should use expected title') t.equal(msg, 'unstarring', 'should use expected msg') t.equal(id, pkgName, 'should use expected id') diff --git a/deps/npm/test/lib/commands/stars.js b/deps/npm/test/lib/commands/stars.js index 4ed6438589..959739653d 100644 --- a/deps/npm/test/lib/commands/stars.js +++ b/deps/npm/test/lib/commands/stars.js @@ -11,9 +11,9 @@ const npm = { }, } const npmFetch = { json: noop } -const npmlog = { warn: noop } +const log = { warn: noop } const mocks = { - npmlog, + 'proc-log': log, 'npm-registry-fetch': npmFetch, '../../../lib/utils/get-identity.js': async () => 'foo', '../../../lib/utils/usage.js': () => 'usage instructions', @@ -24,7 +24,7 @@ const stars = new Stars(npm) t.afterEach(() => { npm.config = { get () {} } - npmlog.warn = noop + log.warn = noop result = '' }) @@ -81,7 +81,7 @@ t.test('unauthorized request', async t => { ) } - npmlog.warn = (title, msg) => { + log.warn = (title, msg) => { t.equal(title, 'stars', 'should use expected title') t.equal( msg, @@ -108,7 +108,7 @@ t.test('unexpected error', async t => { throw new Error('ERROR') } - npmlog.warn = (title, msg) => { + log.warn = (title, msg) => { throw new Error('Should not output extra warning msgs') } @@ -123,7 +123,7 @@ t.test('no pkg starred', async t => { t.plan(2) npmFetch.json = async (uri, opts) => ({ rows: [] }) - npmlog.warn = (title, msg) => { + log.warn = (title, msg) => { t.equal(title, 'stars', 'should use expected title') t.equal( msg, diff --git a/deps/npm/test/lib/commands/start.js b/deps/npm/test/lib/commands/start.js index 1f26f38ead..4f7dc366db 100644 --- a/deps/npm/test/lib/commands/start.js +++ b/deps/npm/test/lib/commands/start.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -12,22 +12,23 @@ t.teardown(() => { // pretty specific internals of runScript const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') -t.test('should run stop script from package.json', async t => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - start: 'node ./test-start.js', - }, - }), +t.test('should run start script from package.json', async t => { + t.plan(2) + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + start: 'node ./test-start.js', + }, + }), + }, + config: { + loglevel: 'silent', + }, }) - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.log.level = 'silent' - npm.localPrefix = prefix - const [scriptShell] = makeSpawnArgs({ path: prefix }) + const [scriptShell] = makeSpawnArgs({ path: npm.prefix }) const script = spawk.spawn(scriptShell, (args) => { t.ok(args.includes('node ./test-start.js "foo"'), 'ran start script with extra args') return true diff --git a/deps/npm/test/lib/commands/stop.js b/deps/npm/test/lib/commands/stop.js index 4f189449ba..53d057b711 100644 --- a/deps/npm/test/lib/commands/stop.js +++ b/deps/npm/test/lib/commands/stop.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -13,21 +13,21 @@ t.teardown(() => { const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') t.test('should run stop script from package.json', async t => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - stop: 'node ./test-stop.js', - }, - }), + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + stop: 'node ./test-stop.js', + }, + }), + }, + config: { + loglevel: 'silent', + }, }) - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.log.level = 'silent' - npm.localPrefix = prefix - const [scriptShell] = makeSpawnArgs({ path: prefix }) + const [scriptShell] = makeSpawnArgs({ path: npm.prefix }) const script = spawk.spawn(scriptShell, (args) => { t.ok(args.includes('node ./test-stop.js "foo"'), 'ran stop script with extra args') return true diff --git a/deps/npm/test/lib/commands/test.js b/deps/npm/test/lib/commands/test.js index 4e5ce289bc..a3dbd3ff4c 100644 --- a/deps/npm/test/lib/commands/test.js +++ b/deps/npm/test/lib/commands/test.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -12,22 +12,22 @@ t.teardown(() => { // pretty specific internals of runScript const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') -t.test('should run stop script from package.json', async t => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - test: 'node ./test-test.js', - }, - }), +t.test('should run test script from package.json', async t => { + const { npm } = await loadMockNpm(t, { + testdir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + test: 'node ./test-test.js', + }, + }), + }, + config: { + loglevel: 'silent', + }, }) - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.log.level = 'silent' - npm.localPrefix = prefix - const [scriptShell] = makeSpawnArgs({ path: prefix }) + const [scriptShell] = makeSpawnArgs({ path: npm.prefix }) const script = spawk.spawn(scriptShell, (args) => { t.ok(args.includes('node ./test-test.js "foo"'), 'ran test script with extra args') return true diff --git a/deps/npm/test/lib/commands/token.js b/deps/npm/test/lib/commands/token.js index 6d0dc9d7e0..65a094a0bc 100644 --- a/deps/npm/test/lib/commands/token.js +++ b/deps/npm/test/lib/commands/token.js @@ -3,25 +3,24 @@ const t = require('tap') const mocks = { profile: {}, output: () => {}, - log: {}, readUserInfo: {}, } const npm = { output: (...args) => mocks.output(...args), } -const Token = t.mock('../../../lib/commands/token.js', { +const mockToken = (otherMocks) => t.mock('../../../lib/commands/token.js', { '../../../lib/utils/otplease.js': (opts, fn) => { return Promise.resolve().then(() => fn(opts)) }, '../../../lib/utils/read-user-info.js': mocks.readUserInfo, 'npm-profile': mocks.profile, - npmlog: mocks.log, + ...otherMocks, }) -const token = new Token(npm) +const tokenWithMocks = (options = {}) => { + const { log, ...mockRequests } = options -const tokenWithMocks = mockRequests => { for (const mod in mockRequests) { if (mod === 'npm') { mockRequests.npm = { ...npm, ...mockRequests.npm } @@ -50,13 +49,24 @@ const tokenWithMocks = mockRequests => { } } - const token = new Token(mockRequests.npm || npm) + const MockedToken = mockToken(log ? { + 'proc-log': { + info: log.info, + }, + npmlog: { + gauge: log.gauge, + newItem: log.newItem, + }, + } : {}) + const token = new MockedToken(mockRequests.npm || npm) return [token, reset] } t.test('completion', t => { t.plan(5) + const [token] = tokenWithMocks() + const testComp = (argv, expect) => { t.resolveMatch(token.completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) } @@ -74,7 +84,7 @@ t.test('completion', t => { t.test('token foobar', async t => { t.plan(2) - const [, reset] = tokenWithMocks({ + const [token, reset] = tokenWithMocks({ log: { gauge: { show: name => { diff --git a/deps/npm/test/lib/commands/unpublish.js b/deps/npm/test/lib/commands/unpublish.js index 6ac2067531..1424adf5c9 100644 --- a/deps/npm/test/lib/commands/unpublish.js +++ b/deps/npm/test/lib/commands/unpublish.js @@ -17,7 +17,6 @@ const testDir = t.testdir({ const npm = mockNpm({ localPrefix: testDir, - log: { silly () {}, verbose () {} }, config, output: (...msg) => { result += msg.join('\n') @@ -30,10 +29,10 @@ const mocks = { 'npm-registry-fetch': { json: noop }, '../../../lib/utils/otplease.js': async (opts, fn) => fn(opts), '../../../lib/utils/get-identity.js': async () => 'foo', + 'proc-log': { silly () {}, verbose () {} }, } t.afterEach(() => { - npm.log = { silly () {}, verbose () {} } npm.localPrefix = testDir result = '' config['dry-run'] = false @@ -44,7 +43,7 @@ t.afterEach(() => { t.test('no args --force', async t => { config.force = true - npm.log = { + const log = { silly (title) { t.equal(title, 'unpublish', 'should silly log args') }, @@ -74,6 +73,7 @@ t.test('no args --force', async t => { const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmpublish, + 'proc-log': log, }) const unpublish = new Unpublish(npm) @@ -147,7 +147,7 @@ t.test('too many args', async t => { }) t.test('unpublish <pkg>@version', async t => { - npm.log = { + const log = { silly (title, key, value) { t.equal(title, 'unpublish', 'should silly log args') if (key === 'spec') { @@ -172,6 +172,7 @@ t.test('unpublish <pkg>@version', async t => { const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmpublish, + 'proc-log': log, }) const unpublish = new Unpublish(npm) diff --git a/deps/npm/test/lib/commands/update.js b/deps/npm/test/lib/commands/update.js index 6ca6dbc87d..aecb2c32b5 100644 --- a/deps/npm/test/lib/commands/update.js +++ b/deps/npm/test/lib/commands/update.js @@ -9,12 +9,10 @@ const config = { const noop = () => null const npm = mockNpm({ globalDir: '', - log: noop, config, prefix: '', }) const mocks = { - npmlog: { warn () {} }, '@npmcli/arborist': class { reify () {} }, @@ -29,22 +27,23 @@ t.afterEach(() => { }) t.test('no args', async t => { - t.plan(3) + t.plan(4) npm.prefix = '/project/a' class Arborist { constructor (args) { + const { log, ...rest } = args t.same( - args, + rest, { ...npm.flatOptions, path: npm.prefix, - log: noop, workspaces: null, }, 'should call arborist contructor with expected args' ) + t.match(log, {}, 'log is passed in') } reify ({ update }) { @@ -65,22 +64,23 @@ t.test('no args', async t => { }) t.test('with args', async t => { - t.plan(3) + t.plan(4) npm.prefix = '/project/a' class Arborist { constructor (args) { + const { log, ...rest } = args t.same( - args, + rest, { ...npm.flatOptions, path: npm.prefix, - log: noop, workspaces: null, }, 'should call arborist contructor with expected args' ) + t.match(log, {}, 'log is passed in') } reify ({ update }) { @@ -108,7 +108,7 @@ t.test('update --depth=<number>', async t => { const Update = t.mock('../../../lib/commands/update.js', { ...mocks, - npmlog: { + 'proc-log': { warn: (title, msg) => { t.equal(title, 'update', 'should print expected title') t.match( @@ -125,7 +125,7 @@ t.test('update --depth=<number>', async t => { }) t.test('update --global', async t => { - t.plan(2) + t.plan(3) const normalizePath = p => p.replace(/\\+/g, '/') const redactCwd = (path) => normalizePath(path) @@ -137,13 +137,15 @@ t.test('update --global', async t => { class Arborist { constructor (args) { - const { path, ...opts } = args + const { path, log, ...rest } = args t.same( - opts, - { ...npm.flatOptions, log: noop, workspaces: undefined }, + rest, + { ...npm.flatOptions, workspaces: undefined }, 'should call arborist contructor with expected options' ) + t.match(log, {}, 'log is passed in') + t.equal( redactCwd(path), '{CWD}/global/lib', diff --git a/deps/npm/test/lib/commands/version.js b/deps/npm/test/lib/commands/version.js index 6603b58106..980353897c 100644 --- a/deps/npm/test/lib/commands/version.js +++ b/deps/npm/test/lib/commands/version.js @@ -1,5 +1,6 @@ const t = require('tap') const { fake: mockNpm } = require('../../fixtures/mock-npm') +const mockGlobals = require('../../fixtures/mock-globals.js') let result = [] @@ -26,294 +27,301 @@ const mocks = { const Version = t.mock('../../../lib/commands/version.js', mocks) const version = new Version(npm) -const _processVersions = process.versions t.afterEach(() => { config.json = false npm.prefix = '' - process.versions = _processVersions result = [] }) -t.test('no args', async t => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-version-no-args', - version: '3.2.1', - }), - }) - npm.prefix = prefix - Object.defineProperty(process, 'versions', { value: { node: '1.0.0' } }) - - await version.exec([]) - - t.same( - result, - [ - { - 'test-version-no-args': '3.2.1', - node: '1.0.0', - npm: '1.0.0', - }, - ], - 'should output expected values for various versions in npm' - ) -}) - -t.test('too many args', async t => { - await t.rejects( - version.exec(['foo', 'bar']), - /npm version/, - 'should throw usage instructions error' - ) -}) - -t.test('completion', async t => { - const testComp = async (argv, expect) => { - const res = await version.completion({ conf: { argv: { remain: argv } } }) - t.strictSame(res, expect, argv.join(' ')) - } - - await testComp( - ['npm', 'version'], - ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'from-git'] - ) - await testComp(['npm', 'version', 'major'], []) - - t.end() -}) - -t.test('failure reading package.json', async t => { - const prefix = t.testdir({}) - npm.prefix = prefix - - await version.exec([]) - - t.same( - result, - [ - { - npm: '1.0.0', - node: '1.0.0', - }, - ], - 'should not have package name on returning object' - ) -}) - -t.test('--json option', async t => { - const prefix = t.testdir({}) - config.json = true - npm.prefix = prefix - Object.defineProperty(process, 'versions', { value: {} }) - - await version.exec([]) - t.same(result, ['{\n "npm": "1.0.0"\n}'], 'should return json stringified result') -}) +t.test('node@1', t => { + mockGlobals(t, { 'process.versions': { node: '1.0.0' } }, { replace: true }) -t.test('with one arg', async t => { - const Version = t.mock('../../../lib/commands/version.js', { - ...mocks, - libnpmversion: (arg, opts) => { - t.equal(arg, 'major', 'should forward expected value') - t.same( - opts, - { - path: '', - }, - 'should forward expected options' - ) - return '4.0.0' - }, - }) - const version = new Version(npm) - - await version.exec(['major']) - t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') -}) + t.test('no args', async t => { + const prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-version-no-args', + version: '3.2.1', + }), + }) + npm.prefix = prefix -t.test('workspaces', async t => { - t.teardown(() => { - npm.localPrefix = '' - npm.prefix = '' - }) + await version.exec([]) - t.test('no args, all workspaces', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], - }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), - }, - }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces([], []) t.same( result, [ { - 'workspaces-test': '1.0.0', - 'workspace-a': '1.0.0', - 'workspace-b': '1.0.0', + 'test-version-no-args': '3.2.1', + node: '1.0.0', npm: '1.0.0', }, ], - 'outputs includes main package and workspace versions' + 'should output expected values for various versions in npm' ) }) - t.test('no args, single workspaces', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], - }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), - }, - }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces([], ['workspace-a']) - t.same( - result, - [ - { - 'workspaces-test': '1.0.0', - 'workspace-a': '1.0.0', - npm: '1.0.0', - }, - ], - 'outputs includes main package and requested workspace versions' + t.test('too many args', async t => { + await t.rejects( + version.exec(['foo', 'bar']), + /npm version/, + 'should throw usage instructions error' ) }) - t.test('no args, all workspaces, workspace with missing name or version', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], - }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - }), - }, - 'workspace-c': { - 'package.json': JSON.stringify({ - version: '1.0.0', - }), - }, - }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces([], []) + t.test('completion', async t => { + const testComp = async (argv, expect) => { + const res = await version.completion({ conf: { argv: { remain: argv } } }) + t.strictSame(res, expect, argv.join(' ')) + } + + await testComp( + ['npm', 'version'], + ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'from-git'] + ) + await testComp(['npm', 'version', 'major'], []) + + t.end() + }) + + t.test('failure reading package.json', async t => { + const prefix = t.testdir({}) + npm.prefix = prefix + + await version.exec([]) + t.same( result, [ { - 'workspaces-test': '1.0.0', - 'workspace-a': '1.0.0', npm: '1.0.0', + node: '1.0.0', }, ], - 'outputs includes main package and valid workspace versions' + 'should not have package name on returning object' ) }) + t.end() +}) - t.test('with one arg, all workspaces', async t => { - const libNpmVersionArgs = [] - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], - }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), - }, - }) +t.test('empty versions', t => { + mockGlobals(t, { 'process.versions': {} }, { replace: true }) + + t.test('--json option', async t => { + const prefix = t.testdir({}) + config.json = true + npm.prefix = prefix + + await version.exec([]) + t.same(result, ['{\n "npm": "1.0.0"\n}'], 'should return json stringified result') + }) + + t.test('with one arg', async t => { const Version = t.mock('../../../lib/commands/version.js', { ...mocks, libnpmversion: (arg, opts) => { - libNpmVersionArgs.push([arg, opts]) - return '2.0.0' + t.equal(arg, 'major', 'should forward expected value') + t.same( + opts, + { + path: '', + }, + 'should forward expected options' + ) + return '4.0.0' }, }) - npm.localPrefix = testDir - npm.prefix = testDir const version = new Version(npm) - await version.execWorkspaces(['major'], []) - t.same( - result, - ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], - 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' - ) + await version.exec(['major']) + t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') }) - t.test('too many args', async t => { - await t.rejects( - version.execWorkspaces(['foo', 'bar'], []), - /npm version/, - 'should throw usage instructions error' - ) + t.test('workspaces', async t => { + t.teardown(() => { + npm.localPrefix = '' + npm.prefix = '' + }) + + t.test('no args, all workspaces', async t => { + const testDir = t.testdir({ + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), + }, + }) + npm.localPrefix = testDir + npm.prefix = testDir + const version = new Version(npm) + await version.execWorkspaces([], []) + t.same( + result, + [ + { + 'workspaces-test': '1.0.0', + 'workspace-a': '1.0.0', + 'workspace-b': '1.0.0', + npm: '1.0.0', + }, + ], + 'outputs includes main package and workspace versions' + ) + }) + + t.test('no args, single workspaces', async t => { + const testDir = t.testdir({ + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), + }, + }) + npm.localPrefix = testDir + npm.prefix = testDir + const version = new Version(npm) + await version.execWorkspaces([], ['workspace-a']) + t.same( + result, + [ + { + 'workspaces-test': '1.0.0', + 'workspace-a': '1.0.0', + npm: '1.0.0', + }, + ], + 'outputs includes main package and requested workspace versions' + ) + }) + + t.test('no args, all workspaces, workspace with missing name or version', async t => { + const testDir = t.testdir({ + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + }), + }, + 'workspace-c': { + 'package.json': JSON.stringify({ + version: '1.0.0', + }), + }, + }) + npm.localPrefix = testDir + npm.prefix = testDir + const version = new Version(npm) + await version.execWorkspaces([], []) + t.same( + result, + [ + { + 'workspaces-test': '1.0.0', + 'workspace-a': '1.0.0', + npm: '1.0.0', + }, + ], + 'outputs includes main package and valid workspace versions' + ) + }) + + t.test('with one arg, all workspaces', async t => { + const libNpmVersionArgs = [] + const testDir = t.testdir({ + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), + }, + }) + const Version = t.mock('../../../lib/commands/version.js', { + ...mocks, + libnpmversion: (arg, opts) => { + libNpmVersionArgs.push([arg, opts]) + return '2.0.0' + }, + }) + npm.localPrefix = testDir + npm.prefix = testDir + const version = new Version(npm) + + await version.execWorkspaces(['major'], []) + t.same( + result, + ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], + 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' + ) + }) + + t.test('too many args', async t => { + await t.rejects( + version.execWorkspaces(['foo', 'bar'], []), + /npm version/, + 'should throw usage instructions error' + ) + }) }) + + t.end() }) diff --git a/deps/npm/test/lib/commands/view.js b/deps/npm/test/lib/commands/view.js index 728787ec4a..035490a79f 100644 --- a/deps/npm/test/lib/commands/view.js +++ b/deps/npm/test/lib/commands/view.js @@ -1,6 +1,7 @@ const t = require('tap') -t.cleanSnapshot = str => str.replace(/published .*? ago/g, 'published {TIME} ago') +t.cleanSnapshot = str => str + .replace(/(published ).*?( ago)/g, '$1{TIME}$2') // run the same as tap does when running directly with node process.stdout.columns = undefined @@ -17,8 +18,8 @@ const cleanLogs = () => { console.log = fn } -// 25 hours ago -const yesterday = new Date(Date.now() - 1000 * 60 * 60 * 25) +// 3 days. its never yesterday and never a week ago +const yesterday = new Date(Date.now() - 1000 * 60 * 60 * 24 * 3) const packument = (nv, opts) => { if (!opts.fullMetadata) { @@ -564,6 +565,12 @@ t.test('workspaces', async t => { pacote: { packument, }, + 'proc-log': { + warn: (msg) => { + warnMsg = msg + }, + silly: () => {}, + }, }) const config = { unicode: false, @@ -571,11 +578,6 @@ t.test('workspaces', async t => { } let warnMsg const npm = mockNpm({ - log: { - warn: (msg) => { - warnMsg = msg - }, - }, config, localPrefix: testDir, }) diff --git a/deps/npm/test/lib/commands/whoami.js b/deps/npm/test/lib/commands/whoami.js index dc6144ec1d..66c3f0c6b3 100644 --- a/deps/npm/test/lib/commands/whoami.js +++ b/deps/npm/test/lib/commands/whoami.js @@ -1,26 +1,24 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm') +const { load: _loadMockNpm } = require('../../fixtures/mock-npm') const username = 'foo' -const { joinedOutput, Npm } = mockNpm(t, { - '../../lib/utils/get-identity.js': () => Promise.resolve(username), -}) -const npm = new Npm() - -t.before(async () => { - await npm.load() +const loadMockNpm = (t, options) => _loadMockNpm(t, { + mocks: { + '../../lib/utils/get-identity.js': () => Promise.resolve(username), + }, + ...options, }) t.test('npm whoami', async (t) => { + const { npm, joinedOutput } = await loadMockNpm(t) await npm.exec('whoami', []) t.equal(joinedOutput(), username, 'should print username') }) t.test('npm whoami --json', async (t) => { - t.teardown(() => { - npm.config.set('json', false) + const { npm, joinedOutput } = await loadMockNpm(t, { + config: { json: true }, }) - npm.config.set('json', true) await npm.exec('whoami', []) t.equal(JSON.parse(joinedOutput()), username, 'should print username') }) diff --git a/deps/npm/test/lib/fixtures/mock-globals.js b/deps/npm/test/lib/fixtures/mock-globals.js new file mode 100644 index 0000000000..02566e575a --- /dev/null +++ b/deps/npm/test/lib/fixtures/mock-globals.js @@ -0,0 +1,321 @@ +const t = require('tap') +const mockGlobals = require('../../fixtures/mock-globals') + +const originals = { + platform: process.platform, + error: console.error, + stderrOn: process.stderr.on, + stderrWrite: process.stderr.write, + shell: process.env.SHELL, + home: process.env.HOME, + argv: process.argv, + env: process.env, + setInterval, +} + +t.test('console', async t => { + await t.test('mocks', async (t) => { + const errors = [] + mockGlobals(t, { + 'console.error': (...args) => errors.push(...args), + }) + + console.error(1) + console.error(2) + console.error(3) + t.strictSame(errors, [1, 2, 3], 'i got my errors') + }) + + t.equal(console.error, originals.error) +}) + +t.test('platform', async (t) => { + t.equal(process.platform, originals.platform) + + await t.test('posix', async (t) => { + mockGlobals(t, { 'process.platform': 'posix' }) + t.equal(process.platform, 'posix') + + await t.test('win32 --> woo', async (t) => { + mockGlobals(t, { 'process.platform': 'win32' }) + t.equal(process.platform, 'win32') + + mockGlobals(t, { 'process.platform': 'woo' }) + t.equal(process.platform, 'woo') + }) + + t.equal(process.platform, 'posix') + }) + + t.equal(process.platform, originals.platform) +}) + +t.test('manual reset', async t => { + let errorHandler, data + + const { reset } = mockGlobals(t, { + 'process.stderr.on': (__, handler) => { + errorHandler = handler + reset['process.stderr.on']() + }, + 'process.stderr.write': (chunk, callback) => { + data = chunk + process.nextTick(() => { + errorHandler({ errno: 'EPIPE' }) + callback() + }) + reset['process.stderr.write']() + }, + }) + + await new Promise((res, rej) => { + process.stderr.on('error', er => er.errno === 'EPIPE' ? res() : rej(er)) + process.stderr.write('hey', res) + }) + + t.equal(process.stderr.on, originals.stderrOn) + t.equal(process.stderr.write, originals.stderrWrite) + t.equal(data, 'hey', 'handles EPIPE errors') + t.ok(errorHandler) +}) + +t.test('reset called multiple times', async (t) => { + await t.test('single reset', async t => { + const { reset } = mockGlobals(t, { 'process.platform': 'z' }) + t.equal(process.platform, 'z') + + reset['process.platform']() + t.equal(process.platform, originals.platform) + + reset['process.platform']() + reset['process.platform']() + reset['process.platform']() + t.equal(process.platform, originals.platform) + }) + + t.equal(process.platform, originals.platform) +}) + +t.test('object mode', async t => { + await t.test('mocks', async t => { + const home = t.testdir() + + mockGlobals(t, { + process: { + stderr: { + on: '1', + }, + env: { + HOME: home, + }, + }, + }) + + t.equal(process.stderr.on, '1') + t.equal(process.env.HOME, home) + }) + + t.equal(process.env.HOME, originals.home) + t.equal(process.stderr.write, originals.stderrWrite) +}) + +t.test('mixed object/string mode', async t => { + await t.test('mocks', async t => { + const home = t.testdir() + + mockGlobals(t, { + 'process.env': { + HOME: home, + TEST: '1', + }, + }) + + t.equal(process.env.HOME, home) + t.equal(process.env.TEST, '1') + }) + + t.equal(process.env.HOME, originals.home) + t.equal(process.env.TEST, undefined) +}) + +t.test('conflicting mixed object/string mode', async t => { + await t.test('same key', async t => { + t.throws( + () => mockGlobals(t, { + process: { + env: { + HOME: '1', + TEST: '1', + NODE_ENV: '1', + }, + stderr: { + write: '1', + }, + }, + 'process.env.HOME': '1', + 'process.stderr.write': '1', + }), + /process.env.HOME,process.stderr.write/ + ) + }) + + await t.test('partial overwrite with replace', async t => { + t.throws( + () => mockGlobals(t, { + process: { + env: { + HOME: '1', + TEST: '1', + NODE_ENV: '1', + }, + stderr: { + write: '1', + }, + }, + 'process.env.HOME': '1', + 'process.stderr.write': '1', + }, { replace: true }), + /process -> process.env.HOME,process.stderr.write/ + ) + }) +}) + +t.test('falsy values', async t => { + await t.test('undefined deletes', async t => { + mockGlobals(t, { 'process.platform': undefined }) + t.notOk(Object.prototype.hasOwnProperty.call(process, 'platform')) + t.equal(process.platform, undefined) + }) + + await t.test('null', async t => { + mockGlobals(t, { 'process.platform': null }) + t.ok(Object.prototype.hasOwnProperty.call(process, 'platform')) + t.equal(process.platform, null) + }) + + t.equal(process.platform, originals.platform) +}) + +t.test('date', async t => { + await t.test('mocks', async t => { + mockGlobals(t, { + 'Date.now': () => 100, + 'Date.prototype.toISOString': () => 'DDD', + }) + t.equal(Date.now(), 100) + t.equal(new Date().toISOString(), 'DDD') + }) + + t.ok(Date.now() > 100) + t.ok(new Date().toISOString().includes('T')) +}) + +t.test('argv', async t => { + await t.test('argv', async t => { + mockGlobals(t, { 'process.argv': ['node', 'woo'] }) + t.strictSame(process.argv, ['node', 'woo']) + }) + + t.strictSame(process.argv, originals.argv) +}) + +t.test('replace', async (t) => { + await t.test('env', async t => { + mockGlobals(t, { 'process.env': { HOME: '1' } }, { replace: true }) + t.strictSame(process.env, { HOME: '1' }) + t.equal(Object.keys(process.env).length, 1) + }) + + await t.test('setInterval', async t => { + mockGlobals(t, { setInterval: 0 }, { replace: true }) + t.strictSame(setInterval, 0) + }) + + t.strictSame(setInterval, originals.setInterval) + t.strictSame(process.env, originals.env) +}) + +t.test('multiple mocks and resets', async (t) => { + const initial = 'a' + const platforms = ['b', 'c', 'd', 'e', 'f', 'g'] + + await t.test('first in, first out', async t => { + mockGlobals(t, { 'process.platform': initial }) + t.equal(process.platform, initial) + + await t.test('platforms', async (t) => { + const resets = platforms.map((platform) => { + const { reset } = mockGlobals(t, { 'process.platform': platform }) + t.equal(process.platform, platform) + return reset['process.platform'] + }).reverse() + + ;[...platforms.reverse()].forEach((platform, index) => { + const reset = resets[index] + const nextPlatform = index === platforms.length - 1 ? initial : platforms[index + 1] + t.equal(process.platform, platform) + reset() + t.equal(process.platform, nextPlatform, 'first reset') + reset() + reset() + t.equal(process.platform, nextPlatform, 'multiple resets are indempotent') + }) + }) + + t.equal(process.platform, initial) + }) + + await t.test('last in,first out', async t => { + mockGlobals(t, { 'process.platform': initial }) + t.equal(process.platform, initial) + + await t.test('platforms', async (t) => { + const resets = platforms.map((platform) => { + const { reset } = mockGlobals(t, { 'process.platform': platform }) + t.equal(process.platform, platform) + return reset['process.platform'] + }) + + resets.forEach((reset, index) => { + // Calling a reset out of order removes it from the stack + // but does not change the descriptor so it should still be the + // last in descriptor until there are none left + const lastPlatform = platforms[platforms.length - 1] + const nextPlatform = index === platforms.length - 1 ? initial : lastPlatform + t.equal(process.platform, lastPlatform) + reset() + t.equal(process.platform, nextPlatform, 'multiple resets are indempotent') + reset() + reset() + t.equal(process.platform, nextPlatform, 'multiple resets are indempotent') + }) + }) + + t.equal(process.platform, initial) + }) + + t.test('reset all', async (t) => { + const { teardown } = mockGlobals(t, { 'process.platform': initial }) + + await t.test('platforms', async (t) => { + const resets = platforms.map((p) => { + const { teardown, reset } = mockGlobals(t, { 'process.platform': p }) + t.equal(process.platform, p) + return [ + reset['process.platform'], + teardown, + ] + }) + + resets.forEach(r => r[1]()) + t.equal(process.platform, initial, 'teardown goes to initial value') + + resets.forEach((r) => r[0]()) + t.equal(process.platform, initial, 'calling resets after teardown does nothing') + }) + + t.equal(process.platform, initial) + teardown() + t.equal(process.platform, originals.platform) + }) +}) diff --git a/deps/npm/test/lib/load-all-commands.js b/deps/npm/test/lib/load-all-commands.js index f813e50b22..248c81a30a 100644 --- a/deps/npm/test/lib/load-all-commands.js +++ b/deps/npm/test/lib/load-all-commands.js @@ -4,21 +4,16 @@ // renders also ensures that any params we've defined in our commands work. const t = require('tap') const util = require('util') -const { real: mockNpm } = require('../fixtures/mock-npm.js') +const { load: loadMockNpm } = require('../fixtures/mock-npm.js') const { cmdList } = require('../../lib/utils/cmd-list.js') -const { Npm, outputs } = mockNpm(t) -const npm = new Npm() - t.test('load each command', async t => { - t.afterEach(() => { - outputs.length = 0 - }) t.plan(cmdList.length) - await npm.load() - npm.config.set('usage', true) // This makes npm.exec output the usage for (const cmd of cmdList.sort((a, b) => a.localeCompare(b, 'en'))) { t.test(cmd, async t => { + const { npm, outputs } = await loadMockNpm(t, { + config: { usage: true }, + }) const impl = await npm.cmd(cmd) if (impl.completion) { t.type(impl.completion, 'function', 'completion, if present, is a function') diff --git a/deps/npm/test/lib/load-all.js b/deps/npm/test/lib/load-all.js index fb45331ba9..e5d7b558c2 100644 --- a/deps/npm/test/lib/load-all.js +++ b/deps/npm/test/lib/load-all.js @@ -1,34 +1,31 @@ const t = require('tap') const glob = require('glob') const { resolve } = require('path') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { load: loadMockNpm } = require('../fixtures/mock-npm') const full = process.env.npm_lifecycle_event === 'check-coverage' if (!full) { t.pass('nothing to do here, not checking for full coverage') } else { - const { Npm } = mockNpm(t) - const npm = new Npm() + t.test('load all', async (t) => { + const { npm } = await loadMockNpm(t, { }) - t.teardown(() => { - const exitHandler = require('../../lib/utils/exit-handler.js') - exitHandler.setNpm(npm) - exitHandler() - }) - - t.before(async t => { - await npm.load() - }) + t.teardown(() => { + const exitHandler = require('../../lib/utils/exit-handler.js') + exitHandler.setNpm(npm) + exitHandler() + }) - t.test('load all the files', t => { - // just load all the files so we measure coverage for the missing tests - const dir = resolve(__dirname, '../../lib') - for (const f of glob.sync(`${dir}/**/*.js`)) { - require(f) - t.pass('loaded ' + f) - } - t.pass('loaded all files') - t.end() + t.test('load all the files', t => { + // just load all the files so we measure coverage for the missing tests + const dir = resolve(__dirname, '../../lib') + for (const f of glob.sync(`${dir}/**/*.js`)) { + require(f) + t.pass('loaded ' + f) + } + t.pass('loaded all files') + t.end() + }) }) } diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js index 1ccd26e375..2a0c5a89d2 100644 --- a/deps/npm/test/lib/npm.js +++ b/deps/npm/test/lib/npm.js @@ -1,7 +1,8 @@ const t = require('tap') +const { resolve, dirname } = require('path') -const npmlog = require('npmlog') -const { real: mockNpm } = require('../fixtures/mock-npm.js') +const { load: loadMockNpm } = require('../fixtures/mock-npm.js') +const mockGlobals = require('../fixtures/mock-globals') // delete this so that we don't have configs from the fact that it // is being run by 'npm test' @@ -15,7 +16,7 @@ for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { // if this test is just run directly, which is also acceptable. if (event === 'test') { t.ok( - ['test', 'run-script'].some(i => i === event), + ['test', 'run-script'].some(i => i === process.env[env]), 'should match "npm test" or "npm run test"' ) } else { @@ -25,41 +26,14 @@ for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { delete process.env[env] } -const { resolve, dirname } = require('path') - -const actualPlatform = process.platform -const beWindows = () => { - Object.defineProperty(process, 'platform', { - value: 'win32', - configurable: true, - }) -} -const bePosix = () => { - Object.defineProperty(process, 'platform', { - value: 'posix', - configurable: true, - }) -} -const argv = [...process.argv] - -t.afterEach(() => { +t.afterEach(async (t) => { for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { delete process.env[env] } - process.env.npm_config_cache = CACHE - process.argv = argv - Object.defineProperty(process, 'platform', { - value: actualPlatform, - configurable: true, - }) }) -const CACHE = t.testdir() -process.env.npm_config_cache = CACHE - t.test('not yet loaded', async t => { - const { Npm, logs } = mockNpm(t) - const npm = new Npm() + const { npm, logs } = await loadMockNpm(t, { load: false }) t.match(npm, { started: Number, command: null, @@ -79,8 +53,7 @@ t.test('not yet loaded', async t => { t.test('npm.load', async t => { t.test('load error', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await loadMockNpm(t, { load: false }) const loadError = new Error('load error') npm.config.load = async () => { throw loadError @@ -103,32 +76,28 @@ t.test('npm.load', async t => { }) t.test('basic loading', async t => { - const { Npm, logs } = mockNpm(t) - const npm = new Npm() - const dir = t.testdir({ - node_modules: {}, + const { npm, logs, prefix: dir, cache } = await loadMockNpm(t, { + testdir: { node_modules: {} }, }) - await npm.load() + t.equal(npm.loaded, true) t.equal(npm.config.loaded, true) t.equal(npm.config.get('force'), false) t.ok(npm.usage, 'has usage') - npm.config.set('prefix', dir) t.match(npm, { flatOptions: {}, }) - t.match(logs, [ - ['timing', 'npm:load', /Completed in [0-9.]+ms/], + t.match(logs.timing.filter(([p]) => p === 'npm:load'), [ + ['npm:load', /Completed in [0-9.]+ms/], ]) - bePosix() - t.equal(resolve(npm.cache), resolve(CACHE), 'cache is cache') + mockGlobals(t, { process: { platform: 'posix' } }) + t.equal(resolve(npm.cache), resolve(cache), 'cache is cache') const newCache = t.testdir() npm.cache = newCache t.equal(npm.config.get('cache'), newCache, 'cache setter sets config') t.equal(npm.cache, newCache, 'cache getter gets new config') - t.equal(npm.log, npmlog, 'npmlog getter') t.equal(npm.lockfileVersion, 2, 'lockfileVersion getter') t.equal(npm.prefix, npm.localPrefix, 'prefix is local prefix') t.not(npm.prefix, npm.globalPrefix, 'prefix is not global prefix') @@ -160,10 +129,9 @@ t.test('npm.load', async t => { t.equal(npm.bin, npm.globalBin, 'bin is global bin after prefix setter') t.not(npm.bin, npm.localBin, 'bin is not local bin after prefix setter') - beWindows() + mockGlobals(t, { process: { platform: 'win32' } }) t.equal(npm.bin, npm.globalBin, 'bin is global bin in windows mode') t.equal(npm.dir, npm.globalDir, 'dir is global dir in windows mode') - bePosix() const tmp = npm.tmp t.match(tmp, String, 'npm.tmp is a string') @@ -171,13 +139,12 @@ t.test('npm.load', async t => { }) t.test('forceful loading', async t => { - process.argv = [...process.argv, '--force', '--color', 'always'] - const { Npm, logs } = mockNpm(t) - const npm = new Npm() - await npm.load() - t.match(logs.filter(l => l[0] !== 'timing'), [ + mockGlobals(t, { + 'process.argv': [...process.argv, '--force', '--color', 'always'], + }) + const { logs } = await loadMockNpm(t) + t.match(logs.warn, [ [ - 'warn', 'using --force', 'Recommended protections disabled.', ], @@ -185,54 +152,42 @@ t.test('npm.load', async t => { }) t.test('node is a symlink', async t => { - const node = actualPlatform === 'win32' ? 'node.exe' : 'node' - const dir = t.testdir({ - '.npmrc': 'foo = bar', - bin: t.fixture('symlink', dirname(process.execPath)), + const node = process.platform === 'win32' ? 'node.exe' : 'node' + mockGlobals(t, { + 'process.argv': [ + node, + process.argv[1], + '--usage', + '--scope=foo', + 'token', + 'revoke', + 'blergggg', + ], }) - - const PATH = process.env.PATH || process.env.Path - process.env.PATH = resolve(dir, 'bin') - process.argv = [ - node, - process.argv[1], - '--prefix', dir, - '--userconfig', `${dir}/.npmrc`, - '--usage', - '--scope=foo', - 'token', - 'revoke', - 'blergggg', - ] - - t.teardown(() => { - process.env.PATH = PATH + const { npm, logs, outputs, prefix } = await loadMockNpm(t, { + testdir: { + bin: t.fixture('symlink', dirname(process.execPath)), + }, + globals: ({ prefix }) => ({ + 'process.env.PATH': resolve(prefix, 'bin'), + }), }) - const { Npm, logs, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() t.equal(npm.config.get('scope'), '@foo', 'added the @ sign to scope') - t.match(logs.filter(l => l[0] !== 'timing' || !/^config:/.test(l[1])), [ - [ - 'timing', - 'npm:load:whichnode', - /Completed in [0-9.]+ms/, - ], - [ - 'verbose', - 'node symlink', - resolve(dir, 'bin', node), - ], - [ - 'timing', - 'npm:load', - /Completed in [0-9.]+ms/, - ], + t.match([ + ...logs.timing.filter(([p]) => p === 'npm:load:whichnode'), + ...logs.verbose, + ...logs.timing.filter(([p]) => p === 'npm:load'), + ], [ + ['npm:load:whichnode', /Completed in [0-9.]+ms/], + ['node symlink', resolve(prefix, 'bin', node)], + ['logfile', /.*-debug-0.log/], + ['npm:load', /Completed in [0-9.]+ms/], ]) - t.equal(process.execPath, resolve(dir, 'bin', node)) + t.equal(process.execPath, resolve(prefix, 'bin', node)) outputs.length = 0 + logs.length = 0 await npm.exec('ll', []) t.equal(npm.command, 'll', 'command set to first npm command') @@ -271,33 +226,34 @@ t.test('npm.load', async t => { }) t.test('--no-workspaces with --workspace', async t => { - const dir = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { test: 'echo test a' }, - }), + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--color', 'false', + '--workspaces', 'false', + '--workspace', 'a', + ], + }) + const { npm } = await loadMockNpm(t, { + load: false, + testdir: { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { test: 'echo test a' }, + }), + }, }, + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['./packages/*'], + }), }, - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['./packages/*'], - }), }) - process.argv = [ - process.execPath, - process.argv[1], - '--userconfig', resolve(dir, '.npmrc'), - '--color', 'false', - '--workspaces', 'false', - '--workspace', 'a', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - npm.localPrefix = dir await t.rejects( npm.exec('run', []), /Can not use --no-workspaces and --workspace at the same time/ @@ -305,47 +261,40 @@ t.test('npm.load', async t => { }) t.test('workspace-aware configs and commands', async t => { - const dir = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { test: 'echo test a' }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - scripts: { test: 'echo test b' }, - }), + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--color', 'false', + '--workspaces', 'true', + ], + }) + const { npm, outputs } = await loadMockNpm(t, { + testdir: { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { test: 'echo test a' }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + scripts: { test: 'echo test b' }, + }), + }, }, + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['./packages/*'], + }), }, - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['./packages/*'], - }), - '.npmrc': '', }) - process.argv = [ - process.execPath, - process.argv[1], - '--userconfig', - resolve(dir, '.npmrc'), - '--color', - 'false', - '--workspaces', - 'true', - ] - - const { Npm, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.localPrefix = dir - // verify that calling the command with a short name still sets // the npm.command property to the full canonical name of the cmd. npm.command = null @@ -368,44 +317,42 @@ t.test('npm.load', async t => { }) t.test('workspaces in global mode', async t => { - const dir = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { test: 'echo test a' }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - scripts: { test: 'echo test b' }, - }), + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--color', + 'false', + '--workspaces', + '--global', + 'true', + ], + }) + const { npm } = await loadMockNpm(t, { + testdir: { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { test: 'echo test a' }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + scripts: { test: 'echo test b' }, + }), + }, }, + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['./packages/*'], + }), }, - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['./packages/*'], - }), }) - process.argv = [ - process.execPath, - process.argv[1], - '--userconfig', - resolve(dir, '.npmrc'), - '--color', - 'false', - '--workspaces', - '--global', - 'true', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.localPrefix = dir // verify that calling the command with a short name still sets // the npm.command property to the full canonical name of the cmd. npm.command = null @@ -418,109 +365,156 @@ t.test('npm.load', async t => { t.test('set process.title', async t => { t.test('basic title setting', async t => { - process.argv = [ - process.execPath, - process.argv[1], - '--usage', - '--scope=foo', - 'ls', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--usage', + '--scope=foo', + 'ls', + ], + }) + const { npm } = await loadMockNpm(t) t.equal(npm.title, 'npm ls') t.equal(process.title, 'npm ls') }) t.test('do not expose token being revoked', async t => { - process.argv = [ - process.execPath, - process.argv[1], - '--usage', - '--scope=foo', - 'token', - 'revoke', - 'deadbeefcafebad', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--usage', + '--scope=foo', + 'token', + 'revoke', + 'deadbeefcafebad', + ], + }) + const { npm } = await loadMockNpm(t) t.equal(npm.title, 'npm token revoke ***') t.equal(process.title, 'npm token revoke ***') }) t.test('do show *** unless a token is actually being revoked', async t => { - process.argv = [ - process.execPath, - process.argv[1], - '--usage', - '--scope=foo', - 'token', - 'revoke', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--usage', + '--scope=foo', + 'token', + 'revoke', + ], + }) + const { npm } = await loadMockNpm(t) t.equal(npm.title, 'npm token revoke') t.equal(process.title, 'npm token revoke') }) }) -t.test('timings', t => { - const { Npm, logs } = mockNpm(t) - const npm = new Npm() - process.emit('time', 'foo') - process.emit('time', 'bar') - t.match(npm.timers.get('foo'), Number, 'foo timer is a number') - t.match(npm.timers.get('bar'), Number, 'foo timer is a number') - process.emit('timeEnd', 'foo') - process.emit('timeEnd', 'bar') - process.emit('timeEnd', 'baz') - t.match(logs, [ - ['timing', 'foo', /Completed in [0-9]+ms/], - ['timing', 'bar', /Completed in [0-9]+ms/], - [ - 'silly', +t.test('debug-log', async t => { + const { npm, debugFile } = await loadMockNpm(t, { load: false }) + + const log1 = ['silly', 'test', 'before load'] + const log2 = ['silly', 'test', 'after load'] + + process.emit('log', ...log1) + await npm.load() + process.emit('log', ...log2) + + const debug = await debugFile() + t.equal(npm.logFiles.length, 1, 'one debug file') + t.match(debug, log1.join(' '), 'before load appears') + t.match(debug, log2.join(' '), 'after load log appears') +}) + +t.test('timings', async t => { + t.test('gets/sets timers', async t => { + const { npm, logs } = await loadMockNpm(t, { load: false }) + process.emit('time', 'foo') + process.emit('time', 'bar') + t.match(npm.unfinishedTimers.get('foo'), Number, 'foo timer is a number') + t.match(npm.unfinishedTimers.get('bar'), Number, 'foo timer is a number') + process.emit('timeEnd', 'foo') + process.emit('timeEnd', 'bar') + process.emit('timeEnd', 'baz') + // npm timer is started by default + process.emit('timeEnd', 'npm') + t.match(logs.timing, [ + ['foo', /Completed in [0-9]+ms/], + ['bar', /Completed in [0-9]+ms/], + ['npm', /Completed in [0-9]+ms/], + ]) + t.match(logs.silly, [[ 'timing', "Tried to end timer that doesn't exist:", 'baz', - ], - ]) - t.notOk(npm.timers.has('foo'), 'foo timer is gone') - t.notOk(npm.timers.has('bar'), 'bar timer is gone') - t.match(npm.timings, { foo: Number, bar: Number }) - t.end() + ]]) + t.notOk(npm.unfinishedTimers.has('foo'), 'foo timer is gone') + t.notOk(npm.unfinishedTimers.has('bar'), 'bar timer is gone') + t.match(npm.finishedTimers, { foo: Number, bar: Number, npm: Number }) + t.end() + }) + + t.test('writes timings file', async t => { + const { npm, timingFile } = await loadMockNpm(t, { + config: { timing: true }, + }) + process.emit('time', 'foo') + process.emit('timeEnd', 'foo') + process.emit('time', 'bar') + npm.unload() + const timings = await timingFile() + t.match(timings, { + command: [], + logfile: String, + logfiles: [String], + version: String, + unfinished: { + bar: [Number, Number], + npm: [Number, Number], + }, + foo: Number, + 'npm:load': Number, + }) + }) + + t.test('does not write timings file with timers:false', async t => { + const { npm, timingFile } = await loadMockNpm(t, { + config: { false: true }, + }) + npm.unload() + await t.rejects(() => timingFile()) + }) }) -t.test('output clears progress and console.logs the message', t => { - const mock = mockNpm(t) - const { Npm, logs } = mock - const npm = new Npm() - npm.output = mock.npmOutput - const { log } = console - const { log: { clearProgress, showProgress } } = npm +t.test('output clears progress and console.logs the message', async t => { + t.plan(2) let showingProgress = true - npm.log.clearProgress = () => showingProgress = false - npm.log.showProgress = () => showingProgress = true - console.log = (...args) => { - t.equal(showingProgress, false, 'should not be showing progress right now') - logs.push(args) - } - t.teardown(() => { - console.log = log - npm.log.showProgress = showProgress - npm.log.clearProgress = clearProgress + const logs = [] + mockGlobals(t, { + 'console.log': (...args) => { + t.equal(showingProgress, false, 'should not be showing progress right now') + logs.push(args) + }, }) - - npm.output('hello') - t.strictSame(logs, [['hello']]) + const { npm } = await loadMockNpm(t, { + load: false, + mocks: { + npmlog: { + clearProgress: () => showingProgress = false, + showProgress: () => showingProgress = true, + }, + }, + }) + npm.originalOutput('hello') + t.match(logs, [['hello']]) t.end() }) t.test('unknown command', async t => { - const mock = mockNpm(t) - const { Npm } = mock - const npm = new Npm() + const { npm } = await loadMockNpm(t, { load: false }) await t.rejects( npm.cmd('thisisnotacommand'), { code: 'EUNKNOWNCOMMAND' } diff --git a/deps/npm/test/lib/utils/audit-error.js b/deps/npm/test/lib/utils/audit-error.js index c683053cbf..bcb7d8c16d 100644 --- a/deps/npm/test/lib/utils/audit-error.js +++ b/deps/npm/test/lib/utils/audit-error.js @@ -3,14 +3,15 @@ const t = require('tap') const LOGS = [] const OUTPUT = [] const output = (...msg) => OUTPUT.push(msg) -const auditError = require('../../../lib/utils/audit-error.js') +const auditError = t.mock('../../../lib/utils/audit-error.js', { + 'proc-log': { + warn: (...msg) => LOGS.push(msg), + }, +}) const npm = { command: null, flatOptions: {}, - log: { - warn: (...msg) => LOGS.push(msg), - }, output, } t.afterEach(() => { diff --git a/deps/npm/test/lib/utils/cleanup-log-files.js b/deps/npm/test/lib/utils/cleanup-log-files.js deleted file mode 100644 index e97cf36b55..0000000000 --- a/deps/npm/test/lib/utils/cleanup-log-files.js +++ /dev/null @@ -1,79 +0,0 @@ -const t = require('tap') - -const glob = require('glob') -const rimraf = require('rimraf') -const mocks = { glob, rimraf } -const cleanup = t.mock('../../../lib/utils/cleanup-log-files.js', { - glob: (...args) => mocks.glob(...args), - rimraf: (...args) => mocks.rimraf(...args), -}) -const { basename } = require('path') - -const fs = require('fs') - -t.test('clean up those files', t => { - const cache = t.testdir({ - _logs: { - '1-debug.log': 'hello', - '2-debug.log': 'hello', - '3-debug.log': 'hello', - '4-debug.log': 'hello', - '5-debug.log': 'hello', - }, - }) - const warn = (...warning) => t.fail('failed cleanup', { warning }) - return cleanup(cache, 3, warn).then(() => { - t.strictSame(fs.readdirSync(cache + '/_logs').sort(), [ - '3-debug.log', - '4-debug.log', - '5-debug.log', - ]) - }) -}) - -t.test('nothing to clean up', t => { - const cache = t.testdir({ - _logs: { - '4-debug.log': 'hello', - '5-debug.log': 'hello', - }, - }) - const warn = (...warning) => t.fail('failed cleanup', { warning }) - return cleanup(cache, 3, warn).then(() => { - t.strictSame(fs.readdirSync(cache + '/_logs').sort(), [ - '4-debug.log', - '5-debug.log', - ]) - }) -}) - -t.test('glob fail', t => { - mocks.glob = (pattern, cb) => cb(new Error('no globbity')) - t.teardown(() => mocks.glob = glob) - const cache = t.testdir({}) - const warn = (...warning) => t.fail('failed cleanup', { warning }) - return cleanup(cache, 3, warn) -}) - -t.test('rimraf fail', t => { - mocks.rimraf = (file, cb) => cb(new Error('youll never rimraf me!')) - t.teardown(() => mocks.rimraf = rimraf) - - const cache = t.testdir({ - _logs: { - '1-debug.log': 'hello', - '2-debug.log': 'hello', - '3-debug.log': 'hello', - '4-debug.log': 'hello', - '5-debug.log': 'hello', - }, - }) - const warnings = [] - const warn = (...warning) => warnings.push(basename(warning[2])) - return cleanup(cache, 3, warn).then(() => { - t.strictSame(warnings.sort((a, b) => a.localeCompare(b, 'en')), [ - '1-debug.log', - '2-debug.log', - ]) - }) -}) diff --git a/deps/npm/test/lib/utils/config/definitions.js b/deps/npm/test/lib/utils/config/definitions.js index f6813a8bc0..bf4b48709a 100644 --- a/deps/npm/test/lib/utils/config/definitions.js +++ b/deps/npm/test/lib/utils/config/definitions.js @@ -1,11 +1,9 @@ const t = require('tap') - const { resolve } = require('path') +const mockGlobals = require('../../../fixtures/mock-globals') // have to fake the node version, or else it'll only pass on this one -Object.defineProperty(process, 'version', { - value: 'v14.8.0', -}) +mockGlobals(t, { 'process.version': 'v14.8.0', 'process.env.NODE_ENV': undefined }) // also fake the npm version, so that it doesn't get reset every time const pkg = require('../../../../package.json') @@ -13,8 +11,6 @@ const pkg = require('../../../../package.json') // this is a pain to keep typing const defpath = '../../../../lib/utils/config/definitions.js' -// set this in the test when we need it -delete process.env.NODE_ENV const definitions = require(defpath) // Tie the definitions to a snapshot so that if they change we are forced to @@ -43,22 +39,19 @@ t.test('basic flattening function camelCases from css-case', t => { t.test('editor', t => { t.test('has EDITOR and VISUAL, use EDITOR', t => { - process.env.EDITOR = 'vim' - process.env.VISUAL = 'mate' + mockGlobals(t, { 'process.env': { EDITOR: 'vim', VISUAL: 'mate' } }) const defs = t.mock(defpath) t.equal(defs.editor.default, 'vim') t.end() }) t.test('has VISUAL but no EDITOR, use VISUAL', t => { - delete process.env.EDITOR - process.env.VISUAL = 'mate' + mockGlobals(t, { 'process.env': { EDITOR: undefined, VISUAL: 'mate' } }) const defs = t.mock(defpath) t.equal(defs.editor.default, 'mate') t.end() }) t.test('has neither EDITOR nor VISUAL, system specific', t => { - delete process.env.EDITOR - delete process.env.VISUAL + mockGlobals(t, { 'process.env': { EDITOR: undefined, VISUAL: undefined } }) const defsWin = t.mock(defpath, { [isWin]: true, }) @@ -74,12 +67,12 @@ t.test('editor', t => { t.test('shell', t => { t.test('windows, env.ComSpec then cmd.exe', t => { - process.env.ComSpec = 'command.com' + mockGlobals(t, { 'process.env.ComSpec': 'command.com' }) const defsComSpec = t.mock(defpath, { [isWin]: true, }) t.equal(defsComSpec.shell.default, 'command.com') - delete process.env.ComSpec + mockGlobals(t, { 'process.env.ComSpec': undefined }) const defsNoComSpec = t.mock(defpath, { [isWin]: true, }) @@ -88,12 +81,12 @@ t.test('shell', t => { }) t.test('nix, SHELL then sh', t => { - process.env.SHELL = '/usr/local/bin/bash' + mockGlobals(t, { 'process.env.SHELL': '/usr/local/bin/bash' }) const defsShell = t.mock(defpath, { [isWin]: false, }) t.equal(defsShell.shell.default, '/usr/local/bin/bash') - delete process.env.SHELL + mockGlobals(t, { 'process.env.SHELL': undefined }) const defsNoShell = t.mock(defpath, { [isWin]: false, }) @@ -136,43 +129,40 @@ t.test('local-address allowed types', t => { }) t.test('unicode allowed?', t => { - const { LC_ALL, LC_CTYPE, LANG } = process.env - t.teardown(() => Object.assign(process.env, { LC_ALL, LC_CTYPE, LANG })) + const setGlobal = (obj = {}) => mockGlobals(t, { 'process.env': obj }) - process.env.LC_ALL = 'utf8' - process.env.LC_CTYPE = 'UTF-8' - process.env.LANG = 'Unicode utf-8' + setGlobal({ LC_ALL: 'utf8', LC_CTYPE: 'UTF-8', LANG: 'Unicode utf-8' }) const lcAll = t.mock(defpath) t.equal(lcAll.unicode.default, true) - process.env.LC_ALL = 'no unicode for youUUUU!' + setGlobal({ LC_ALL: 'no unicode for youUUUU!' }) const noLcAll = t.mock(defpath) t.equal(noLcAll.unicode.default, false) - delete process.env.LC_ALL + setGlobal({ LC_ALL: undefined }) const lcCtype = t.mock(defpath) t.equal(lcCtype.unicode.default, true) - process.env.LC_CTYPE = 'something other than unicode version 8' + setGlobal({ LC_CTYPE: 'something other than unicode version 8' }) const noLcCtype = t.mock(defpath) t.equal(noLcCtype.unicode.default, false) - delete process.env.LC_CTYPE + setGlobal({ LC_CTYPE: undefined }) const lang = t.mock(defpath) t.equal(lang.unicode.default, true) - process.env.LANG = 'ISO-8859-1' + setGlobal({ LANG: 'ISO-8859-1' }) const noLang = t.mock(defpath) t.equal(noLang.unicode.default, false) t.end() }) t.test('cache', t => { - process.env.LOCALAPPDATA = 'app/data/local' + mockGlobals(t, { 'process.env.LOCALAPPDATA': 'app/data/local' }) const defsWinLocalAppData = t.mock(defpath, { [isWin]: true, }) t.equal(defsWinLocalAppData.cache.default, 'app/data/local/npm-cache') - delete process.env.LOCALAPPDATA + mockGlobals(t, { 'process.env.LOCALAPPDATA': undefined }) const defsWinNoLocalAppData = t.mock(defpath, { [isWin]: true, }) @@ -241,7 +231,7 @@ t.test('flatteners that populate flat.omit array', t => { definitions.omit.flatten('omit', obj, flat) t.strictSame(flat, { omit: ['optional'] }, 'do not omit what is included') - process.env.NODE_ENV = 'production' + mockGlobals(t, { 'process.env.NODE_ENV': 'production' }) const defProdEnv = t.mock(defpath) t.strictSame(defProdEnv.omit.default, ['dev'], 'omit dev in production') t.end() @@ -372,42 +362,79 @@ t.test('cache-min', t => { }) t.test('color', t => { - const { isTTY } = process.stdout - t.teardown(() => process.stdout.isTTY = isTTY) + const setTTY = (stream, value) => mockGlobals(t, { [`process.${stream}.isTTY`]: value }) const flat = {} const obj = { color: 'always' } definitions.color.flatten('color', obj, flat) - t.strictSame(flat, { color: true }, 'true when --color=always') + t.strictSame(flat, { color: true, logColor: true }, 'true when --color=always') obj.color = false definitions.color.flatten('color', obj, flat) - t.strictSame(flat, { color: false }, 'true when --no-color') + t.strictSame(flat, { color: false, logColor: false }, 'true when --no-color') - process.stdout.isTTY = false + setTTY('stdout', false) obj.color = true definitions.color.flatten('color', obj, flat) - t.strictSame(flat, { color: false }, 'no color when stdout not tty') - process.stdout.isTTY = true + t.strictSame(flat, { color: false, logColor: false }, 'no color when stdout not tty') + setTTY('stdout', true) definitions.color.flatten('color', obj, flat) - t.strictSame(flat, { color: true }, '--color turns on color when stdout is tty') + t.strictSame(flat, { color: true, logColor: false }, '--color turns on color when stdout is tty') + setTTY('stdout', false) - delete process.env.NO_COLOR + setTTY('stderr', false) + obj.color = true + definitions.color.flatten('color', obj, flat) + t.strictSame(flat, { color: false, logColor: false }, 'no color when stderr not tty') + setTTY('stderr', true) + definitions.color.flatten('color', obj, flat) + t.strictSame(flat, { color: false, logColor: true }, '--color turns on color when stderr is tty') + setTTY('stderr', false) + + const setColor = (value) => mockGlobals(t, { 'process.env.NO_COLOR': value }) + + setColor(undefined) const defsAllowColor = t.mock(defpath) t.equal(defsAllowColor.color.default, true, 'default true when no NO_COLOR env') - process.env.NO_COLOR = '0' + setColor('0') const defsNoColor0 = t.mock(defpath) t.equal(defsNoColor0.color.default, true, 'default true when no NO_COLOR=0') - process.env.NO_COLOR = '1' + setColor('1') const defsNoColor1 = t.mock(defpath) t.equal(defsNoColor1.color.default, false, 'default false when no NO_COLOR=1') t.end() }) +t.test('progress', t => { + const setEnv = ({ tty, term } = {}) => mockGlobals(t, { + 'process.stderr.isTTY': tty, + 'process.env.TERM': term, + }) + + const flat = {} + + definitions.progress.flatten('progress', {}, flat) + t.strictSame(flat, { progress: false }) + + setEnv({ tty: true, term: 'notdumb' }) + definitions.progress.flatten('progress', { progress: true }, flat) + t.strictSame(flat, { progress: true }) + + setEnv({ tty: false, term: 'notdumb' }) + definitions.progress.flatten('progress', { progress: true }, flat) + t.strictSame(flat, { progress: false }) + + setEnv({ tty: true, term: 'dumb' }) + definitions.progress.flatten('progress', { progress: true }, flat) + t.strictSame(flat, { progress: false }) + + t.end() +}) + t.test('retry options', t => { const obj = {} // <config>: flat.retry[<option>] @@ -488,15 +515,15 @@ t.test('maxSockets', t => { t.end() }) -t.test('projectScope', t => { +t.test('scope', t => { const obj = { scope: 'asdf' } const flat = {} definitions.scope.flatten('scope', obj, flat) - t.strictSame(flat, { projectScope: '@asdf' }, 'prepend @ if needed') + t.strictSame(flat, { scope: '@asdf', projectScope: '@asdf' }, 'prepend @ if needed') obj.scope = '@asdf' definitions.scope.flatten('scope', obj, flat) - t.strictSame(flat, { projectScope: '@asdf' }, 'leave untouched if has @') + t.strictSame(flat, { scope: '@asdf', projectScope: '@asdf' }, 'leave untouched if has @') t.end() }) diff --git a/deps/npm/test/lib/utils/did-you-mean.js b/deps/npm/test/lib/utils/did-you-mean.js index 185368d61f..d3cb3a24f0 100644 --- a/deps/npm/test/lib/utils/did-you-mean.js +++ b/deps/npm/test/lib/utils/did-you-mean.js @@ -1,11 +1,9 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm.js') -const { Npm } = mockNpm(t) -const npm = new Npm() +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') const dym = require('../../../lib/utils/did-you-mean.js') t.test('did-you-mean', async t => { - await npm.load() + const { npm } = await loadMockNpm(t) t.test('with package.json', async t => { const testdir = t.testdir({ 'package.json': JSON.stringify({ diff --git a/deps/npm/test/lib/utils/display.js b/deps/npm/test/lib/utils/display.js new file mode 100644 index 0000000000..30cd2cc270 --- /dev/null +++ b/deps/npm/test/lib/utils/display.js @@ -0,0 +1,85 @@ +const t = require('tap') +const log = require('../../../lib/utils/log-shim') +const mockLogs = require('../../fixtures/mock-logs') +const mockGlobals = require('../../fixtures/mock-globals') + +const mockDisplay = (t, mocks) => { + const { logs, logMocks } = mockLogs(mocks) + const Display = t.mock('../../../lib/utils/display', { + ...mocks, + ...logMocks, + }) + const display = new Display() + t.teardown(() => display.off()) + return { display, logs } +} + +t.test('setup', async (t) => { + const { display } = mockDisplay(t) + + display.load({ timing: true, loglevel: 'notice' }) + t.equal(log.level, 'timing') + + display.load({ timing: false, loglevel: 'notice' }) + t.equal(log.level, 'notice') + + display.load({ color: true }) + t.equal(log.useColor(), true) + + display.load({ unicode: true }) + t.equal(log.gauge._theme.hasUnicode, true) + + display.load({ unicode: false }) + t.equal(log.gauge._theme.hasUnicode, false) + + mockGlobals(t, { 'process.stderr.isTTY': true }) + display.load({ progress: true }) + t.equal(log.progressEnabled, true) +}) + +t.test('can log', async (t) => { + const explains = [] + const { display, logs } = mockDisplay(t, { + npmlog: { + error: (...args) => logs.push(['error', ...args]), + warn: (...args) => logs.push(['warn', ...args]), + }, + '../../../lib/utils/explain-eresolve.js': { + explain: (...args) => { + explains.push(args) + return 'explanation' + }, + }, + }) + + display.log('error', 'test') + t.match(logs.error, [['test']]) + + display.log('warn', 'ERESOLVE', 'hello', { some: 'object' }) + t.match(logs.warn, [['ERESOLVE', 'hello']]) + t.match(explains, [[{ some: 'object' }, false, 2]]) +}) + +t.test('handles log throwing', async (t) => { + const errors = [] + mockGlobals(t, { + 'console.error': (...args) => errors.push(args), + }) + const { display } = mockDisplay(t, { + npmlog: { + verbose: () => { + throw new Error('verbose') + }, + }, + '../../../lib/utils/explain-eresolve.js': { + explain: () => { + throw new Error('explain') + }, + }, + }) + + display.log('warn', 'ERESOLVE', 'hello', { some: 'object' }) + t.match(errors, [ + [/attempt to log .* crashed/, Error('explain'), Error('verbose')], + ]) +}) diff --git a/deps/npm/test/lib/utils/error-message.js b/deps/npm/test/lib/utils/error-message.js index 1959b9217a..ddc88c1d99 100644 --- a/deps/npm/test/lib/utils/error-message.js +++ b/deps/npm/test/lib/utils/error-message.js @@ -1,87 +1,51 @@ const t = require('tap') const path = require('path') -const { real: mockNpm } = require('../../fixtures/mock-npm.js') -const { Npm } = mockNpm(t, { - '../../package.json': { - version: '123.456.789-npm', +const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js') +const mockGlobals = require('../../fixtures/mock-globals.js') +const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js') + +t.cleanSnapshot = p => cleanDate(cleanCwd(p)) + +mockGlobals(t, { + process: { + getuid: () => 867, + getgid: () => 5309, + arch: 'x64', + version: '123.456.789-node', + platform: 'posix', }, }) -const npm = new Npm() -const { Npm: UnloadedNpm } = mockNpm(t, { - '../../package.json': { - version: '123.456.789-npm', - }, -}) -const unloadedNpm = new UnloadedNpm() - -// make a bunch of stuff consistent for snapshots - -process.getuid = () => 867 -process.getgid = () => 5309 - -Object.defineProperty(process, 'arch', { - value: 'x64', - configurable: true, -}) - -Object.defineProperty(process, 'version', { - value: '123.456.789-node', - configurable: true, -}) -const CACHE = '/some/cache/dir' -const testdir = t.testdir({}) -t.before(async () => { - await npm.load() - npm.localPrefix = testdir - unloadedNpm.localPrefix = testdir - npm.config.set('cache', CACHE) - npm.config.set('node-version', '99.99.99') - npm.version = '123.456.789-npm' - unloadedNpm.version = '123.456.789-npm' -}) - -const { resolve } = require('path') - -const npmlog = require('npmlog') -const verboseLogs = [] -npmlog.verbose = (...message) => { - verboseLogs.push(message) -} - -const EXPLAIN_CALLED = [] -const mocks = { - '../../../lib/utils/explain-eresolve.js': { - report: (...args) => { - EXPLAIN_CALLED.push(args) - return 'explanation' +const loadMockNpm = async (t, { load, command, testdir, config } = {}) => { + const { npm, ...rest } = await _loadMockNpm(t, { + load, + testdir, + config, + mocks: { + '../../package.json': { + version: '123.456.789-npm', + }, }, - }, - // XXX ??? - get '../../../lib/utils/is-windows.js' () { - return process.platform === 'win32' - }, -} -let errorMessage = t.mock('../../../lib/utils/error-message.js', { ...mocks }) - -const beWindows = () => { - Object.defineProperty(process, 'platform', { - value: 'win32', - configurable: true, }) - errorMessage = t.mock('../../../lib/utils/error-message.js', { ...mocks }) + if (command !== undefined) { + npm.command = command + } + return { + npm, + ...rest, + } } -const bePosix = () => { - Object.defineProperty(process, 'platform', { - value: 'posix', - configurable: true, - }) - errorMessage = t.mock('../../../lib/utils/error-message.js', { ...mocks }) -} +const errorMessage = (er, { mocks, logMocks, npm } = {}) => + t.mock('../../../lib/utils/error-message.js', { ...mocks, ...logMocks })(er, npm) -t.test('just simple messages', t => { - npm.command = 'audit' +t.test('just simple messages', async t => { + const npm = await loadMockNpm(t, { + command: 'audit', + config: { + 'node-version': '99.99.99', + }, + }) const codes = [ 'ENOAUDIT', 'ENOLOCK', @@ -108,7 +72,7 @@ t.test('just simple messages', t => { 'ERR_SOCKET_TIMEOUT', ] t.plan(codes.length) - codes.forEach(code => { + codes.forEach(async code => { const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -124,8 +88,8 @@ t.test('just simple messages', t => { }) }) -t.test('replace message/stack sensistive info', t => { - npm.command = 'audit' +t.test('replace message/stack sensistive info', async t => { + const npm = await loadMockNpm(t, { command: 'audit' }) const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -139,10 +103,10 @@ t.test('replace message/stack sensistive info', t => { stack, }) t.matchSnapshot(errorMessage(er, npm)) - t.end() }) -t.test('bad engine without config loaded', t => { +t.test('bad engine without config loaded', async t => { + const npm = await loadMockNpm(t, { load: false }) const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -154,11 +118,11 @@ t.test('bad engine without config loaded', t => { file, stack, }) - t.matchSnapshot(errorMessage(er, unloadedNpm)) - t.end() + t.matchSnapshot(errorMessage(er, npm)) }) -t.test('enoent without a file', t => { +t.test('enoent without a file', async t => { + const npm = await loadMockNpm(t) const path = '/some/path' const pkgid = 'some@package' const stack = 'dummy stack trace' @@ -169,11 +133,10 @@ t.test('enoent without a file', t => { stack, }) t.matchSnapshot(errorMessage(er, npm)) - t.end() }) -t.test('enolock without a command', t => { - npm.command = null +t.test('enolock without a command', async t => { + const npm = await loadMockNpm(t, { command: null }) const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -186,12 +149,12 @@ t.test('enolock without a command', t => { stack, }) t.matchSnapshot(errorMessage(er, npm)) - t.end() }) -t.test('default message', t => { +t.test('default message', async t => { + const npm = await loadMockNpm(t) t.matchSnapshot(errorMessage(new Error('error object'), npm)) - t.matchSnapshot(errorMessage('error string'), npm) + t.matchSnapshot(errorMessage('error string', npm)) t.matchSnapshot(errorMessage(Object.assign(new Error('cmd err'), { cmd: 'some command', signal: 'SIGYOLO', @@ -199,10 +162,10 @@ t.test('default message', t => { stdout: 'stdout', stderr: 'stderr', }), npm)) - t.end() }) -t.test('args are cleaned', t => { +t.test('args are cleaned', async t => { + const npm = await loadMockNpm(t) t.matchSnapshot(errorMessage(Object.assign(new Error('cmd err'), { cmd: 'some command', signal: 'SIGYOLO', @@ -210,35 +173,25 @@ t.test('args are cleaned', t => { stdout: 'stdout', stderr: 'stderr', }), npm)) - t.end() }) -t.test('eacces/eperm', t => { - const runTest = (windows, loaded, cachePath, cacheDest) => t => { +t.test('eacces/eperm', async t => { + const runTest = (windows, loaded, cachePath, cacheDest) => async t => { if (windows) { - beWindows() - } else { - bePosix() + mockGlobals(t, { 'process.platform': 'win32' }) } - - const path = `${cachePath ? CACHE : '/not/cache/dir'}/path` - const dest = `${cacheDest ? CACHE : '/not/cache/dir'}/dest` + const npm = await loadMockNpm(t, { windows, load: loaded }) + const path = `${cachePath ? npm.cache : '/not/cache/dir'}/path` + const dest = `${cacheDest ? npm.cache : '/not/cache/dir'}/dest` const er = Object.assign(new Error('whoopsie'), { code: 'EACCES', path, dest, stack: 'dummy stack trace', }) - verboseLogs.length = 0 - if (loaded) { - t.matchSnapshot(errorMessage(er, npm)) - } else { - t.matchSnapshot(errorMessage(er, unloadedNpm)) - } - t.matchSnapshot(verboseLogs) - t.end() - verboseLogs.length = 0 + t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(npm.logs.verbose) } for (const windows of [true, false]) { @@ -251,12 +204,13 @@ t.test('eacces/eperm', t => { } } } - t.end() }) t.test('json parse', t => { - t.test('merge conflict in package.json', t => { - const dir = t.testdir({ + mockGlobals(t, { 'process.argv': ['arg', 'v'] }) + + t.test('merge conflict in package.json', async t => { + const testdir = { 'package.json': ` { "array": [ @@ -295,59 +249,35 @@ t.test('json parse', t => { } } `, - }) - const { prefix } = npm - const { argv } = process - t.teardown(() => { - Object.defineProperty(npm, 'prefix', { - value: prefix, - configurable: true, - }) - process.argv = argv - }) - Object.defineProperty(npm, 'prefix', { value: dir, configurable: true }) - process.argv = ['arg', 'v'] + } + const npm = await loadMockNpm(t, { testdir }) t.matchSnapshot(errorMessage(Object.assign(new Error('conflicted'), { code: 'EJSONPARSE', - path: resolve(dir, 'package.json'), + path: path.resolve(npm.prefix, 'package.json'), }), npm)) t.end() }) - t.test('just regular bad json in package.json', t => { - const dir = t.testdir({ + t.test('just regular bad json in package.json', async t => { + const testdir = { 'package.json': 'not even slightly json', - }) - const { prefix } = npm - const { argv } = process - t.teardown(() => { - Object.defineProperty(npm, 'prefix', { - value: prefix, - configurable: true, - }) - process.argv = argv - }) - Object.defineProperty(npm, 'prefix', { value: dir, configurable: true }) - process.argv = ['arg', 'v'] + } + const npm = await loadMockNpm(t, { testdir }) t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), { code: 'EJSONPARSE', - path: resolve(dir, 'package.json'), + path: path.resolve(npm.prefix, 'package.json'), }), npm)) t.end() }) - t.test('json somewhere else', t => { - const dir = t.testdir({ + t.test('json somewhere else', async t => { + const testdir = { 'blerg.json': 'not even slightly json', - }) - const { argv } = process - t.teardown(() => { - process.argv = argv - }) - process.argv = ['arg', 'v'] + } + const npm = await loadMockNpm(t, { testdir }) t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), { code: 'EJSONPARSE', - path: `${dir}/blerg.json`, + path: path.resolve(npm.prefix, 'blerg.json'), }), npm)) t.end() }) @@ -355,7 +285,9 @@ t.test('json parse', t => { t.end() }) -t.test('eotp/e401', t => { +t.test('eotp/e401', async t => { + const npm = await loadMockNpm(t) + t.test('401, no auth headers', t => { t.matchSnapshot(errorMessage(Object.assign(new Error('nope'), { code: 'E401', @@ -406,11 +338,11 @@ t.test('eotp/e401', t => { }) } }) - - t.end() }) -t.test('404', t => { +t.test('404', async t => { + const npm = await loadMockNpm(t) + t.test('no package id', t => { const er = Object.assign(new Error('404 not found'), { code: 'E404' }) t.matchSnapshot(errorMessage(er, npm)) @@ -448,10 +380,11 @@ t.test('404', t => { t.matchSnapshot(errorMessage(er, npm)) t.end() }) - t.end() }) -t.test('bad platform', t => { +t.test('bad platform', async t => { + const npm = await loadMockNpm(t) + t.test('string os/arch', t => { const er = Object.assign(new Error('a bad plat'), { pkgid: 'lodash@1.0.0', @@ -484,19 +417,30 @@ t.test('bad platform', t => { t.matchSnapshot(errorMessage(er, npm)) t.end() }) - - t.end() }) -t.test('explain ERESOLVE errors', t => { +t.test('explain ERESOLVE errors', async t => { + const npm = await loadMockNpm(t) + const EXPLAIN_CALLED = [] + const er = Object.assign(new Error('could not resolve'), { code: 'ERESOLVE', }) - t.matchSnapshot(errorMessage(er, npm)) + + t.matchSnapshot(errorMessage(er, { + ...npm, + mocks: { + '../../../lib/utils/explain-eresolve.js': { + report: (...args) => { + EXPLAIN_CALLED.push(args) + return 'explanation' + }, + }, + }, + })) t.match(EXPLAIN_CALLED, [[ er, - undefined, + false, path.resolve(npm.cache, 'eresolve-report.txt'), ]]) - t.end() }) diff --git a/deps/npm/test/lib/utils/exit-handler.js b/deps/npm/test/lib/utils/exit-handler.js index adc7c3f4e9..54bf48f89b 100644 --- a/deps/npm/test/lib/utils/exit-handler.js +++ b/deps/npm/test/lib/utils/exit-handler.js @@ -1,177 +1,213 @@ -/* eslint-disable no-extend-native */ -/* eslint-disable no-global-assign */ const t = require('tap') -const EventEmitter = require('events') const os = require('os') -const fs = require('fs') -const path = require('path') - -const { real: mockNpm } = require('../../fixtures/mock-npm') - -// generic error to be used in tests -const err = Object.assign(new Error('ERROR'), { code: 'ERROR' }) -err.stack = 'Error: ERROR' - -const redactCwd = (path) => { - const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - return normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') +const EventEmitter = require('events') +const { format } = require('../../../lib/utils/log-file') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') +const mockGlobals = require('../../fixtures/mock-globals') +const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot') + +const pick = (obj, ...keys) => keys.reduce((acc, key) => { + acc[key] = obj[key] + return acc +}, {}) + +t.formatSnapshot = (obj) => { + if (Array.isArray(obj)) { + return obj + .map((i) => Array.isArray(i) ? i.join(' ') : i) + .join('\n') + } + return obj } -t.cleanSnapshot = (str) => redactCwd(str) - -const cacheFolder = t.testdir({}) -const logFile = path.resolve(cacheFolder, '_logs', 'expecteddate-debug.log') -const timingFile = path.resolve(cacheFolder, '_timing.json') - -const { Npm } = mockNpm(t, { - '../../package.json': { - version: '1.0.0', - }, -}) -const npm = new Npm() - -t.before(async () => { - await npm.load() - npm.config.set('cache', cacheFolder) -}) +t.cleanSnapshot = (path) => cleanDate(cleanCwd(path)) +// Config loading is dependent on env so strip those from snapshots + .replace(/.*timing config:load:.*\n/gm, '') + .replace(/(Completed in )\d+(ms)/g, '$1{TIME}$2') // cut off process from script so that it won't quit the test runner // while trying to run through the myriad of cases. need to make it // have all the functions signal-exit relies on so that it doesn't // nerf itself, thinking global.process is broken or gone. -const _process = process -process = Object.assign( - new EventEmitter(), - { - argv: ['/node', ..._process.argv.slice(1)], - cwd: _process.cwd, - env: _process.env, +mockGlobals(t, { + process: Object.assign(new EventEmitter(), { + ...pick(process, 'execPath', 'stdout', 'stderr', 'cwd', 'env'), + argv: ['/node', ...process.argv.slice(1)], version: 'v1.0.0', + kill: () => {}, + reallyExit: (code) => process.exit(code), + pid: 123456, exit: (code) => { process.exitCode = code || process.exitCode || 0 process.emit('exit', process.exitCode) }, - stdout: { write (_, cb) { - cb() - } }, - stderr: { write () {} }, - hrtime: _process.hrtime, - kill: () => {}, - reallyExit: (code) => process.exit(code), - pid: 123456, + }), +}, { replace: true }) + +const mockExitHandler = async (t, { init, load, testdir, config } = {}) => { + const errors = [] + mockGlobals(t, { 'console.error': (err) => errors.push(err) }) + + const { npm, logMocks, ...rest } = await loadMockNpm(t, { + init, + load, + testdir, + mocks: { + '../../package.json': { + version: '1.0.0', + }, + }, + config: { + loglevel: 'notice', + ...config, + }, + }) + + const exitHandler = t.mock('../../../lib/utils/exit-handler.js', { + '../../../lib/utils/error-message.js': (err) => ({ + ...err, + summary: [['ERR SUMMARY', err.message]], + detail: [['ERR DETAIL', err.message]], + }), + os: { + type: () => 'Foo', + release: () => '1.0.0', + }, + ...logMocks, + }) + + if (npm) { + exitHandler.setNpm(npm) } -) - -const osType = os.type -const osRelease = os.release -// overrides OS type/release for cross platform snapshots -os.type = () => 'Foo' -os.release = () => '1.0.0' - -// generates logfile name with mocked date -const _toISOString = Date.prototype.toISOString -Date.prototype.toISOString = () => 'expecteddate' - -const consoleError = console.error -const errors = [] -console.error = (err) => { - errors.push(err) -} -t.teardown(() => { - os.type = osType - os.release = osRelease - // needs to put process back in its place in order for tap to exit properly - process = _process - Date.prototype.toISOString = _toISOString - console.error = consoleError -}) -t.afterEach(() => { - errors.length = 0 - npm.log.level = 'silent' - // clear out the 'A complete log' message - npm.log.record.length = 0 - delete process.exitCode -}) + t.teardown(() => { + delete process.exitCode + process.removeAllListeners('exit') + }) -const mocks = { - '../../../lib/utils/error-message.js': (err) => ({ - ...err, - summary: [['ERR', err.message]], - detail: [['ERR', err.message]], - }), + return { + ...rest, + errors, + npm, + // // Make it async to make testing ergonomics a little + // // easier so we dont need to t.plan() every test to + // // make sure we get process.exit called + exitHandler: (...args) => new Promise(resolve => { + process.once('exit', resolve) + exitHandler(...args) + }), + } } -const exitHandler = t.mock('../../../lib/utils/exit-handler.js', mocks) -exitHandler.setNpm(npm) - -t.test('exit handler never called - loglevel silent', (t) => { - npm.log.level = 'silent' - process.emit('exit', 1) - const logData = fs.readFileSync(logFile, 'utf8') - t.match(logData, 'Exit handler never called!') - t.match(errors, [''], 'logs one empty string to console.error') - t.end() -}) +// Create errors with properties to be used in tests +const err = (message = '', options = {}, noStack = false) => { + const e = Object.assign( + new Error(message), + typeof options !== 'object' ? { code: options } : options + ) + e.stack = options.stack || `Error: ${message}` + if (noStack) { + delete e.stack + } + return e +} -t.test('exit handler never called - loglevel notice', (t) => { - npm.log.level = 'notice' - process.emit('exit', 1) - const logData = fs.readFileSync(logFile, 'utf8') - t.match(logData, 'Exit handler never called!') - t.match(errors, ['', ''], 'logs two empty strings to console.error') - t.end() -}) +t.test('handles unknown error with logs and debug file', async (t) => { + const { exitHandler, debugFile, logs } = await mockExitHandler(t) -t.test('handles unknown error', (t) => { - t.plan(2) + await exitHandler(err('Unknown error', 'ECODE')) - npm.log.level = 'notice' + const debugContent = await debugFile() - process.once('timeEnd', (msg) => { - t.equal(msg, 'npm', 'should trigger timeEnd for npm') + t.equal(process.exitCode, 1) + logs.forEach((logItem, i) => { + const logLines = format(i, ...logItem).trim().split(os.EOL) + logLines.forEach((line) => { + t.match(debugContent.trim(), line, 'log appears in debug file') + }) }) - exitHandler(err) - const logData = fs.readFileSync(logFile, 'utf8') - t.matchSnapshot( - logData, - 'should have expected log contents for unknown error' - ) - t.end() + const lastLog = debugContent + .split('\n') + .reduce((__, l) => parseInt(l.match(/^(\d+)\s/)[1])) + t.equal(logs.length, lastLog + 1) + t.match(logs.error, [ + ['code', 'ECODE'], + ['ERR SUMMARY', 'Unknown error'], + ['ERR DETAIL', 'Unknown error'], + ]) + t.match(debugContent, /\d+ error code ECODE/) + t.match(debugContent, /\d+ error ERR SUMMARY Unknown error/) + t.match(debugContent, /\d+ error ERR DETAIL Unknown error/) + t.matchSnapshot(logs, 'logs') + t.matchSnapshot(debugContent, 'debug file contents') }) -t.test('fail to write logfile', (t) => { - t.plan(1) - - t.teardown(() => { - npm.config.set('cache', cacheFolder) +t.test('exit handler never called - loglevel silent', async (t) => { + const { logs, errors } = await mockExitHandler(t, { + config: { loglevel: 'silent' }, }) + process.emit('exit', 1) + t.match(logs.error, [ + ['', /Exit handler never called/], + ['', /error with npm itself/], + ]) + t.strictSame(errors, [''], 'logs one empty string to console.error') +}) - const badDir = t.testdir({ - _logs: 'is a file', - }) +t.test('exit handler never called - loglevel notice', async (t) => { + const { logs, errors } = await mockExitHandler(t) + process.emit('exit', 1) + t.equal(process.exitCode, 1) + t.match(logs.error, [ + ['', /Exit handler never called/], + ['', /error with npm itself/], + ]) + t.strictSame(errors, ['', ''], 'logs two empty strings to console.error') +}) + +t.test('exit handler never called - no npm', async (t) => { + const { logs, errors } = await mockExitHandler(t, { init: false }) + process.emit('exit', 1) + t.equal(process.exitCode, 1) + t.match(logs.error, [ + ['', /Exit handler never called/], + ['', /error with npm itself/], + ]) + t.strictSame(errors, [''], 'logs one empty string to console.error') +}) - npm.config.set('cache', badDir) +t.test('exit handler called - no npm', async (t) => { + const { exitHandler, errors } = await mockExitHandler(t, { init: false }) + await exitHandler() + t.equal(process.exitCode, 1) + t.match(errors, [/Error: Exit prior to setting npm in exit handler/]) +}) - t.doesNotThrow( - () => exitHandler(err), - 'should not throw on cache write failure' - ) +t.test('exit handler called - no npm with error', async (t) => { + const { exitHandler, errors } = await mockExitHandler(t, { init: false }) + await exitHandler(err('something happened')) + t.equal(process.exitCode, 1) + t.match(errors, [/Error: something happened/]) }) -t.test('console.log output using --json', (t) => { - t.plan(1) +t.test('exit handler called - no npm with error without stack', async (t) => { + const { exitHandler, errors } = await mockExitHandler(t, { init: false }) + await exitHandler(err('something happened', {}, true)) + t.equal(process.exitCode, 1) + t.match(errors, [/something happened/]) +}) - npm.config.set('json', true) - t.teardown(() => { - npm.config.set('json', false) +t.test('console.log output using --json', async (t) => { + const { exitHandler, errors } = await mockExitHandler(t, { + config: { + json: true, + }, }) - exitHandler(new Error('Error: EBADTHING Something happened')) + await exitHandler(err('Error: EBADTHING Something happened')) + + t.equal(process.exitCode, 1) t.same( JSON.parse(errors[0]), { @@ -185,213 +221,223 @@ t.test('console.log output using --json', (t) => { ) }) -t.test('throw a non-error obj', (t) => { - t.plan(2) +t.test('throw a non-error obj', async (t) => { + const { exitHandler, logs } = await mockExitHandler(t) - const weirdError = { + await exitHandler({ code: 'ESOMETHING', message: 'foo bar', - } - - process.once('exit', code => { - t.equal(code, 1, 'exits with exitCode 1') }) - exitHandler(weirdError) - t.match( - npm.log.record.find(r => r.level === 'error'), - { message: 'foo bar' } - ) + + t.equal(process.exitCode, 1) + t.match(logs.error, [ + ['weird error', { code: 'ESOMETHING', message: 'foo bar' }], + ]) }) -t.test('throw a string error', (t) => { - t.plan(2) - const error = 'foo bar' +t.test('throw a string error', async (t) => { + const { exitHandler, logs } = await mockExitHandler(t) - process.once('exit', code => { - t.equal(code, 1, 'exits with exitCode 1') - }) - exitHandler(error) - t.match( - npm.log.record.find(r => r.level === 'error'), - { message: 'foo bar' } - ) + await exitHandler('foo bar') + + t.equal(process.exitCode, 1) + t.match(logs.error, [ + ['', 'foo bar'], + ]) }) -t.test('update notification', (t) => { - const updateMsg = 'you should update npm!' - npm.updateNotification = updateMsg - npm.log.level = 'silent' +t.test('update notification', async (t) => { + const { exitHandler, logs, npm } = await mockExitHandler(t) + npm.updateNotification = 'you should update npm!' - t.teardown(() => { - delete npm.updateNotification - }) + await exitHandler() - exitHandler() - t.match( - npm.log.record.find(r => r.level === 'notice'), - { message: 'you should update npm!' } - ) - t.end() + t.match(logs.notice, [ + ['', 'you should update npm!'], + ]) }) -t.test('npm.config not ready', (t) => { - t.plan(1) +t.test('npm.config not ready', async (t) => { + const { exitHandler, logs, errors } = await mockExitHandler(t, { + load: false, + }) - const { Npm: Unloaded } = mockNpm(t) - const unloaded = new Unloaded() + await exitHandler() - t.teardown(() => { - exitHandler.setNpm(npm) + t.equal(process.exitCode, 1) + t.match(errors, [ + /Error: Exit prior to config file resolving./, + ], 'should exit with config error msg') + t.match(logs.verbose, [ + ['stack', /Error: Exit prior to config file resolving./], + ], 'should exit with config error msg') +}) + +t.test('timing with no error', async (t) => { + const { exitHandler, timingFile, npm, logs } = await mockExitHandler(t, { + config: { + timing: true, + }, }) - exitHandler.setNpm(unloaded) + await exitHandler() + const timingFileData = await timingFile() + + t.equal(process.exitCode, 0) + + t.match(logs.error, [ + ['', /A complete log of this run can be found in:[\s\S]*-debug-\d\.log/], + ]) - exitHandler() t.match( - errors[0], - /Error: Exit prior to config file resolving./, - 'should exit with config error msg' + timingFileData, + Object.keys(npm.finishedTimers).reduce((acc, k) => { + acc[k] = Number + return acc + }, {}) ) - t.end() + t.strictSame(npm.unfinishedTimers, new Map()) + t.match(timingFileData, { + command: [], + version: '1.0.0', + npm: Number, + logfile: String, + logfiles: [String], + }) }) -t.test('timing', (t) => { - npm.config.set('timing', true) - - t.teardown(() => { - fs.unlinkSync(timingFile) - npm.config.set('timing', false) +t.test('unfinished timers', async (t) => { + const { exitHandler, timingFile, npm } = await mockExitHandler(t, { + config: { + timing: true, + }, }) - exitHandler() - const timingData = JSON.parse(fs.readFileSync(timingFile, 'utf8')) - t.match(timingData, { version: '1.0.0', 'config:load:defaults': Number }) - t.end() -}) + process.emit('time', 'foo') + process.emit('time', 'bar') -t.test('timing - with error', (t) => { - npm.config.set('timing', true) + await exitHandler() + const timingFileData = await timingFile() - t.teardown(() => { - fs.unlinkSync(timingFile) - npm.config.set('timing', false) + t.equal(process.exitCode, 0) + t.match(npm.unfinishedTimers, new Map([['foo', Number], ['bar', Number]])) + t.match(timingFileData, { + command: [], + version: '1.0.0', + npm: Number, + logfile: String, + logfiles: [String], + unfinished: { + foo: [Number, Number], + bar: [Number, Number], + }, }) - - exitHandler(err) - const timingData = JSON.parse(fs.readFileSync(timingFile, 'utf8')) - t.match(timingData, { version: '1.0.0', 'config:load:defaults': Number }) - t.end() }) -t.test('uses code from errno', (t) => { - t.plan(1) +t.test('uses code from errno', async (t) => { + const { exitHandler, logs } = await mockExitHandler(t) - process.once('exit', code => { - t.equal(code, 127, 'should set exitCode from errno') - }) - exitHandler(Object.assign( - new Error('Error with errno'), - { - errno: 127, - } - )) + await exitHandler(err('Error with errno', { errno: 127 })) + t.equal(process.exitCode, 127) + t.match(logs.error, [['errno', 127]]) }) -t.test('uses code from number', (t) => { - t.plan(1) +t.test('uses code from number', async (t) => { + const { exitHandler, logs } = await mockExitHandler(t) - process.once('exit', code => { - t.equal(code, 404, 'should set exitCode from a number') - }) - exitHandler(Object.assign( - new Error('Error with code type number'), - { - code: 404, - } - )) + await exitHandler(err('Error with code type number', 404)) + t.equal(process.exitCode, 404) + t.match(logs.error, [['code', 404]]) }) -t.test('call exitHandler with no error', (t) => { - t.plan(1) - process.once('exit', code => { - t.equal(code, 0, 'should end up with exitCode 0 (default)') - }) - exitHandler() +t.test('uses all err special properties', async t => { + const { exitHandler, logs } = await mockExitHandler(t) + + const keys = ['code', 'syscall', 'file', 'path', 'dest', 'errno'] + const properties = keys.reduce((acc, k) => { + acc[k] = `${k}-hey` + return acc + }, {}) + + await exitHandler(err('Error with code type number', properties)) + t.equal(process.exitCode, 1) + t.match(logs.error, keys.map((k) => [k, `${k}-hey`]), 'all special keys get logged') }) -t.test('defaults to log error msg if stack is missing', (t) => { - const { Npm: Unloaded } = mockNpm(t) - const unloaded = new Unloaded() +t.test('verbose logs replace info on err props', async t => { + const { exitHandler, logs } = await mockExitHandler(t) - t.teardown(() => { - exitHandler.setNpm(npm) - }) + const keys = ['type', 'stack', 'statusCode', 'pkgid'] + const properties = keys.reduce((acc, k) => { + acc[k] = `${k}-https://user:pass@registry.npmjs.org/` + return acc + }, {}) - exitHandler.setNpm(unloaded) - const noStackErr = Object.assign( - new Error('Error with no stack'), - { - code: 'ENOSTACK', - errno: 127, - } + await exitHandler(err('Error with code type number', properties)) + t.equal(process.exitCode, 1) + t.match( + logs.verbose.filter(([p]) => p !== 'logfile'), + keys.map((k) => [k, `${k}-https://user:***@registry.npmjs.org/`]), + 'all special keys get replaced' ) - delete noStackErr.stack +}) - exitHandler(noStackErr) - t.equal(errors[0], 'Error with no stack', 'should use error msg') - t.end() +t.test('call exitHandler with no error', async (t) => { + const { exitHandler, logs } = await mockExitHandler(t) + + await exitHandler() + + t.equal(process.exitCode, 0) + t.match(logs.error, []) +}) + +t.test('defaults to log error msg if stack is missing when unloaded', async (t) => { + const { exitHandler, logs, errors } = await mockExitHandler(t, { load: false }) + + await exitHandler(err('Error with no stack', { code: 'ENOSTACK', errno: 127 }, true)) + t.equal(process.exitCode, 127) + t.same(errors, ['Error with no stack'], 'should use error msg') + t.match(logs.error, [ + ['code', 'ENOSTACK'], + ['errno', 127], + ]) }) -t.test('exits uncleanly when only emitting exit event', (t) => { - t.plan(2) +t.test('exits uncleanly when only emitting exit event', async (t) => { + const { logs } = await mockExitHandler(t) - npm.log.level = 'silent' process.emit('exit') - const logData = fs.readFileSync(logFile, 'utf8') - t.match(logData, 'Exit handler never called!') - t.match(process.exitCode, 1, 'exitCode coerced to 1') + + t.match(logs.error, [['', 'Exit handler never called!']]) + t.equal(process.exitCode, 1, 'exitCode coerced to 1') t.end() }) -t.test('do no fancy handling for shellouts', t => { - const { command } = npm - const LOG_RECORD = [] - npm.command = 'exec' +t.test('do no fancy handling for shellouts', async t => { + const { exitHandler, npm, logs } = await mockExitHandler(t) - t.teardown(() => { - npm.command = command - }) - t.beforeEach(() => LOG_RECORD.length = 0) + npm.command = 'exec' - const loudNoises = () => npm.log.record - .filter(({ level }) => ['warn', 'error'].includes(level)) + const loudNoises = () => + logs.filter(([level]) => ['warn', 'error'].includes(level)) - t.test('shellout with a numeric error code', t => { - t.plan(2) - process.once('exit', code => { - t.equal(code, 5, 'got expected exit code') - }) - exitHandler(Object.assign(new Error(), { code: 5 })) + t.test('shellout with a numeric error code', async t => { + await exitHandler(err('', 5)) + t.equal(process.exitCode, 5, 'got expected exit code') t.strictSame(loudNoises(), [], 'no noisy warnings') }) - t.test('shellout without a numeric error code (something in npm)', t => { - t.plan(2) - process.once('exit', code => { - t.equal(code, 1, 'got expected exit code') - }) - exitHandler(Object.assign(new Error(), { code: 'banana stand' })) + t.test('shellout without a numeric error code (something in npm)', async t => { + await exitHandler(err('', 'banana stand')) + t.equal(process.exitCode, 1, 'got expected exit code') // should log some warnings and errors, because something weird happened t.strictNotSame(loudNoises(), [], 'bring the noise') t.end() }) - t.test('shellout with code=0 (extra weird?)', t => { - t.plan(2) - process.once('exit', code => { - t.equal(code, 1, 'got expected exit code') - }) - exitHandler(Object.assign(new Error(), { code: 0 })) + t.test('shellout with code=0 (extra weird?)', async t => { + await exitHandler(Object.assign(new Error(), { code: 0 })) + t.equal(process.exitCode, 1, 'got expected exit code') t.strictNotSame(loudNoises(), [], 'bring the noise') }) diff --git a/deps/npm/test/lib/utils/get-project-scope.js b/deps/npm/test/lib/utils/get-project-scope.js deleted file mode 100644 index 9737b06433..0000000000 --- a/deps/npm/test/lib/utils/get-project-scope.js +++ /dev/null @@ -1,48 +0,0 @@ -const getProjectScope = require('../../../lib/utils/get-project-scope.js') -const t = require('tap') - -t.test('package.json with scope', t => { - const dir = t.testdir({ - 'package.json': JSON.stringify({ name: '@foo/bar' }), - }) - t.equal(getProjectScope(dir), '@foo') - t.end() -}) - -t.test('package.json with slash, but no @', t => { - const dir = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo/bar' }), - }) - t.equal(getProjectScope(dir), '') - t.end() -}) - -t.test('package.json without scope', t => { - const dir = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), - }) - t.equal(getProjectScope(dir), '') - t.end() -}) - -t.test('package.json without name', t => { - const dir = t.testdir({ - 'package.json': JSON.stringify({}), - }) - t.equal(getProjectScope(dir), '') - t.end() -}) - -t.test('package.json not JSON', t => { - const dir = t.testdir({ - 'package.json': 'hello', - }) - t.equal(getProjectScope(dir), '') - t.end() -}) - -t.test('no package.json', t => { - const dir = t.testdir({}) - t.equal(getProjectScope(dir), '') - t.end() -}) diff --git a/deps/npm/test/lib/utils/is-windows-bash.js b/deps/npm/test/lib/utils/is-windows-bash.js index 94fde0ace1..0fbebdf8e3 100644 --- a/deps/npm/test/lib/utils/is-windows-bash.js +++ b/deps/npm/test/lib/utils/is-windows-bash.js @@ -1,4 +1,5 @@ const t = require('tap') +const mockGlobal = require('../../fixtures/mock-globals.js') const isWindowsBash = () => { delete require.cache[require.resolve('../../../lib/utils/is-windows-bash.js')] @@ -6,23 +7,24 @@ const isWindowsBash = () => { return require('../../../lib/utils/is-windows-bash.js') } -Object.defineProperty(process, 'platform', { - value: 'posix', - configurable: true, -}) -t.equal(isWindowsBash(), false, 'false when not windows') +t.test('posix', (t) => { + mockGlobal(t, { 'process.platform': 'posix' }) + t.equal(isWindowsBash(), false, 'false when not windows') -Object.defineProperty(process, 'platform', { - value: 'win32', - configurable: true, + t.end() }) -process.env.MSYSTEM = 'not ming' -process.env.TERM = 'dumb' -t.equal(isWindowsBash(), false, 'false when not mingw or cygwin') -process.env.TERM = 'cygwin' -t.equal(isWindowsBash(), true, 'true when cygwin') +t.test('win32', (t) => { + mockGlobal(t, { 'process.platform': 'win32' }) + + mockGlobal(t, { 'process.env': { TERM: 'dumb', MSYSTEM: undefined } }) + t.equal(isWindowsBash(), false, 'false when not mingw or cygwin') + + mockGlobal(t, { 'process.env.TERM': 'cygwin' }) + t.equal(isWindowsBash(), true, 'true when cygwin') -process.env.MSYSTEM = 'MINGW64' -process.env.TERM = 'dumb' -t.equal(isWindowsBash(), true, 'true when mingw') + mockGlobal(t, { 'process.env': { TERM: 'dumb', MSYSTEM: 'MINGW64' } }) + t.equal(isWindowsBash(), true, 'true when mingw') + + t.end() +}) diff --git a/deps/npm/test/lib/utils/log-file.js b/deps/npm/test/lib/utils/log-file.js new file mode 100644 index 0000000000..adc1a2e03f --- /dev/null +++ b/deps/npm/test/lib/utils/log-file.js @@ -0,0 +1,333 @@ +const t = require('tap') +const _fs = require('fs') +const fs = _fs.promises +const path = require('path') +const os = require('os') +const fsMiniPass = require('fs-minipass') +const rimraf = require('rimraf') +const LogFile = require('../../../lib/utils/log-file.js') +const { cleanCwd } = require('../../fixtures/clean-snapshot') + +t.cleanSnapshot = (path) => cleanCwd(path) + +const last = arr => arr[arr.length - 1] +const range = (n) => Array.from(Array(n).keys()) +const makeOldLogs = (count) => { + const d = new Date() + d.setHours(-1) + d.setSeconds(0) + return range(count / 2).reduce((acc, i) => { + const cloneDate = new Date(d.getTime()) + cloneDate.setSeconds(i) + acc[LogFile.fileName(LogFile.logId(cloneDate), 0)] = 'hello' + acc[LogFile.fileName(LogFile.logId(cloneDate), 1)] = 'hello' + return acc + }, {}) +} + +const cleanErr = (message) => { + const err = new Error(message) + const stack = err.stack.split('\n') + err.stack = stack[0] + '\n' + range(10) + .map((__, i) => stack[1].replace(/^(\s+at\s).*/, `$1stack trace line ${i}`)) + .join('\n') + return err +} + +const loadLogFile = async (t, { buffer = [], mocks, testdir = {}, ...options } = {}) => { + const root = t.testdir(testdir) + const MockLogFile = t.mock('../../../lib/utils/log-file.js', mocks) + const logFile = new MockLogFile(Object.keys(options).length ? options : undefined) + buffer.forEach((b) => logFile.log(...b)) + await logFile.load({ dir: root, ...options }) + t.teardown(() => logFile.off()) + return { + root, + logFile, + LogFile, + readLogs: async () => { + const logDir = await fs.readdir(root) + const logFiles = logDir.map((f) => path.join(root, f)) + .filter((f) => _fs.existsSync(f)) + return Promise.all(logFiles.map(async (f) => { + const content = await fs.readFile(f, 'utf8') + const rawLogs = content.split(os.EOL) + return { + filename: f, + content, + rawLogs, + logs: rawLogs.filter(Boolean), + } + })) + }, + } +} + +t.test('init', async t => { + const maxLogsPerFile = 10 + const { root, logFile, readLogs } = await loadLogFile(t, { + maxLogsPerFile, + maxFilesPerProcess: 20, + buffer: [['error', 'buffered']], + }) + + for (const i of range(50)) { + logFile.log('error', `log ${i}`) + } + + // Ignored + logFile.log('pause') + logFile.log('resume') + logFile.log('pause') + + for (const i of range(50)) { + logFile.log('verb', `log ${i}`) + } + + logFile.off() + logFile.log('error', 'ignored') + + const logs = await readLogs() + t.equal(logs.length, 11, 'total log files') + t.ok(logs.slice(0, 10).every(f => f.logs.length === maxLogsPerFile), 'max logs per file') + t.ok(last(logs).logs.length, 1, 'last file has remaining logs') + t.ok(logs.every(f => last(f.rawLogs) === ''), 'all logs end with newline') + t.strictSame( + logFile.files, + logs.map((l) => path.resolve(root, l.filename)) + ) +}) + +t.test('max files per process', async t => { + const maxLogsPerFile = 10 + const maxFilesPerProcess = 5 + const { logFile, readLogs } = await loadLogFile(t, { + maxLogsPerFile, + maxFilesPerProcess, + }) + + for (const i of range(maxLogsPerFile * maxFilesPerProcess)) { + logFile.log('error', `log ${i}`) + } + + for (const i of range(5)) { + logFile.log('verbose', `log ${i}`) + } + + const logs = await readLogs() + t.equal(logs.length, maxFilesPerProcess, 'total log files') + t.equal(last(last(logs).logs), '49 error log 49') +}) + +t.test('stream error', async t => { + let times = 0 + const { logFile, readLogs } = await loadLogFile(t, { + maxLogsPerFile: 1, + maxFilesPerProcess: 99, + mocks: { + 'fs-minipass': { + WriteStreamSync: class { + constructor (...args) { + if (times >= 5) { + throw new Error('bad stream') + } + times++ + return new fsMiniPass.WriteStreamSync(...args) + } + }, + }, + }, + }) + + for (const i of range(10)) { + logFile.log('verbose', `log ${i}`) + } + + const logs = await readLogs() + t.equal(logs.length, 5, 'total log files') +}) + +t.test('initial stream error', async t => { + const { logFile, readLogs } = await loadLogFile(t, { + mocks: { + 'fs-minipass': { + WriteStreamSync: class { + constructor (...args) { + throw new Error('no stream') + } + }, + }, + }, + }) + + for (const i of range(10)) { + logFile.log('verbose', `log ${i}`) + } + + const logs = await readLogs() + t.equal(logs.length, 0, 'total log files') +}) + +t.test('turns off', async t => { + const { logFile, readLogs } = await loadLogFile(t) + + logFile.log('error', 'test') + logFile.off() + logFile.log('error', 'test2') + logFile.load() + + const logs = await readLogs() + t.equal(logs.length, 1) + t.equal(logs[0].logs[0], '0 error test') +}) + +t.test('cleans logs', async t => { + const logsMax = 5 + const { readLogs } = await loadLogFile(t, { + logsMax, + testdir: makeOldLogs(10), + }) + + const logs = await readLogs() + t.equal(logs.length, logsMax + 1) +}) + +t.test('doesnt clean current log by default', async t => { + const logsMax = 0 + const { readLogs, logFile } = await loadLogFile(t, { + logsMax, + testdir: makeOldLogs(10), + }) + + logFile.log('error', 'test') + + const logs = await readLogs() + t.equal(logs.length, 1) + t.match(last(logs).content, /\d+ error test/) +}) + +t.test('negative logs max', async t => { + const logsMax = -10 + const { readLogs, logFile } = await loadLogFile(t, { + logsMax, + testdir: makeOldLogs(10), + }) + + logFile.log('error', 'test') + + const logs = await readLogs() + t.equal(logs.length, 1) + t.match(last(logs).content, /\d+ error test/) +}) + +t.test('doesnt need to clean', async t => { + const logsMax = 20 + const oldLogs = 10 + const { readLogs } = await loadLogFile(t, { + logsMax, + testdir: makeOldLogs(oldLogs), + }) + + const logs = await readLogs() + t.equal(logs.length, oldLogs + 1) +}) + +t.test('glob error', async t => { + const { readLogs } = await loadLogFile(t, { + logsMax: 5, + mocks: { + glob: () => { + throw new Error('bad glob') + }, + }, + }) + + const logs = await readLogs() + t.equal(logs.length, 1) + t.match(last(logs).content, /error cleaning log files .* bad glob/) +}) + +t.test('rimraf error', async t => { + const logsMax = 5 + const oldLogs = 10 + let count = 0 + const { readLogs } = await loadLogFile(t, { + logsMax, + testdir: makeOldLogs(oldLogs), + mocks: { + rimraf: (...args) => { + if (count >= 3) { + throw new Error('bad rimraf') + } + count++ + return rimraf(...args) + }, + }, + }) + + const logs = await readLogs() + t.equal(logs.length, oldLogs - 3 + 1) + t.match(last(logs).content, /error removing log file .* bad rimraf/) +}) + +t.test('delete log file while open', async t => { + const { logFile, root, readLogs } = await loadLogFile(t) + + logFile.log('error', '', 'log 1') + const [log] = await readLogs(true) + t.match(log.content, /\d+ error log 1/) + + await fs.unlink(path.resolve(root, log.filename)) + + logFile.log('error', '', 'log 2') + const logs = await readLogs() + + // XXX: do some retry logic after error? + t.strictSame(logs, [], 'logs arent written after error') +}) + +t.test('snapshot', async t => { + const { logFile, readLogs } = await loadLogFile(t) + + logFile.log('error', '', 'no prefix') + logFile.log('error', 'prefix', 'with prefix') + logFile.log('error', 'prefix', 1, 2, 3) + + const nestedObj = { obj: { with: { many: { props: 1 } } } } + logFile.log('verbose', '', nestedObj) + logFile.log('verbose', '', JSON.stringify(nestedObj)) + logFile.log('verbose', '', JSON.stringify(nestedObj, null, 2)) + + const arr = ['test', 'with', 'an', 'array'] + logFile.log('verbose', '', arr) + logFile.log('verbose', '', JSON.stringify(arr)) + logFile.log('verbose', '', JSON.stringify(arr, null, 2)) + + const nestedArr = ['test', ['with', ['an', ['array']]]] + logFile.log('verbose', '', nestedArr) + logFile.log('verbose', '', JSON.stringify(nestedArr)) + logFile.log('verbose', '', JSON.stringify(nestedArr, null, 2)) + + // XXX: multiple errors are hard to parse visually + // the second error should start on a newline + logFile.log(...[ + 'error', + 'pre', + 'has', + 'many', + 'errors', + cleanErr('message'), + cleanErr('message2'), + ]) + + const err = new Error('message') + delete err.stack + logFile.log(...[ + 'error', + 'nostack', + err, + ]) + + const logs = await readLogs() + t.matchSnapshot(logs.map(l => l.content).join('\n')) +}) diff --git a/deps/npm/test/lib/utils/log-shim.js b/deps/npm/test/lib/utils/log-shim.js new file mode 100644 index 0000000000..dee4efbaa4 --- /dev/null +++ b/deps/npm/test/lib/utils/log-shim.js @@ -0,0 +1,100 @@ +const t = require('tap') + +const makeShim = (mocks) => t.mock('../../../lib/utils/log-shim.js', mocks) + +const loggers = [ + 'notice', + 'error', + 'warn', + 'info', + 'verbose', + 'http', + 'silly', + 'pause', + 'resume', +] + +t.test('has properties', (t) => { + const shim = makeShim() + + t.match(shim, { + level: String, + levels: {}, + gauge: {}, + stream: {}, + heading: undefined, + enableColor: Function, + disableColor: Function, + enableUnicode: Function, + disableUnicode: Function, + enableProgress: Function, + disableProgress: Function, + ...loggers.reduce((acc, l) => { + acc[l] = Function + return acc + }, {}), + }) + + t.match(Object.keys(shim).sort(), [ + 'level', + 'heading', + 'levels', + 'gauge', + 'stream', + 'tracker', + 'useColor', + 'enableColor', + 'disableColor', + 'enableUnicode', + 'disableUnicode', + 'enableProgress', + 'disableProgress', + 'progressEnabled', + 'clearProgress', + 'showProgress', + 'newItem', + 'newGroup', + ...loggers, + ].sort()) + + t.end() +}) + +t.test('works with npmlog/proclog proxy', t => { + const procLog = { silly: () => 'SILLY' } + const npmlog = { level: 'woo', enableColor: () => true } + const shim = makeShim({ npmlog, 'proc-log': procLog }) + + t.equal(shim.level, 'woo', 'can get a property') + + npmlog.level = 'hey' + t.strictSame( + [shim.level, npmlog.level], + ['hey', 'hey'], + 'can get a property after update on npmlog' + ) + + shim.level = 'test' + t.strictSame( + [shim.level, npmlog.level], + ['test', 'test'], + 'can get a property after update on shim' + ) + + t.ok(shim.enableColor(), 'can call method on shim to call npmlog') + t.equal(shim.silly(), 'SILLY', 'can call method on proclog') + t.notOk(shim.LEVELS, 'only includes levels from npmlog') + t.throws(() => shim.gauge = 100, 'cant set getters properies') + + t.end() +}) + +t.test('works with npmlog/proclog proxy', t => { + const shim = makeShim() + + loggers.forEach((k) => { + t.doesNotThrow(() => shim[k]('test')) + }) + + t.end() +}) diff --git a/deps/npm/test/lib/utils/npm-usage.js b/deps/npm/test/lib/utils/npm-usage.js index 77254a80d0..035d4bbb21 100644 --- a/deps/npm/test/lib/utils/npm-usage.js +++ b/deps/npm/test/lib/utils/npm-usage.js @@ -1,10 +1,8 @@ const t = require('tap') -const { real: mockNpm } = require('../../fixtures/mock-npm.js') -const { Npm } = mockNpm(t) -const npm = new Npm() +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') t.test('usage', async t => { - await npm.load() + const { npm } = await loadMockNpm(t) t.afterEach(() => { npm.config.set('viewer', null) npm.config.set('long', false) diff --git a/deps/npm/test/lib/utils/proc-log-listener.js b/deps/npm/test/lib/utils/proc-log-listener.js deleted file mode 100644 index d580defa8a..0000000000 --- a/deps/npm/test/lib/utils/proc-log-listener.js +++ /dev/null @@ -1,41 +0,0 @@ -const t = require('tap') -const { inspect } = require('util') - -const logs = [] -const npmlog = { - warn: (...args) => logs.push(['warn', ...args]), - verbose: (...args) => logs.push(['verbose', ...args]), -} - -t.mock('../../../lib/utils/proc-log-listener.js', { - npmlog, -})() - -process.emit('log', 'warn', 'hello', 'i am a warning') -t.strictSame(logs, [['warn', 'hello', 'i am a warning']]) -logs.length = 0 - -const nopeError = new Error('nope') -npmlog.warn = () => { - throw nopeError -} - -process.emit('log', 'warn', 'fail') -t.strictSame(logs, [[ - 'verbose', - `attempt to log ${inspect(['warn', 'fail'])} crashed`, - nopeError, -]]) -logs.length = 0 - -npmlog.verbose = () => { - throw nopeError -} -const consoleErrors = [] -console.error = (...args) => consoleErrors.push(args) -process.emit('log', 'warn', 'fail2') -t.strictSame(logs, []) -t.strictSame(consoleErrors, [[ - `attempt to log ${inspect(['warn', 'fail2'])} crashed`, - nopeError, -]]) diff --git a/deps/npm/test/lib/utils/pulse-till-done.js b/deps/npm/test/lib/utils/pulse-till-done.js index acbf66396a..9f7a94614d 100644 --- a/deps/npm/test/lib/utils/pulse-till-done.js +++ b/deps/npm/test/lib/utils/pulse-till-done.js @@ -1,18 +1,17 @@ const t = require('tap') let pulseStarted = null -const npmlog = { - gauge: { - pulse: () => { - if (pulseStarted) { - pulseStarted() - } - }, - }, -} const pulseTillDone = t.mock('../../../lib/utils/pulse-till-done.js', { - npmlog, + npmlog: { + gauge: { + pulse: () => { + if (pulseStarted) { + pulseStarted() + } + }, + }, + }, }) t.test('pulses (with promise)', async (t) => { diff --git a/deps/npm/test/lib/utils/read-user-info.js b/deps/npm/test/lib/utils/read-user-info.js index 35101f1d70..be805a2a87 100644 --- a/deps/npm/test/lib/utils/read-user-info.js +++ b/deps/npm/test/lib/utils/read-user-info.js @@ -7,11 +7,6 @@ const read = (opts, cb) => { return cb(null, readResult) } -const npmlog = { - clearProgress: () => {}, - showProgress: () => {}, -} - const npmUserValidate = { username: (username) => { if (username === 'invalid') { @@ -29,12 +24,23 @@ const npmUserValidate = { }, } +let logMsg = null const readUserInfo = t.mock('../../../lib/utils/read-user-info.js', { read, - npmlog, + npmlog: { + clearProgress: () => {}, + showProgress: () => {}, + }, + 'proc-log': { + warn: (msg) => logMsg = msg, + }, 'npm-user-validate': npmUserValidate, }) +t.beforeEach(() => { + logMsg = null +}) + t.test('otp', async (t) => { readResult = '1234' t.teardown(() => { @@ -75,11 +81,7 @@ t.test('username - invalid warns and retries', async (t) => { readOpts = null }) - let logMsg - const log = { - warn: (msg) => logMsg = msg, - } - const pResult = readUserInfo.username(null, null, { log }) + const pResult = readUserInfo.username(null, null) // have to swap it to a valid username after execution starts // or it will loop forever readResult = 'valid' @@ -105,11 +107,7 @@ t.test('email - invalid warns and retries', async (t) => { readOpts = null }) - let logMsg - const log = { - warn: (msg) => logMsg = msg, - } - const pResult = readUserInfo.email(null, null, { log }) + const pResult = readUserInfo.email(null, null) readResult = 'foo@bar.baz' const result = await pResult t.equal(result, 'foo@bar.baz', 'received the email') diff --git a/deps/npm/test/lib/utils/reify-output.js b/deps/npm/test/lib/utils/reify-output.js index 9a1bffb403..4e9ed7133c 100644 --- a/deps/npm/test/lib/utils/reify-output.js +++ b/deps/npm/test/lib/utils/reify-output.js @@ -1,7 +1,9 @@ const t = require('tap') +const log = require('../../../lib/utils/log-shim') -const log = require('npmlog') -log.level = 'warn' +const _level = log.level +t.beforeEach(() => log.level = 'warn') +t.teardown(() => log.level = _level) t.cleanSnapshot = str => str.replace(/in [0-9]+m?s/g, 'in {TIME}') @@ -237,7 +239,6 @@ t.test('showing and not showing audit report', async t => { npm.output = out => { t.fail('should not get output when silent', { actual: out }) } - t.teardown(() => log.level = 'warn') log.level = 'silent' reifyOutput(npm, { actualTree: { inventory: { size: 999 }, children: [] }, diff --git a/deps/npm/test/lib/utils/setup-log.js b/deps/npm/test/lib/utils/setup-log.js deleted file mode 100644 index 7f907bc7e4..0000000000 --- a/deps/npm/test/lib/utils/setup-log.js +++ /dev/null @@ -1,296 +0,0 @@ -const t = require('tap') - -const settings = { - level: 'warn', -} -t.afterEach(() => { - Object.keys(settings).forEach(k => { - delete settings[k] - }) -}) - -const WARN_CALLED = [] -const npmlog = { - warn: (...args) => { - WARN_CALLED.push(args) - }, - levels: { - silly: -Infinity, - verbose: 1000, - info: 2000, - timing: 2500, - http: 3000, - notice: 3500, - warn: 4000, - error: 5000, - silent: Infinity, - }, - settings, - enableColor: () => { - settings.color = true - }, - disableColor: () => { - settings.color = false - }, - enableUnicode: () => { - settings.unicode = true - }, - disableUnicode: () => { - settings.unicode = false - }, - enableProgress: () => { - settings.progress = true - }, - disableProgress: () => { - settings.progress = false - }, - get heading () { - return settings.heading - }, - set heading (h) { - settings.heading = h - }, - get level () { - return settings.level - }, - set level (l) { - settings.level = l - }, -} - -const EXPLAIN_CALLED = [] -const setupLog = t.mock('../../../lib/utils/setup-log.js', { - '../../../lib/utils/explain-eresolve.js': { - explain: (...args) => { - EXPLAIN_CALLED.push(args) - return 'explanation' - }, - }, - npmlog, -}) - -const config = obj => ({ - get (k) { - return obj[k] - }, - set (k, v) { - obj[k] = v - }, -}) - -t.test('setup with color=always and unicode', t => { - npmlog.warn('ERESOLVE', 'hello', { some: 'object' }) - t.strictSame(EXPLAIN_CALLED, [], 'log.warn() not patched yet') - t.strictSame(WARN_CALLED, [['ERESOLVE', 'hello', { some: 'object' }]]) - WARN_CALLED.length = 0 - - setupLog(config({ - loglevel: 'warn', - color: 'always', - unicode: true, - progress: false, - })) - - npmlog.warn('ERESOLVE', 'hello', { some: { other: 'object' } }) - t.strictSame(EXPLAIN_CALLED, [[{ some: { other: 'object' } }, true, 2]], - 'log.warn(ERESOLVE) patched to call explainEresolve()') - t.strictSame(WARN_CALLED, [ - ['ERESOLVE', 'hello'], - ['', 'explanation'], - ], 'warn the explanation') - EXPLAIN_CALLED.length = 0 - WARN_CALLED.length = 0 - npmlog.warn('some', 'other', 'thing') - t.strictSame(EXPLAIN_CALLED, [], 'do not try to explain other things') - t.strictSame(WARN_CALLED, [['some', 'other', 'thing']], 'warnings passed through') - - t.strictSame(settings, { - level: 'warn', - color: true, - unicode: true, - progress: false, - heading: 'npm', - }) - - t.end() -}) - -t.test('setup with color=true, no unicode, and non-TTY terminal', t => { - const { isTTY: stderrIsTTY } = process.stderr - const { isTTY: stdoutIsTTY } = process.stdout - t.teardown(() => { - process.stderr.isTTY = stderrIsTTY - process.stdout.isTTY = stdoutIsTTY - }) - process.stderr.isTTY = false - process.stdout.isTTY = false - - setupLog(config({ - loglevel: 'warn', - color: false, - progress: false, - heading: 'asdf', - })) - - t.strictSame(settings, { - level: 'warn', - color: false, - unicode: false, - progress: false, - heading: 'asdf', - }) - - t.end() -}) - -t.test('setup with color=true, no unicode, and dumb TTY terminal', t => { - const { isTTY: stderrIsTTY } = process.stderr - const { isTTY: stdoutIsTTY } = process.stdout - const { TERM } = process.env - t.teardown(() => { - process.stderr.isTTY = stderrIsTTY - process.stdout.isTTY = stdoutIsTTY - process.env.TERM = TERM - }) - process.stderr.isTTY = true - process.stdout.isTTY = true - process.env.TERM = 'dumb' - - setupLog(config({ - loglevel: 'warn', - color: true, - progress: false, - heading: 'asdf', - })) - - t.strictSame(settings, { - level: 'warn', - color: true, - unicode: false, - progress: false, - heading: 'asdf', - }) - - t.end() -}) - -t.test('setup with color=true, no unicode, and non-dumb TTY terminal', t => { - const { isTTY: stderrIsTTY } = process.stderr - const { isTTY: stdoutIsTTY } = process.stdout - const { TERM } = process.env - t.teardown(() => { - process.stderr.isTTY = stderrIsTTY - process.stdout.isTTY = stdoutIsTTY - process.env.TERM = TERM - }) - process.stderr.isTTY = true - process.stdout.isTTY = true - process.env.TERM = 'totes not dum' - - setupLog(config({ - loglevel: 'warn', - color: true, - progress: true, - heading: 'asdf', - })) - - t.strictSame(settings, { - level: 'warn', - color: true, - unicode: false, - progress: true, - heading: 'asdf', - }) - - t.end() -}) - -t.test('setup with non-TTY stdout, TTY stderr', t => { - const { isTTY: stderrIsTTY } = process.stderr - const { isTTY: stdoutIsTTY } = process.stdout - const { TERM } = process.env - t.teardown(() => { - process.stderr.isTTY = stderrIsTTY - process.stdout.isTTY = stdoutIsTTY - process.env.TERM = TERM - }) - process.stderr.isTTY = true - process.stdout.isTTY = false - process.env.TERM = 'definitely not a dummy' - - setupLog(config({ - loglevel: 'warn', - color: true, - progress: true, - heading: 'asdf', - })) - - t.strictSame(settings, { - level: 'warn', - color: true, - unicode: false, - progress: true, - heading: 'asdf', - }) - - t.end() -}) - -t.test('setup with TTY stdout, non-TTY stderr', t => { - const { isTTY: stderrIsTTY } = process.stderr - const { isTTY: stdoutIsTTY } = process.stdout - const { TERM } = process.env - t.teardown(() => { - process.stderr.isTTY = stderrIsTTY - process.stdout.isTTY = stdoutIsTTY - process.env.TERM = TERM - }) - process.stderr.isTTY = false - process.stdout.isTTY = true - - setupLog(config({ - loglevel: 'warn', - color: true, - progress: true, - heading: 'asdf', - })) - - t.strictSame(settings, { - level: 'warn', - color: false, - unicode: false, - progress: false, - heading: 'asdf', - }) - - t.end() -}) - -t.test('set loglevel to timing', t => { - setupLog(config({ - timing: true, - loglevel: 'notice', - })) - t.equal(settings.level, 'timing') - t.end() -}) - -t.test('silent has no logging', t => { - const { isTTY: stderrIsTTY } = process.stderr - const { isTTY: stdoutIsTTY } = process.stdout - const { TERM } = process.env - t.teardown(() => { - process.stderr.isTTY = stderrIsTTY - process.stdout.isTTY = stdoutIsTTY - process.env.TERM = TERM - }) - process.stderr.isTTY = true - process.stdout.isTTY = true - process.env.TERM = 'totes not dum' - - setupLog(config({ - loglevel: 'silent', - })) - t.equal(settings.progress, false, 'progress disabled when silent') - t.end() -}) diff --git a/deps/npm/test/lib/utils/tar.js b/deps/npm/test/lib/utils/tar.js index 19d9491694..adc5cb3649 100644 --- a/deps/npm/test/lib/utils/tar.js +++ b/deps/npm/test/lib/utils/tar.js @@ -2,18 +2,20 @@ const t = require('tap') const pack = require('libnpmpack') const ssri = require('ssri') -const { logTar, getContents } = require('../../../lib/utils/tar.js') +const { getContents } = require('../../../lib/utils/tar.js') -const printLogs = (tarball, unicode) => { +const mockTar = ({ notice }) => t.mock('../../../lib/utils/tar.js', { + 'proc-log': { + notice, + }, +}) + +const printLogs = (tarball, options) => { const logs = [] - logTar(tarball, { - log: { - notice: (...args) => { - args.map(el => logs.push(el)) - }, - }, - unicode, + const { logTar } = mockTar({ + notice: (...args) => args.map(el => logs.push(el)), }) + logTar(tarball, options) return logs.join('\n') } @@ -41,16 +43,14 @@ t.test('should log tarball contents', async (t) => { version: '1.0.0', }, tarball) - t.matchSnapshot(printLogs(tarballContents, false)) + t.matchSnapshot(printLogs(tarballContents)) }) t.test('should log tarball contents with unicode', async (t) => { - const { logTar } = t.mock('../../../lib/utils/tar.js', { - npmlog: { - notice: (str) => { - t.ok(true, 'defaults to npmlog') - return str - }, + const { logTar } = mockTar({ + notice: (str) => { + t.ok(true, 'defaults to proc-log') + return str }, }) @@ -64,26 +64,6 @@ t.test('should log tarball contents with unicode', async (t) => { t.end() }) -t.test('should default to npmlog', async (t) => { - const { logTar } = t.mock('../../../lib/utils/tar.js', { - npmlog: { - notice: (str) => { - t.ok(true, 'defaults to npmlog') - return str - }, - }, - }) - - logTar({ - files: [], - bundled: [], - size: 0, - unpackedSize: 0, - integrity: '', - }) - t.end() -}) - t.test('should getContents of a tarball', async (t) => { const testDir = t.testdir({ 'package.json': JSON.stringify({ diff --git a/deps/npm/test/lib/utils/timers.js b/deps/npm/test/lib/utils/timers.js new file mode 100644 index 0000000000..6127f346b1 --- /dev/null +++ b/deps/npm/test/lib/utils/timers.js @@ -0,0 +1,82 @@ +const t = require('tap') +const { resolve } = require('path') +const fs = require('graceful-fs') +const mockLogs = require('../../fixtures/mock-logs') + +const mockTimers = (t, options) => { + const { logs, logMocks } = mockLogs() + const Timers = t.mock('../../../lib/utils/timers', { + ...logMocks, + }) + const timers = new Timers(options) + t.teardown(() => timers.off()) + return { timers, logs } +} + +t.test('getters', async (t) => { + const { timers } = mockTimers(t) + t.match(timers.unfinished, new Map()) + t.match(timers.finished, {}) +}) + +t.test('listens/stops on process', async (t) => { + const { timers } = mockTimers(t) + process.emit('time', 'foo') + process.emit('time', 'bar') + process.emit('timeEnd', 'bar') + t.match(timers.unfinished, new Map([['foo', Number]])) + t.match(timers.finished, { bar: Number }) + timers.off() + process.emit('time', 'baz') + t.notOk(timers.unfinished.get('baz')) +}) + +t.test('initial timer', async (t) => { + const { timers } = mockTimers(t, { start: 'foo' }) + process.emit('timeEnd', 'foo') + t.match(timers.finished, { foo: Number }) +}) + +t.test('initial listener', async (t) => { + const events = [] + const listener = (...args) => events.push(args) + const { timers } = mockTimers(t, { listener }) + process.emit('time', 'foo') + process.emit('time', 'bar') + process.emit('timeEnd', 'bar') + timers.off(listener) + process.emit('timeEnd', 'foo') + t.equal(events.length, 1) + t.match(events, [['bar', Number]]) +}) + +t.test('finish unstarted timer', async (t) => { + const { logs } = mockTimers(t) + process.emit('timeEnd', 'foo') + t.match(logs.silly, [['timing', /^Tried to end timer/, 'foo']]) +}) + +t.test('writes file', async (t) => { + const { timers } = mockTimers(t) + const dir = t.testdir() + process.emit('time', 'foo') + process.emit('timeEnd', 'foo') + timers.load({ dir }) + timers.writeFile({ some: 'data' }) + const data = JSON.parse(fs.readFileSync(resolve(dir, '_timing.json'))) + t.match(data, { + some: 'data', + foo: Number, + unfinished: { + npm: [Number, Number], + }, + }) +}) + +t.test('fails to write file', async (t) => { + const { logs, timers } = mockTimers(t) + timers.writeFile() + t.match(logs.warn, [ + ['timing', 'could not write timing file', Error], + ]) +}) diff --git a/deps/npm/test/lib/utils/unsupported.js b/deps/npm/test/lib/utils/unsupported.js index 4d806cefc4..2703044a22 100644 --- a/deps/npm/test/lib/utils/unsupported.js +++ b/deps/npm/test/lib/utils/unsupported.js @@ -1,5 +1,6 @@ const t = require('tap') const unsupported = require('../../../lib/utils/unsupported.js') +const mockGlobals = require('../../fixtures/mock-globals.js') const versions = [ // broken unsupported @@ -55,42 +56,30 @@ t.test('checkForBrokenNode', t => { // run it once to not fail unsupported.checkForBrokenNode() - const { exit } = process - const { error } = console - const versionPropDesc = Object.getOwnPropertyDescriptor(process, 'version') - - t.teardown(() => { - process.exit = exit - Object.defineProperty(process, 'version', versionPropDesc) - console.error = error - }) - - // then make it a thing that fails - process.exit = code => { - t.equal(code, 1) - t.strictSame(logs, expectLogs) - t.end() - } - Object.defineProperty(process, 'version', { value: '1.2.3', configurable: true }) const logs = [] const expectLogs = [ 'ERROR: npm is known not to run on Node.js 1.2.3', "You'll need to upgrade to a newer Node.js version in order to use this", 'version of npm. You can find the latest version at https://nodejs.org/', ] - console.error = msg => logs.push(msg) + + // then make it a thing that fails + mockGlobals(t, { + 'console.error': msg => logs.push(msg), + 'process.version': '1.2.3', + 'process.exit': (code) => { + t.equal(code, 1) + t.strictSame(logs, expectLogs) + t.end() + }, + }) + unsupported.checkForBrokenNode() }) t.test('checkForUnsupportedNode', t => { - const npmlog = require('npmlog') - const { warn } = npmlog - const versionPropDesc = Object.getOwnPropertyDescriptor(process, 'version') - - t.teardown(() => { - Object.defineProperty(process, 'version', versionPropDesc) - npmlog.warn = warn - }) + // run it once to not fail or warn + unsupported.checkForUnsupportedNode() const logs = [] const expectLogs = [ @@ -99,14 +88,15 @@ t.test('checkForUnsupportedNode', t => { "can't make any promises that npm will work with this version.", 'You can find the latest version at https://nodejs.org/', ] - npmlog.warn = (section, msg) => logs.push(msg) - - // run it once to not fail or warn - unsupported.checkForUnsupportedNode() // then make it a thing that fails - Object.defineProperty(process, 'version', { value: '8.0.0' }) + mockGlobals(t, { + 'console.error': msg => logs.push(msg), + 'process.version': '8.0.0', + }) + unsupported.checkForUnsupportedNode() + t.strictSame(logs, expectLogs) t.end() }) diff --git a/deps/npm/test/lib/utils/update-notifier.js b/deps/npm/test/lib/utils/update-notifier.js index 78ff93825e..a7a800c602 100644 --- a/deps/npm/test/lib/utils/update-notifier.js +++ b/deps/npm/test/lib/utils/update-notifier.js @@ -36,18 +36,13 @@ const pacote = { }, } -const npm = { +const defaultNpm = { flatOptions, - log: { useColor: () => true }, version: CURRENT_VERSION, config: { get: k => k !== 'global' }, command: 'view', argv: ['npm'], } -const npmNoColor = { - ...npm, - log: { useColor: () => false }, -} const { basename } = require('path') @@ -80,12 +75,6 @@ const fs = { }, } -const updateNotifier = t.mock('../../../lib/utils/update-notifier.js', { - '@npmcli/ci-detect': () => ciMock, - pacote, - fs, -}) - t.afterEach(() => { MANIFEST_REQUEST.length = 0 STAT_ERROR = null @@ -94,16 +83,21 @@ t.afterEach(() => { WRITE_ERROR = null }) -const runUpdateNotifier = async npm => { - await updateNotifier(npm) - return npm.updateNotification +const runUpdateNotifier = async ({ color = true, ...npmOptions } = {}) => { + const _npm = { ...defaultNpm, ...npmOptions } + await t.mock('../../../lib/utils/update-notifier.js', { + '@npmcli/ci-detect': () => ciMock, + pacote, + fs, + npmlog: { useColor: () => color }, + })(_npm) + return _npm.updateNotification } t.test('situations in which we do not notify', t => { t.test('nothing to do if notifier disabled', async t => { t.equal( await runUpdateNotifier({ - ...npm, config: { get: k => k !== 'update-notifier' }, }), null @@ -114,7 +108,6 @@ t.test('situations in which we do not notify', t => { t.test('do not suggest update if already updating', async t => { t.equal( await runUpdateNotifier({ - ...npm, flatOptions: { ...flatOptions, global: true }, command: 'install', argv: ['npm'], @@ -127,7 +120,6 @@ t.test('situations in which we do not notify', t => { t.test('do not suggest update if already updating with spec', async t => { t.equal( await runUpdateNotifier({ - ...npm, flatOptions: { ...flatOptions, global: true }, command: 'install', argv: ['npm@latest'], @@ -138,31 +130,31 @@ t.test('situations in which we do not notify', t => { }) t.test('do not update if same as latest', async t => { - t.equal(await runUpdateNotifier(npm), null) + t.equal(await runUpdateNotifier(), null) t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version') }) t.test('check if stat errors (here for coverage)', async t => { STAT_ERROR = new Error('blorg') - t.equal(await runUpdateNotifier(npm), null) + t.equal(await runUpdateNotifier(), null) t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version') }) t.test('ok if write errors (here for coverage)', async t => { WRITE_ERROR = new Error('grolb') - t.equal(await runUpdateNotifier(npm), null) + t.equal(await runUpdateNotifier(), null) t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version') }) t.test('ignore pacote failures (here for coverage)', async t => { PACOTE_ERROR = new Error('pah-KO-tchay') - t.equal(await runUpdateNotifier(npm), null) + t.equal(await runUpdateNotifier(), null) t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version') }) t.test('do not update if newer than latest, but same as next', async t => { - t.equal(await runUpdateNotifier({ ...npm, version: NEXT_VERSION }), null) + t.equal(await runUpdateNotifier({ version: NEXT_VERSION }), null) const reqs = ['npm@latest', `npm@^${NEXT_VERSION}`] t.strictSame(MANIFEST_REQUEST, reqs, 'requested latest and next versions') }) t.test('do not update if on the latest beta', async t => { - t.equal(await runUpdateNotifier({ ...npm, version: CURRENT_BETA }), null) + t.equal(await runUpdateNotifier({ version: CURRENT_BETA }), null) const reqs = [`npm@^${CURRENT_BETA}`] t.strictSame(MANIFEST_REQUEST, reqs, 'requested latest and next versions') }) @@ -172,21 +164,21 @@ t.test('situations in which we do not notify', t => { ciMock = null }) ciMock = 'something' - t.equal(await runUpdateNotifier(npm), null) + t.equal(await runUpdateNotifier(), null) t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests') }) t.test('only check weekly for GA releases', async t => { // One week (plus five minutes to account for test environment fuzziness) STAT_MTIME = Date.now() - 1000 * 60 * 60 * 24 * 7 + 1000 * 60 * 5 - t.equal(await runUpdateNotifier(npm), null) + t.equal(await runUpdateNotifier(), null) t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests') }) t.test('only check daily for betas', async t => { // One day (plus five minutes to account for test environment fuzziness) STAT_MTIME = Date.now() - 1000 * 60 * 60 * 24 + 1000 * 60 * 5 - t.equal(await runUpdateNotifier({ ...npm, version: HAVE_BETA }), null) + t.equal(await runUpdateNotifier({ version: HAVE_BETA }), null) t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests') }) @@ -196,9 +188,9 @@ t.test('situations in which we do not notify', t => { t.test('notification situations', t => { t.test('new beta available', async t => { const version = HAVE_BETA - t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color') + t.matchSnapshot(await runUpdateNotifier({ version }), 'color') t.matchSnapshot( - await runUpdateNotifier({ ...npmNoColor, version }), + await runUpdateNotifier({ version, color: false }), 'no color' ) t.strictSame(MANIFEST_REQUEST, [`npm@^${version}`, `npm@^${version}`]) @@ -206,9 +198,9 @@ t.test('notification situations', t => { t.test('patch to next version', async t => { const version = NEXT_PATCH - t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color') + t.matchSnapshot(await runUpdateNotifier({ version }), 'color') t.matchSnapshot( - await runUpdateNotifier({ ...npmNoColor, version }), + await runUpdateNotifier({ version, color: false }), 'no color' ) t.strictSame(MANIFEST_REQUEST, [ @@ -221,9 +213,9 @@ t.test('notification situations', t => { t.test('minor to next version', async t => { const version = NEXT_MINOR - t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color') + t.matchSnapshot(await runUpdateNotifier({ version }), 'color') t.matchSnapshot( - await runUpdateNotifier({ ...npmNoColor, version }), + await runUpdateNotifier({ version, color: false }), 'no color' ) t.strictSame(MANIFEST_REQUEST, [ @@ -236,9 +228,9 @@ t.test('notification situations', t => { t.test('patch to current', async t => { const version = CURRENT_PATCH - t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color') + t.matchSnapshot(await runUpdateNotifier({ version }), 'color') t.matchSnapshot( - await runUpdateNotifier({ ...npmNoColor, version }), + await runUpdateNotifier({ version, color: false }), 'no color' ) t.strictSame(MANIFEST_REQUEST, ['npm@latest', 'npm@latest']) @@ -246,9 +238,9 @@ t.test('notification situations', t => { t.test('minor to current', async t => { const version = CURRENT_MINOR - t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color') + t.matchSnapshot(await runUpdateNotifier({ version }), 'color') t.matchSnapshot( - await runUpdateNotifier({ ...npmNoColor, version }), + await runUpdateNotifier({ version, color: false }), 'no color' ) t.strictSame(MANIFEST_REQUEST, ['npm@latest', 'npm@latest']) @@ -256,9 +248,9 @@ t.test('notification situations', t => { t.test('major to current', async t => { const version = CURRENT_MAJOR - t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color') + t.matchSnapshot(await runUpdateNotifier({ version }), 'color') t.matchSnapshot( - await runUpdateNotifier({ ...npmNoColor, version }), + await runUpdateNotifier({ version, color: false }), 'no color' ) t.strictSame(MANIFEST_REQUEST, ['npm@latest', 'npm@latest']) |