From 06d7b8e8c86221fd98960a061ad2daac9f9acb5e Mon Sep 17 00:00:00 2001 From: npm team Date: Thu, 15 Jul 2021 20:09:18 +0000 Subject: [PATCH] deps: upgrade npm to 7.20.3 Updates npm from 7.19.1 to 7.20.3. Refs: https://github.com/nodejs/node/pull/39403 PR-URL: https://github.com/nodejs/node/pull/39579 Backport-PR-URL: https://github.com/nodejs/node/pull/39590 Reviewed-By: Myles Borins Reviewed-By: Beth Griggs --- deps/npm/docs/content/commands/npm-audit.md | 4 + deps/npm/docs/content/commands/npm-ci.md | 10 + deps/npm/docs/content/commands/npm-config.md | 11 + deps/npm/docs/content/commands/npm-dedupe.md | 7 +- deps/npm/docs/content/commands/npm-explain.md | 3 + .../docs/content/commands/npm-find-dupes.md | 7 +- deps/npm/docs/content/commands/npm-fund.md | 3 + deps/npm/docs/content/commands/npm-init.md | 1 + .../content/commands/npm-install-ci-test.md | 10 + .../docs/content/commands/npm-install-test.md | 7 +- deps/npm/docs/content/commands/npm-install.md | 7 +- deps/npm/docs/content/commands/npm-link.md | 7 +- deps/npm/docs/content/commands/npm-ls.md | 3 + deps/npm/docs/content/commands/npm-org.md | 3 + .../npm/docs/content/commands/npm-outdated.md | 3 + deps/npm/docs/content/commands/npm-pack.md | 3 + deps/npm/docs/content/commands/npm-pkg.md | 245 +++++ deps/npm/docs/content/commands/npm-profile.md | 3 + deps/npm/docs/content/commands/npm-prune.md | 3 + deps/npm/docs/content/commands/npm-search.md | 3 + deps/npm/docs/content/commands/npm-team.md | 3 + .../docs/content/commands/npm-unpublish.md | 1 + deps/npm/docs/content/commands/npm-update.md | 44 +- deps/npm/docs/content/commands/npm-version.md | 3 + deps/npm/docs/content/commands/npm-view.md | 5 +- .../docs/content/configuring-npm/folders.md | 6 +- .../content/configuring-npm/package-json.md | 12 +- deps/npm/docs/content/using-npm/config.md | 20 +- deps/npm/docs/content/using-npm/scripts.md | 7 +- deps/npm/docs/content/using-npm/workspaces.md | 2 +- deps/npm/docs/output/commands/npm-audit.html | 5 + deps/npm/docs/output/commands/npm-ci.html | 11 +- deps/npm/docs/output/commands/npm-config.html | 13 +- deps/npm/docs/output/commands/npm-dedupe.html | 7 +- .../npm/docs/output/commands/npm-explain.html | 4 + .../docs/output/commands/npm-find-dupes.html | 7 +- deps/npm/docs/output/commands/npm-fund.html | 4 + deps/npm/docs/output/commands/npm-init.html | 1 + .../output/commands/npm-install-ci-test.html | 11 +- .../output/commands/npm-install-test.html | 7 +- .../npm/docs/output/commands/npm-install.html | 7 +- deps/npm/docs/output/commands/npm-link.html | 7 +- deps/npm/docs/output/commands/npm-ls.html | 6 +- deps/npm/docs/output/commands/npm-org.html | 4 + .../docs/output/commands/npm-outdated.html | 4 + deps/npm/docs/output/commands/npm-pack.html | 4 + deps/npm/docs/output/commands/npm-pkg.html | 343 +++++++ .../npm/docs/output/commands/npm-profile.html | 4 + deps/npm/docs/output/commands/npm-prune.html | 4 + deps/npm/docs/output/commands/npm-search.html | 4 + deps/npm/docs/output/commands/npm-team.html | 4 + .../docs/output/commands/npm-unpublish.html | 1 + deps/npm/docs/output/commands/npm-update.html | 37 +- .../npm/docs/output/commands/npm-version.html | 4 + deps/npm/docs/output/commands/npm-view.html | 6 +- deps/npm/docs/output/commands/npm.html | 2 +- .../docs/output/configuring-npm/folders.html | 6 +- .../output/configuring-npm/package-json.html | 11 +- deps/npm/docs/output/using-npm/config.html | 22 +- deps/npm/docs/output/using-npm/scripts.html | 7 +- .../npm/docs/output/using-npm/workspaces.html | 2 +- deps/npm/lib/base-command.js | 1 - deps/npm/lib/ci.js | 1 + deps/npm/lib/config.js | 8 +- deps/npm/lib/install-ci-test.js | 8 - deps/npm/lib/ls.js | 2 +- deps/npm/lib/npm.js | 60 +- deps/npm/lib/outdated.js | 2 +- deps/npm/lib/pkg.js | 152 +++ deps/npm/lib/publish.js | 5 +- deps/npm/lib/utils/cmd-list.js | 1 + deps/npm/lib/utils/config/definition.js | 32 +- deps/npm/lib/utils/config/definitions.js | 41 +- deps/npm/lib/utils/error-message.js | 1 + deps/npm/lib/utils/exit-handler.js | 216 ++-- deps/npm/lib/utils/explain-eresolve.js | 15 +- deps/npm/lib/utils/perf.js | 23 - deps/npm/lib/utils/queryable.js | 314 ++++++ deps/npm/lib/utils/update-notifier.js | 15 +- deps/npm/lib/view.js | 56 +- deps/npm/man/man1/npm-audit.1 | 8 + deps/npm/man/man1/npm-ci.1 | 13 + deps/npm/man/man1/npm-config.1 | 17 + deps/npm/man/man1/npm-dedupe.1 | 7 +- deps/npm/man/man1/npm-explain.1 | 6 + deps/npm/man/man1/npm-find-dupes.1 | 7 +- deps/npm/man/man1/npm-fund.1 | 6 + deps/npm/man/man1/npm-init.1 | 2 + deps/npm/man/man1/npm-install-ci-test.1 | 13 + deps/npm/man/man1/npm-install-test.1 | 7 +- deps/npm/man/man1/npm-install.1 | 7 +- deps/npm/man/man1/npm-link.1 | 7 +- deps/npm/man/man1/npm-ls.1 | 8 +- deps/npm/man/man1/npm-org.1 | 6 + deps/npm/man/man1/npm-outdated.1 | 6 + deps/npm/man/man1/npm-pack.1 | 6 + deps/npm/man/man1/npm-pkg.1 | 294 ++++++ deps/npm/man/man1/npm-profile.1 | 6 + deps/npm/man/man1/npm-prune.1 | 6 + deps/npm/man/man1/npm-search.1 | 6 + deps/npm/man/man1/npm-team.1 | 6 + deps/npm/man/man1/npm-unpublish.1 | 2 + deps/npm/man/man1/npm-update.1 | 46 +- deps/npm/man/man1/npm-version.1 | 6 + deps/npm/man/man1/npm-view.1 | 8 +- deps/npm/man/man1/npm.1 | 2 +- deps/npm/man/man5/folders.5 | 6 +- deps/npm/man/man5/package-json.5 | 12 +- deps/npm/man/man7/config.7 | 28 +- deps/npm/man/man7/scripts.7 | 7 +- deps/npm/man/man7/workspaces.7 | 2 +- .../arborist/lib/arborist/build-ideal-tree.js | 811 +++------------ .../@npmcli/arborist/lib/arborist/index.js | 2 +- .../arborist/lib/arborist/load-actual.js | 2 +- .../arborist/lib/arborist/load-virtual.js | 2 +- .../@npmcli/arborist/lib/arborist/rebuild.js | 6 +- .../@npmcli/arborist/lib/arborist/reify.js | 169 ++- .../@npmcli/arborist/lib/calc-dep-flags.js | 6 +- .../@npmcli/arborist/lib/can-place-dep.js | 405 ++++++++ .../arborist/lib/deepest-nesting-target.js | 16 + .../node_modules/@npmcli/arborist/lib/diff.js | 8 +- .../node_modules/@npmcli/arborist/lib/edge.js | 2 + .../node_modules/@npmcli/arborist/lib/node.js | 46 +- .../@npmcli/arborist/lib/peer-entry-sets.js | 72 ++ .../@npmcli/arborist/lib/peer-set.js | 25 - .../@npmcli/arborist/lib/place-dep.js | 536 ++++++++++ .../@npmcli/arborist/lib/printable.js | 10 + .../@npmcli/arborist/lib/shrinkwrap.js | 14 +- .../@npmcli/arborist/package.json | 11 +- .../node_modules/@npmcli/git/lib/errors.js | 36 + .../npm/node_modules/@npmcli/git/lib/index.js | 3 +- .../@npmcli/git/lib/make-error.js | 33 + .../@npmcli/git/lib/should-retry.js | 17 - .../npm/node_modules/@npmcli/git/lib/spawn.js | 9 +- .../npm/node_modules/@npmcli/git/package.json | 2 +- .../make-fetch-happen/lib/cache/entry.js | 30 +- .../make-fetch-happen/lib/cache/policy.js | 2 +- .../make-fetch-happen/lib/remote.js | 1 + .../make-fetch-happen/package.json | 2 +- deps/npm/node_modules/mime-db/HISTORY.md | 6 + deps/npm/node_modules/mime-db/db.json | 40 +- deps/npm/node_modules/mime-db/package.json | 8 +- deps/npm/node_modules/mime-types/HISTORY.md | 7 + deps/npm/node_modules/mime-types/package.json | 8 +- .../node_modules/minipass-fetch/lib/index.js | 25 +- .../minipass-fetch/lib/request.js | 4 + .../node_modules/minipass-fetch/package.json | 2 +- deps/npm/node_modules/pacote/lib/fetcher.js | 8 + deps/npm/node_modules/pacote/lib/git.js | 7 +- deps/npm/node_modules/pacote/package.json | 4 +- ...{receiveBuffer.d.ts => receivebuffer.d.ts} | 0 deps/npm/package.json | 10 +- .../smoke-tests/index.js.test.cjs | 91 +- .../tap-snapshots/test/lib/config.js.test.cjs | 10 +- .../test/lib/load-all-commands.js.test.cjs | 63 +- .../test/lib/utils/cmd-list.js.test.cjs | 1 + .../lib/utils/config/definitions.js.test.cjs | 22 +- .../lib/utils/config/describe-all.js.test.cjs | 19 +- .../test/lib/utils/config/index.js.test.cjs | 3 + .../test/lib/utils/error-message.js.test.cjs | 23 + .../test/lib/utils/exit-handler.js.test.cjs | 20 +- .../lib/utils/explain-eresolve.js.test.cjs | 151 +++ .../test/lib/utils/npm-usage.js.test.cjs | 93 +- .../lib/utils/update-notifier.js.test.cjs | 60 +- .../test/fixtures/eresolve-explanations.js | 253 ++++- deps/npm/test/fixtures/mock-npm.js | 16 +- deps/npm/test/lib/config.js | 26 +- deps/npm/test/lib/link.js | 2 +- deps/npm/test/lib/npm.js | 25 + deps/npm/test/lib/pkg.js | 737 +++++++++++++ deps/npm/test/lib/publish.js | 100 ++ deps/npm/test/lib/utils/config/definition.js | 7 + deps/npm/test/lib/utils/config/definitions.js | 33 +- deps/npm/test/lib/utils/error-message.js | 1 + deps/npm/test/lib/utils/exit-handler.js | 532 ++++------ deps/npm/test/lib/utils/perf.js | 38 - deps/npm/test/lib/utils/queryable.js | 965 ++++++++++++++++++ 177 files changed, 6469 insertions(+), 1750 deletions(-) create mode 100644 deps/npm/docs/content/commands/npm-pkg.md create mode 100644 deps/npm/docs/output/commands/npm-pkg.html create mode 100644 deps/npm/lib/pkg.js delete mode 100644 deps/npm/lib/utils/perf.js create mode 100644 deps/npm/lib/utils/queryable.js create mode 100644 deps/npm/man/man1/npm-pkg.1 create mode 100644 deps/npm/node_modules/@npmcli/arborist/lib/can-place-dep.js create mode 100644 deps/npm/node_modules/@npmcli/arborist/lib/deepest-nesting-target.js create mode 100644 deps/npm/node_modules/@npmcli/arborist/lib/peer-entry-sets.js delete mode 100644 deps/npm/node_modules/@npmcli/arborist/lib/peer-set.js create mode 100644 deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js create mode 100644 deps/npm/node_modules/@npmcli/git/lib/errors.js create mode 100644 deps/npm/node_modules/@npmcli/git/lib/make-error.js delete mode 100644 deps/npm/node_modules/@npmcli/git/lib/should-retry.js rename deps/npm/node_modules/socks/typings/common/{receiveBuffer.d.ts => receivebuffer.d.ts} (100%) create mode 100644 deps/npm/test/lib/pkg.js delete mode 100644 deps/npm/test/lib/utils/perf.js create mode 100644 deps/npm/test/lib/utils/queryable.js diff --git a/deps/npm/docs/content/commands/npm-audit.md b/deps/npm/docs/content/commands/npm-audit.md index 704d7a15fb8f19..94b16b27bd7ed9 100644 --- a/deps/npm/docs/content/commands/npm-audit.md +++ b/deps/npm/docs/content/commands/npm-audit.md @@ -232,6 +232,7 @@ mistakes, unnecessary performance degradation, and malicious input. * Allow unpublishing all versions of a published package. * Allow conflicting peerDependencies to be installed in the root project. * Implicitly set `--yes` during `npm init`. +* Allow clobbering existing values in `npm pkg` If you don't have a clear idea of what you want to do, it is strongly recommended that you do not use this option! @@ -243,6 +244,9 @@ recommended that you do not use this option! Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `package-lock-only` diff --git a/deps/npm/docs/content/commands/npm-ci.md b/deps/npm/docs/content/commands/npm-ci.md index 9645bae7e2f43d..31c92b13c5cdd3 100644 --- a/deps/npm/docs/content/commands/npm-ci.md +++ b/deps/npm/docs/content/commands/npm-ci.md @@ -69,6 +69,16 @@ cache: +#### `audit` + +* Default: true +* Type: Boolean + +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. + #### `ignore-scripts` * Default: false diff --git a/deps/npm/docs/content/commands/npm-config.md b/deps/npm/docs/content/commands/npm-config.md index f2868cb8909a91..9e76a23671e861 100644 --- a/deps/npm/docs/content/commands/npm-config.md +++ b/deps/npm/docs/content/commands/npm-config.md @@ -104,6 +104,9 @@ global config. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `global` @@ -128,6 +131,14 @@ folder instead of the current working directory. See The command to run for `npm edit` and `npm config edit`. +#### `location` + +* Default: "user" unless `--global` is passed, which will also set this value + to "global" +* Type: "global", "user", or "project" + +When passed to `npm config` this refers to which config file to use. + #### `long` * Default: false diff --git a/deps/npm/docs/content/commands/npm-dedupe.md b/deps/npm/docs/content/commands/npm-dedupe.md index fbccc410532924..324e6a71b7a3eb 100644 --- a/deps/npm/docs/content/commands/npm-dedupe.md +++ b/deps/npm/docs/content/commands/npm-dedupe.md @@ -164,9 +164,10 @@ will *not* run any pre- or post-scripts. * Default: true * Type: Boolean -When "true" submit audit reports alongside `npm install` runs to the default -registry and all registries configured for scopes. See the documentation for -[`npm audit`](/commands/npm-audit) for details on what is submitted. +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. #### `bin-links` diff --git a/deps/npm/docs/content/commands/npm-explain.md b/deps/npm/docs/content/commands/npm-explain.md index 0e50d7ae43343b..3a87ee8e438bad 100644 --- a/deps/npm/docs/content/commands/npm-explain.md +++ b/deps/npm/docs/content/commands/npm-explain.md @@ -63,6 +63,9 @@ node_modules/nyc/node_modules/find-up Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `workspace` diff --git a/deps/npm/docs/content/commands/npm-find-dupes.md b/deps/npm/docs/content/commands/npm-find-dupes.md index 28281d5678ab70..3b28f6443decda 100644 --- a/deps/npm/docs/content/commands/npm-find-dupes.md +++ b/deps/npm/docs/content/commands/npm-find-dupes.md @@ -107,9 +107,10 @@ will *not* run any pre- or post-scripts. * Default: true * Type: Boolean -When "true" submit audit reports alongside `npm install` runs to the default -registry and all registries configured for scopes. See the documentation for -[`npm audit`](/commands/npm-audit) for details on what is submitted. +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. #### `bin-links` diff --git a/deps/npm/docs/content/commands/npm-fund.md b/deps/npm/docs/content/commands/npm-fund.md index 3dc5292b490a17..ec5f5a37fdb716 100644 --- a/deps/npm/docs/content/commands/npm-fund.md +++ b/deps/npm/docs/content/commands/npm-fund.md @@ -73,6 +73,9 @@ test-workspaces-fund@1.0.0 Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `browser` diff --git a/deps/npm/docs/content/commands/npm-init.md b/deps/npm/docs/content/commands/npm-init.md index 23e8e70d9e9132..54c3bdb4b74ab9 100644 --- a/deps/npm/docs/content/commands/npm-init.md +++ b/deps/npm/docs/content/commands/npm-init.md @@ -175,6 +175,7 @@ mistakes, unnecessary performance degradation, and malicious input. * Allow unpublishing all versions of a published package. * Allow conflicting peerDependencies to be installed in the root project. * Implicitly set `--yes` during `npm init`. +* Allow clobbering existing values in `npm pkg` If you don't have a clear idea of what you want to do, it is strongly recommended that you do not use this option! diff --git a/deps/npm/docs/content/commands/npm-install-ci-test.md b/deps/npm/docs/content/commands/npm-install-ci-test.md index c337905a0566e9..2640311cf94be7 100644 --- a/deps/npm/docs/content/commands/npm-install-ci-test.md +++ b/deps/npm/docs/content/commands/npm-install-ci-test.md @@ -20,6 +20,16 @@ This command runs `npm ci` followed immediately by `npm test`. +#### `audit` + +* Default: true +* Type: Boolean + +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. + #### `ignore-scripts` * Default: false diff --git a/deps/npm/docs/content/commands/npm-install-test.md b/deps/npm/docs/content/commands/npm-install-test.md index deefbd96b52fd1..c8533cafedd7a3 100644 --- a/deps/npm/docs/content/commands/npm-install-test.md +++ b/deps/npm/docs/content/commands/npm-install-test.md @@ -149,9 +149,10 @@ will *not* run any pre- or post-scripts. * Default: true * Type: Boolean -When "true" submit audit reports alongside `npm install` runs to the default -registry and all registries configured for scopes. See the documentation for -[`npm audit`](/commands/npm-audit) for details on what is submitted. +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. #### `bin-links` diff --git a/deps/npm/docs/content/commands/npm-install.md b/deps/npm/docs/content/commands/npm-install.md index e5091e6604c917..70d4c0d46ffeb2 100644 --- a/deps/npm/docs/content/commands/npm-install.md +++ b/deps/npm/docs/content/commands/npm-install.md @@ -533,9 +533,10 @@ will *not* run any pre- or post-scripts. * Default: true * Type: Boolean -When "true" submit audit reports alongside `npm install` runs to the default -registry and all registries configured for scopes. See the documentation for -[`npm audit`](/commands/npm-audit) for details on what is submitted. +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. #### `bin-links` diff --git a/deps/npm/docs/content/commands/npm-link.md b/deps/npm/docs/content/commands/npm-link.md index b1c6066768a99e..c7b385009519a0 100644 --- a/deps/npm/docs/content/commands/npm-link.md +++ b/deps/npm/docs/content/commands/npm-link.md @@ -233,9 +233,10 @@ will *not* run any pre- or post-scripts. * Default: true * Type: Boolean -When "true" submit audit reports alongside `npm install` runs to the default -registry and all registries configured for scopes. See the documentation for -[`npm audit`](/commands/npm-audit) for details on what is submitted. +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. #### `bin-links` diff --git a/deps/npm/docs/content/commands/npm-ls.md b/deps/npm/docs/content/commands/npm-ls.md index 1f401fa956ff8d..350f40a9991e52 100644 --- a/deps/npm/docs/content/commands/npm-ls.md +++ b/deps/npm/docs/content/commands/npm-ls.md @@ -91,6 +91,9 @@ upon by the current project. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `long` diff --git a/deps/npm/docs/content/commands/npm-org.md b/deps/npm/docs/content/commands/npm-org.md index e6df560acfba36..269f5cc3ee5b88 100644 --- a/deps/npm/docs/content/commands/npm-org.md +++ b/deps/npm/docs/content/commands/npm-org.md @@ -87,6 +87,9 @@ password, npm will prompt on the command line for one. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `parseable` diff --git a/deps/npm/docs/content/commands/npm-outdated.md b/deps/npm/docs/content/commands/npm-outdated.md index bc9263d7aeda73..40e5feafd4cc61 100644 --- a/deps/npm/docs/content/commands/npm-outdated.md +++ b/deps/npm/docs/content/commands/npm-outdated.md @@ -104,6 +104,9 @@ upon by the current project. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `long` diff --git a/deps/npm/docs/content/commands/npm-pack.md b/deps/npm/docs/content/commands/npm-pack.md index 95070262784378..cd4a175919e7eb 100644 --- a/deps/npm/docs/content/commands/npm-pack.md +++ b/deps/npm/docs/content/commands/npm-pack.md @@ -34,6 +34,9 @@ Note: This is NOT honored by other network related commands, eg `dist-tags`, Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `pack-destination` diff --git a/deps/npm/docs/content/commands/npm-pkg.md b/deps/npm/docs/content/commands/npm-pkg.md new file mode 100644 index 00000000000000..78b13cf9e9a000 --- /dev/null +++ b/deps/npm/docs/content/commands/npm-pkg.md @@ -0,0 +1,245 @@ +--- +title: npm-pkg +section: 1 +description: Manages your package.json +--- + +### Synopsis + +```bash +npm pkg get [ [. ...]] +npm pkg set = [.= ...] +npm pkg delete [. ...] +``` + +### Description + +A command that automates the management of `package.json` files. +`npm pkg` provide 3 different sub commands that allow you to modify or retrieve +values for given object keys in your `packge.json`. + +The syntax to retrieve and set fields is a dot separated representation of +the nested object properties to be found within your `package.json`, it's the +same notation used in [`npm view`](/commands/npm-view) to retrieve information +from the registry manifest, below you can find more examples on how to use it. + +Returned values are always in **json** format. + +* `npm pkg get ` + + Retrieves a value `key`, defined in your `package.json` file. + + For example, in order to retrieve the name of the current package, you + can run: + + ```bash + npm pkg get name + ``` + + It's also possible to retrieve multiple values at once: + + ```bash + npm pkg get name version + ``` + + You can view child fields by separating them with a period. To retrieve + the value of a test `script` value, you would run the following command: + + ```bash + npm pkg get scripts.test + ``` + + For fields that are arrays, requesting a non-numeric field will return + all of the values from the objects in the list. For example, to get all + the contributor emails for a package, you would run: + + ```bash + npm pkg get contributors.email + ``` + + You may also use numeric indices in square braces to specifically select + an item in an array field. To just get the email address of the first + contributor in the list, you can run: + + ```bash + npm pkg get contributors[0].email + ``` + +* `npm pkg set =` + + Sets a `value` in your `package.json` based on the `field` value. When + saving to your `package.json` file the same set of rules used during + `npm install` and other cli commands that touches the `package.json` file + are used, making sure to respect the existing indentation and possibly + applying some validation prior to saving values to the file. + + The same syntax used to retrieve values from your package can also be used + to define new properties or overriding existing ones, below are some + examples of how the dot separated syntax can be used to edit your + `package.json` file. + + Defining a new bin named `mynewcommand` in your `package.json` that points + to a file `cli.js`: + + ```bash + npm pkg set bin.mynewcommand=cli.js + ``` + + Setting multiple fields at once is also possible: + + ```bash + npm pkg set description='Awesome package' engines.node='>=10' + ``` + + It's also possible to add to array values, for example to add a new + contributor entry: + + ```bash + npm pkg set contributors[0].name='Foo' contributors[0].email='foo@bar.ca' + ``` + + You may also append items to the end of an array using the special + empty bracket notation: + + ```bash + npm pkg set contributors[].name='Foo' contributors[].name='Bar' + ``` + + It's also possible to parse values as json prior to saving them to your + `package.json` file, for example in order to set a `"private": true` + property: + + ```bash + npm pkg set private=true --json + ``` + + It also enables saving values as numbers: + + ```bash + npm pkg set tap.timeout=60 --json + ``` + +* `npm pkg delete ` + + Deletes a `key` from your `package.json` + + The same syntax used to set values from your package can also be used + to remove existing ones. For example, in order to remove a script named + build: + + ```bash + npm pkg delete scripts.build + ``` + +### Workspaces support + +You can set/get/delete items across your configured workspaces by using the +`workspace` or `workspaces` config options. + +For example, setting a `funding` value across all configured workspaces +of a project: + +```bash +npm pkg set funding=https://example.com --ws +``` + +When using `npm pkg get` to retrieve info from your configured workspaces, the +returned result will be in a json format in which top level keys are the +names of each workspace, the values of these keys will be the result values +returned from each of the configured workspaces, e.g: + +``` +npm pkg get name version --ws +{ + "a": { + "name": "a", + "version": "1.0.0" + }, + "b": { + "name": "b", + "version": "1.0.0" + } +} +``` + +### Configuration + + + +#### `force` + +* Default: false +* Type: Boolean + +Removes various protections against unfortunate side effects, common +mistakes, unnecessary performance degradation, and malicious input. + +* Allow clobbering non-npm files in global installs. +* Allow the `npm version` command to work on an unclean git repository. +* Allow deleting the cache folder with `npm cache clean`. +* Allow installing packages that have an `engines` declaration requiring a + different version of npm. +* Allow installing packages that have an `engines` declaration requiring a + different version of `node`, even if `--engine-strict` is enabled. +* Allow `npm audit fix` to install modules outside your stated dependency + range (including SemVer-major changes). +* Allow unpublishing all versions of a published package. +* Allow conflicting peerDependencies to be installed in the root project. +* Implicitly set `--yes` during `npm init`. +* Allow clobbering existing values in `npm pkg` + +If you don't have a clear idea of what you want to do, it is strongly +recommended that you do not use this option! + +#### `json` + +* Default: false +* Type: Boolean + +Whether or not to output JSON data, rather than the normal output. + +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + +Not supported by all npm commands. + +#### `workspace` + +* Default: +* Type: String (can be set multiple times) + +Enable running a command in the context of the configured workspaces of the +current project while filtering by running only the workspaces defined by +this configuration option. + +Valid values for the `workspace` config are either: + +* Workspace names +* Path to a workspace directory +* Path to a parent workspace directory (will result to selecting all of the + nested workspaces) + +When set for the `npm init` command, this may be set to the folder of a +workspace which does not yet exist, to create the folder and set it up as a +brand new workspace within the project. + +This value is not exported to the environment for child processes. + +#### `workspaces` + +* Default: false +* Type: Boolean + +Enable running a command in the context of **all** the configured +workspaces. + +This value is not exported to the environment for child processes. + + +## See Also + +* [npm install](/commands/npm-install) +* [npm init](/commands/npm-init) +* [npm config](/commands/npm-config) +* [npm set-script](/commands/npm-set-script) +* [workspaces](/using-npm/workspaces) diff --git a/deps/npm/docs/content/commands/npm-profile.md b/deps/npm/docs/content/commands/npm-profile.md index 63aa46540d32d5..079440d7858153 100644 --- a/deps/npm/docs/content/commands/npm-profile.md +++ b/deps/npm/docs/content/commands/npm-profile.md @@ -91,6 +91,9 @@ The base URL of the npm registry. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `parseable` diff --git a/deps/npm/docs/content/commands/npm-prune.md b/deps/npm/docs/content/commands/npm-prune.md index ecb6bdcd6cb148..d9b5b068f7a4b3 100644 --- a/deps/npm/docs/content/commands/npm-prune.md +++ b/deps/npm/docs/content/commands/npm-prune.md @@ -75,6 +75,9 @@ Note: This is NOT honored by other network related commands, eg `dist-tags`, Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `workspace` diff --git a/deps/npm/docs/content/commands/npm-search.md b/deps/npm/docs/content/commands/npm-search.md index 08c955e64b5554..e30287635b56f6 100644 --- a/deps/npm/docs/content/commands/npm-search.md +++ b/deps/npm/docs/content/commands/npm-search.md @@ -55,6 +55,9 @@ Show extended information in `ls`, `search`, and `help-search`. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `color` diff --git a/deps/npm/docs/content/commands/npm-team.md b/deps/npm/docs/content/commands/npm-team.md index 31b09c7ce22b75..c7d5defcc63c1d 100644 --- a/deps/npm/docs/content/commands/npm-team.md +++ b/deps/npm/docs/content/commands/npm-team.md @@ -138,6 +138,9 @@ Output parseable results from commands that write to standard output. For Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. diff --git a/deps/npm/docs/content/commands/npm-unpublish.md b/deps/npm/docs/content/commands/npm-unpublish.md index bc8fbc7a53b3d4..82779ab65938c9 100644 --- a/deps/npm/docs/content/commands/npm-unpublish.md +++ b/deps/npm/docs/content/commands/npm-unpublish.md @@ -82,6 +82,7 @@ mistakes, unnecessary performance degradation, and malicious input. * Allow unpublishing all versions of a published package. * Allow conflicting peerDependencies to be installed in the root project. * Implicitly set `--yes` during `npm init`. +* Allow clobbering existing values in `npm pkg` If you don't have a clear idea of what you want to do, it is strongly recommended that you do not use this option! diff --git a/deps/npm/docs/content/commands/npm-update.md b/deps/npm/docs/content/commands/npm-update.md index 4c9271c6633c3a..c4f7694e19a81d 100644 --- a/deps/npm/docs/content/commands/npm-update.md +++ b/deps/npm/docs/content/commands/npm-update.md @@ -15,7 +15,9 @@ aliases: up, upgrade ### Description This command will update all the packages listed to the latest version -(specified by the `tag` config), respecting semver. +(specified by the `tag` config), respecting the semver constraints of +both your package and its dependencies (if they also require the same +package). It will also install missing packages. @@ -101,6 +103,39 @@ Then `npm update` will install `dep1@0.4.1`, because that is the highest-sorting version that satisfies `^0.4.0` (`>= 0.4.0 <0.5.0`) +#### Subdependencies + +Suppose your app now also has a dependency on `dep2` + +```json +{ + "name": "my-app", + "dependencies": { + "dep1": "^1.0.0", + "dep2": "1.0.0" + } +} +``` + +and `dep2` itself depends on this limited range of `dep1` + +```json +{ +"name": "dep2", + "dependencies": { + "dep1": "~1.1.1" + } +} +``` + +Then `npm update` will install `dep1@1.1.2` because that is the highest +version that `dep2` allows. npm will prioritize having a single version +of `dep1` in your tree rather than two when that single version can +satisfy the semver requirements of multiple dependencies in your tree. +In this case if you really did need your package to use a newer version +you would need to use `npm install`. + + #### Updating Globally-Installed Packages `npm update -g` will apply the `update` action to each globally installed @@ -220,9 +255,10 @@ will *not* run any pre- or post-scripts. * Default: true * Type: Boolean -When "true" submit audit reports alongside `npm install` runs to the default -registry and all registries configured for scopes. See the documentation for -[`npm audit`](/commands/npm-audit) for details on what is submitted. +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. #### `bin-links` diff --git a/deps/npm/docs/content/commands/npm-version.md b/deps/npm/docs/content/commands/npm-version.md index d24207d1e7e341..a3e34153a06da8 100644 --- a/deps/npm/docs/content/commands/npm-version.md +++ b/deps/npm/docs/content/commands/npm-version.md @@ -47,6 +47,9 @@ Tag the commit when using the `npm version` command. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `preid` diff --git a/deps/npm/docs/content/commands/npm-view.md b/deps/npm/docs/content/commands/npm-view.md index 8cbd3267b4bf05..b3d5df86e34a40 100644 --- a/deps/npm/docs/content/commands/npm-view.md +++ b/deps/npm/docs/content/commands/npm-view.md @@ -49,7 +49,7 @@ npm view opts@$(npm view ronn dependencies.opts) For fields that are arrays, requesting a non-numeric field will return all of the values from the objects in the list. For example, to get all -the contributor names for the `express` package, you would run: +the contributor email addresses for the `express` package, you would run: ```bash npm view express contributors.email @@ -105,6 +105,9 @@ npm view connect versions Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `workspace` diff --git a/deps/npm/docs/content/configuring-npm/folders.md b/deps/npm/docs/content/configuring-npm/folders.md index 75e31cd733161f..218870765b2625 100644 --- a/deps/npm/docs/content/configuring-npm/folders.md +++ b/deps/npm/docs/content/configuring-npm/folders.md @@ -45,14 +45,16 @@ Global installs on Windows go to `{prefix}/node_modules` (that is, no Scoped packages are installed the same way, except they are grouped together in a sub-folder of the relevant `node_modules` folder with the name of that scope prefix by the @ symbol, e.g. `npm install @myorg/package` would place -the package in `{prefix}/node_modules/@myorg/package`. See [`scope`](/using-npm/scope) for more details. +the package in `{prefix}/node_modules/@myorg/package`. See +[`scope`](/using-npm/scope) for more details. If you wish to `require()` a package, then install it locally. #### Executables When in global mode, executables are linked into `{prefix}/bin` on Unix, -or directly into `{prefix}` on Windows. +or directly into `{prefix}` on Windows. Ensure that path is in your +terminal's `PATH` environment to run them. When in local mode, executables are linked into `./node_modules/.bin` so that they can be made available to scripts run diff --git a/deps/npm/docs/content/configuring-npm/package-json.md b/deps/npm/docs/content/configuring-npm/package-json.md index 5cacf68ba175f9..0fc5dc5075ee3c 100644 --- a/deps/npm/docs/content/configuring-npm/package-json.md +++ b/deps/npm/docs/content/configuring-npm/package-json.md @@ -341,9 +341,12 @@ install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the "npm" executable.) To use this, supply a `bin` field in your package.json which is a map of -command name to local file name. On install, npm will symlink that file -into `prefix/bin` for global installs, or `./node_modules/.bin/` for local -installs. +command name to local file name. When this package is installed +globally, that file will be linked where global bins go so it is +available to run by name. When this package is installed as a +dependency in another package, the file will be linked where it will be +available to that package either directly by `npm exec` or by name in other +scripts when invoking them via `npm run-script`. For example, myapp could have this: @@ -388,6 +391,9 @@ executable! Note that you can also set the executable files using [directories.bin](#directoriesbin). +See [folders](/configuring-npm/folders#executables) for more info on +executables. + ### man Specify either a single file or an array of filenames to put in place for diff --git a/deps/npm/docs/content/using-npm/config.md b/deps/npm/docs/content/using-npm/config.md index 1036895101fcc1..c4d1afed35cc8b 100644 --- a/deps/npm/docs/content/using-npm/config.md +++ b/deps/npm/docs/content/using-npm/config.md @@ -67,6 +67,7 @@ The following shorthands are parsed on the command-line: * `--desc`: `--description` * `-f`: `--force` * `-g`: `--global` +* `-L`: `--location` * `-d`: `--loglevel info` * `-s`: `--loglevel silent` * `--silent`: `--loglevel silent` @@ -170,9 +171,10 @@ to the same value as the current version. * Default: true * Type: Boolean -When "true" submit audit reports alongside `npm install` runs to the default -registry and all registries configured for scopes. See the documentation for -[`npm audit`](/commands/npm-audit) for details on what is submitted. +When "true" submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for [`npm audit`](/commands/npm-audit) for details on what is +submitted. #### `audit-level` @@ -495,6 +497,7 @@ mistakes, unnecessary performance degradation, and malicious input. * Allow unpublishing all versions of a published package. * Allow conflicting peerDependencies to be installed in the root project. * Implicitly set `--yes` during `npm init`. +* Allow clobbering existing values in `npm pkg` If you don't have a clear idea of what you want to do, it is strongly recommended that you do not use this option! @@ -694,6 +697,9 @@ number, if not already set in package.json. Whether or not to output JSON data, rather than the normal output. +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + Not supported by all npm commands. #### `key` @@ -753,6 +759,14 @@ Used with `npm ls`, limiting output to only those packages that are linked. The IP address of the local interface to use when making connections to the npm registry. Must be IPv4 in versions of Node prior to 0.12. +#### `location` + +* Default: "user" unless `--global` is passed, which will also set this value + to "global" +* Type: "global", "user", or "project" + +When passed to `npm config` this refers to which config file to use. + #### `loglevel` * Default: "notice" diff --git a/deps/npm/docs/content/using-npm/scripts.md b/deps/npm/docs/content/using-npm/scripts.md index 8df9660ca8f4cd..8fd5c5c0dbc9d8 100644 --- a/deps/npm/docs/content/using-npm/scripts.md +++ b/deps/npm/docs/content/using-npm/scripts.md @@ -54,7 +54,8 @@ situations. These scripts happen in addition to the `pre`, `post`, the prepare script will be run, before the package is packaged and installed. -* As of `npm@7` these scripts run in the background +* As of `npm@7` these scripts run in the background. + To see the output, run with: `--foreground-scripts`. **prepublish** (DEPRECATED) * Does not run during `npm publish`, but does run during `npm ci` @@ -303,8 +304,8 @@ Scripts are run by passing the line as a script argument to `sh`. If the script exits with a code other than 0, then this will abort the process. -Note that these script files don't have to be nodejs or even -javascript programs. They just have to be some kind of executable +Note that these script files don't have to be Node.js or even +JavaScript programs. They just have to be some kind of executable file. ### Best Practices diff --git a/deps/npm/docs/content/using-npm/workspaces.md b/deps/npm/docs/content/using-npm/workspaces.md index 829168864abe45..7cc125b3c7a7cc 100644 --- a/deps/npm/docs/content/using-npm/workspaces.md +++ b/deps/npm/docs/content/using-npm/workspaces.md @@ -37,7 +37,7 @@ Workspaces are usually defined via the `workspaces` property of the Given the above `package.json` example living at a current working directory `.` that contains a folder named `workspace-a` that itself contains -a `package.json` inside it, defining a nodejs package, e.g: +a `package.json` inside it, defining a Node.js package, e.g: ``` . diff --git a/deps/npm/docs/output/commands/npm-audit.html b/deps/npm/docs/output/commands/npm-audit.html index a1c58d89633742..5cffb546dc721c 100644 --- a/deps/npm/docs/output/commands/npm-audit.html +++ b/deps/npm/docs/output/commands/npm-audit.html @@ -309,6 +309,7 @@

force

  • Allow unpublishing all versions of a published package.
  • Allow conflicting peerDependencies to be installed in the root project.
  • Implicitly set --yes during npm init.
  • +
  • Allow clobbering existing values in npm pkg
  • If you don’t have a clear idea of what you want to do, it is strongly recommended that you do not use this option!

    @@ -318,6 +319,10 @@

    json

  • Type: Boolean
  • Whether or not to output JSON data, rather than the normal output.

    +
      +
    • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
    • +

    Not supported by all npm commands.

    package-lock-only

      diff --git a/deps/npm/docs/output/commands/npm-ci.html b/deps/npm/docs/output/commands/npm-ci.html index 82049f7287d04a..9f5c85b36374da 100644 --- a/deps/npm/docs/output/commands/npm-ci.html +++ b/deps/npm/docs/output/commands/npm-ci.html @@ -141,7 +141,7 @@

      npm-ci

      Table of contents

      - +

      Synopsis

      @@ -193,6 +193,15 @@

      Example

      Configuration

      +

      audit

      +
        +
      • Default: true
      • +
      • Type: Boolean
      • +
      +

      When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

      ignore-scripts

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      global

        @@ -228,6 +232,13 @@

        editor

      • Type: String

      The command to run for npm edit and npm config edit.

      +

      location

      +
        +
      • Default: “user” unless --global is passed, which will also set this value +to “global”
      • +
      • Type: “global”, “user”, or “project”
      • +
      +

      When passed to npm config this refers to which config file to use.

      long

      • Default: false
      • diff --git a/deps/npm/docs/output/commands/npm-dedupe.html b/deps/npm/docs/output/commands/npm-dedupe.html index c1fe98aeead67b..9de232141e17a2 100644 --- a/deps/npm/docs/output/commands/npm-dedupe.html +++ b/deps/npm/docs/output/commands/npm-dedupe.html @@ -269,9 +269,10 @@

        audit

      • Default: true
      • Type: Boolean
      -

      When “true” submit audit reports alongside npm install runs to the default -registry and all registries configured for scopes. See the documentation for -npm audit for details on what is submitted.

      +

      When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

      • Default: true
      • diff --git a/deps/npm/docs/output/commands/npm-explain.html b/deps/npm/docs/output/commands/npm-explain.html index 1c3afda5a1632f..decfd4d556e6e3 100644 --- a/deps/npm/docs/output/commands/npm-explain.html +++ b/deps/npm/docs/output/commands/npm-explain.html @@ -190,6 +190,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      workspace

        diff --git a/deps/npm/docs/output/commands/npm-find-dupes.html b/deps/npm/docs/output/commands/npm-find-dupes.html index d727f561dfefca..9f6c4de7857077 100644 --- a/deps/npm/docs/output/commands/npm-find-dupes.html +++ b/deps/npm/docs/output/commands/npm-find-dupes.html @@ -228,9 +228,10 @@

        audit

      • Default: true
      • Type: Boolean
      -

      When “true” submit audit reports alongside npm install runs to the default -registry and all registries configured for scopes. See the documentation for -npm audit for details on what is submitted.

      +

      When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

      • Default: true
      • diff --git a/deps/npm/docs/output/commands/npm-fund.html b/deps/npm/docs/output/commands/npm-fund.html index a37ff56e145118..074ac10573592e 100644 --- a/deps/npm/docs/output/commands/npm-fund.html +++ b/deps/npm/docs/output/commands/npm-fund.html @@ -195,6 +195,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      browser

        diff --git a/deps/npm/docs/output/commands/npm-init.html b/deps/npm/docs/output/commands/npm-init.html index 79538c36ace191..eaa5dfe0f72c88 100644 --- a/deps/npm/docs/output/commands/npm-init.html +++ b/deps/npm/docs/output/commands/npm-init.html @@ -273,6 +273,7 @@

        force

      • Allow unpublishing all versions of a published package.
      • Allow conflicting peerDependencies to be installed in the root project.
      • Implicitly set --yes during npm init.
      • +
      • Allow clobbering existing values in npm pkg

      If you don’t have a clear idea of what you want to do, it is strongly recommended that you do not use this option!

      diff --git a/deps/npm/docs/output/commands/npm-install-ci-test.html b/deps/npm/docs/output/commands/npm-install-ci-test.html index 3982ad2da20f19..d7414ff56cf904 100644 --- a/deps/npm/docs/output/commands/npm-install-ci-test.html +++ b/deps/npm/docs/output/commands/npm-install-ci-test.html @@ -141,7 +141,7 @@

      npm-install-ci-test

      Table of contents

      - +

      Synopsis

      @@ -154,6 +154,15 @@

      Description

      Configuration

      +

      audit

      +
        +
      • Default: true
      • +
      • Type: Boolean
      • +
      +

      When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

      ignore-scripts

      • Default: false
      • diff --git a/deps/npm/docs/output/commands/npm-install-test.html b/deps/npm/docs/output/commands/npm-install-test.html index be781628967ce0..d2f536e5d811c6 100644 --- a/deps/npm/docs/output/commands/npm-install-test.html +++ b/deps/npm/docs/output/commands/npm-install-test.html @@ -267,9 +267,10 @@

        audit

      • Default: true
      • Type: Boolean
      -

      When “true” submit audit reports alongside npm install runs to the default -registry and all registries configured for scopes. See the documentation for -npm audit for details on what is submitted.

      +

      When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

      • Default: true
      • diff --git a/deps/npm/docs/output/commands/npm-install.html b/deps/npm/docs/output/commands/npm-install.html index a081c98e1b263c..cebc5ac780edd4 100644 --- a/deps/npm/docs/output/commands/npm-install.html +++ b/deps/npm/docs/output/commands/npm-install.html @@ -589,9 +589,10 @@

        audit

      • Default: true
      • Type: Boolean
      -

      When “true” submit audit reports alongside npm install runs to the default -registry and all registries configured for scopes. See the documentation for -npm audit for details on what is submitted.

      +

      When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

      • Default: true
      • diff --git a/deps/npm/docs/output/commands/npm-link.html b/deps/npm/docs/output/commands/npm-link.html index d558cb9d0a535b..6ac2699867e6d2 100644 --- a/deps/npm/docs/output/commands/npm-link.html +++ b/deps/npm/docs/output/commands/npm-link.html @@ -323,9 +323,10 @@

        audit

      • Default: true
      • Type: Boolean
      -

      When “true” submit audit reports alongside npm install runs to the default -registry and all registries configured for scopes. See the documentation for -npm audit for details on what is submitted.

      +

      When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

      • Default: true
      • diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index e79b119cee8bab..324980536dc102 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -159,7 +159,7 @@

        Description

        the results to only the paths to the packages named. Note that nested packages will also show the paths to the specified packages. For example, running npm ls promzard in npm’s source tree will show:

        -
        npm@7.19.1 /path/to/npm
        +
        npm@7.20.3 /path/to/npm
         └─┬ init-package-json@0.0.4
           └── promzard@0.1.5
         
        @@ -208,6 +208,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      long

        diff --git a/deps/npm/docs/output/commands/npm-org.html b/deps/npm/docs/output/commands/npm-org.html index 3b6df5123f9e23..b9b976f05f9ef6 100644 --- a/deps/npm/docs/output/commands/npm-org.html +++ b/deps/npm/docs/output/commands/npm-org.html @@ -197,6 +197,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      parseable

        diff --git a/deps/npm/docs/output/commands/npm-outdated.html b/deps/npm/docs/output/commands/npm-outdated.html index 3a45257b3d1065..2584460fe6b9dc 100644 --- a/deps/npm/docs/output/commands/npm-outdated.html +++ b/deps/npm/docs/output/commands/npm-outdated.html @@ -230,6 +230,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      long

        diff --git a/deps/npm/docs/output/commands/npm-pack.html b/deps/npm/docs/output/commands/npm-pack.html index 622d88306cadc4..a569ff799aab1d 100644 --- a/deps/npm/docs/output/commands/npm-pack.html +++ b/deps/npm/docs/output/commands/npm-pack.html @@ -167,6 +167,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      pack-destination

        diff --git a/deps/npm/docs/output/commands/npm-pkg.html b/deps/npm/docs/output/commands/npm-pkg.html new file mode 100644 index 00000000000000..1f8a86e76e5725 --- /dev/null +++ b/deps/npm/docs/output/commands/npm-pkg.html @@ -0,0 +1,343 @@ + +npm-pkg + + + + + +
        +
        +

        npm-pkg

        +Manages your package.json +
        + +
        +

        Table of contents

        + +
        + +

        Synopsis

        +
        npm pkg get [<field> [.<subfield> ...]]
        +npm pkg set <field>=<value> [.<subfield>=<value> ...]
        +npm pkg delete <field> [.<subfield> ...]
        +
        +

        Description

        +

        A command that automates the management of package.json files. +npm pkg provide 3 different sub commands that allow you to modify or retrieve +values for given object keys in your packge.json.

        +

        The syntax to retrieve and set fields is a dot separated representation of +the nested object properties to be found within your package.json, it’s the +same notation used in npm view to retrieve information +from the registry manifest, below you can find more examples on how to use it.

        +

        Returned values are always in json format.

        +
          +
        • +

          npm pkg get <field>

          +

          Retrieves a value key, defined in your package.json file.

          +

          For example, in order to retrieve the name of the current package, you +can run:

          +
          npm pkg get name
          +
          +

          It’s also possible to retrieve multiple values at once:

          +
          npm pkg get name version
          +
          +

          You can view child fields by separating them with a period. To retrieve +the value of a test script value, you would run the following command:

          +
          npm pkg get scripts.test
          +
          +

          For fields that are arrays, requesting a non-numeric field will return +all of the values from the objects in the list. For example, to get all +the contributor emails for a package, you would run:

          +
          npm pkg get contributors.email
          +
          +

          You may also use numeric indices in square braces to specifically select +an item in an array field. To just get the email address of the first +contributor in the list, you can run:

          +
          npm pkg get contributors[0].email
          +
          +
        • +
        • +

          npm pkg set <field>=<value>

          +

          Sets a value in your package.json based on the field value. When +saving to your package.json file the same set of rules used during +npm install and other cli commands that touches the package.json file +are used, making sure to respect the existing indentation and possibly +applying some validation prior to saving values to the file.

          +

          The same syntax used to retrieve values from your package can also be used +to define new properties or overriding existing ones, below are some +examples of how the dot separated syntax can be used to edit your +package.json file.

          +

          Defining a new bin named mynewcommand in your package.json that points +to a file cli.js:

          +
          npm pkg set bin.mynewcommand=cli.js
          +
          +

          Setting multiple fields at once is also possible:

          +
          npm pkg set description='Awesome package' engines.node='>=10'
          +
          +

          It’s also possible to add to array values, for example to add a new +contributor entry:

          +
          npm pkg set contributors[0].name='Foo' contributors[0].email='foo@bar.ca'
          +
          +

          You may also append items to the end of an array using the special +empty bracket notation:

          +
          npm pkg set contributors[].name='Foo' contributors[].name='Bar'
          +
          +

          It’s also possible to parse values as json prior to saving them to your +package.json file, for example in order to set a "private": true +property:

          +
          npm pkg set private=true --json
          +
          +

          It also enables saving values as numbers:

          +
          npm pkg set tap.timeout=60 --json
          +
          +
        • +
        • +

          npm pkg delete <key>

          +

          Deletes a key from your package.json

          +

          The same syntax used to set values from your package can also be used +to remove existing ones. For example, in order to remove a script named +build:

          +
          npm pkg delete scripts.build
          +
          +
        • +
        +

        Workspaces support

        +

        You can set/get/delete items across your configured workspaces by using the +workspace or workspaces config options.

        +

        For example, setting a funding value across all configured workspaces +of a project:

        +
        npm pkg set funding=https://example.com --ws
        +
        +

        When using npm pkg get to retrieve info from your configured workspaces, the +returned result will be in a json format in which top level keys are the +names of each workspace, the values of these keys will be the result values +returned from each of the configured workspaces, e.g:

        +
        npm pkg get name version --ws
        +{
        +  "a": {
        +    "name": "a",
        +    "version": "1.0.0"
        +  },
        +  "b": {
        +    "name": "b",
        +    "version": "1.0.0"
        +  }
        +}
        +
        +

        Configuration

        + + +

        force

        +
          +
        • Default: false
        • +
        • Type: Boolean
        • +
        +

        Removes various protections against unfortunate side effects, common +mistakes, unnecessary performance degradation, and malicious input.

        +
          +
        • Allow clobbering non-npm files in global installs.
        • +
        • Allow the npm version command to work on an unclean git repository.
        • +
        • Allow deleting the cache folder with npm cache clean.
        • +
        • Allow installing packages that have an engines declaration requiring a +different version of npm.
        • +
        • Allow installing packages that have an engines declaration requiring a +different version of node, even if --engine-strict is enabled.
        • +
        • Allow npm audit fix to install modules outside your stated dependency +range (including SemVer-major changes).
        • +
        • Allow unpublishing all versions of a published package.
        • +
        • Allow conflicting peerDependencies to be installed in the root project.
        • +
        • Implicitly set --yes during npm init.
        • +
        • Allow clobbering existing values in npm pkg
        • +
        +

        If you don’t have a clear idea of what you want to do, it is strongly +recommended that you do not use this option!

        +

        json

        +
          +
        • Default: false
        • +
        • Type: Boolean
        • +
        +

        Whether or not to output JSON data, rather than the normal output.

        +
          +
        • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
        • +
        +

        Not supported by all npm commands.

        +

        workspace

        +
          +
        • Default:
        • +
        • Type: String (can be set multiple times)
        • +
        +

        Enable running a command in the context of the configured workspaces of the +current project while filtering by running only the workspaces defined by +this configuration option.

        +

        Valid values for the workspace config are either:

        +
          +
        • Workspace names
        • +
        • Path to a workspace directory
        • +
        • Path to a parent workspace directory (will result to selecting all of the +nested workspaces)
        • +
        +

        When set for the npm init command, this may be set to the folder of a +workspace which does not yet exist, to create the folder and set it up as a +brand new workspace within the project.

        +

        This value is not exported to the environment for child processes.

        +

        workspaces

        +
          +
        • Default: false
        • +
        • Type: Boolean
        • +
        +

        Enable running a command in the context of all the configured +workspaces.

        +

        This value is not exported to the environment for child processes.

        + +

        See Also

        + +
        + + +
        + + + + \ No newline at end of file diff --git a/deps/npm/docs/output/commands/npm-profile.html b/deps/npm/docs/output/commands/npm-profile.html index 3f79af93ea3c8c..0c24fffead70d8 100644 --- a/deps/npm/docs/output/commands/npm-profile.html +++ b/deps/npm/docs/output/commands/npm-profile.html @@ -227,6 +227,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      parseable

        diff --git a/deps/npm/docs/output/commands/npm-prune.html b/deps/npm/docs/output/commands/npm-prune.html index 6011d914b0034e..2dcfe0e1ce5483 100644 --- a/deps/npm/docs/output/commands/npm-prune.html +++ b/deps/npm/docs/output/commands/npm-prune.html @@ -197,6 +197,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      workspace

        diff --git a/deps/npm/docs/output/commands/npm-search.html b/deps/npm/docs/output/commands/npm-search.html index e3bcffc665ff11..634229987f2c6f 100644 --- a/deps/npm/docs/output/commands/npm-search.html +++ b/deps/npm/docs/output/commands/npm-search.html @@ -183,6 +183,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      color

        diff --git a/deps/npm/docs/output/commands/npm-team.html b/deps/npm/docs/output/commands/npm-team.html index 5f848d566380b9..3e0d06db228fa9 100644 --- a/deps/npm/docs/output/commands/npm-team.html +++ b/deps/npm/docs/output/commands/npm-team.html @@ -247,6 +247,10 @@

        json

      • Type: Boolean

      Whether or not to output JSON data, rather than the normal output.

      +
        +
      • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
      • +

      Not supported by all npm commands.

      See Also

      diff --git a/deps/npm/docs/output/commands/npm-unpublish.html b/deps/npm/docs/output/commands/npm-unpublish.html index 59beb148dfd484..3d330e9db5fd06 100644 --- a/deps/npm/docs/output/commands/npm-unpublish.html +++ b/deps/npm/docs/output/commands/npm-unpublish.html @@ -202,6 +202,7 @@

      force

    • Allow unpublishing all versions of a published package.
    • Allow conflicting peerDependencies to be installed in the root project.
    • Implicitly set --yes during npm init.
    • +
    • Allow clobbering existing values in npm pkg

    If you don’t have a clear idea of what you want to do, it is strongly recommended that you do not use this option!

    diff --git a/deps/npm/docs/output/commands/npm-update.html b/deps/npm/docs/output/commands/npm-update.html index 044345ab35e63f..f2491347aee66f 100644 --- a/deps/npm/docs/output/commands/npm-update.html +++ b/deps/npm/docs/output/commands/npm-update.html @@ -141,7 +141,7 @@

    npm-update

    Table of contents

    - +

    Synopsis

    @@ -151,7 +151,9 @@

    Table of contents

    Description

    This command will update all the packages listed to the latest version -(specified by the tag config), respecting semver.

    +(specified by the tag config), respecting the semver constraints of +both your package and its dependencies (if they also require the same +package).

    It will also install missing packages.

    If the -g flag is specified, this command will update globally installed packages.

    @@ -209,6 +211,30 @@

    Caret Dependencies below 1.0.0

    Then npm update will install dep1@0.4.1, because that is the highest-sorting version that satisfies ^0.4.0 (>= 0.4.0 <0.5.0)

    +

    Subdependencies

    +

    Suppose your app now also has a dependency on dep2

    +
    {
    +  "name": "my-app",
    +  "dependencies": {
    +      "dep1": "^1.0.0",
    +      "dep2": "1.0.0"
    +  }
    +}
    +
    +

    and dep2 itself depends on this limited range of dep1

    +
    {
    +"name": "dep2",
    +  "dependencies": {
    +    "dep1": "~1.1.1"
    +  }
    +}
    +
    +

    Then npm update will install dep1@1.1.2 because that is the highest +version that dep2 allows. npm will prioritize having a single version +of dep1 in your tree rather than two when that single version can +satisfy the semver requirements of multiple dependencies in your tree. +In this case if you really did need your package to use a newer version +you would need to use npm install.

    Updating Globally-Installed Packages

    npm update -g will apply the update action to each globally installed package that is outdated – that is, has a version that is different from @@ -310,9 +336,10 @@

    audit

  • Default: true
  • Type: Boolean
  • -

    When “true” submit audit reports alongside npm install runs to the default -registry and all registries configured for scopes. See the documentation for -npm audit for details on what is submitted.

    +

    When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

    • Default: true
    • diff --git a/deps/npm/docs/output/commands/npm-version.html b/deps/npm/docs/output/commands/npm-version.html index 1889060401bb77..c81569608d55c9 100644 --- a/deps/npm/docs/output/commands/npm-version.html +++ b/deps/npm/docs/output/commands/npm-version.html @@ -179,6 +179,10 @@

      json

    • Type: Boolean

    Whether or not to output JSON data, rather than the normal output.

    +
      +
    • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
    • +

    Not supported by all npm commands.

    preid

      diff --git a/deps/npm/docs/output/commands/npm-view.html b/deps/npm/docs/output/commands/npm-view.html index 54400bd44e87c7..1a0eba4c1431fe 100644 --- a/deps/npm/docs/output/commands/npm-view.html +++ b/deps/npm/docs/output/commands/npm-view.html @@ -171,7 +171,7 @@

      Description

      For fields that are arrays, requesting a non-numeric field will return all of the values from the objects in the list. For example, to get all -the contributor names for the express package, you would run:

      +the contributor email addresses for the express package, you would run:

      npm view express contributors.email
       

      You may also use numeric indices in square braces to specifically select @@ -207,6 +207,10 @@

      json

    • Type: Boolean

    Whether or not to output JSON data, rather than the normal output.

    +
      +
    • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
    • +

    Not supported by all npm commands.

    workspace

    -

    When “true” submit audit reports alongside npm install runs to the default -registry and all registries configured for scopes. See the documentation for -npm audit for details on what is submitted.

    +

    When “true” submit audit reports alongside the current npm command to the +default registry and all registries configured for scopes. See the +documentation for npm audit for details on what is +submitted.

    audit-level

    • Default: null
    • @@ -554,6 +556,7 @@

      force

    • Allow unpublishing all versions of a published package.
    • Allow conflicting peerDependencies to be installed in the root project.
    • Implicitly set --yes during npm init.
    • +
    • Allow clobbering existing values in npm pkg

    If you don’t have a clear idea of what you want to do, it is strongly recommended that you do not use this option!

    @@ -726,6 +729,10 @@

    json

  • Type: Boolean
  • Whether or not to output JSON data, rather than the normal output.

    +
      +
    • In npm pkg set it enables parsing set values with JSON.parse() before +saving them to your package.json.
    • +

    Not supported by all npm commands.

    key

      @@ -773,6 +780,13 @@

      local-address

    The IP address of the local interface to use when making connections to the npm registry. Must be IPv4 in versions of Node prior to 0.12.

    +

    location

    +
      +
    • Default: “user” unless --global is passed, which will also set this value +to “global”
    • +
    • Type: “global”, “user”, or “project”
    • +
    +

    When passed to npm config this refers to which config file to use.

    loglevel

    • Default: “notice”
    • diff --git a/deps/npm/docs/output/using-npm/scripts.html b/deps/npm/docs/output/using-npm/scripts.html index 320fcb248ced12..9b1a2e322e3621 100644 --- a/deps/npm/docs/output/using-npm/scripts.html +++ b/deps/npm/docs/output/using-npm/scripts.html @@ -198,7 +198,8 @@

      Life Cycle Scripts

      installed.

    • -

      As of npm@7 these scripts run in the background

      +

      As of npm@7 these scripts run in the background. +To see the output, run with: --foreground-scripts.

    prepublish (DEPRECATED)

    @@ -408,8 +409,8 @@

    Exiting

    Scripts are run by passing the line as a script argument to sh.

    If the script exits with a code other than 0, then this will abort the process.

    -

    Note that these script files don’t have to be nodejs or even -javascript programs. They just have to be some kind of executable +

    Note that these script files don’t have to be Node.js or even +JavaScript programs. They just have to be some kind of executable file.

    Best Practices

      diff --git a/deps/npm/docs/output/using-npm/workspaces.html b/deps/npm/docs/output/using-npm/workspaces.html index 55bdb32ec460d8..f0a5945d61153e 100644 --- a/deps/npm/docs/output/using-npm/workspaces.html +++ b/deps/npm/docs/output/using-npm/workspaces.html @@ -169,7 +169,7 @@

      Defining workspaces

      Given the above package.json example living at a current working directory . that contains a folder named workspace-a that itself contains -a package.json inside it, defining a nodejs package, e.g:

      +a package.json inside it, defining a Node.js package, e.g:

      .
       +-- package.json
       `-- workspace-a
      diff --git a/deps/npm/lib/base-command.js b/deps/npm/lib/base-command.js
      index 4077733a934b07..870c69acc492d7 100644
      --- a/deps/npm/lib/base-command.js
      +++ b/deps/npm/lib/base-command.js
      @@ -75,7 +75,6 @@ class BaseCommand {
         }
       
         async setWorkspaces (filters) {
      -    // TODO npm guards workspaces/global mode so we should use this.npm.prefix?
           const ws = await getWorkspaces(filters, { path: this.npm.localPrefix })
           this.workspaces = ws
           this.workspaceNames = [...ws.keys()]
      diff --git a/deps/npm/lib/ci.js b/deps/npm/lib/ci.js
      index 3ff4b65badb49f..6634ffcdc19bcb 100644
      --- a/deps/npm/lib/ci.js
      +++ b/deps/npm/lib/ci.js
      @@ -33,6 +33,7 @@ class CI extends ArboristWorkspaceCmd {
         /* istanbul ignore next - see test/lib/load-all-commands.js */
         static get params () {
           return [
      +      'audit',
             'ignore-scripts',
             'script-shell',
           ]
      diff --git a/deps/npm/lib/config.js b/deps/npm/lib/config.js
      index d1585f414dca89..a56dd92ffbde6a 100644
      --- a/deps/npm/lib/config.js
      +++ b/deps/npm/lib/config.js
      @@ -56,6 +56,7 @@ class Config extends BaseCommand {
             'json',
             'global',
             'editor',
      +      'location',
             'long',
           ]
         }
      @@ -137,7 +138,7 @@ class Config extends BaseCommand {
           if (!args.length)
             throw this.usageError()
       
      -    const where = this.npm.config.get('global') ? 'global' : 'user'
      +    const where = this.npm.config.get('location')
           for (const [key, val] of Object.entries(keyValues(args))) {
             this.npm.log.info('config', 'set %j %j', key, val)
             this.npm.config.set(key, val || '', where)
      @@ -167,16 +168,15 @@ class Config extends BaseCommand {
           if (!keys.length)
             throw this.usageError()
       
      -    const where = this.npm.config.get('global') ? 'global' : 'user'
      +    const where = this.npm.config.get('location')
           for (const key of keys)
             this.npm.config.delete(key, where)
           await this.npm.config.save(where)
         }
       
         async edit () {
      -    const global = this.npm.config.get('global')
           const e = this.npm.config.get('editor')
      -    const where = global ? 'global' : 'user'
      +    const where = this.npm.config.get('location')
           const file = this.npm.config.data.get(where).source
       
           // save first, just to make sure it's synced up
      diff --git a/deps/npm/lib/install-ci-test.js b/deps/npm/lib/install-ci-test.js
      index 0d408178b33f2d..871f24b2f32d6a 100644
      --- a/deps/npm/lib/install-ci-test.js
      +++ b/deps/npm/lib/install-ci-test.js
      @@ -13,14 +13,6 @@ class InstallCITest extends CI {
           return 'install-ci-test'
         }
       
      -  /* istanbul ignore next - see test/lib/load-all-commands.js */
      -  static get params () {
      -    return [
      -      'ignore-scripts',
      -      'script-shell',
      -    ]
      -  }
      -
         exec (args, cb) {
           this.npm.commands.ci(args, (er) => {
             if (er)
      diff --git a/deps/npm/lib/ls.js b/deps/npm/lib/ls.js
      index 7540692911976c..91e9a9dd3dba8d 100644
      --- a/deps/npm/lib/ls.js
      +++ b/deps/npm/lib/ls.js
      @@ -138,7 +138,7 @@ class LS extends ArboristWorkspaceCmd {
                 !(node instanceof Arborist.Node) || (currentDepth > depthToPrint)
               return (shouldSkipChildren)
                 ? []
      -          : [...(node.target || node).edgesOut.values()]
      +          : [...(node.target).edgesOut.values()]
                   .filter(filterBySelectedWorkspaces)
                   .filter(filterByEdgesTypes({
                     currentDepth,
      diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js
      index 7046a84d0bcfa2..db3559a384bd7e 100644
      --- a/deps/npm/lib/npm.js
      +++ b/deps/npm/lib/npm.js
      @@ -1,12 +1,7 @@
      -// The order of the code in this file is relevant, because a lot of things
      -// require('npm.js'), but also we need to use some of those modules.  So,
      -// we define and instantiate the singleton ahead of loading any modules
      -// required for its methods.
      -
      -// these are all dependencies used in the ctor
       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'))
      @@ -37,23 +32,51 @@ const proxyCmds = new Proxy({}, {
         },
       })
       
      +// 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')
       
      +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')
      +
       let warnedNonDashArg = false
       const _runCmd = Symbol('_runCmd')
       const _load = Symbol('_load')
       const _tmpFolder = Symbol('_tmpFolder')
       const _title = Symbol('_title')
      +
       const npm = module.exports = new class extends EventEmitter {
         constructor () {
           super()
      -    // TODO make this only ever load once (or unload) in tests
      -    require('./utils/perf.js')
           this.started = Date.now()
           this.command = null
           this.commands = proxyCmds
      +    this.timings = timings
      +    this.timers = timers
      +    this.perfStart()
           procLogListener()
           process.emit('time', 'npm')
           this.version = require('../package.json').version
      @@ -67,6 +90,16 @@ const npm = module.exports = new class extends EventEmitter {
           this.updateNotification = null
         }
       
      +  perfStart () {
      +    process.on('time', processOnTimeHandler)
      +    process.on('timeEnd', processOnTimeEndHandler)
      +  }
      +
      +  perfStop () {
      +    process.off('time', processOnTimeHandler)
      +    process.off('timeEnd', processOnTimeEndHandler)
      +  }
      +
         get shelloutCommands () {
           return shellouts
         }
      @@ -317,16 +350,5 @@ const npm = module.exports = new class extends EventEmitter {
         }
       }()
       
      -// now load everything required by the class methods
      -
      -const log = require('npmlog')
      -
      -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')
      -
       if (require.main === module)
         require('./cli.js')(process)
      diff --git a/deps/npm/lib/outdated.js b/deps/npm/lib/outdated.js
      index 9d60d143d71ce2..01e268fe96aee8 100644
      --- a/deps/npm/lib/outdated.js
      +++ b/deps/npm/lib/outdated.js
      @@ -158,7 +158,7 @@ class Outdated extends ArboristWorkspaceCmd {
             edge.from
               && this.filterSet
               && this.filterSet.size > 0
      -        && !this.filterSet.has(edge.from.target || edge.from)
      +        && !this.filterSet.has(edge.from.target)
       
           if (filteredOut)
             return
      diff --git a/deps/npm/lib/pkg.js b/deps/npm/lib/pkg.js
      new file mode 100644
      index 00000000000000..9ba92c930e1f0e
      --- /dev/null
      +++ b/deps/npm/lib/pkg.js
      @@ -0,0 +1,152 @@
      +const PackageJson = require('@npmcli/package-json')
      +const BaseCommand = require('./base-command.js')
      +const Queryable = require('./utils/queryable.js')
      +
      +class Pkg extends BaseCommand {
      +  static get description () {
      +    return 'Manages your package.json'
      +  }
      +
      +  /* istanbul ignore next - see test/lib/load-all-commands.js */
      +  static get name () {
      +    return 'pkg'
      +  }
      +
      +  /* istanbul ignore next - see test/lib/load-all-commands.js */
      +  static get usage () {
      +    return [
      +      'set = [= ...]',
      +      'get [ [ ...]]',
      +      'delete  [ ...]',
      +    ]
      +  }
      +
      +  /* istanbul ignore next - see test/lib/load-all-commands.js */
      +  static get params () {
      +    return [
      +      'force',
      +      'json',
      +      'workspace',
      +      'workspaces',
      +    ]
      +  }
      +
      +  exec (args, cb) {
      +    this.prefix = this.npm.localPrefix
      +    this.pkg(args).then(() => cb()).catch(cb)
      +  }
      +
      +  execWorkspaces (args, filters, cb) {
      +    this.pkgWorkspaces(args, filters).then(() => cb()).catch(cb)
      +  }
      +
      +  async pkg (args) {
      +    if (this.npm.config.get('global')) {
      +      throw Object.assign(
      +        new Error(`There's no package.json file to manage on global mode`),
      +        { code: 'EPKGGLOBAL' }
      +      )
      +    }
      +
      +    const [cmd, ..._args] = args
      +    switch (cmd) {
      +      case 'get':
      +        return this.get(_args)
      +      case 'set':
      +        return this.set(_args)
      +      case 'delete':
      +        return this.delete(_args)
      +      default:
      +        throw this.usageError()
      +    }
      +  }
      +
      +  async pkgWorkspaces (args, filters) {
      +    await this.setWorkspaces(filters)
      +    const result = {}
      +    for (const [workspaceName, workspacePath] of this.workspaces.entries()) {
      +      this.prefix = workspacePath
      +      result[workspaceName] = await this.pkg(args)
      +    }
      +    // when running in workspaces names, make sure to key by workspace
      +    // name the results of each value retrieved in each ws
      +    this.npm.output(JSON.stringify(result, null, 2))
      +  }
      +
      +  async get (args) {
      +    const pkgJson = await PackageJson.load(this.prefix)
      +
      +    const { content } = pkgJson
      +    let result = !args.length && content
      +
      +    if (!result) {
      +      const q = new Queryable(content)
      +      result = q.query(args)
      +
      +      // in case there's only a single result from the query
      +      // just prints that one element to stdout
      +      if (Object.keys(result).length === 1)
      +        result = result[args]
      +    }
      +
      +    // only outputs if not running with workspaces config,
      +    // in case you're retrieving info for workspaces the pkgWorkspaces
      +    // will handle the output to make sure it get keyed by ws name
      +    if (!this.workspaces)
      +      this.npm.output(JSON.stringify(result, null, 2))
      +
      +    return result
      +  }
      +
      +  async set (args) {
      +    const setError = () =>
      +      Object.assign(
      +        new TypeError('npm pkg set expects a key=value pair of args.'),
      +        { code: 'EPKGSET' }
      +      )
      +
      +    if (!args.length)
      +      throw setError()
      +
      +    const force = this.npm.config.get('force')
      +    const json = this.npm.config.get('json')
      +    const pkgJson = await PackageJson.load(this.prefix)
      +    const q = new Queryable(pkgJson.content)
      +    for (const arg of args) {
      +      const [key, ...rest] = arg.split('=')
      +      const value = rest.join('=')
      +      if (!key || !value)
      +        throw setError()
      +
      +      q.set(key, json ? JSON.parse(value) : value, { force })
      +    }
      +
      +    pkgJson.update(q.toJSON())
      +    await pkgJson.save()
      +  }
      +
      +  async delete (args) {
      +    const setError = () =>
      +      Object.assign(
      +        new TypeError('npm pkg delete expects key args.'),
      +        { code: 'EPKGDELETE' }
      +      )
      +
      +    if (!args.length)
      +      throw setError()
      +
      +    const pkgJson = await PackageJson.load(this.prefix)
      +    const q = new Queryable(pkgJson.content)
      +    for (const key of args) {
      +      if (!key)
      +        throw setError()
      +
      +      q.delete(key)
      +    }
      +
      +    pkgJson.update(q.toJSON())
      +    await pkgJson.save()
      +  }
      +}
      +
      +module.exports = Pkg
      diff --git a/deps/npm/lib/publish.js b/deps/npm/lib/publish.js
      index f35388a30f4ed7..9c747eb5068f0c 100644
      --- a/deps/npm/lib/publish.js
      +++ b/deps/npm/lib/publish.js
      @@ -66,6 +66,7 @@ class Publish extends BaseCommand {
           const dryRun = this.npm.config.get('dry-run')
           const json = this.npm.config.get('json')
           const defaultTag = this.npm.config.get('tag')
      +    const ignoreScripts = this.npm.config.get('ignore-scripts')
           const silent = log.level === 'silent'
       
           if (semver.validRange(defaultTag))
      @@ -82,7 +83,7 @@ class Publish extends BaseCommand {
             flatten(manifest.publishConfig, opts)
       
           // only run scripts for directory type publishes
      -    if (spec.type === 'directory') {
      +    if (spec.type === 'directory' && !ignoreScripts) {
             await runScript({
               event: 'prepublishOnly',
               path: spec.fetchSpec,
      @@ -119,7 +120,7 @@ class Publish extends BaseCommand {
             await otplease(opts, opts => libpub(manifest, tarballData, opts))
           }
       
      -    if (spec.type === 'directory') {
      +    if (spec.type === 'directory' && !ignoreScripts) {
             await runScript({
               event: 'publish',
               path: spec.fetchSpec,
      diff --git a/deps/npm/lib/utils/cmd-list.js b/deps/npm/lib/utils/cmd-list.js
      index c865cdabb4014e..26da5390065886 100644
      --- a/deps/npm/lib/utils/cmd-list.js
      +++ b/deps/npm/lib/utils/cmd-list.js
      @@ -122,6 +122,7 @@ const cmdList = [
         'diff',
         'dist-tag',
         'ping',
      +  'pkg',
       
         'test',
         'stop',
      diff --git a/deps/npm/lib/utils/config/definition.js b/deps/npm/lib/utils/config/definition.js
      index 507be6a6440423..1354851326adfd 100644
      --- a/deps/npm/lib/utils/config/definition.js
      +++ b/deps/npm/lib/utils/config/definition.js
      @@ -91,13 +91,27 @@ ${noEnvExport}`)
       }
       
       const describeUsage = (def) => {
      -  let key = `--${def.key}`
      -  if (def.short && typeof def.short === 'string')
      -    key = `-${def.short}|${key}`
      +  let key = ''
       
         // Single type
      -  if (!Array.isArray(def.type))
      -    return `${key}${def.type === Boolean ? '' : ' ' + def.hint}`
      +  if (!Array.isArray(def.type)) {
      +    if (def.short)
      +      key = `-${def.short}|`
      +
      +    if (def.type === Boolean && def.default !== false)
      +      key = `${key}--no-${def.key}`
      +    else
      +      key = `${key}--${def.key}`
      +
      +    if (def.type !== Boolean)
      +      key = `${key} ${def.hint}`
      +
      +    return key
      +  }
      +
      +  key = `--${def.key}`
      +  if (def.short)
      +    key = `-${def.short}|--${def.key}`
       
         // Multiple types
         let types = def.type
      @@ -120,8 +134,12 @@ const describeUsage = (def) => {
           description = def.hint
         }
       
      -  if (bool)
      -    key = `${key}|${key}`
      +  if (bool) {
      +    // Currently none of our multi-type configs with boolean values default to
      +    // false so all their hints should show `--no-`, if we ever add ones that
      +    // default to false we can branch the logic here
      +    key = `--no-${def.key}|${key}`
      +  }
       
         const usage = `${key} ${description}`
         if (multiple)
      diff --git a/deps/npm/lib/utils/config/definitions.js b/deps/npm/lib/utils/config/definitions.js
      index d540b0fc67e82a..abe6bda70d8bc5 100644
      --- a/deps/npm/lib/utils/config/definitions.js
      +++ b/deps/npm/lib/utils/config/definitions.js
      @@ -203,10 +203,10 @@ define('audit', {
         default: true,
         type: Boolean,
         description: `
      -    When "true" submit audit reports alongside \`npm install\` runs to the
      +    When "true" submit audit reports alongside the current npm command to the
           default registry and all registries configured for scopes.  See the
      -    documentation for [\`npm audit\`](/commands/npm-audit) for details on
      -    what is submitted.
      +    documentation for [\`npm audit\`](/commands/npm-audit) for details on what
      +    is submitted.
         `,
         flatten,
       })
      @@ -440,6 +440,7 @@ define('cidr', {
       
       define('color', {
         default: !process.env.NO_COLOR || process.env.NO_COLOR === '0',
      +  usage: '--color|--no-color|--color always',
         defaultDescription: `
           true unless the NO_COLOR environ is set to something other than '0'
         `,
      @@ -715,6 +716,7 @@ define('force', {
           * Allow unpublishing all versions of a published package.
           * Allow conflicting peerDependencies to be installed in the root project.
           * Implicitly set \`--yes\` during \`npm init\`.
      +    * Allow clobbering existing values in \`npm pkg\`
       
           If you don't have a clear idea of what you want to do, it is strongly
           recommended that you do not use this option!
      @@ -1029,6 +1031,9 @@ define('json', {
         description: `
           Whether or not to output JSON data, rather than the normal output.
       
      +    * In \`npm pkg set\` it enables parsing set values with JSON.parse()
      +    before saving them to your \`package.json\`.
      +
           Not supported by all npm commands.
         `,
         flatten,
      @@ -1103,6 +1108,31 @@ define('local-address', {
         flatten,
       })
       
      +define('location', {
      +  default: 'user',
      +  short: 'L',
      +  type: [
      +    'global',
      +    'user',
      +    'project',
      +  ],
      +  defaultDescription: `
      +    "user" unless \`--global\` is passed, which will also set this value to "global"
      +  `,
      +  description: `
      +    When passed to \`npm config\` this refers to which config file to use.
      +  `,
      +  // NOTE: the flattener here deliberately does not alter the value of global
      +  // for now, this is to avoid inadvertently causing any breakage. the value of
      +  // global, however, does modify this flag.
      +  flatten (key, obj, flatOptions) {
      +    // if global is set, we override ourselves
      +    if (obj.global)
      +      obj.location = 'global'
      +    flatOptions.location = obj.location
      +  },
      +})
      +
       define('loglevel', {
         default: 'notice',
         type: [
      @@ -1200,7 +1230,10 @@ define('noproxy', {
           Also accepts a comma-delimited string.
         `,
         flatten (key, obj, flatOptions) {
      -    flatOptions.noProxy = obj[key].join(',')
      +    if (Array.isArray(obj[key]))
      +      flatOptions.noProxy = obj[key].join(',')
      +    else
      +      flatOptions.noProxy = obj[key]
         },
       })
       
      diff --git a/deps/npm/lib/utils/error-message.js b/deps/npm/lib/utils/error-message.js
      index 125cdf8c53581b..3b590f712e783c 100644
      --- a/deps/npm/lib/utils/error-message.js
      +++ b/deps/npm/lib/utils/error-message.js
      @@ -269,6 +269,7 @@ module.exports = (er, npm) => {
           case 'ECONNRESET':
           case 'ENOTFOUND':
           case 'ETIMEDOUT':
      +    case 'ERR_SOCKET_TIMEOUT':
           case 'EAI_FAIL':
             short.push(['network', er.message])
             detail.push([
      diff --git a/deps/npm/lib/utils/exit-handler.js b/deps/npm/lib/utils/exit-handler.js
      index 931527704b9b71..95c9655a716cf3 100644
      --- a/deps/npm/lib/utils/exit-handler.js
      +++ b/deps/npm/lib/utils/exit-handler.js
      @@ -1,4 +1,3 @@
      -const log = require('npmlog')
       const os = require('os')
       const path = require('path')
       const writeFileAtomic = require('write-file-atomic')
      @@ -13,8 +12,6 @@ let logFileName
       let npm // set by the cli
       let wroteLogFile = false
       
      -const timings = {}
      -
       const getLogFile = () => {
         // we call this multiple times, so we need to treat it as a singleton because
         // the date is part of the name
      @@ -24,17 +21,15 @@ const getLogFile = () => {
         return logFileName
       }
       
      -process.on('timing', (name, value) => {
      -  if (timings[name])
      -    timings[name] += value
      -  else
      -    timings[name] = value
      -})
      -
       process.on('exit', code => {
      +  // process.emit is synchronous, so the timeEnd handler will run before the
      +  // unfinished timer check below
         process.emit('timeEnd', 'npm')
      -  log.disableProgress()
      -  if (npm.config && npm.config.loaded && npm.config.get('timing')) {
      +  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'))
      @@ -44,7 +39,7 @@ process.on('exit', code => {
               command: process.argv.slice(2),
               logfile: getLogFile(),
               version: npm.version,
      -        ...timings,
      +        ...npm.timings,
             }) + '\n')
       
             const st = fs.lstatSync(path.dirname(npm.config.get('cache')))
      @@ -56,27 +51,27 @@ process.on('exit', code => {
         }
       
         if (!code)
      -    log.info('ok')
      +    npm.log.info('ok')
         else {
      -    log.verbose('code', code)
      +    npm.log.verbose('code', code)
           if (!exitHandlerCalled) {
      -      log.error('', 'Exit handler never called!')
      +      npm.log.error('', 'Exit handler never called!')
             console.error('')
      -      log.error('', 'This is an error with npm itself. Please report this error at:')
      -      log.error('', '    ')
      +      npm.log.error('', 'This is an error with npm itself. Please report this error at:')
      +      npm.log.error('', '    ')
             // TODO this doesn't have an npm.config.loaded guard
             writeLogFile()
           }
         }
         // In timing mode we always write the log file
      -  if (npm.config && npm.config.loaded && npm.config.get('timing') && !wroteLogFile)
      +  if (npm.config.loaded && npm.config.get('timing') && !wroteLogFile)
           writeLogFile()
         if (wroteLogFile) {
           // just a line break
      -    if (log.levels[log.level] <= log.levels.error)
      +    if (npm.log.levels[npm.log.level] <= npm.log.levels.error)
             console.error('')
       
      -    log.error(
      +    npm.log.error(
             '',
             [
               'A complete log of this run can be found in:',
      @@ -88,121 +83,114 @@ process.on('exit', code => {
         // these are needed for the tests to have a clean slate in each test case
         exitHandlerCalled = false
         wroteLogFile = false
      -
      -  // actually exit.
      -  process.exit(code)
       })
       
      -const exit = (code, noLog) => {
      -  log.verbose('exit', code || 0)
      -  if (log.level === 'silent')
      -    noLog = true
      -
      -  // noLog is true if there was an error, including if config wasn't loaded, so
      -  // this doesn't need a config.loaded guard
      -  if (code && !noLog)
      -    writeLogFile()
      -
      -  // Exit directly -- nothing in the CLI should still be running in the
      -  // background at this point, and this makes sure anything left dangling
      -  // for whatever reason gets thrown away, instead of leaving the CLI open
      -  process.stdout.write('', () => {
      -    process.exit(code)
      -  })
      -}
      -
       const exitHandler = (err) => {
      -  log.disableProgress()
      -  if (!npm.config || !npm.config.loaded) {
      -    // logging won't work unless we pretend that it's ready
      +  npm.log.disableProgress()
      +  if (!npm.config.loaded) {
           err = err || new Error('Exit prior to config file resolving.')
           console.error(err.stack || err.message)
         }
       
      -  if (exitHandlerCalled)
      -    err = err || new Error('Exit handler called more than once.')
      -
      -  // only show the notification if it finished before the other stuff we
      -  // were doing.  no need to hang on `npm -v` or something.
      +  // only show the notification if it finished.
         if (typeof npm.updateNotification === 'string') {
      -    const { level } = log
      -    log.level = log.levels.notice
      -    log.notice('', npm.updateNotification)
      -    log.level = level
      +    const { level } = npm.log
      +    npm.log.level = 'notice'
      +    npm.log.notice('', npm.updateNotification)
      +    npm.log.level = level
         }
       
         exitHandlerCalled = true
      -  if (!err)
      -    return exit()
      -
      -  // if we got a command that just shells out to something else, then it
      -  // will presumably print its own errors and exit with a proper status
      -  // code if there's a problem.  If we got an error with a code=0, then...
      -  // something else went wrong along the way, so maybe an npm problem?
      -  const isShellout = npm.shelloutCommands.includes(npm.command)
      -  const quietShellout = isShellout && typeof err.code === 'number' && err.code
      -  if (quietShellout)
      -    return exit(err.code, true)
      -  else if (typeof err === 'string') {
      -    log.error('', err)
      -    return exit(1, true)
      -  } else if (!(err instanceof Error)) {
      -    log.error('weird error', err)
      -    return exit(1, true)
      -  }
      -
      -  if (!err.code) {
      -    const matchErrorCode = err.message.match(/^(?:Error: )?(E[A-Z]+)/)
      -    err.code = matchErrorCode && matchErrorCode[1]
      -  }
       
      -  for (const k of ['type', 'stack', 'statusCode', 'pkgid']) {
      -    const v = err[k]
      -    if (v)
      -      log.verbose(k, replaceInfo(v))
      +  let exitCode
      +  let noLog
      +
      +  if (err) {
      +    exitCode = 1
      +    // if we got a command that just shells out to something else, then it
      +    // will presumably print its own errors and exit with a proper status
      +    // code if there's a problem.  If we got an error with a code=0, then...
      +    // something else went wrong along the way, so maybe an npm problem?
      +    const isShellout = npm.shelloutCommands.includes(npm.command)
      +    const quietShellout = isShellout && typeof err.code === 'number' && err.code
      +    if (quietShellout) {
      +      exitCode = err.code
      +      noLog = true
      +    } else if (typeof err === 'string') {
      +      noLog = true
      +      npm.log.error('', err)
      +    } else if (!(err instanceof Error)) {
      +      noLog = true
      +      npm.log.error('weird error', err)
      +    } else {
      +      if (!err.code) {
      +        const matchErrorCode = err.message.match(/^(?:Error: )?(E[A-Z]+)/)
      +        err.code = matchErrorCode && matchErrorCode[1]
      +      }
      +
      +      for (const k of ['type', 'stack', 'statusCode', 'pkgid']) {
      +        const v = err[k]
      +        if (v)
      +          npm.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)
      +
      +      for (const k of ['code', 'syscall', 'file', 'path', 'dest', 'errno']) {
      +        const v = err[k]
      +        if (v)
      +          npm.log.error(k, v)
      +      }
      +
      +      const msg = errorMessage(err, npm)
      +      for (const errline of [...msg.summary, ...msg.detail])
      +        npm.log.error(...errline)
      +
      +      if (npm.config.loaded && npm.config.get('json')) {
      +        const error = {
      +          error: {
      +            code: err.code,
      +            summary: messageText(msg.summary),
      +            detail: messageText(msg.detail),
      +          },
      +        }
      +        console.error(JSON.stringify(error, null, 2))
      +      }
      +
      +      if (typeof err.errno === 'number')
      +        exitCode = err.errno
      +      else if (typeof err.code === 'number')
      +        exitCode = err.code
      +    }
         }
      +  npm.log.verbose('exit', exitCode || 0)
       
      -  log.verbose('cwd', process.cwd())
      -
      -  const args = replaceInfo(process.argv)
      -  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)
      -      log.error(k, v)
      -  }
      +  if (npm.log.level === 'silent')
      +    noLog = true
       
      -  const msg = errorMessage(err, npm)
      -  for (const errline of [...msg.summary, ...msg.detail])
      -    log.error(...errline)
      -
      -  if (npm.config && npm.config.get('json')) {
      -    const error = {
      -      error: {
      -        code: err.code,
      -        summary: messageText(msg.summary),
      -        detail: messageText(msg.detail),
      -      },
      -    }
      -    console.error(JSON.stringify(error, null, 2))
      -  }
      +  // 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()
       
      -  exit(typeof err.errno === 'number' ? err.errno : typeof err.code === 'number' ? err.code : 1)
      +  // 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
      +  // wait for that to happen.
      +  process.stdout.write('', () => process.exit(exitCode))
       }
       
       const messageText = msg => msg.map(line => line.slice(1).join(' ')).join('\n')
       
       const writeLogFile = () => {
      -  if (wroteLogFile)
      -    return
      -
         try {
           let logOutput = ''
      -    log.record.forEach(m => {
      +    npm.log.record.forEach(m => {
             const p = [m.id, m.level]
             if (m.prefix)
               p.push(m.prefix)
      @@ -225,7 +213,7 @@ const writeLogFile = () => {
           fs.chownSync(file, st.uid, st.gid)
       
           // truncate once it's been written.
      -    log.record.length = 0
      +    npm.log.record.length = 0
           wroteLogFile = true
         } catch (ex) {
       
      diff --git a/deps/npm/lib/utils/explain-eresolve.js b/deps/npm/lib/utils/explain-eresolve.js
      index fa3c6bda52293f..b25e3e4a9ccd0d 100644
      --- a/deps/npm/lib/utils/explain-eresolve.js
      +++ b/deps/npm/lib/utils/explain-eresolve.js
      @@ -9,26 +9,33 @@ const { explainEdge, explainNode, printNode } = require('./explain-dep.js')
       // The full report (ie, depth=Infinity) is always written to the cache folder
       // at ${cache}/eresolve-report.txt along with full json.
       const explain = (expl, color, depth) => {
      -  const { edge, current, peerConflict, currentEdge } = expl
      +  const { edge, dep, current, peerConflict, currentEdge } = expl
       
         const out = []
      -  if (edge.from && edge.from.whileInstalling)
      -    out.push('While resolving: ' + printNode(edge.from.whileInstalling, color))
      +  const whileInstalling = dep && dep.whileInstalling ||
      +    current && current.whileInstalling ||
      +    edge && edge.from && edge.from.whileInstalling
      +  if (whileInstalling)
      +    out.push('While resolving: ' + printNode(whileInstalling, color))
       
         // it "should" be impossible for an ERESOLVE explanation to lack both
         // current and currentEdge, but better to have a less helpful error
         // than a crashing failure.
         if (current)
           out.push('Found: ' + explainNode(current, depth, color))
      +  else if (peerConflict && peerConflict.current)
      +    out.push('Found: ' + explainNode(peerConflict.current, depth, color))
         else if (currentEdge)
           out.push('Found: ' + explainEdge(currentEdge, depth, color))
      +  else /* istanbul ignore else - should always have one */ if (edge)
      +    out.push('Found: ' + explainEdge(edge, depth, color))
       
         out.push('\nCould not resolve dependency:\n' +
           explainEdge(edge, depth, color))
       
         if (peerConflict) {
           const heading = '\nConflicting peer dependency:'
      -    const pc = explainNode(peerConflict, depth, color)
      +    const pc = explainNode(peerConflict.peer, depth, color)
           out.push(heading + ' ' + pc)
         }
       
      diff --git a/deps/npm/lib/utils/perf.js b/deps/npm/lib/utils/perf.js
      deleted file mode 100644
      index 4961054d909ad6..00000000000000
      --- a/deps/npm/lib/utils/perf.js
      +++ /dev/null
      @@ -1,23 +0,0 @@
      -const log = require('npmlog')
      -const timings = new Map()
      -
      -process.on('time', (name) => {
      -  timings.set(name, Date.now())
      -})
      -
      -process.on('timeEnd', (name) => {
      -  if (timings.has(name)) {
      -    const ms = Date.now() - timings.get(name)
      -    process.emit('timing', name, ms)
      -    log.timing(name, `Completed in ${ms}ms`)
      -    timings.delete(name)
      -  } else
      -    log.silly('timing', "Tried to end timer that doesn't exist:", name)
      -})
      -
      -// for tests
      -/* istanbul ignore next */
      -exports.reset = () => {
      -  process.removeAllListeners('time')
      -  process.removeAllListeners('timeEnd')
      -}
      diff --git a/deps/npm/lib/utils/queryable.js b/deps/npm/lib/utils/queryable.js
      new file mode 100644
      index 00000000000000..e10eba3b5f092a
      --- /dev/null
      +++ b/deps/npm/lib/utils/queryable.js
      @@ -0,0 +1,314 @@
      +const util = require('util')
      +const _data = Symbol('data')
      +const _delete = Symbol('delete')
      +const _append = Symbol('append')
      +
      +const sqBracketsMatcher = str => str.match(/(.+)\[([^\]]+)\]\.?(.*)$/)
      +
      +// replaces any occurence of an empty-brackets (e.g: []) with a special
      +// Symbol(append) to represent it, this is going to be useful for the setter
      +// method that will push values to the end of the array when finding these
      +const replaceAppendSymbols = str => {
      +  const matchEmptyBracket = str.match(/^(.*)\[\]\.?(.*)$/)
      +
      +  if (matchEmptyBracket) {
      +    const [, pre, post] = matchEmptyBracket
      +    return [...replaceAppendSymbols(pre), _append, post].filter(Boolean)
      +  }
      +
      +  return [str]
      +}
      +
      +const parseKeys = (key) => {
      +  const sqBracketItems = new Set()
      +  sqBracketItems.add(_append)
      +  const parseSqBrackets = (str) => {
      +    const index = sqBracketsMatcher(str)
      +
      +    // once we find square brackets, we recursively parse all these
      +    if (index) {
      +      const preSqBracketPortion = index[1]
      +
      +      // we want to have a `new String` wrapper here in order to differentiate
      +      // between multiple occurences of the same string, e.g:
      +      // foo.bar[foo.bar] should split into { foo: { bar: { 'foo.bar': {} } }
      +      /* eslint-disable-next-line no-new-wrappers */
      +      const foundKey = new String(index[2])
      +      const postSqBracketPortion = index[3]
      +
      +      // we keep track of items found during this step to make sure
      +      // we don't try to split-separate keys that were defined within
      +      // square brackets, since the key name itself might contain dots
      +      sqBracketItems.add(foundKey)
      +
      +      // returns an array that contains either dot-separate items (that will
      +      // be splitted appart during the next step OR the fully parsed keys
      +      // read from square brackets, e.g:
      +      // foo.bar[1.0.0].a.b -> ['foo.bar', '1.0.0', 'a.b']
      +      return [
      +        ...parseSqBrackets(preSqBracketPortion),
      +        foundKey,
      +        ...(
      +          postSqBracketPortion
      +            ? parseSqBrackets(postSqBracketPortion)
      +            : []
      +        ),
      +      ]
      +    }
      +
      +    // at the end of parsing, any usage of the special empty-bracket syntax
      +    // (e.g: foo.array[]) has  not yet been parsed, here we'll take care
      +    // of parsing it and adding a special symbol to represent it in
      +    // the resulting list of keys
      +    return replaceAppendSymbols(str)
      +  }
      +
      +  const res = []
      +  // starts by parsing items defined as square brackets, those might be
      +  // representing properties that have a dot in the name or just array
      +  // indexes, e.g: foo[1.0.0] or list[0]
      +  const sqBracketKeys = parseSqBrackets(key.trim())
      +
      +  for (const k of sqBracketKeys) {
      +    // keys parsed from square brackets should just be added to list of
      +    // resulting keys as they might have dots as part of the key
      +    if (sqBracketItems.has(k))
      +      res.push(k)
      +    else {
      +      // splits the dot-sep property names and add them to the list of keys
      +      for (const splitKey of k.split('.'))
      +        /* eslint-disable-next-line no-new-wrappers */
      +        res.push(new String(splitKey))
      +    }
      +  }
      +
      +  // returns an ordered list of strings in which each entry
      +  // represents a key in an object defined by the previous entry
      +  return res
      +}
      +
      +const getter = ({ data, key }) => {
      +  // keys are a list in which each entry represents the name of
      +  // a property that should be walked through the object in order to
      +  // return the final found value
      +  const keys = parseKeys(key)
      +  let _data = data
      +  let label = ''
      +
      +  for (const k of keys) {
      +    // empty-bracket-shortcut-syntax is not supported on getter
      +    if (k === _append) {
      +      throw Object.assign(
      +        new Error('Empty brackets are not valid syntax for retrieving values.'),
      +        { code: 'EINVALIDSYNTAX' }
      +      )
      +    }
      +
      +    // extra logic to take into account printing array, along with its
      +    // special syntax in which using a dot-sep property name after an
      +    // arry will expand it's results, e.g:
      +    // arr.name -> arr[0].name=value, arr[1].name=value, ...
      +    const maybeIndex = Number(k)
      +    if (Array.isArray(_data) && !Number.isInteger(maybeIndex)) {
      +      _data = _data.reduce((acc, i, index) => {
      +        acc[`${label}[${index}].${k}`] = i[k]
      +        return acc
      +      }, {})
      +      return _data
      +    } else {
      +      // if can't find any more values, it means it's just over
      +      // and there's nothing to return
      +      if (!_data[k])
      +        return undefined
      +
      +      // otherwise sets the next value
      +      _data = _data[k]
      +    }
      +
      +    label += k
      +  }
      +
      +  // these are some legacy expectations from
      +  // the old API consumed by lib/view.js
      +  if (Array.isArray(_data) && _data.length <= 1)
      +    _data = _data[0]
      +
      +  return {
      +    [key]: _data,
      +  }
      +}
      +
      +const setter = ({ data, key, value, force }) => {
      +  // setter goes to recursively transform the provided data obj,
      +  // setting properties from the list of parsed keys, e.g:
      +  // ['foo', 'bar', 'baz'] -> { foo: { bar: { baz:  {} } }
      +  const keys = parseKeys(key)
      +  const setKeys = (_data, _key) => {
      +    // handles array indexes, converting valid integers to numbers,
      +    // note that occurences of Symbol(append) will throw,
      +    // so we just ignore these for now
      +    let maybeIndex = Number.NaN
      +    try {
      +      maybeIndex = Number(_key)
      +    } catch (err) {}
      +    if (!Number.isNaN(maybeIndex))
      +      _key = maybeIndex
      +
      +    // creates new array in case key is an index
      +    // and the array obj is not yet defined
      +    const keyIsAnArrayIndex = _key === maybeIndex || _key === _append
      +    const dataHasNoItems = !Object.keys(_data).length
      +    if (keyIsAnArrayIndex && dataHasNoItems && !Array.isArray(_data))
      +      _data = []
      +
      +    // converting from array to an object is also possible, in case the
      +    // user is using force mode, we should also convert existing arrays
      +    // to an empty object if the current _data is an array
      +    if (force && Array.isArray(_data) && !keyIsAnArrayIndex)
      +      _data = { ..._data }
      +
      +    // the _append key is a special key that is used to represent
      +    // the empty-bracket notation, e.g: arr[] -> arr[arr.length]
      +    if (_key === _append) {
      +      if (!Array.isArray(_data)) {
      +        throw Object.assign(
      +          new Error(`Can't use append syntax in non-Array element`),
      +          { code: 'ENOAPPEND' }
      +        )
      +      }
      +      _key = _data.length
      +    }
      +
      +    // retrieves the next data object to recursively iterate on,
      +    // throws if trying to override a literal value or add props to an array
      +    const next = () => {
      +      const haveContents =
      +        !force &&
      +        _data[_key] != null &&
      +        value !== _delete
      +      const shouldNotOverrideLiteralValue =
      +        !(typeof _data[_key] === 'object')
      +      // if the next obj to recurse is an array and the next key to be
      +      // appended to the resulting obj is not an array index, then it
      +      // should throw since we can't append arbitrary props to arrays
      +      const shouldNotAddPropsToArrays =
      +        typeof keys[0] !== 'symbol' &&
      +        Array.isArray(_data[_key]) &&
      +        Number.isNaN(Number(keys[0]))
      +
      +      const overrideError =
      +        haveContents &&
      +        shouldNotOverrideLiteralValue
      +      if (overrideError) {
      +        throw Object.assign(
      +          new Error(`Property ${_key} already exists and is not an Array or Object.`),
      +          { code: 'EOVERRIDEVALUE' }
      +        )
      +      }
      +
      +      const addPropsToArrayError =
      +        haveContents &&
      +        shouldNotAddPropsToArrays
      +      if (addPropsToArrayError) {
      +        throw Object.assign(
      +          new Error(`Can't add property ${key} to an Array.`),
      +          { code: 'ENOADDPROP' }
      +        )
      +      }
      +
      +      return typeof _data[_key] === 'object' ? _data[_key] || {} : {}
      +    }
      +
      +    // sets items from the parsed array of keys as objects, recurses to
      +    // setKeys in case there are still items to be handled, otherwise it
      +    // just sets the original value set by the user
      +    if (keys.length)
      +      _data[_key] = setKeys(next(), keys.shift())
      +    else {
      +      // handles special deletion cases for obj props / array items
      +      if (value === _delete) {
      +        if (Array.isArray(_data))
      +          _data.splice(_key, 1)
      +        else
      +          delete _data[_key]
      +      } else
      +        // finally, sets the value in its right place
      +        _data[_key] = value
      +    }
      +
      +    return _data
      +  }
      +
      +  setKeys(data, keys.shift())
      +}
      +
      +class Queryable {
      +  constructor (obj) {
      +    if (!obj || typeof obj !== 'object') {
      +      throw Object.assign(
      +        new Error('Queryable needs an object to query properties from.'),
      +        { code: 'ENOQUERYABLEOBJ' }
      +      )
      +    }
      +
      +    this[_data] = obj
      +  }
      +
      +  query (queries) {
      +    // this ugly interface here is meant to be a compatibility layer
      +    // with the legacy API lib/view.js is consuming, if at some point
      +    // we refactor that command then we can revisit making this nicer
      +    if (queries === '')
      +      return { '': this[_data] }
      +
      +    const q = query => getter({
      +      data: this[_data],
      +      key: query,
      +    })
      +
      +    if (Array.isArray(queries)) {
      +      let res = {}
      +      for (const query of queries)
      +        res = { ...res, ...q(query) }
      +      return res
      +    } else
      +      return q(queries)
      +  }
      +
      +  // return the value for a single query if found, otherwise returns undefined
      +  get (query) {
      +    const obj = this.query(query)
      +    if (obj)
      +      return obj[query]
      +  }
      +
      +  // creates objects along the way for the provided `query` parameter
      +  // and assigns `value` to the last property of the query chain
      +  set (query, value, { force } = {}) {
      +    setter({
      +      data: this[_data],
      +      key: query,
      +      value,
      +      force,
      +    })
      +  }
      +
      +  // deletes the value of the property found at `query`
      +  delete (query) {
      +    setter({
      +      data: this[_data],
      +      key: query,
      +      value: _delete,
      +    })
      +  }
      +
      +  toJSON () {
      +    return this[_data]
      +  }
      +
      +  [util.inspect.custom] () {
      +    return this.toJSON()
      +  }
      +}
      +
      +module.exports = Queryable
      diff --git a/deps/npm/lib/utils/update-notifier.js b/deps/npm/lib/utils/update-notifier.js
      index ed5806ced2a7d9..14c4fac0d58b35 100644
      --- a/deps/npm/lib/utils/update-notifier.js
      +++ b/deps/npm/lib/utils/update-notifier.js
      @@ -33,12 +33,6 @@ const checkTimeout = async (npm, duration) => {
         return t > st.mtime
       }
       
      -const updateTimeout = async npm => {
      -  // best effort, if this fails, it's ok.
      -  // might be using /dev/null as the cache or something weird like that.
      -  await writeFile(lastCheckedFile(npm), '').catch(() => {})
      -}
      -
       const updateNotifier = async (npm, spec = 'latest') => {
         // never check for updates in CI, when updating npm already, or opted out
         if (!npm.config.get('update-notifier') ||
      @@ -111,15 +105,16 @@ const updateNotifier = async (npm, spec = 'latest') => {
           `${oldc} -> ${latestc}\n` +
           `Changelog: ${changelogc}\n` +
           `Run ${cmdc} to update!\n`
      -  const messagec = !useColor ? message : chalk.bgBlack.white(message)
       
      -  return messagec
      +  return message
       }
       
       // only update the notification timeout if we actually finished checking
       module.exports = async npm => {
         const notification = await updateNotifier(npm)
      -  // intentional.  do not await this.  it's a best-effort update.
      -  updateTimeout(npm)
      +  // intentional.  do not await this.  it's a best-effort update.  if this
      +  // fails, it's ok.  might be using /dev/null as the cache or something weird
      +  // like that.
      +  writeFile(lastCheckedFile(npm), '').catch(() => {})
         npm.updateNotification = notification
       }
      diff --git a/deps/npm/lib/view.js b/deps/npm/lib/view.js
      index 788df3ed0b4d83..47e631f5565c0d 100644
      --- a/deps/npm/lib/view.js
      +++ b/deps/npm/lib/view.js
      @@ -17,6 +17,7 @@ const { packument } = require('pacote')
       const readFile = promisify(fs.readFile)
       const readJson = async file => jsonParse(await readFile(file, 'utf8'))
       
      +const Queryable = require('./utils/queryable.js')
       const BaseCommand = require('./base-command.js')
       class View extends BaseCommand {
         /* istanbul ignore next - see test/lib/load-all-commands.js */
      @@ -459,56 +460,13 @@ function showFields (data, version, fields) {
             o[k] = s[k]
           })
         })
      -  return search(o, fields.split('.'), version.version, fields)
      -}
       
      -function search (data, fields, version, title) {
      -  let field
      -  const tail = fields
      -  while (!field && fields.length)
      -    field = tail.shift()
      -  fields = [field].concat(tail)
      -  let o
      -  if (!field && !tail.length) {
      -    o = {}
      -    o[version] = {}
      -    o[version][title] = data
      -    return o
      -  }
      -  let index = field.match(/(.+)\[([^\]]+)\]$/)
      -  if (index) {
      -    field = index[1]
      -    index = index[2]
      -    if (data[field] && data[field][index])
      -      return search(data[field][index], tail, version, title)
      -    else
      -      field = field + '[' + index + ']'
      -  }
      -  if (Array.isArray(data)) {
      -    if (data.length === 1)
      -      return search(data[0], fields, version, title)
      -
      -    let results = []
      -    data.forEach((data, i) => {
      -      const tl = title.length
      -      const newt = title.substr(0, tl - fields.join('.').length - 1) +
      -                 '[' + i + ']' + [''].concat(fields).join('.')
      -      results.push(search(data, fields.slice(), version, newt))
      -    })
      -    results = results.reduce(reducer, {})
      -    return results
      -  }
      -  if (!data[field])
      -    return undefined
      -  data = data[field]
      -  if (tail.length) {
      -    // there are more fields to deal with.
      -    return search(data, tail, version, title)
      -  }
      -  o = {}
      -  o[version] = {}
      -  o[version][title] = data
      -  return o
      +  const queryable = new Queryable(o)
      +  const s = queryable.query(fields)
      +  const res = { [version.version]: s }
      +
      +  if (s)
      +    return res
       }
       
       function cleanup (data) {
      diff --git a/deps/npm/man/man1/npm-audit.1 b/deps/npm/man/man1/npm-audit.1
      index ba569a749e9058..b1638993cf8a5d 100644
      --- a/deps/npm/man/man1/npm-audit.1
      +++ b/deps/npm/man/man1/npm-audit.1
      @@ -263,6 +263,8 @@ Allow unpublishing all versions of a published package\.
       Allow conflicting peerDependencies to be installed in the root project\.
       .IP \(bu 2
       Implicitly set \fB\-\-yes\fP during \fBnpm init\fP\|\.
      +.IP \(bu 2
      +Allow clobbering existing values in \fBnpm pkg\fP
       
       .RE
       .P
      @@ -278,6 +280,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBpackage\-lock\-only\fP
      diff --git a/deps/npm/man/man1/npm-ci.1 b/deps/npm/man/man1/npm-ci.1
      index 0d11f277eea839..f4ad77607e77ae 100644
      --- a/deps/npm/man/man1/npm-ci.1
      +++ b/deps/npm/man/man1/npm-ci.1
      @@ -81,6 +81,19 @@ cache:
       .SS Configuration
       
       
      +.SS \fBaudit\fP
      +.RS 0
      +.IP \(bu 2
      +Default: true
      +.IP \(bu 2
      +Type: Boolean
      +
      +.RE
      +.P
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBignore\-scripts\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-config.1 b/deps/npm/man/man1/npm-config.1
      index 70a2d136495eba..405160025f1895 100644
      --- a/deps/npm/man/man1/npm-config.1
      +++ b/deps/npm/man/man1/npm-config.1
      @@ -107,6 +107,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBglobal\fP
      @@ -142,6 +148,17 @@ Type: String
       .RE
       .P
       The command to run for \fBnpm edit\fP and \fBnpm config edit\fP\|\.
      +.SS \fBlocation\fP
      +.RS 0
      +.IP \(bu 2
      +Default: "user" unless \fB\-\-global\fP is passed, which will also set this value
      +to "global"
      +.IP \(bu 2
      +Type: "global", "user", or "project"
      +
      +.RE
      +.P
      +When passed to \fBnpm config\fP this refers to which config file to use\.
       .SS \fBlong\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-dedupe.1 b/deps/npm/man/man1/npm-dedupe.1
      index 664f973b763688..2930a90609d4ea 100644
      --- a/deps/npm/man/man1/npm-dedupe.1
      +++ b/deps/npm/man/man1/npm-dedupe.1
      @@ -188,9 +188,10 @@ Type: Boolean
       
       .RE
       .P
      -When "true" submit audit reports alongside \fBnpm install\fP runs to the default
      -registry and all registries configured for scopes\. See the documentation for
      -npm help \fBaudit\fP for details on what is submitted\.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBbin\-links\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-explain.1 b/deps/npm/man/man1/npm-explain.1
      index ee436af72dfaf9..dee71496115b35 100644
      --- a/deps/npm/man/man1/npm-explain.1
      +++ b/deps/npm/man/man1/npm-explain.1
      @@ -67,6 +67,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBworkspace\fP
      diff --git a/deps/npm/man/man1/npm-find-dupes.1 b/deps/npm/man/man1/npm-find-dupes.1
      index 740ea6b4ce15f2..285dc3128d8cf0 100644
      --- a/deps/npm/man/man1/npm-find-dupes.1
      +++ b/deps/npm/man/man1/npm-find-dupes.1
      @@ -125,9 +125,10 @@ Type: Boolean
       
       .RE
       .P
      -When "true" submit audit reports alongside \fBnpm install\fP runs to the default
      -registry and all registries configured for scopes\. See the documentation for
      -npm help \fBaudit\fP for details on what is submitted\.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBbin\-links\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-fund.1 b/deps/npm/man/man1/npm-fund.1
      index 073096e37b15f9..a1fc486010dc17 100644
      --- a/deps/npm/man/man1/npm-fund.1
      +++ b/deps/npm/man/man1/npm-fund.1
      @@ -73,6 +73,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBbrowser\fP
      diff --git a/deps/npm/man/man1/npm-init.1 b/deps/npm/man/man1/npm-init.1
      index cf630053bd1625..bce9c09f6ed0ca 100644
      --- a/deps/npm/man/man1/npm-init.1
      +++ b/deps/npm/man/man1/npm-init.1
      @@ -211,6 +211,8 @@ Allow unpublishing all versions of a published package\.
       Allow conflicting peerDependencies to be installed in the root project\.
       .IP \(bu 2
       Implicitly set \fB\-\-yes\fP during \fBnpm init\fP\|\.
      +.IP \(bu 2
      +Allow clobbering existing values in \fBnpm pkg\fP
       
       .RE
       .P
      diff --git a/deps/npm/man/man1/npm-install-ci-test.1 b/deps/npm/man/man1/npm-install-ci-test.1
      index b5c9bb4c57a4c6..b2fad00b06b2f1 100644
      --- a/deps/npm/man/man1/npm-install-ci-test.1
      +++ b/deps/npm/man/man1/npm-install-ci-test.1
      @@ -16,6 +16,19 @@ This command runs \fBnpm ci\fP followed immediately by \fBnpm test\fP\|\.
       .SS Configuration
       
       
      +.SS \fBaudit\fP
      +.RS 0
      +.IP \(bu 2
      +Default: true
      +.IP \(bu 2
      +Type: Boolean
      +
      +.RE
      +.P
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBignore\-scripts\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-install-test.1 b/deps/npm/man/man1/npm-install-test.1
      index ccd9c6ef055440..0b403e8fee7865 100644
      --- a/deps/npm/man/man1/npm-install-test.1
      +++ b/deps/npm/man/man1/npm-install-test.1
      @@ -181,9 +181,10 @@ Type: Boolean
       
       .RE
       .P
      -When "true" submit audit reports alongside \fBnpm install\fP runs to the default
      -registry and all registries configured for scopes\. See the documentation for
      -npm help \fBaudit\fP for details on what is submitted\.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBbin\-links\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-install.1 b/deps/npm/man/man1/npm-install.1
      index b6c5fece489aa1..5ad3b9024fddfe 100644
      --- a/deps/npm/man/man1/npm-install.1
      +++ b/deps/npm/man/man1/npm-install.1
      @@ -583,9 +583,10 @@ Type: Boolean
       
       .RE
       .P
      -When "true" submit audit reports alongside \fBnpm install\fP runs to the default
      -registry and all registries configured for scopes\. See the documentation for
      -npm help \fBaudit\fP for details on what is submitted\.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBbin\-links\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-link.1 b/deps/npm/man/man1/npm-link.1
      index 7f4ae29f812697..3527512232360d 100644
      --- a/deps/npm/man/man1/npm-link.1
      +++ b/deps/npm/man/man1/npm-link.1
      @@ -271,9 +271,10 @@ Type: Boolean
       
       .RE
       .P
      -When "true" submit audit reports alongside \fBnpm install\fP runs to the default
      -registry and all registries configured for scopes\. See the documentation for
      -npm help \fBaudit\fP for details on what is submitted\.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBbin\-links\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1
      index 3fe8962f231764..0c6d83ee6d9161 100644
      --- a/deps/npm/man/man1/npm-ls.1
      +++ b/deps/npm/man/man1/npm-ls.1
      @@ -26,7 +26,7 @@ example, running \fBnpm ls promzard\fP in npm's source tree will show:
       .P
       .RS 2
       .nf
      -npm@7\.19\.1 /path/to/npm
      +npm@7\.20\.3 /path/to/npm
       └─┬ init\-package\-json@0\.0\.4
         └── promzard@0\.1\.5
       .fi
      @@ -94,6 +94,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBlong\fP
      diff --git a/deps/npm/man/man1/npm-org.1 b/deps/npm/man/man1/npm-org.1
      index faf5beccf779a1..ca4d12eb3b466b 100644
      --- a/deps/npm/man/man1/npm-org.1
      +++ b/deps/npm/man/man1/npm-org.1
      @@ -103,6 +103,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBparseable\fP
      diff --git a/deps/npm/man/man1/npm-outdated.1 b/deps/npm/man/man1/npm-outdated.1
      index 44949711c0a700..5bea638d57d8e9 100644
      --- a/deps/npm/man/man1/npm-outdated.1
      +++ b/deps/npm/man/man1/npm-outdated.1
      @@ -126,6 +126,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBlong\fP
      diff --git a/deps/npm/man/man1/npm-pack.1 b/deps/npm/man/man1/npm-pack.1
      index f881df420ad8c4..7402a53f7c9c9d 100644
      --- a/deps/npm/man/man1/npm-pack.1
      +++ b/deps/npm/man/man1/npm-pack.1
      @@ -37,6 +37,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBpack\-destination\fP
      diff --git a/deps/npm/man/man1/npm-pkg.1 b/deps/npm/man/man1/npm-pkg.1
      new file mode 100644
      index 00000000000000..48044b58ae77a2
      --- /dev/null
      +++ b/deps/npm/man/man1/npm-pkg.1
      @@ -0,0 +1,294 @@
      +.TH "NPM\-PKG" "1" "July 2021" "" ""
      +.SH "NAME"
      +\fBnpm-pkg\fR \- Manages your package\.json
      +.SS Synopsis
      +.P
      +.RS 2
      +.nf
      +npm pkg get [ [\. \.\.\.]]
      +npm pkg set = [\.= \.\.\.]
      +npm pkg delete  [\. \.\.\.]
      +.fi
      +.RE
      +.SS Description
      +.P
      +A command that automates the management of \fBpackage\.json\fP files\.
      +\fBnpm pkg\fP provide 3 different sub commands that allow you to modify or retrieve
      +values for given object keys in your \fBpackge\.json\fP\|\.
      +.P
      +The syntax to retrieve and set fields is a dot separated representation of
      +the nested object properties to be found within your \fBpackage\.json\fP, it's the
      +same notation used in npm help \fBview\fP to retrieve information
      +from the registry manifest, below you can find more examples on how to use it\.
      +.P
      +Returned values are always in \fBjson\fR format\.
      +.RS 0
      +.IP \(bu 2
      +\fBnpm pkg get \fP
      +  Retrieves a value \fBkey\fP, defined in your \fBpackage\.json\fP file\.
      +  For example, in order to retrieve the name of the current package, you
      +  can run:
      +.P
      +.RS 2
      +.nf
      +  npm pkg get name
      +.fi
      +.RE
      +  It's also possible to retrieve multiple values at once:
      +.P
      +.RS 2
      +.nf
      +  npm pkg get name version
      +.fi
      +.RE
      +  You can view child fields by separating them with a period\. To retrieve
      +  the value of a test \fBscript\fP value, you would run the following command:
      +.P
      +.RS 2
      +.nf
      +  npm pkg get scripts\.test
      +.fi
      +.RE
      +  For fields that are arrays, requesting a non\-numeric field will return
      +  all of the values from the objects in the list\. For example, to get all
      +  the contributor emails for a package, you would run:
      +.P
      +.RS 2
      +.nf
      +  npm pkg get contributors\.email
      +.fi
      +.RE
      +  You may also use numeric indices in square braces to specifically select
      +  an item in an array field\. To just get the email address of the first
      +  contributor in the list, you can run:
      +.P
      +.RS 2
      +.nf
      +  npm pkg get contributors[0]\.email
      +.fi
      +.RE
      +.IP \(bu 2
      +\fBnpm pkg set =\fP
      +  Sets a \fBvalue\fP in your \fBpackage\.json\fP based on the \fBfield\fP value\. When
      +  saving to your \fBpackage\.json\fP file the same set of rules used during
      +  \fBnpm install\fP and other cli commands that touches the \fBpackage\.json\fP file
      +  are used, making sure to respect the existing indentation and possibly
      +  applying some validation prior to saving values to the file\.
      +  The same syntax used to retrieve values from your package can also be used
      +  to define new properties or overriding existing ones, below are some
      +  examples of how the dot separated syntax can be used to edit your
      +  \fBpackage\.json\fP file\.
      +  Defining a new bin named \fBmynewcommand\fP in your \fBpackage\.json\fP that points
      +  to a file \fBcli\.js\fP:
      +.P
      +.RS 2
      +.nf
      +  npm pkg set bin\.mynewcommand=cli\.js
      +.fi
      +.RE
      +  Setting multiple fields at once is also possible:
      +.P
      +.RS 2
      +.nf
      +  npm pkg set description='Awesome package' engines\.node='>=10'
      +.fi
      +.RE
      +  It's also possible to add to array values, for example to add a new
      +  contributor entry:
      +.P
      +.RS 2
      +.nf
      +  npm pkg set contributors[0]\.name='Foo' contributors[0]\.email='foo@bar\.ca'
      +.fi
      +.RE
      +  You may also append items to the end of an array using the special
      +  empty bracket notation:
      +.P
      +.RS 2
      +.nf
      +  npm pkg set contributors[]\.name='Foo' contributors[]\.name='Bar'
      +.fi
      +.RE
      +  It's also possible to parse values as json prior to saving them to your
      +  \fBpackage\.json\fP file, for example in order to set a \fB"private": true\fP
      +  property:
      +.P
      +.RS 2
      +.nf
      +  npm pkg set private=true \-\-json
      +.fi
      +.RE
      +  It also enables saving values as numbers:
      +.P
      +.RS 2
      +.nf
      +  npm pkg set tap\.timeout=60 \-\-json
      +.fi
      +.RE
      +.IP \(bu 2
      +\fBnpm pkg delete \fP
      +  Deletes a \fBkey\fP from your \fBpackage\.json\fP
      +  The same syntax used to set values from your package can also be used
      +  to remove existing ones\. For example, in order to remove a script named
      +  build:
      +.P
      +.RS 2
      +.nf
      +  npm pkg delete scripts\.build
      +.fi
      +.RE
      +
      +.RE
      +.SS Workspaces support
      +.P
      +You can set/get/delete items across your configured workspaces by using the
      +\fBworkspace\fP or \fBworkspaces\fP config options\.
      +.P
      +For example, setting a \fBfunding\fP value across all configured workspaces
      +of a project:
      +.P
      +.RS 2
      +.nf
      +npm pkg set funding=https://example\.com \-\-ws
      +.fi
      +.RE
      +.P
      +When using \fBnpm pkg get\fP to retrieve info from your configured workspaces, the
      +returned result will be in a json format in which top level keys are the
      +names of each workspace, the values of these keys will be the result values
      +returned from each of the configured workspaces, e\.g:
      +.P
      +.RS 2
      +.nf
      +npm pkg get name version \-\-ws
      +{
      +  "a": {
      +    "name": "a",
      +    "version": "1\.0\.0"
      +  },
      +  "b": {
      +    "name": "b",
      +    "version": "1\.0\.0"
      +  }
      +}
      +.fi
      +.RE
      +.SS Configuration
      +
      +
      +.SS \fBforce\fP
      +.RS 0
      +.IP \(bu 2
      +Default: false
      +.IP \(bu 2
      +Type: Boolean
      +
      +.RE
      +.P
      +Removes various protections against unfortunate side effects, common
      +mistakes, unnecessary performance degradation, and malicious input\.
      +.RS 0
      +.IP \(bu 2
      +Allow clobbering non\-npm files in global installs\.
      +.IP \(bu 2
      +Allow the \fBnpm version\fP command to work on an unclean git repository\.
      +.IP \(bu 2
      +Allow deleting the cache folder with \fBnpm cache clean\fP\|\.
      +.IP \(bu 2
      +Allow installing packages that have an \fBengines\fP declaration requiring a
      +different version of npm\.
      +.IP \(bu 2
      +Allow installing packages that have an \fBengines\fP declaration requiring a
      +different version of \fBnode\fP, even if \fB\-\-engine\-strict\fP is enabled\.
      +.IP \(bu 2
      +Allow \fBnpm audit fix\fP to install modules outside your stated dependency
      +range (including SemVer\-major changes)\.
      +.IP \(bu 2
      +Allow unpublishing all versions of a published package\.
      +.IP \(bu 2
      +Allow conflicting peerDependencies to be installed in the root project\.
      +.IP \(bu 2
      +Implicitly set \fB\-\-yes\fP during \fBnpm init\fP\|\.
      +.IP \(bu 2
      +Allow clobbering existing values in \fBnpm pkg\fP
      +
      +.RE
      +.P
      +If you don't have a clear idea of what you want to do, it is strongly
      +recommended that you do not use this option!
      +.SS \fBjson\fP
      +.RS 0
      +.IP \(bu 2
      +Default: false
      +.IP \(bu 2
      +Type: Boolean
      +
      +.RE
      +.P
      +Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
      +.P
      +Not supported by all npm commands\.
      +.SS \fBworkspace\fP
      +.RS 0
      +.IP \(bu 2
      +Default:
      +.IP \(bu 2
      +Type: String (can be set multiple times)
      +
      +.RE
      +.P
      +Enable running a command in the context of the configured workspaces of the
      +current project while filtering by running only the workspaces defined by
      +this configuration option\.
      +.P
      +Valid values for the \fBworkspace\fP config are either:
      +.RS 0
      +.IP \(bu 2
      +Workspace names
      +.IP \(bu 2
      +Path to a workspace directory
      +.IP \(bu 2
      +Path to a parent workspace directory (will result to selecting all of the
      +nested workspaces)
      +
      +.RE
      +.P
      +When set for the \fBnpm init\fP command, this may be set to the folder of a
      +workspace which does not yet exist, to create the folder and set it up as a
      +brand new workspace within the project\.
      +.P
      +This value is not exported to the environment for child processes\.
      +.SS \fBworkspaces\fP
      +.RS 0
      +.IP \(bu 2
      +Default: false
      +.IP \(bu 2
      +Type: Boolean
      +
      +.RE
      +.P
      +Enable running a command in the context of \fBall\fR the configured
      +workspaces\.
      +.P
      +This value is not exported to the environment for child processes\.
      +
      +.SH See Also
      +.RS 0
      +.IP \(bu 2
      +npm help install
      +.IP \(bu 2
      +npm help init
      +.IP \(bu 2
      +npm help config
      +.IP \(bu 2
      +npm help set\-script
      +.IP \(bu 2
      +npm help workspaces
      +
      +.RE
      diff --git a/deps/npm/man/man1/npm-profile.1 b/deps/npm/man/man1/npm-profile.1
      index 5402a125fe6591..930fbf2d9402af 100644
      --- a/deps/npm/man/man1/npm-profile.1
      +++ b/deps/npm/man/man1/npm-profile.1
      @@ -105,6 +105,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBparseable\fP
      diff --git a/deps/npm/man/man1/npm-prune.1 b/deps/npm/man/man1/npm-prune.1
      index 863283a87cb0b7..41b7b00a5cdb1c 100644
      --- a/deps/npm/man/man1/npm-prune.1
      +++ b/deps/npm/man/man1/npm-prune.1
      @@ -80,6 +80,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBworkspace\fP
      diff --git a/deps/npm/man/man1/npm-search.1 b/deps/npm/man/man1/npm-search.1
      index 9b0b17b433ccd7..d500a4e8ef8b92 100644
      --- a/deps/npm/man/man1/npm-search.1
      +++ b/deps/npm/man/man1/npm-search.1
      @@ -57,6 +57,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBcolor\fP
      diff --git a/deps/npm/man/man1/npm-team.1 b/deps/npm/man/man1/npm-team.1
      index 2fef23d16b084a..54e27248b54b80 100644
      --- a/deps/npm/man/man1/npm-team.1
      +++ b/deps/npm/man/man1/npm-team.1
      @@ -150,6 +150,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       
      diff --git a/deps/npm/man/man1/npm-unpublish.1 b/deps/npm/man/man1/npm-unpublish.1
      index 8bee0313fca987..edef7115fc040a 100644
      --- a/deps/npm/man/man1/npm-unpublish.1
      +++ b/deps/npm/man/man1/npm-unpublish.1
      @@ -93,6 +93,8 @@ Allow unpublishing all versions of a published package\.
       Allow conflicting peerDependencies to be installed in the root project\.
       .IP \(bu 2
       Implicitly set \fB\-\-yes\fP during \fBnpm init\fP\|\.
      +.IP \(bu 2
      +Allow clobbering existing values in \fBnpm pkg\fP
       
       .RE
       .P
      diff --git a/deps/npm/man/man1/npm-update.1 b/deps/npm/man/man1/npm-update.1
      index 6e1ccbcaadff30..ca717f8d02fb2e 100644
      --- a/deps/npm/man/man1/npm-update.1
      +++ b/deps/npm/man/man1/npm-update.1
      @@ -13,7 +13,9 @@ aliases: up, upgrade
       .SS Description
       .P
       This command will update all the packages listed to the latest version
      -(specified by the \fBtag\fP config), respecting semver\.
      +(specified by the \fBtag\fP config), respecting the semver constraints of
      +both your package and its dependencies (if they also require the same
      +package)\.
       .P
       It will also install missing packages\.
       .P
      @@ -103,6 +105,41 @@ If the dependence were on \fB^0\.4\.0\fP:
       .P
       Then \fBnpm update\fP will install \fBdep1@0\.4\.1\fP, because that is the highest\-sorting
       version that satisfies \fB^0\.4\.0\fP (\fB>= 0\.4\.0 <0\.5\.0\fP)
      +.SS Subdependencies
      +.P
      +Suppose your app now also has a dependency on \fBdep2\fP
      +.P
      +.RS 2
      +.nf
      +{
      +  "name": "my\-app",
      +  "dependencies": {
      +      "dep1": "^1\.0\.0",
      +      "dep2": "1\.0\.0"
      +  }
      +}
      +.fi
      +.RE
      +.P
      +and \fBdep2\fP itself depends on this limited range of \fBdep1\fP
      +.P
      +.RS 2
      +.nf
      +{
      +"name": "dep2",
      +  "dependencies": {
      +    "dep1": "~1\.1\.1"
      +  }
      +}
      +.fi
      +.RE
      +.P
      +Then \fBnpm update\fP will install \fBdep1@1\.1\.2\fP because that is the highest
      +version that \fBdep2\fP allows\.  npm will prioritize having a single version
      +of \fBdep1\fP in your tree rather than two when that single version can
      +satisfy the semver requirements of multiple dependencies in your tree\.
      +In this case if you really did need your package to use a newer version
      +you would need to use \fBnpm install\fP\|\.
       .SS Updating Globally\-Installed Packages
       .P
       \fBnpm update \-g\fP will apply the \fBupdate\fP action to each globally installed
      @@ -250,9 +287,10 @@ Type: Boolean
       
       .RE
       .P
      -When "true" submit audit reports alongside \fBnpm install\fP runs to the default
      -registry and all registries configured for scopes\. See the documentation for
      -npm help \fBaudit\fP for details on what is submitted\.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBbin\-links\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man1/npm-version.1 b/deps/npm/man/man1/npm-version.1
      index 874337beb37927..f798ed97a15223 100644
      --- a/deps/npm/man/man1/npm-version.1
      +++ b/deps/npm/man/man1/npm-version.1
      @@ -56,6 +56,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBpreid\fP
      diff --git a/deps/npm/man/man1/npm-view.1 b/deps/npm/man/man1/npm-view.1
      index 08d9fe0abd3a9f..a63cab9feec386 100644
      --- a/deps/npm/man/man1/npm-view.1
      +++ b/deps/npm/man/man1/npm-view.1
      @@ -55,7 +55,7 @@ npm view opts@$(npm view ronn dependencies\.opts)
       .P
       For fields that are arrays, requesting a non\-numeric field will return
       all of the values from the objects in the list\. For example, to get all
      -the contributor names for the \fBexpress\fP package, you would run:
      +the contributor email addresses for the \fBexpress\fP package, you would run:
       .P
       .RS 2
       .nf
      @@ -124,6 +124,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBworkspace\fP
      diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1
      index d73ecc120df55c..725c286aaec2ab 100644
      --- a/deps/npm/man/man1/npm.1
      +++ b/deps/npm/man/man1/npm.1
      @@ -10,7 +10,7 @@ npm  [args]
       .RE
       .SS Version
       .P
      -7\.19\.1
      +7\.20\.3
       .SS Description
       .P
       npm is the package manager for the Node JavaScript platform\.  It puts
      diff --git a/deps/npm/man/man5/folders.5 b/deps/npm/man/man5/folders.5
      index e0f5574b747694..80b6db8074002f 100644
      --- a/deps/npm/man/man5/folders.5
      +++ b/deps/npm/man/man5/folders.5
      @@ -46,13 +46,15 @@ Global installs on Windows go to \fB{prefix}/node_modules\fP (that is, no
       Scoped packages are installed the same way, except they are grouped together
       in a sub\-folder of the relevant \fBnode_modules\fP folder with the name of that
       scope prefix by the @ symbol, e\.g\. \fBnpm install @myorg/package\fP would place
      -the package in \fB{prefix}/node_modules/@myorg/package\fP\|\. See npm help \fBscope\fP for more details\.
      +the package in \fB{prefix}/node_modules/@myorg/package\fP\|\. See
      +npm help \fBscope\fP for more details\.
       .P
       If you wish to \fBrequire()\fP a package, then install it locally\.
       .SS Executables
       .P
       When in global mode, executables are linked into \fB{prefix}/bin\fP on Unix,
      -or directly into \fB{prefix}\fP on Windows\.
      +or directly into \fB{prefix}\fP on Windows\.  Ensure that path is in your
      +terminal's \fBPATH\fP environment to run them\.
       .P
       When in local mode, executables are linked into
       \fB\|\./node_modules/\.bin\fP so that they can be made available to scripts run
      diff --git a/deps/npm/man/man5/package-json.5 b/deps/npm/man/man5/package-json.5
      index f97a3d2d5fdb1d..323394188a455b 100644
      --- a/deps/npm/man/man5/package-json.5
      +++ b/deps/npm/man/man5/package-json.5
      @@ -388,9 +388,12 @@ install into the PATH\. npm makes this pretty easy (in fact, it uses this
       feature to install the "npm" executable\.)
       .P
       To use this, supply a \fBbin\fP field in your package\.json which is a map of
      -command name to local file name\. On install, npm will symlink that file
      -into \fBprefix/bin\fP for global installs, or \fB\|\./node_modules/\.bin/\fP for local
      -installs\.
      +command name to local file name\. When this package is installed
      +globally, that file will be linked where global bins go so it is
      +available to run by name\.  When this package is installed as a
      +dependency in another package, the file will be linked where it will be
      +available to that package either directly by \fBnpm exec\fP or by name in other
      +scripts when invoking them via \fBnpm run\-script\fP\|\.
       .P
       For example, myapp could have this:
       .P
      @@ -439,6 +442,9 @@ Please make sure that your file(s) referenced in \fBbin\fP starts with
       executable!
       .P
       Note that you can also set the executable files using directories\.bin \fI#directoriesbin\fR\|\.
      +.P
      +See npm help folders for more info on
      +executables\.
       .SS man
       .P
       Specify either a single file or an array of filenames to put in place for
      diff --git a/deps/npm/man/man7/config.7 b/deps/npm/man/man7/config.7
      index 048dcf14113927..ac0a415f10a363 100644
      --- a/deps/npm/man/man7/config.7
      +++ b/deps/npm/man/man7/config.7
      @@ -72,6 +72,8 @@ The following shorthands are parsed on the command\-line:
       .IP \(bu 2
       \fB\-g\fP: \fB\-\-global\fP
       .IP \(bu 2
      +\fB\-L\fP: \fB\-\-location\fP
      +.IP \(bu 2
       \fB\-d\fP: \fB\-\-loglevel info\fP
       .IP \(bu 2
       \fB\-s\fP: \fB\-\-loglevel silent\fP
      @@ -226,9 +228,10 @@ Type: Boolean
       
       .RE
       .P
      -When "true" submit audit reports alongside \fBnpm install\fP runs to the default
      -registry and all registries configured for scopes\. See the documentation for
      -npm help \fBaudit\fP for details on what is submitted\.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes\. See the
      +documentation for npm help \fBaudit\fP for details on what is
      +submitted\.
       .SS \fBaudit\-level\fP
       .RS 0
       .IP \(bu 2
      @@ -663,6 +666,8 @@ Allow unpublishing all versions of a published package\.
       Allow conflicting peerDependencies to be installed in the root project\.
       .IP \(bu 2
       Implicitly set \fB\-\-yes\fP during \fBnpm init\fP\|\.
      +.IP \(bu 2
      +Allow clobbering existing values in \fBnpm pkg\fP
       
       .RE
       .P
      @@ -931,6 +936,12 @@ Type: Boolean
       .RE
       .P
       Whether or not to output JSON data, rather than the normal output\.
      +.RS 0
      +.IP \(bu 2
      +In \fBnpm pkg set\fP it enables parsing set values with JSON\.parse() before
      +saving them to your \fBpackage\.json\fP\|\.
      +
      +.RE
       .P
       Not supported by all npm commands\.
       .SS \fBkey\fP
      @@ -1007,6 +1018,17 @@ Type: IP Address
       .P
       The IP address of the local interface to use when making connections to the
       npm registry\. Must be IPv4 in versions of Node prior to 0\.12\.
      +.SS \fBlocation\fP
      +.RS 0
      +.IP \(bu 2
      +Default: "user" unless \fB\-\-global\fP is passed, which will also set this value
      +to "global"
      +.IP \(bu 2
      +Type: "global", "user", or "project"
      +
      +.RE
      +.P
      +When passed to \fBnpm config\fP this refers to which config file to use\.
       .SS \fBloglevel\fP
       .RS 0
       .IP \(bu 2
      diff --git a/deps/npm/man/man7/scripts.7 b/deps/npm/man/man7/scripts.7
      index 56a3326b6c445e..cac6ab0a2a3565 100644
      --- a/deps/npm/man/man7/scripts.7
      +++ b/deps/npm/man/man7/scripts.7
      @@ -60,7 +60,8 @@ script, its \fBdependencies\fP and \fBdevDependencies\fP will be installed, and
       the prepare script will be run, before the package is packaged and
       installed\.
       .IP \(bu 2
      -As of \fBnpm@7\fP these scripts run in the background
      +As of \fBnpm@7\fP these scripts run in the background\.
      +To see the output, run with: \fB\-\-foreground\-scripts\fP\|\.
       
       .RE
       .P
      @@ -391,8 +392,8 @@ Scripts are run by passing the line as a script argument to \fBsh\fP\|\.
       If the script exits with a code other than 0, then this will abort the
       process\.
       .P
      -Note that these script files don't have to be nodejs or even
      -javascript programs\. They just have to be some kind of executable
      +Note that these script files don't have to be Node\.js or even
      +JavaScript programs\. They just have to be some kind of executable
       file\.
       .SS Best Practices
       .RS 0
      diff --git a/deps/npm/man/man7/workspaces.7 b/deps/npm/man/man7/workspaces.7
      index 70abfd5f97235f..52128895a4acb7 100644
      --- a/deps/npm/man/man7/workspaces.7
      +++ b/deps/npm/man/man7/workspaces.7
      @@ -35,7 +35,7 @@ npm help \fBpackage\.json\fP file, e\.g:
       .P
       Given the above \fBpackage\.json\fP example living at a current working
       directory \fB\|\.\fP that contains a folder named \fBworkspace\-a\fP that itself contains
      -a \fBpackage\.json\fP inside it, defining a nodejs package, e\.g:
      +a \fBpackage\.json\fP inside it, defining a Node\.js package, e\.g:
       .P
       .RS 2
       .nf
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
      index 5db11eb3832eb0..7ef42289d297bb 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
      @@ -3,14 +3,20 @@ const rpj = require('read-package-json-fast')
       const npa = require('npm-package-arg')
       const pacote = require('pacote')
       const cacache = require('cacache')
      -const semver = require('semver')
       const promiseCallLimit = require('promise-call-limit')
      -const getPeerSet = require('../peer-set.js')
       const realpath = require('../../lib/realpath.js')
       const { resolve, dirname } = require('path')
       const { promisify } = require('util')
       const treeCheck = require('../tree-check.js')
       const readdir = promisify(require('readdir-scoped-modules'))
      +const { depth } = require('treeverse')
      +
      +const {
      +  OK,
      +  REPLACE,
      +  CONFLICT,
      +} = require('../can-place-dep.js')
      +const PlaceDep = require('../place-dep.js')
       
       const debug = require('../debug.js')
       const fromPath = require('../from-path.js')
      @@ -19,20 +25,9 @@ const Shrinkwrap = require('../shrinkwrap.js')
       const Node = require('../node.js')
       const Link = require('../link.js')
       const addRmPkgDeps = require('../add-rm-pkg-deps.js')
      -const gatherDepSet = require('../gather-dep-set.js')
       const optionalSet = require('../optional-set.js')
       const {checkEngine, checkPlatform} = require('npm-install-checks')
       
      -// enum of return values for canPlaceDep.
      -// No, this is a conflict, you may not put that package here
      -const CONFLICT = Symbol('CONFLICT')
      -// Yes, this is fine, and should not be a problem
      -const OK = Symbol('OK')
      -// No need, because the package already here is fine
      -const KEEP = Symbol('KEEP')
      -// Yes, clobber the package that is already here
      -const REPLACE = Symbol('REPLACE')
      -
       const relpath = require('../relpath.js')
       
       // note: some of these symbols are shared so we can hit
      @@ -47,7 +42,6 @@ const _flagsSuspect = Symbol.for('flagsSuspect')
       const _workspaces = Symbol.for('workspaces')
       const _prune = Symbol('prune')
       const _preferDedupe = Symbol('preferDedupe')
      -const _pruneDedupable = Symbol('pruneDedupable')
       const _legacyBundling = Symbol('legacyBundling')
       const _parseSettings = Symbol('parseSettings')
       const _initTree = Symbol('initTree')
      @@ -65,10 +59,6 @@ const _loadWorkspaces = Symbol.for('loadWorkspaces')
       const _linkFromSpec = Symbol('linkFromSpec')
       const _loadPeerSet = Symbol('loadPeerSet')
       const _updateNames = Symbol.for('updateNames')
      -const _placeDep = Symbol.for('placeDep')
      -const _canPlaceDep = Symbol.for('canPlaceDep')
      -const _canPlacePeers = Symbol('canPlacePeers')
      -const _pruneForReplacement = Symbol('pruneForReplacement')
       const _fixDepFlags = Symbol('fixDepFlags')
       const _resolveLinks = Symbol('resolveLinks')
       const _rootNodeFromPackage = Symbol('rootNodeFromPackage')
      @@ -100,12 +90,8 @@ const _checkPlatform = Symbol('checkPlatform')
       const _virtualRoots = Symbol('virtualRoots')
       const _virtualRoot = Symbol('virtualRoot')
       
      -// used for the ERESOLVE error to show the last peer conflict encountered
      -const _peerConflict = Symbol('peerConflict')
      -
       const _failPeerConflict = Symbol('failPeerConflict')
       const _explainPeerConflict = Symbol('explainPeerConflict')
      -const _warnPeerConflict = Symbol('warnPeerConflict')
       const _edgesOverridden = Symbol('edgesOverridden')
       // exposed symbol for unit testing the placeDep method directly
       const _peerSetSource = Symbol.for('peerSetSource')
      @@ -163,7 +149,6 @@ module.exports = cls => class IdealTreeBuilder extends cls {
           this[_loadFailures] = new Set()
           this[_linkNodes] = new Set()
           this[_manifests] = new Map()
      -    this[_peerConflict] = null
           this[_edgesOverridden] = new Set()
           this[_resolvedAdd] = []
       
      @@ -227,17 +212,13 @@ module.exports = cls => class IdealTreeBuilder extends cls {
           return treeCheck(this.idealTree)
         }
       
      -  [_checkEngineAndPlatform] () {
      -    // engine/platform checks throw, so start the promise chain off first
      -    return Promise.resolve()
      -      .then(() => {
      -        for (const node of this.idealTree.inventory.values()) {
      -          if (!node.optional) {
      -            this[_checkEngine](node)
      -            this[_checkPlatform](node)
      -          }
      -        }
      -      })
      +  async [_checkEngineAndPlatform] () {
      +    for (const node of this.idealTree.inventory.values()) {
      +      if (!node.optional) {
      +        this[_checkEngine](node)
      +        this[_checkPlatform](node)
      +      }
      +    }
         }
       
         [_checkPlatform] (node) {
      @@ -324,7 +305,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
             .then(async root => {
               if (!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk) {
                 await new this.constructor(this.options).loadActual({ root })
      -          const tree = root.target || root
      +          const tree = root.target
                 // even though we didn't load it from a package-lock.json FILE,
                 // we still loaded it "from disk", meaning we have to reset
                 // dep flags before assuming that any mutations were reflected.
      @@ -396,7 +377,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
         // update.names request by queueing nodes dependent on those named.
         async [_applyUserRequests] (options) {
           process.emit('time', 'idealTree:userRequests')
      -    const tree = this.idealTree.target || this.idealTree
      +    const tree = this.idealTree.target
       
           if (!this[_workspaces].length)
             await this[_applyUserRequestsToNode](tree, options)
      @@ -532,7 +513,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
           /* istanbul ignore else - should also be covered by realpath failure */
           if (filepath) {
             const { name } = spec
      -      const tree = this.idealTree.target || this.idealTree
      +      const tree = this.idealTree.target
             spec = npa(`file:${relpath(tree.path, filepath)}`, tree.path)
             spec.name = name
           }
      @@ -730,7 +711,7 @@ This is a one-time fix-up, please be patient...
         // or extraneous.
         [_buildDeps] () {
           process.emit('time', 'idealTree:buildDeps')
      -    const tree = this.idealTree.target || this.idealTree
      +    const tree = this.idealTree.target
           this[_depsQueue].push(tree)
           this.log.silly('idealTree', 'buildDeps')
           this.addTracker('idealTree', tree.name, '')
      @@ -788,7 +769,11 @@ This is a one-time fix-up, please be patient...
             const Arborist = this.constructor
             const opt = { ...this.options }
             await cacache.tmp.withTmp(this.cache, opt, async path => {
      -        await pacote.extract(node.resolved, path, opt)
      +        await pacote.extract(node.resolved, path, {
      +          ...opt,
      +          resolved: node.resolved,
      +          integrity: node.integrity,
      +        })
       
               if (hasShrinkwrap) {
                 await new Arborist({ ...this.options, path })
      @@ -846,7 +831,7 @@ This is a one-time fix-up, please be patient...
           const tasks = []
           const peerSource = this[_peerSetSource].get(node) || node
           for (const edge of this[_problemEdges](node)) {
      -      if (this[_edgesOverridden].has(edge))
      +      if (edge.overridden)
               continue
       
             // peerSetSource is only relevant when we have a peerEntryEdge
      @@ -890,34 +875,101 @@ This is a one-time fix-up, please be patient...
             tasks.push({edge, dep})
           }
       
      -    const placed = tasks
      +    const placeDeps = tasks
             .sort((a, b) => a.edge.name.localeCompare(b.edge.name, 'en'))
      -      .map(({ edge, dep }) => this[_placeDep](dep, node, edge))
      +      .map(({ edge, dep }) => new PlaceDep({
      +        edge,
      +        dep,
      +
      +        explicitRequest: this[_explicitRequests].has(edge),
      +        updateNames: this[_updateNames],
      +        auditReport: this.auditReport,
      +        force: this[_force],
      +        preferDedupe: this[_preferDedupe],
      +        legacyBundling: this[_legacyBundling],
      +        strictPeerDeps: this[_strictPeerDeps],
      +        legacyPeerDeps: this.legacyPeerDeps,
      +        globalStyle: this[_globalStyle],
      +      }))
       
           const promises = []
      -    for (const set of placed) {
      -      for (const node of set) {
      -        this[_mutateTree] = true
      -        this.addTracker('idealTree', node.name, node.location)
      -        this[_depsQueue].push(node)
      -
      -        // we're certainly going to need these soon, fetch them asap
      -        // if it fails at this point, though, dont' worry because it
      -        // may well be an optional dep that has gone missing.  it'll
      -        // fail later anyway.
      -        const from = fromPath(node)
      -        promises.push(...this[_problemEdges](node).map(e =>
      -          this[_fetchManifest](npa.resolve(e.name, e.spec, from))
      -            .catch(er => null)))
      -      }
      +    for (const pd of placeDeps) {
      +      // placing a dep is actually a tree of placing the dep itself
      +      // and all of its peer group that aren't already met by the tree
      +      depth({
      +        tree: pd,
      +        getChildren: pd => pd.children,
      +        visit: pd => {
      +          const { placed, edge, canPlace: cpd } = pd
      +          // if we didn't place anything, nothing to do here
      +          if (!placed)
      +            return
      +
      +          // we placed something, that means we changed the tree
      +          if (placed.errors.length)
      +            this[_loadFailures].add(placed)
      +          this[_mutateTree] = true
      +          if (cpd.canPlaceSelf === OK) {
      +            for (const edgeIn of placed.edgesIn) {
      +              if (edgeIn === edge)
      +                continue
      +              const { from, valid, overridden } = edgeIn
      +              if (!overridden && !valid && !this[_depsSeen].has(from)) {
      +                this.addTracker('idealTree', from.name, from.location)
      +                this[_depsQueue].push(edgeIn.from)
      +              }
      +            }
      +          } else {
      +            /* istanbul ignore else - should be only OK or REPLACE here */
      +            if (cpd.canPlaceSelf === REPLACE) {
      +              // this may also create some invalid edges, for example if we're
      +              // intentionally causing something to get nested which was
      +              // previously placed in this location.
      +              for (const edgeIn of placed.edgesIn) {
      +                if (edgeIn === edge)
      +                  continue
      +
      +                const { valid, overridden } = edgeIn
      +                if (!valid && !overridden) {
      +                  // if it's already been visited, we have to re-visit
      +                  // otherwise, just enqueue normally.
      +                  this[_depsSeen].delete(edgeIn.from)
      +                  this[_depsQueue].push(edgeIn.from)
      +                }
      +              }
      +            }
      +          }
      +
      +          /* istanbul ignore if - should be impossible */
      +          if (cpd.canPlaceSelf === CONFLICT) {
      +            debug(() => {
      +              const er = new Error('placed with canPlaceSelf=CONFLICT')
      +              throw Object.assign(er, { placeDep: pd })
      +            })
      +            return
      +          }
      +
      +          // lastly, also check for the missing deps of the node we placed
      +          this[_depsQueue].push(placed)
      +
      +          // pre-fetch any problem edges, since we'll need these soon
      +          // if it fails at this point, though, dont' worry because it
      +          // may well be an optional dep that has gone missing.  it'll
      +          // fail later anyway.
      +          const from = fromPath(placed)
      +          promises.push(...this[_problemEdges](placed).map(e =>
      +            this[_fetchManifest](npa.resolve(e.name, e.spec, from))
      +              .catch(er => null)))
      +        },
      +      })
           }
      -    await Promise.all(promises)
       
           for (const { to } of node.edgesOut.values()) {
      -      if (to && to.isLink)
      +      if (to && to.isLink && to.target)
               this[_linkNodes].add(to)
           }
       
      +    await Promise.all(promises)
           return this[_buildDepStep]()
         }
       
      @@ -1172,8 +1224,10 @@ This is a one-time fix-up, please be patient...
                 // allow it.  either we're overriding, or it's not something
                 // that will be installed by default anyway, and we'll fail when
                 // we get to the point where we need to, if we need to.
      -          if (conflictOK || !required.has(dep))
      +          if (conflictOK || !required.has(dep)) {
      +            edge.overridden = true
                   continue
      +          }
       
                 // problem
                 this[_failPeerConflict](edge, parentEdge)
      @@ -1215,9 +1269,7 @@ This is a one-time fix-up, please be patient...
         [_explainPeerConflict] (edge, currentEdge) {
           const node = edge.from
           const curNode = node.resolve(edge.name)
      -    const pc = this[_peerConflict] || { peer: null, current: null }
      -    const current = curNode ? curNode.explain() : pc.current
      -    const peerConflict = pc.peer
      +    const current = curNode.explain()
           return {
             code: 'ERESOLVE',
             current,
      @@ -1226,640 +1278,11 @@ This is a one-time fix-up, please be patient...
             // the tree handling logic.
             currentEdge: currentEdge ? currentEdge.explain() : null,
             edge: edge.explain(),
      -      peerConflict,
             strictPeerDeps: this[_strictPeerDeps],
             force: this[_force],
           }
         }
       
      -  [_warnPeerConflict] (edge) {
      -    // track that we've overridden this edge, so that we don't keep trying
      -    // to re-resolve it in an infinite loop.
      -    this[_edgesOverridden].add(edge)
      -    const expl = this[_explainPeerConflict](edge)
      -    this.log.warn('ERESOLVE', 'overriding peer dependency', expl)
      -  }
      -
      -  // starting from either node, or in the case of non-root peer deps,
      -  // the node's parent, walk up the tree until we find the first spot
      -  // where this dep cannot be placed, and use the one right before that.
      -  // place dep, requested by node, to satisfy edge
      -  // XXX split this out into a separate method or mixin?  It's quite a lot
      -  // of functionality that ought to have its own unit tests more conveniently.
      -  [_placeDep] (dep, node, edge, peerEntryEdge = null, peerPath = []) {
      -    if (edge.to &&
      -        !edge.error &&
      -        !this[_explicitRequests].has(edge) &&
      -        !this[_updateNames].includes(edge.name) &&
      -        !this[_isVulnerable](edge.to))
      -      return []
      -
      -    // top nodes should still get peer deps from their fsParent if possible,
      -    // and only install locally if there's no other option, eg for a link
      -    // outside of the project root, or for a conflicted dep.
      -    const start = edge.peer && !node.isProjectRoot ? node.resolveParent || node
      -      : node
      -
      -    let target
      -    let canPlace = null
      -    let isSource = false
      -    const source = this[_peerSetSource].get(dep)
      -    for (let check = start; check; check = check.resolveParent) {
      -      // we always give the FIRST place we possibly *can* put this a little
      -      // extra prioritization with peer dep overrides and deduping
      -      if (check === source)
      -        isSource = true
      -
      -      // if the current location has a peerDep on it, then we can't place here
      -      // this is pretty rare to hit, since we always prefer deduping peers.
      -      const checkEdge = check.edgesOut.get(edge.name)
      -      if (!check.isTop && checkEdge && checkEdge.peer)
      -        continue
      -
      -      const cp = this[_canPlaceDep](dep, check, edge, peerEntryEdge, peerPath, isSource)
      -      isSource = false
      -
      -      // anything other than a conflict is fine to proceed with
      -      if (cp !== CONFLICT) {
      -        canPlace = cp
      -        target = check
      -      } else
      -        break
      -
      -      // nest packages like npm v1 and v2
      -      // very disk-inefficient
      -      if (this[_legacyBundling])
      -        break
      -
      -      // when installing globally, or just in global style, we never place
      -      // deps above the first level.
      -      const tree = this.idealTree && this.idealTree.target || this.idealTree
      -      if (this[_globalStyle] && check.resolveParent === tree)
      -        break
      -    }
      -
      -    // if we can't find a target, that means that the last placed checked
      -    // (and all the places before it) had a copy already.  if we're in
      -    // --force mode, then the user has explicitly said that they're ok
      -    // with conflicts.  This can only occur in --force mode in the case
      -    // when a node was added to the tree with a peerOptional dep that we
      -    // ignored, and then later, that edge became invalid, and we fail to
      -    // resolve it.  We will warn about it in a moment.
      -    if (!target) {
      -      if (this[_force]) {
      -        // we know that there is a dep (not the root) which is the target
      -        // of this edge, or else it wouldn't have been a conflict.
      -        target = edge.to.resolveParent
      -        canPlace = KEEP
      -      } else
      -        this[_failPeerConflict](edge)
      -    } else {
      -      // it worked, so we clearly have no peer conflicts at this point.
      -      this[_peerConflict] = null
      -    }
      -
      -    this.log.silly(
      -      'placeDep',
      -      target.location || 'ROOT',
      -      `${dep.name}@${dep.version}`,
      -      canPlace.description || /* istanbul ignore next */ canPlace,
      -      `for: ${node.package._id || node.location}`,
      -      `want: ${edge.spec || '*'}`
      -    )
      -
      -    // Can only get KEEP here if the original edge was valid,
      -    // and we're checking for an update but it's already up to date.
      -    if (canPlace === KEEP) {
      -      if (edge.peer && !target.children.get(edge.name).satisfies(edge)) {
      -        // this is an overridden peer dep
      -        this[_warnPeerConflict](edge)
      -      }
      -
      -      // if we get a KEEP in a update scenario, then we MAY have something
      -      // already duplicating this unnecessarily!  For example:
      -      // ```
      -      // root
      -      // +-- x (dep: y@1.x)
      -      // |   +-- y@1.0.0
      -      // +-- y@1.1.0
      -      // ```
      -      // Now say we do `reify({update:['y']})`, and the latest version is
      -      // 1.1.0, which we already have in the root.  We'll try to place y@1.1.0
      -      // first in x, then in the root, ending with KEEP, because we already
      -      // have it.  In that case, we ought to REMOVE the nm/x/nm/y node, because
      -      // it is an unnecessary duplicate.
      -      this[_pruneDedupable](target)
      -      return []
      -    }
      -
      -    // figure out which of this node's peer deps will get placed as well
      -    const virtualRoot = dep.parent
      -
      -    const newDep = new dep.constructor({
      -      name: dep.name,
      -      pkg: dep.package,
      -      resolved: dep.resolved,
      -      integrity: dep.integrity,
      -      legacyPeerDeps: this.legacyPeerDeps,
      -      error: dep.errors[0],
      -      ...(dep.target ? { target: dep.target, realpath: dep.target.path } : {}),
      -    })
      -    if (this[_loadFailures].has(dep))
      -      this[_loadFailures].add(newDep)
      -
      -    const placed = [newDep]
      -    const oldChild = target.children.get(edge.name)
      -    if (oldChild) {
      -      // if we're replacing, we should also remove any nodes for edges that
      -      // are now invalid, and where this (or its deps) is the only dependent,
      -      // and also recurse on that pruning.  Otherwise leaving that dep node
      -      // around can result in spurious conflicts pushing nodes deeper into
      -      // the tree than needed in the case of cycles that will be removed
      -      // later anyway.
      -      const oldDeps = []
      -      for (const [name, edge] of oldChild.edgesOut.entries()) {
      -        if (!newDep.edgesOut.has(name) && edge.to)
      -          oldDeps.push(...gatherDepSet([edge.to], e => e.to !== edge.to))
      -      }
      -      newDep.replace(oldChild)
      -      this[_pruneForReplacement](newDep, oldDeps)
      -      // this may also create some invalid edges, for example if we're
      -      // intentionally causing something to get nested which was previously
      -      // placed in this location.
      -      for (const edgeIn of newDep.edgesIn) {
      -        if (edgeIn.invalid && edgeIn !== edge) {
      -          this[_depsQueue].push(edgeIn.from)
      -          this[_depsSeen].delete(edgeIn.from)
      -        }
      -      }
      -    } else
      -      newDep.parent = target
      -
      -    if (edge.peer && !newDep.satisfies(edge)) {
      -      // this is an overridden peer dep
      -      this[_warnPeerConflict](edge)
      -    }
      -
      -    // If the edge is not an error, then we're updating something, and
      -    // MAY end up putting a better/identical node further up the tree in
      -    // a way that causes an unnecessary duplication.  If so, remove the
      -    // now-unnecessary node.
      -    if (edge.valid && edge.to && edge.to !== newDep)
      -      this[_pruneDedupable](edge.to, false)
      -
      -    // visit any dependents who are upset by this change
      -    // if it's an angry overridden peer edge, however, make sure we
      -    // skip over it!
      -    for (const edgeIn of newDep.edgesIn) {
      -      if (edgeIn !== edge && !edgeIn.valid && !this[_depsSeen].has(edge.from)) {
      -        this.addTracker('idealTree', edgeIn.from.name, edgeIn.from.location)
      -        this[_depsQueue].push(edgeIn.from)
      -      }
      -    }
      -
      -    // in case we just made some duplicates that can be removed,
      -    // prune anything deeper in the tree that can be replaced by this
      -    if (this.idealTree) {
      -      for (const node of this.idealTree.inventory.query('name', newDep.name)) {
      -        if (node.isDescendantOf(target))
      -          this[_pruneDedupable](node, false)
      -      }
      -    }
      -
      -    // also place its unmet or invalid peer deps at this location
      -    // note that newDep has now been removed from the virtualRoot set
      -    // by virtue of being placed in the target's node_modules.
      -    // loop through any peer deps from the thing we just placed, and place
      -    // those ones as well.  it's safe to do this with the virtual nodes,
      -    // because we're copying rather than moving them out of the virtual root,
      -    // otherwise they'd be gone and the peer set would change throughout
      -    // this loop.
      -    for (const peerEdge of newDep.edgesOut.values()) {
      -      const peer = virtualRoot.children.get(peerEdge.name)
      -
      -      // Note: if the virtualRoot *doesn't* have the peer, then that means
      -      // it's an optional peer dep.  If it's not being properly met (ie,
      -      // peerEdge.valid is false), that this is likely heading for an
      -      // ERESOLVE error, unless it can walk further up the tree.
      -      if (!peerEdge.peer || peerEdge.valid || !peer)
      -        continue
      -
      -      const peerPlaced = this[_placeDep](
      -        peer, newDep, peerEdge, peerEntryEdge || edge, peerPath)
      -      placed.push(...peerPlaced)
      -    }
      -
      -    // we're done with this now, clean it up.
      -    this[_virtualRoots].delete(virtualRoot.sourceReference)
      -
      -    return placed
      -  }
      -
      -  // prune all the nodes in a branch of the tree that can be safely removed
      -  // This is only the most basic duplication detection; it finds if there
      -  // is another satisfying node further up the tree, and if so, dedupes.
      -  // Even in legacyBundling mode, we do this amount of deduplication.
      -  [_pruneDedupable] (node, descend = true) {
      -    if (node.canDedupe(this[_preferDedupe])) {
      -      node.root = null
      -      return
      -    }
      -    if (descend) {
      -      // sort these so that they're deterministically ordered
      -      // otherwise, resulting tree shape is dependent on the order
      -      // in which they happened to be resolved.
      -      const nodeSort = (a, b) => a.location.localeCompare(b.location, 'en')
      -
      -      const children = [...node.children.values()].sort(nodeSort)
      -      const fsChildren = [...node.fsChildren].sort(nodeSort)
      -      for (const child of children)
      -        this[_pruneDedupable](child)
      -      for (const topNode of fsChildren) {
      -        const children = [...topNode.children.values()].sort(nodeSort)
      -        for (const child of children)
      -          this[_pruneDedupable](child)
      -      }
      -    }
      -  }
      -
      -  [_pruneForReplacement] (node, oldDeps) {
      -    // gather up all the invalid edgesOut, and any now-extraneous
      -    // deps that the new node doesn't depend on but the old one did.
      -    const invalidDeps = new Set([...node.edgesOut.values()]
      -      .filter(e => e.to && !e.valid).map(e => e.to))
      -    for (const dep of oldDeps) {
      -      const set = gatherDepSet([dep], e => e.to !== dep && e.valid)
      -      for (const dep of set)
      -        invalidDeps.add(dep)
      -    }
      -
      -    // ignore dependency edges from the node being replaced, but
      -    // otherwise filter the set down to just the set with no
      -    // dependencies from outside the set, except the node in question.
      -    const deps = gatherDepSet(invalidDeps, edge =>
      -      edge.from !== node && edge.to !== node && edge.valid)
      -
      -    // now just delete whatever's left, because it's junk
      -    for (const dep of deps)
      -      dep.parent = null
      -  }
      -
      -  // check if we can place DEP in TARGET to satisfy EDGE
      -  // Need to verify:
      -  // - no child by that name there already
      -  // - target does not have a peer dep on name
      -  // - no higher-level pkg by that name and incompatible spec is depended on
      -  //   by anything lower in the tree.
      -  // - node's peer deps and meta-peer deps are siblings in a virtual root at
      -  //   this point.  make sure that the whole family can come along, so apply
      -  //   the same checks to each of them.  They may land higher up in the tree,
      -  //   but we need to know that they CAN live here.
      -  // Responses:
      -  // - OK - Yes, because there is nothing there and no conflicts caused
      -  // - REPLACE - Yes, and you can clobber what's there
      -  // - KEEP - No, but what's there is fine
      -  // - CONFLICT - You may not put that there
      -  //
      -  // Check peers on OK or REPLACE.  KEEP and CONFLICT do not require peer
      -  // checking, because either we're leaving it alone, or it won't work anyway.
      -  // When we check peers, we pass along the peerEntryEdge to track the
      -  // original edge that caused us to load the family of peer dependencies.
      -  [_canPlaceDep] (dep, target, edge, peerEntryEdge = null, peerPath = [], isSource = false) {
      -    /* istanbul ignore next */
      -    debug(() => {
      -      if (!dep)
      -        throw new Error('no dep??')
      -    })
      -    const entryEdge = peerEntryEdge || edge
      -    const source = this[_peerSetSource].get(dep)
      -
      -    isSource = isSource || target === source
      -    // if we're overriding the source, then we care if the *target* is
      -    // ours, even if it wasn't actually the original source, since we
      -    // are depending on something that has a dep that can't go in its own
      -    // folder.  for example, a -> b, b -> PEER(a).  Even though a is the
      -    // source, b has to be installed up a level, and if the root package
      -    // depends on a, and it has a conflict, it's our problem.  So, the root
      -    // (or whatever is bringing in a) becomes the "effective source" for
      -    // the purposes of this calculation.
      -    const { isProjectRoot, isWorkspace } = isSource ? target : source || {}
      -    const isMine = isProjectRoot || isWorkspace
      -
      -    // Useful testing thingie right here.
      -    // peerEntryEdge should *always* be a non-peer dependency, or a peer
      -    // dependency from the root node.  When we get spurious ERESOLVE errors,
      -    // or *don't* get ERESOLVE errors when we should, check to see if this
      -    // fails, because it MAY mean we got off track somehow.
      -    /* istanbul ignore next - debug check, should be impossible */
      -    debug(() => {
      -      if (peerEntryEdge && peerEntryEdge.peer && !peerEntryEdge.from.isTop)
      -        throw new Error('lost original peerEntryEdge somehow?')
      -    })
      -
      -    if (target.children.has(edge.name)) {
      -      const current = target.children.get(edge.name)
      -
      -      // same thing = keep, UNLESS the current doesn't satisfy and new
      -      // one does satisfy.  This can happen if it's a link to a matching target
      -      // at a different location, which satisfies a version dep, but not a
      -      // file: dep.  If neither of them satisfy, then we can replace it,
      -      // because presumably it's better for a peer or something.
      -      if (dep.matches(current)) {
      -        if (current.satisfies(edge) || !dep.satisfies(edge))
      -          return KEEP
      -      }
      -
      -      const { version: curVer } = current
      -      const { version: newVer } = dep
      -      const tryReplace = curVer && newVer && semver.gte(newVer, curVer)
      -      if (tryReplace && dep.canReplace(current)) {
      -        const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath, isSource)
      -        /* istanbul ignore else - It's extremely rare that a replaceable
      -         * node would be a conflict, if the current one wasn't a conflict,
      -         * but it is theoretically possible if peer deps are pinned.  In
      -         * that case we treat it like any other conflict, and keep trying */
      -        if (res !== CONFLICT)
      -          return res
      -      }
      -
      -      // ok, can't replace the current with new one, but maybe current is ok?
      -      // no need to check if it's a peer that's valid to be here, because
      -      // peers are always placed along with their entry source
      -      if (edge.satisfiedBy(current))
      -        return KEEP
      -
      -      // if we prefer deduping, then try replacing newer with older
      -      // we always prefer to dedupe peers, because they are trying
      -      // a bit harder to be singletons.
      -      const preferDedupe = this[_preferDedupe] || edge.peer
      -      if (preferDedupe && !tryReplace && dep.canReplace(current)) {
      -        const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath, isSource)
      -        /* istanbul ignore else - It's extremely rare that a replaceable
      -         * node would be a conflict, if the current one wasn't a conflict,
      -         * but it is theoretically possible if peer deps are pinned.  In
      -         * that case we treat it like any other conflict, and keep trying */
      -        if (res !== CONFLICT)
      -          return res
      -      }
      -
      -      // check for conflict override cases.
      -      // first: is this the only place this thing can go?  If the target is
      -      // the source, then one of these things are true.
      -      //
      -      // 1. the conflicted dep was deduped up to here from a lower dependency
      -      // w -> (x,y)
      -      // x -> (z)
      -      // y -> PEER(p@1)
      -      // z -> (q)
      -      // q -> (p@2)
      -      //
      -      // When building, let's say that x is fully placed, with all of its
      -      // deps, and we're _adding_ y.  Since the peer on p@1 was not initially
      -      // present, it's been deduped up to w, and now needs to be pushed out.
      -      // Replace it, and potentially also replace its peer set (though that'll
      -      // be accomplished by making the same determination when we call
      -      // _canPlacePeers)
      -      //
      -      // 2. the dep we're TRYING to place here ought to be overridden by the
      -      // one that's here now, because current is (a) a direct dep of the
      -      // source, or (b) an already-placed peer in a conflicted peer set, or
      -      // (c) an already-placed peer in a different peer set at the same level.
      -      // If strict or ours, conflict.  Otherwise, keep.
      -      if (isSource) {
      -        // check to see if the current module could go deeper in the tree
      -        let canReplace = true
      -        // only do this check when we're placing peers.  when we're placing
      -        // the original in the source, we know that the edge from the source
      -        // is the thing we're trying to place, so its peer set will need to be
      -        // placed here as well.  the virtualRoot already has the appropriate
      -        // overrides applied.
      -        if (peerEntryEdge) {
      -          const currentPeerSet = getPeerSet(current)
      -
      -          // We are effectively replacing currentPeerSet with newPeerSet
      -          // If there are any non-peer deps coming into the currentPeerSet,
      -          // which are currently valid, and are from the target, then that
      -          // means that we have to ensure that they're not going to be made
      -          // invalid by putting the newPeerSet in place.
      -          // If the edge comes from somewhere deeper than the target, then
      -          // that's fine, because we'll create an invalid edge, detect it,
      -          // and duplicate the node further into the tree.
      -          // loop through the currentPeerSet checking for valid edges on
      -          // the members of the peer set which will be made invalid.
      -          const targetEdges = new Set()
      -          for (const p of currentPeerSet) {
      -            for (const edge of p.edgesIn) {
      -              // edge from within the peerSet, ignore
      -              if (currentPeerSet.has(edge.from))
      -                continue
      -              // only care about valid edges from target.
      -              // edges from elsewhere can dupe if offended, invalid edges
      -              // are already being fixed or will be later.
      -              if (edge.from !== target || !edge.valid)
      -                continue
      -              targetEdges.add(edge)
      -            }
      -          }
      -
      -          for (const edge of targetEdges) {
      -            // see if we intend to replace this one anyway
      -            const rep = dep.parent.children.get(edge.name)
      -            const current = edge.to
      -            if (!rep) {
      -              // this isn't one we're replacing.  but it WAS included in the
      -              // peerSet for some reason, so make sure that it's still
      -              // ok with the replacements in the new peerSet
      -              for (const curEdge of current.edgesOut.values()) {
      -                const newRepDep = dep.parent.children.get(curEdge.name)
      -                if (curEdge.valid && newRepDep && !newRepDep.satisfies(curEdge)) {
      -                  canReplace = false
      -                  break
      -                }
      -              }
      -              continue
      -            }
      -
      -            // was this replacement already an override of some sort?
      -            const override = [...rep.edgesIn].some(e => !e.valid)
      -            // if we have a rep, and it's ok to put in this location, and
      -            // it's not already part of an override in the peerSet, then
      -            // we can continue with it.
      -            if (rep.satisfies(edge) && !override)
      -              continue
      -            // Otherwise, we cannot replace.
      -            canReplace = false
      -            break
      -          }
      -          // if we're going to be replacing the peerSet, we have to remove
      -          // and re-resolve any members of the old peerSet that are not
      -          // present in the new one, and which will have invalid edges.
      -          // We know that they're not depended upon by the target, or else
      -          // they would have caused a conflict, so they'll get landed deeper
      -          // in the tree, if possible.
      -          if (canReplace) {
      -            let needNesting = false
      -            OUTER: for (const node of currentPeerSet) {
      -              const rep = dep.parent.children.get(node.name)
      -              // has a replacement, already addressed above
      -              if (rep)
      -                continue
      -
      -              // ok, it has been placed here to dedupe, see if it needs to go
      -              // back deeper within the tree.
      -              for (const edge of node.edgesOut.values()) {
      -                const repDep = dep.parent.children.get(edge.name)
      -                // not in new peerSet, maybe fine.
      -                if (!repDep)
      -                  continue
      -
      -                // new thing will be fine, no worries
      -                if (repDep.satisfies(edge))
      -                  continue
      -
      -                // uhoh, we'll have to nest them.
      -                needNesting = true
      -                break OUTER
      -              }
      -            }
      -
      -            // to nest, just delete everything without a target dep
      -            // that's in the current peerSet, and add their dependants
      -            // to the _depsQueue for evaluation.  Some of these MAY end
      -            // up in the same location again, and that's fine.
      -            if (needNesting) {
      -              // avoid mutating the tree while we're examining it
      -              const dependants = new Set()
      -              const reresolve = new Set()
      -              OUTER: for (const node of currentPeerSet) {
      -                const rep = dep.parent.children.get(node.name)
      -                if (rep)
      -                  continue
      -                // create a separate set for each one, so we can skip any
      -                // that might somehow have an incoming target edge
      -                const deps = new Set()
      -                for (const edge of node.edgesIn) {
      -                  // a target dep, skip this dep entirely, already addressed
      -                  // ignoring for coverage, because it really ought to be
      -                  // impossible, but I can't prove it yet, so this is here
      -                  // for safety.
      -                  /* istanbul ignore if - should be impossible */
      -                  if (edge.from === target)
      -                    continue OUTER
      -                  // ignore this edge, it'll either be replaced or re-resolved
      -                  if (currentPeerSet.has(edge.from))
      -                    continue
      -                  // ok, we care about this one.
      -                  deps.add(edge.from)
      -                }
      -                reresolve.add(node)
      -                for (const d of deps)
      -                  dependants.add(d)
      -              }
      -              for (const dependant of dependants) {
      -                this[_depsQueue].push(dependant)
      -                this[_depsSeen].delete(dependant)
      -              }
      -              for (const node of reresolve)
      -                node.root = null
      -            }
      -          }
      -        }
      -
      -        if (canReplace) {
      -          const ret = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath, isSource)
      -          /* istanbul ignore else - extremely rare that the peer set would
      -           * conflict if we can replace the node in question, but theoretically
      -           * possible, if peer deps are pinned aggressively. */
      -          if (ret !== CONFLICT)
      -            return ret
      -        }
      -
      -        // so it's not a deeper dep that's been deduped.  That means that the
      -        // only way it could have ended up here is if it's a conflicted peer.
      -        /* istanbul ignore else - would have already crashed if not forced,
      -         * and either mine or strict, when creating the peerSet.  Keeping this
      -         * check so that we're not only relying on action at a distance. */
      -        if (!this[_strictPeerDeps] && !isMine || this[_force]) {
      -          this[_warnPeerConflict](edge, dep)
      -          return KEEP
      -        }
      -      }
      -
      -      // no justification for overriding, and no agreement possible.
      -      return CONFLICT
      -    }
      -
      -    // no existing node at this location!
      -    // check to see if the target doesn't have a child by that name,
      -    // but WANTS one, and won't be happy with this one.  if this is the
      -    // edge we're looking to resolve, then not relevant, of course.
      -    if (target !== entryEdge.from && target.edgesOut.has(dep.name)) {
      -      const targetEdge = target.edgesOut.get(dep.name)
      -      // It might be that the dep would not be valid here, BUT some other
      -      // version would.  Could to try to resolve that, but that makes this no
      -      // longer a pure synchronous function.  ugh.
      -      // This is a pretty unlikely scenario in a normal install, because we
      -      // resolve the peer dep set against the parent dependencies, and
      -      // presumably they all worked together SOMEWHERE to get published in the
      -      // first place, and since we resolve shallower deps before deeper ones,
      -      // this can only occur by a child having a peer dep that does not satisfy
      -      // the parent.  It can happen if we're doing a deep update limited by
      -      // a specific name, however, or if a dep makes an incompatible change
      -      // to its peer dep in a non-semver-major version bump, or if the parent
      -      // is unbounded in its dependency list.
      -      if (!targetEdge.satisfiedBy(dep))
      -        return CONFLICT
      -    }
      -
      -    // check to see what that name resolves to here, and who may depend on
      -    // being able to reach it by crawling up past this parent.  we know
      -    // at this point that it's not the target's direct child node.  if it's
      -    // a direct dep of the target, we just make the invalid edge and
      -    // resolve it later.
      -    const current = target !== entryEdge.from && target.resolve(dep.name)
      -    if (current) {
      -      for (const edge of current.edgesIn.values()) {
      -        if (edge.from.isDescendantOf(target) && edge.valid) {
      -          if (!edge.satisfiedBy(dep))
      -            return CONFLICT
      -        }
      -      }
      -    }
      -
      -    // no objections!  ok to place here
      -    return this[_canPlacePeers](dep, target, edge, OK, peerEntryEdge, peerPath, isSource)
      -  }
      -
      -  // make sure the family of peer deps can live here alongside it.
      -  // this doesn't guarantee that THIS solution will be the one we take,
      -  // but it does establish that SOME solution exists at this level in
      -  // the tree.
      -  [_canPlacePeers] (dep, target, edge, ret, peerEntryEdge, peerPath, isSource) {
      -    // do not go in cycles when we're resolving a peer group
      -    if (!dep.parent || peerEntryEdge && peerPath.includes(dep))
      -      return ret
      -
      -    const entryEdge = peerEntryEdge || edge
      -    peerPath = [...peerPath, dep]
      -
      -    for (const peerEdge of dep.edgesOut.values()) {
      -      if (!peerEdge.peer || !peerEdge.to)
      -        continue
      -      const peer = peerEdge.to
      -      const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, entryEdge, peerPath, isSource)
      -      if (canPlacePeer !== CONFLICT)
      -        continue
      -
      -      const current = target.resolve(peer.name)
      -      this[_peerConflict] = {
      -        peer: peer.explain(peerEdge),
      -        current: current && current.explain(),
      -      }
      -      return CONFLICT
      -    }
      -    return ret
      -  }
      -
         // go through all the links in the this[_linkNodes] set
         // for each one:
         // - if outside the root, ignore it, assume it's fine, it's not our problem
      @@ -1876,7 +1299,8 @@ This is a one-time fix-up, please be patient...
             if (link.root !== this.idealTree)
               continue
       
      -      const external = /^\.\.(\/|$)/.test(relpath(this.path, link.realpath))
      +      const tree = this.idealTree.target
      +      const external = !link.target.isDescendantOf(tree)
       
             // outside the root, somebody else's problem, ignore it
             if (external && !this[_follow])
      @@ -1940,6 +1364,7 @@ This is a one-time fix-up, please be patient...
           const needPrune = metaFromDisk && (mutateTree || flagsSuspect)
           if (this[_prune] && needPrune)
             this[_idealTreePrune]()
      +
           process.emit('timeEnd', 'idealTree:fixDepFlags')
         }
       
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js
      index 94501cae12c840..b26a26c2be2abe 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js
      @@ -81,7 +81,7 @@ class Arborist extends Base {
               const dep = edge.to
               if (dep) {
                 set.add(dep)
      -          if (dep.target)
      +          if (dep.isLink)
                   set.add(dep.target)
               }
             }
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-actual.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-actual.js
      index 9fca7d6425da05..86856d868b4269 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-actual.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-actual.js
      @@ -315,7 +315,7 @@ module.exports = cls => class ActualLoader extends cls {
       
         [_loadFSTree] (node) {
           const did = this[_actualTreeLoaded]
      -    node = node.target || node
      +    node = node.target
       
           // if a Link target has started, but not completed, then
           // a Promise will be in the cache to indicate this.
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js
      index a98ed23b2a458c..d1edcaca01d7e1 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js
      @@ -221,7 +221,7 @@ module.exports = cls => class VirtualLoader extends cls {
         [assignBundles] (nodes) {
           for (const [location, node] of nodes) {
             // Skip assignment of parentage for the root package
      -      if (!location || node.target && !node.target.location)
      +      if (!location || node.isLink && !node.target.location)
               continue
             const { name, parent, package: { inBundle }} = node
       
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/rebuild.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/rebuild.js
      index d189ad8c99e3ca..8e447bb8f5ad16 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/rebuild.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/rebuild.js
      @@ -169,7 +169,7 @@ module.exports = cls => class Builder extends cls {
           const queue = [...set].sort(sortNodes)
       
           for (const node of queue) {
      -      const { package: { bin, scripts = {} } } = node
      +      const { package: { bin, scripts = {} } } = node.target
             const { preinstall, install, postinstall, prepare } = scripts
             const tests = { bin, preinstall, install, postinstall, prepare }
             for (const [key, has] of Object.entries(tests)) {
      @@ -202,7 +202,7 @@ module.exports = cls => class Builder extends cls {
               !(meta.originalLockfileVersion >= 2)
           }
       
      -    const { package: pkg, hasInstallScript } = node
      +    const { package: pkg, hasInstallScript } = node.target
           const { gypfile, bin, scripts = {} } = pkg
       
           const { preinstall, install, postinstall, prepare } = scripts
      @@ -263,7 +263,7 @@ module.exports = cls => class Builder extends cls {
               devOptional,
               package: pkg,
               location,
      -      } = node.target || node
      +      } = node.target
       
             // skip any that we know we'll be deleting
             if (this[_trashList].has(path))
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
      index f259a69b548e10..1cfa6034eadb8b 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
      @@ -5,6 +5,7 @@ const pacote = require('pacote')
       const AuditReport = require('../audit-report.js')
       const {subset, intersects} = require('semver')
       const npa = require('npm-package-arg')
      +const debug = require('../debug.js')
       
       const {dirname, resolve, relative} = require('path')
       const {depth: dfwalk} = require('treeverse')
      @@ -50,6 +51,7 @@ const _createSparseTree = Symbol.for('createSparseTree')
       const _loadShrinkwrapsAndUpdateTrees = Symbol.for('loadShrinkwrapsAndUpdateTrees')
       const _shrinkwrapInflated = Symbol('shrinkwrapInflated')
       const _bundleUnpacked = Symbol('bundleUnpacked')
      +const _bundleMissing = Symbol('bundleMissing')
       const _reifyNode = Symbol.for('reifyNode')
       const _extractOrLink = Symbol('extractOrLink')
       // defined by rebuild mixin
      @@ -83,8 +85,9 @@ const _omitPeer = Symbol('omitPeer')
       
       const _global = Symbol.for('global')
       
      +const _pruneBundledMetadeps = Symbol('pruneBundledMetadeps')
      +
       // defined by Ideal mixin
      -const _pruneBundledMetadeps = Symbol.for('pruneBundledMetadeps')
       const _resolvedAdd = Symbol.for('resolvedAdd')
       const _usePackageLock = Symbol.for('usePackageLock')
       const _formatPackageLock = Symbol.for('formatPackageLock')
      @@ -112,6 +115,10 @@ module.exports = cls => class Reifier extends cls {
           this[_sparseTreeDirs] = new Set()
           this[_sparseTreeRoots] = new Set()
           this[_trashList] = new Set()
      +    // the nodes we unpack to read their bundles
      +    this[_bundleUnpacked] = new Set()
      +    // child nodes we'd EXPECT to be included in a bundle, but aren't
      +    this[_bundleMissing] = new Set()
         }
       
         // public method
      @@ -289,8 +296,8 @@ module.exports = cls => class Reifier extends cls {
       
           const filterNodes = []
           if (this[_global] && this.explicitRequests.size) {
      -      const idealTree = this.idealTree.target || this.idealTree
      -      const actualTree = this.actualTree.target || this.actualTree
      +      const idealTree = this.idealTree.target
      +      const actualTree = this.actualTree.target
             // we ONLY are allowed to make changes in the global top-level
             // children where there's an explicit request.
             for (const { name } of this.explicitRequests) {
      @@ -334,7 +341,7 @@ module.exports = cls => class Reifier extends cls {
         // removed later on in the process.  optionally, also mark them
         // as a retired paths, so that we move them out of the way and
         // replace them when rolling back on failure.
      -  [_addNodeToTrashList] (node, retire) {
      +  [_addNodeToTrashList] (node, retire = false) {
           const paths = [node.path, ...node.binPaths]
           const moves = this[_retiredPaths]
           this.log.silly('reify', 'mark', retire ? 'retired' : 'deleted', paths)
      @@ -404,10 +411,9 @@ module.exports = cls => class Reifier extends cls {
             return
       
           process.emit('time', 'reify:trashOmits')
      -    // node.parent is checked to make sure this is a node that's in the tree, and
      -    // not the parent-less top level nodes
      +
           const filter = node =>
      -      node.isDescendantOf(this.idealTree) &&
      +      node.top.isProjectRoot &&
               (node.peer && this[_omitPeer] ||
                 node.dev && this[_omitDev] ||
                 node.optional && this[_omitOptional] ||
      @@ -611,10 +617,9 @@ module.exports = cls => class Reifier extends cls {
         [_loadBundlesAndUpdateTrees] (
           depth = 0, bundlesByDepth = this[_getBundlesByDepth]()
         ) {
      -    if (depth === 0) {
      -      this[_bundleUnpacked] = new Set()
      +    if (depth === 0)
             process.emit('time', 'reify:loadBundles')
      -    }
      +
           const maxBundleDepth = bundlesByDepth.get('maxBundleDepth')
           if (depth > maxBundleDepth) {
             // if we did something, then prune the tree and update the diffs
      @@ -643,14 +648,30 @@ module.exports = cls => class Reifier extends cls {
           }))
           // then load their unpacked children and move into the ideal tree
             .then(nodes =>
      -        promiseAllRejectLate(nodes.map(node => new this.constructor({
      -          ...this.options,
      -          path: node.path,
      -        }).loadActual({
      -          root: node,
      -          // don't transplant any sparse folders we created
      -          transplantFilter: node => node.package._id,
      -        }))))
      +        promiseAllRejectLate(nodes.map(async node => {
      +          const arb = new this.constructor({
      +            ...this.options,
      +            path: node.path,
      +          })
      +          const notTransplanted = new Set(node.children.keys())
      +          await arb.loadActual({
      +            root: node,
      +            // don't transplant any sparse folders we created
      +            // loadActual will set node.package to {} for empty directories
      +            // if by chance there are some empty folders in the node_modules
      +            // tree for some other reason, then ok, ignore those too.
      +            transplantFilter: node => {
      +              if (node.package._id) {
      +                // it's actually in the bundle if it gets transplanted
      +                notTransplanted.delete(node.name)
      +                return true
      +              } else
      +                return false
      +            },
      +          })
      +          for (const name of notTransplanted)
      +            this[_bundleMissing].add(node.children.get(name))
      +        })))
           // move onto the next level of bundled items
             .then(() => this[_loadBundlesAndUpdateTrees](depth + 1, bundlesByDepth))
         }
      @@ -664,7 +685,7 @@ module.exports = cls => class Reifier extends cls {
               const node = diff.ideal
               if (!node)
                 return
      -        if (node.isProjectRoot || (node.target && node.target.isProjectRoot))
      +        if (node.isProjectRoot)
                 return
       
               const { bundleDependencies } = node.package
      @@ -686,6 +707,27 @@ module.exports = cls => class Reifier extends cls {
         // https://github.com/npm/cli/issues/1597#issuecomment-667639545
         [_pruneBundledMetadeps] (bundlesByDepth) {
           const bundleShadowed = new Set()
      +
      +    // Example dep graph:
      +    // root -> (a, c)
      +    // a -> BUNDLE(b)
      +    // b -> c
      +    // c -> b
      +    //
      +    // package tree:
      +    // root
      +    // +-- a
      +    // |   +-- b(1)
      +    // |   +-- c(1)
      +    // +-- b(2)
      +    // +-- c(2)
      +    // 1. mark everything that's shadowed by anything in the bundle.  This
      +    //    marks b(2) and c(2).
      +    // 2. anything with edgesIn from outside the set, mark not-extraneous,
      +    //    remove from set.  This unmarks c(2).
      +    // 3. continue until no change
      +    // 4. remove everything in the set from the tree.  b(2) is pruned
      +
           // create the list of nodes shadowed by children of bundlers
           for (const bundles of bundlesByDepth.values()) {
             // skip the 'maxBundleDepth' item
      @@ -701,36 +743,50 @@ module.exports = cls => class Reifier extends cls {
               }
             }
           }
      -    let changed = true
      -    while (changed) {
      -      changed = false
      -      for (const shadow of bundleShadowed) {
      -        if (!shadow.extraneous) {
      -          bundleShadowed.delete(shadow)
      -          continue
      +
      +    // lib -> (a@1.x) BUNDLE(a@1.2.3 (b@1.2.3))
      +    // a@1.2.3 -> (b@1.2.3)
      +    // a@1.3.0 -> (b@2)
      +    // b@1.2.3 -> ()
      +    // b@2 -> (c@2)
      +    //
      +    // root
      +    // +-- lib
      +    // |   +-- a@1.2.3
      +    // |   +-- b@1.2.3
      +    // +-- b@2 <-- shadowed, now extraneous
      +    // +-- c@2 <-- also shadowed, because only dependent is shadowed
      +    for (const shadow of bundleShadowed) {
      +      for (const shadDep of shadow.edgesOut.values()) {
      +        /* istanbul ignore else - pretty unusual situation, just being
      +         * defensive here. Would mean that a bundled dep has a dependency
      +         * that is unmet. which, weird, but if you bundle it, we take
      +         * whatever you put there and assume the publisher knows best. */
      +        if (shadDep.to) {
      +          bundleShadowed.add(shadDep.to)
      +          shadDep.to.extraneous = true
               }
      +      }
      +    }
       
      +    let changed
      +    do {
      +      changed = false
      +      for (const shadow of bundleShadowed) {
               for (const edge of shadow.edgesIn) {
      -          if (!edge.from.extraneous) {
      +          if (!bundleShadowed.has(edge.from)) {
                   shadow.extraneous = false
                   bundleShadowed.delete(shadow)
                   changed = true
      -          } else {
      -            for (const shadDep of shadow.edgesOut.values()) {
      -              /* istanbul ignore else - pretty unusual situation, just being
      -               * defensive here. Would mean that a bundled dep has a dependency
      -               * that is unmet. which, weird, but if you bundle it, we take
      -               * whatever you put there and assume the publisher knows best. */
      -              if (shadDep.to)
      -                bundleShadowed.add(shadDep.to)
      -            }
      +            break
                 }
               }
             }
      -    }
      +    } while (changed)
      +
           for (const shadow of bundleShadowed) {
      -      shadow.parent = null
             this[_addNodeToTrashList](shadow)
      +      shadow.root = null
           }
         }
       
      @@ -781,6 +837,7 @@ module.exports = cls => class Reifier extends cls {
               const node = diff.ideal
               const bd = this[_bundleUnpacked].has(node)
               const sw = this[_shrinkwrapInflated].has(node)
      +        const bundleMissing = this[_bundleMissing].has(node)
       
               // check whether we still need to unpack this one.
               // test the inDepBundle last, since that's potentially a tree walk.
      @@ -788,7 +845,7 @@ module.exports = cls => class Reifier extends cls {
                 !node.isRoot && // root node already exists
                 !bd && // already unpacked to read bundle
                 !sw && // already unpacked to read sw
      -          !node.inDepBundle // already unpacked by another dep's bundle
      +          (bundleMissing || !node.inDepBundle) // already unpacked by another dep's bundle
       
               if (doUnpack)
                 unpacks.push(this[_reifyNode](node))
      @@ -815,8 +872,26 @@ module.exports = cls => class Reifier extends cls {
           const moves = this[_retiredPaths]
           this[_retiredUnchanged] = {}
           return promiseAllRejectLate(this.diff.children.map(diff => {
      -      const realFolder = (diff.actual || diff.ideal).path
      +      // skip if nothing was retired
      +      if (diff.action !== 'CHANGE' && diff.action !== 'REMOVE')
      +        return
      +
      +      const { path: realFolder } = diff.actual
             const retireFolder = moves[realFolder]
      +      /* istanbul ignore next - should be impossible */
      +      debug(() => {
      +        if (!retireFolder) {
      +          const er = new Error('trying to un-retire but not retired')
      +          throw Object.assign(er, {
      +            realFolder,
      +            retireFolder,
      +            actual: diff.actual,
      +            ideal: diff.ideal,
      +            action: diff.action,
      +          })
      +        }
      +      })
      +
             this[_retiredUnchanged][retireFolder] = []
             return promiseAllRejectLate(diff.unchanged.map(node => {
               // no need to roll back links, since we'll just delete them anyway
      @@ -824,7 +899,7 @@ module.exports = cls => class Reifier extends cls {
                 return mkdirp(dirname(node.path)).then(() => this[_reifyNode](node))
       
               // will have been moved/unpacked along with bundler
      -        if (node.inDepBundle)
      +        if (node.inDepBundle && !this[_bundleMissing].has(node))
                 return
       
               this[_retiredUnchanged][retireFolder].push(node)
      @@ -887,6 +962,18 @@ module.exports = cls => class Reifier extends cls {
             filter: diff => diff.action === 'ADD' || diff.action === 'CHANGE',
           })
       
      +    // pick up link nodes from the unchanged list as we want to run their
      +    // scripts in every install despite of having a diff status change
      +    for (const node of this.diff.unchanged) {
      +      const tree = node.root.target
      +
      +      // skip links that only live within node_modules as they are most
      +      // likely managed by packages we installed, we only want to rebuild
      +      // unchanged links we directly manage
      +      if (node.isLink && node.target.fsTop === tree)
      +        nodes.push(node)
      +    }
      +
           return this.rebuild({ nodes, handleOptionalFailure: true })
             .then(() => process.emit('timeEnd', 'reify:build'))
         }
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js b/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js
      index 21d8ddcf7b442e..968fc83c5136cf 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js
      @@ -29,7 +29,7 @@ const calcDepFlagsStep = (node) => {
         resetParents(node, 'optional')
       
         // for links, map their hierarchy appropriately
      -  if (node.target) {
      +  if (node.isLink) {
           node.target.dev = node.dev
           node.target.optional = node.optional
           node.target.devOptional = node.devOptional
      @@ -92,10 +92,10 @@ const unsetFlag = (node, flag) => {
             tree: node,
             visit: node => {
               node.extraneous = node[flag] = false
      -        if (node.target)
      +        if (node.isLink)
                 node.target.extraneous = node.target[flag] = false
             },
      -      getChildren: node => [...(node.target || node).edgesOut.values()]
      +      getChildren: node => [...node.target.edgesOut.values()]
               .filter(edge => edge.to && edge.to[flag] &&
                 (flag !== 'peer' && edge.type === 'peer' || edge.type === 'prod'))
               .map(edge => edge.to),
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/can-place-dep.js b/deps/npm/node_modules/@npmcli/arborist/lib/can-place-dep.js
      new file mode 100644
      index 00000000000000..cf6b800c44ea23
      --- /dev/null
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/can-place-dep.js
      @@ -0,0 +1,405 @@
      +// Internal methods used by buildIdealTree.
      +// Answer the question: "can I put this dep here?"
      +//
      +// IMPORTANT: *nothing* in this class should *ever* modify or mutate the tree
      +// at all.  The contract here is strictly limited to read operations.  We call
      +// this in the process of walking through the ideal tree checking many
      +// different potential placement targets for a given node.  If a change is made
      +// to the tree along the way, that can cause serious problems!
      +//
      +// In order to enforce this restriction, in debug mode, canPlaceDep() will
      +// snapshot the tree at the start of the process, and then at the end, will
      +// verify that it still matches the snapshot, and throw an error if any changes
      +// occurred.
      +//
      +// The algorithm is roughly like this:
      +// - check the node itself:
      +//   - if there is no version present, and no conflicting edges from target,
      +//     OK, provided all peers can be placed at or above the target.
      +//   - if the current version matches, KEEP
      +//   - if there is an older version present, which can be replaced, then
      +//     - if satisfying and preferDedupe? KEEP
      +//     - else: REPLACE
      +//   - if there is a newer version present, and preferDedupe, REPLACE
      +//   - if the version present satisfies the edge, KEEP
      +//   - else: CONFLICT
      +// - if the node is not in conflict, check each of its peers:
      +//   - if the peer can be placed in the target, continue
      +//   - else if the peer can be placed in a parent, and there is no other
      +//     conflicting version shadowing it, continue
      +//   - else CONFLICT
      +// - If the peers are not in conflict, return the original node's value
      +//
      +// An exception to this logic is that if the target is the deepest location
      +// that a node can be placed, and the conflicting node can be placed deeper,
      +// then we will return REPLACE rather than CONFLICT, and Arborist will queue
      +// the replaced node for resolution elsewhere.
      +
      +const semver = require('semver')
      +const debug = require('./debug.js')
      +const peerEntrySets = require('./peer-entry-sets.js')
      +const deepestNestingTarget = require('./deepest-nesting-target.js')
      +
      +const CONFLICT = Symbol('CONFLICT')
      +const OK = Symbol('OK')
      +const REPLACE = Symbol('REPLACE')
      +const KEEP = Symbol('KEEP')
      +
      +class CanPlaceDep {
      +  // dep is a dep that we're trying to place.  it should already live in
      +  // a virtual tree where its peer set is loaded as children of the root.
      +  // target is the actual place where we're trying to place this dep
      +  // in a node_modules folder.
      +  // edge is the edge that we're trying to satisfy with this placement.
      +  // parent is the CanPlaceDep object of the entry node when placing a peer.
      +  constructor (options) {
      +    const {
      +      dep,
      +      target,
      +      edge,
      +      preferDedupe,
      +      parent = null,
      +      peerPath = [],
      +      explicitRequest = false,
      +    } = options
      +
      +    debug(() => {
      +      if (!dep)
      +        throw new Error('no dep provided to CanPlaceDep')
      +
      +      if (!target)
      +        throw new Error('no target provided to CanPlaceDep')
      +
      +      if (!edge)
      +        throw new Error('no edge provided to CanPlaceDep')
      +
      +      this._nodeSnapshot = JSON.stringify(dep)
      +      this._treeSnapshot = JSON.stringify(target.root)
      +    })
      +
      +    // the result of whether we can place it or not
      +    this.canPlace = null
      +    // if peers conflict, but this one doesn't, then that is useful info
      +    this.canPlaceSelf = null
      +
      +    this.dep = dep
      +    this.target = target
      +    this.edge = edge
      +    this.explicitRequest = explicitRequest
      +
      +    // preventing cycles when we check peer sets
      +    this.peerPath = peerPath
      +    // we always prefer to dedupe peers, because they are trying
      +    // a bit harder to be singletons.
      +    this.preferDedupe = !!preferDedupe || edge.peer
      +    this.parent = parent
      +    this.children = []
      +
      +    this.isSource = target === this.peerSetSource
      +    this.name = edge.name
      +    this.current = target.children.get(this.name)
      +    this.targetEdge = target.edgesOut.get(this.name)
      +    this.conflicts = new Map()
      +
      +    // check if this dep was already subject to a peerDep override while
      +    // building the peerSet.
      +    this.edgeOverride = !dep.satisfies(edge)
      +
      +    this.canPlace = this.checkCanPlace()
      +    if (!this.canPlaceSelf)
      +      this.canPlaceSelf = this.canPlace
      +
      +    debug(() => {
      +      const nodeSnapshot = JSON.stringify(dep)
      +      const treeSnapshot = JSON.stringify(target.root)
      +      /* istanbul ignore if */
      +      if (this._nodeSnapshot !== nodeSnapshot) {
      +        throw Object.assign(new Error('dep changed in CanPlaceDep'), {
      +          expect: this._nodeSnapshot,
      +          actual: nodeSnapshot,
      +        })
      +      }
      +      /* istanbul ignore if */
      +      if (this._treeSnapshot !== treeSnapshot) {
      +        throw Object.assign(new Error('tree changed in CanPlaceDep'), {
      +          expect: this._treeSnapshot,
      +          actual: treeSnapshot,
      +        })
      +      }
      +    })
      +  }
      +
      +  checkCanPlace () {
      +    const { target, targetEdge, current, dep } = this
      +
      +    // if the dep failed to load, we're going to fail the build or
      +    // prune it out anyway, so just move forward placing/replacing it.
      +    if (dep.errors.length)
      +      return current ? REPLACE : OK
      +
      +    // cannot place peers inside their dependents, except for tops
      +    if (targetEdge && targetEdge.peer && !target.isTop)
      +      return CONFLICT
      +
      +    if (targetEdge && !dep.satisfies(targetEdge) && targetEdge !== this.edge)
      +      return CONFLICT
      +
      +    return current ? this.checkCanPlaceCurrent() : this.checkCanPlaceNoCurrent()
      +  }
      +
      +  // we know that the target has a dep by this name in its node_modules
      +  // already.  Can return KEEP, REPLACE, or CONFLICT.
      +  checkCanPlaceCurrent () {
      +    const { preferDedupe, explicitRequest, current, target, edge, dep } = this
      +
      +    if (dep.matches(current)) {
      +      if (current.satisfies(edge) || this.edgeOverride)
      +        return explicitRequest ? REPLACE : KEEP
      +    }
      +
      +    const { version: curVer } = current
      +    const { version: newVer } = dep
      +    const tryReplace = curVer && newVer && semver.gte(newVer, curVer)
      +    if (tryReplace && dep.canReplace(current)) {
      +      /* XXX-istanbul ignore else - It's extremely rare that a replaceable
      +       * node would be a conflict, if the current one wasn't a conflict,
      +       * but it is theoretically possible if peer deps are pinned.  In
      +       * that case we treat it like any other conflict, and keep trying */
      +      const cpp = this.canPlacePeers(REPLACE)
      +      if (cpp !== CONFLICT)
      +        return cpp
      +    }
      +
      +    // ok, can't replace the current with new one, but maybe current is ok?
      +    if (current.satisfies(edge) && (!explicitRequest || preferDedupe))
      +      return KEEP
      +
      +    // if we prefer deduping, then try replacing newer with older
      +    if (preferDedupe && !tryReplace && dep.canReplace(current)) {
      +      const cpp = this.canPlacePeers(REPLACE)
      +      if (cpp !== CONFLICT)
      +        return cpp
      +    }
      +
      +    // Check for interesting cases!
      +    // First, is this the deepest place that this thing can go, and NOT the
      +    // deepest place where the conflicting dep can go?  If so, replace it,
      +    // and let it re-resolve deeper in the tree.
      +    const myDeepest = this.deepestNestingTarget
      +
      +    // ok, i COULD be placed deeper, so leave the current one alone.
      +    if (target !== myDeepest)
      +      return CONFLICT
      +
      +    // if we are not checking a peerDep, then we MUST place it here, in the
      +    // target that has a non-peer dep on it.
      +    if (!edge.peer && target === edge.from)
      +      return this.canPlacePeers(REPLACE)
      +
      +    // if we aren't placing a peer in a set, then we're done here.
      +    // This is ignored because it SHOULD be redundant, as far as I can tell,
      +    // with the deepest target and target===edge.from tests.  But until we
      +    // can prove that isn't possible, this condition is here for safety.
      +    /* istanbul ignore if - allegedly impossible */
      +    if (!this.parent && !edge.peer)
      +      return CONFLICT
      +
      +    // check the deps in the peer group for each edge into that peer group
      +    // if ALL of them can be pushed deeper, or if it's ok to replace its
      +    // members with the contents of the new peer group, then we're good.
      +    let canReplace = true
      +    for (const [entryEdge, currentPeers] of peerEntrySets(current)) {
      +      if (entryEdge === this.edge || entryEdge === this.peerEntryEdge)
      +        continue
      +
      +      // First, see if it's ok to just replace the peerSet entirely.
      +      // we do this by walking out from the entryEdge, because in a case like
      +      // this:
      +      //
      +      // v -> PEER(a@1||2)
      +      // a@1 -> PEER(b@1)
      +      // a@2 -> PEER(b@2)
      +      // b@1 -> PEER(a@1)
      +      // b@2 -> PEER(a@2)
      +      //
      +      // root
      +      // +-- v
      +      // +-- a@2
      +      // +-- b@2
      +      //
      +      // Trying to place a peer group of (a@1, b@1) would fail to note that
      +      // they can be replaced, if we did it by looping 1 by 1.  If we are
      +      // replacing something, we don't have to check its peer deps, because
      +      // the peerDeps in the placed peerSet will presumably satisfy.
      +      const entryNode = entryEdge.to
      +      const entryRep = dep.parent.children.get(entryNode.name)
      +      if (entryRep) {
      +        if (entryRep.canReplace(entryNode, dep.parent.children.keys()))
      +          continue
      +      }
      +
      +      let canClobber = !entryRep
      +      if (!entryRep) {
      +        const peerReplacementWalk = new Set([entryNode])
      +        OUTER: for (const currentPeer of peerReplacementWalk) {
      +          for (const edge of currentPeer.edgesOut.values()) {
      +            if (!edge.peer || !edge.valid)
      +              continue
      +            const rep = dep.parent.children.get(edge.name)
      +            if (!rep) {
      +              if (edge.to)
      +                peerReplacementWalk.add(edge.to)
      +              continue
      +            }
      +            if (!rep.satisfies(edge)) {
      +              canClobber = false
      +              break OUTER
      +            }
      +          }
      +        }
      +      }
      +      if (canClobber)
      +        continue
      +
      +      // ok, we can't replace, but maybe we can nest the current set deeper?
      +      let canNestCurrent = true
      +      for (const currentPeer of currentPeers) {
      +        if (!canNestCurrent)
      +          break
      +
      +        // still possible to nest this peerSet
      +        const curDeep = deepestNestingTarget(entryEdge.from, currentPeer.name)
      +        if (curDeep === target || target.isDescendantOf(curDeep)) {
      +          canNestCurrent = false
      +          canReplace = false
      +        }
      +        if (canNestCurrent)
      +          continue
      +      }
      +    }
      +
      +    // if we can nest or replace all the current peer groups, we can replace.
      +    if (canReplace)
      +      return this.canPlacePeers(REPLACE)
      +
      +    return CONFLICT
      +  }
      +
      +  checkCanPlaceNoCurrent () {
      +    const { target, peerEntryEdge, dep, name } = this
      +
      +    // check to see what that name resolves to here, and who may depend on
      +    // being able to reach it by crawling up past the parent.  we know
      +    // that it's not the target's direct child node, and if it was a direct
      +    // dep of the target, we would have conflicted earlier.
      +    const current = target !== peerEntryEdge.from && target.resolve(name)
      +    if (current) {
      +      for (const edge of current.edgesIn.values()) {
      +        if (edge.from.isDescendantOf(target) && edge.valid) {
      +          if (!dep.satisfies(edge))
      +            return CONFLICT
      +        }
      +      }
      +    }
      +
      +    // no objections, so this is fine as long as peers are ok here.
      +    return this.canPlacePeers(OK)
      +  }
      +
      +  get deepestNestingTarget () {
      +    const start = this.parent ? this.parent.deepestNestingTarget
      +      : this.edge.from
      +    return deepestNestingTarget(start, this.name)
      +  }
      +
      +  get conflictChildren () {
      +    return this.allChildren.filter(c => c.canPlace === CONFLICT)
      +  }
      +
      +  get allChildren () {
      +    const set = new Set(this.children)
      +    for (const child of set) {
      +      for (const grandchild of child.children)
      +        set.add(grandchild)
      +    }
      +    return [...set]
      +  }
      +
      +  get top () {
      +    return this.parent ? this.parent.top : this
      +  }
      +
      +  // check if peers can go here.  returns state or CONFLICT
      +  canPlacePeers (state) {
      +    this.canPlaceSelf = state
      +    if (this._canPlacePeers)
      +      return this._canPlacePeers
      +
      +    // TODO: represent peerPath in ERESOLVE error somehow?
      +    const peerPath = [...this.peerPath, this.dep]
      +    let sawConflict = false
      +    for (const peerEdge of this.dep.edgesOut.values()) {
      +      if (!peerEdge.peer || !peerEdge.to || peerPath.includes(peerEdge.to))
      +        continue
      +      const peer = peerEdge.to
      +      // it may be the case that the *initial* dep can be nested, but a peer
      +      // of that dep needs to be placed shallower, because the target has
      +      // a peer dep on the peer as well.
      +      const target = deepestNestingTarget(this.target, peer.name)
      +      const cpp = new CanPlaceDep({
      +        dep: peer,
      +        target,
      +        parent: this,
      +        edge: peerEdge,
      +        peerPath,
      +        // always place peers in preferDedupe mode
      +        preferDedupe: true,
      +      })
      +      /* istanbul ignore next */
      +      debug(() => {
      +        if (this.children.some(c => c.dep === cpp.dep))
      +          throw new Error('checking same dep repeatedly')
      +      })
      +      this.children.push(cpp)
      +
      +      if (cpp.canPlace === CONFLICT)
      +        sawConflict = true
      +    }
      +
      +    this._canPlacePeers = sawConflict ? CONFLICT : state
      +    return this._canPlacePeers
      +  }
      +
      +  // what is the node that is causing this peerSet to be placed?
      +  get peerSetSource () {
      +    return this.parent ? this.parent.peerSetSource : this.edge.from
      +  }
      +
      +  get peerEntryEdge () {
      +    return this.top.edge
      +  }
      +
      +  static get CONFLICT () {
      +    return CONFLICT
      +  }
      +
      +  static get OK () {
      +    return OK
      +  }
      +
      +  static get REPLACE () {
      +    return REPLACE
      +  }
      +
      +  static get KEEP () {
      +    return KEEP
      +  }
      +
      +  get description () {
      +    const { canPlace } = this
      +    return canPlace && canPlace.description ||
      +    /* istanbul ignore next - old node affordance */ canPlace
      +  }
      +}
      +
      +module.exports = CanPlaceDep
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/deepest-nesting-target.js b/deps/npm/node_modules/@npmcli/arborist/lib/deepest-nesting-target.js
      new file mode 100644
      index 00000000000000..cbaa396f3f2513
      --- /dev/null
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/deepest-nesting-target.js
      @@ -0,0 +1,16 @@
      +// given a starting node, what is the *deepest* target where name could go?
      +// This is not on the Node class for the simple reason that we sometimes
      +// need to check the deepest *potential* target for a Node that is not yet
      +// added to the tree where we are checking.
      +const deepestNestingTarget = (start, name) => {
      +  for (const target of start.ancestry()) {
      +    // note: this will skip past the first target if edge is peer
      +    if (target.isProjectRoot || !target.resolveParent)
      +      return target
      +    const targetEdge = target.edgesOut.get(name)
      +    if (!targetEdge || !targetEdge.peer)
      +      return target
      +  }
      +}
      +
      +module.exports = deepestNestingTarget
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/diff.js b/deps/npm/node_modules/@npmcli/arborist/lib/diff.js
      index 1f8eff0f0c4d9c..2008ef7a35bddf 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/diff.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/diff.js
      @@ -45,8 +45,7 @@ class Diff {
             const { root } = filterNode
             if (root !== ideal && root !== actual)
               throw new Error('invalid filterNode: outside idealTree/actualTree')
      -      const { target } = root
      -      const rootTarget = target || root
      +      const rootTarget = root.target
             const edge = [...rootTarget.edgesOut.values()].filter(e => {
               return e.to && (e.to === filterNode || e.to.target === filterNode)
             })[0]
      @@ -56,8 +55,7 @@ class Diff {
             filterSet.add(actual)
             if (edge && edge.to) {
               filterSet.add(edge.to)
      -        if (edge.to.target)
      -          filterSet.add(edge.to.target)
      +        filterSet.add(edge.to.target)
             }
             filterSet.add(filterNode)
       
      @@ -65,7 +63,7 @@ class Diff {
               tree: filterNode,
               visit: node => filterSet.add(node),
               getChildren: node => {
      -          node = node.target || node
      +          node = node.target
                 const loc = node.location
                 const idealNode = ideal.inventory.get(loc)
                 const ideals = !idealNode ? []
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/edge.js b/deps/npm/node_modules/@npmcli/arborist/lib/edge.js
      index 79510d509f2830..0bd9021d56a706 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/edge.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/edge.js
      @@ -37,6 +37,7 @@ const printableEdge = (edge) => {
           ...(edgeFrom != null ? { from: edgeFrom } : {}),
           ...(edgeTo ? { to: edgeTo } : {}),
           ...(edge.error ? { error: edge.error } : {}),
      +    ...(edge.overridden ? { overridden: true } : {}),
         })
       }
       
      @@ -72,6 +73,7 @@ class Edge {
             throw new TypeError('must provide "from" node')
           this[_setFrom](from)
           this[_error] = this[_loadError]()
      +    this.overridden = false
         }
       
         satisfiedBy (node) {
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/node.js b/deps/npm/node_modules/@npmcli/arborist/lib/node.js
      index c21bc46cfb5396..d77b18355ff31c 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/node.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/node.js
      @@ -409,7 +409,7 @@ class Node {
         }
       
         isDescendantOf (node) {
      -    for (let p = this; p; p = p.parent) {
      +    for (let p = this; p; p = p.resolveParent) {
             if (p === node)
               return true
           }
      @@ -481,6 +481,11 @@ class Node {
           return this === this.root || this === this.root.target
         }
       
      +  * ancestry () {
      +    for (let anc = this; anc; anc = anc.resolveParent)
      +      yield anc
      +  }
      +
         set root (root) {
           // setting to null means this is the new root
           // should only ever be one step
      @@ -649,7 +654,7 @@ class Node {
               })
       
               if (this.isLink) {
      -          const target = node.target || node
      +          const target = node.target
                 this[_target] = target
                 this[_package] = target.package
                 target.linksIn.add(this)
      @@ -878,16 +883,31 @@ class Node {
         // root dependency brings peer deps along with it.  In that case, we
         // will go ahead and create the invalid state, and then try to resolve
         // it with more tree construction, because it's a user request.
      -  canReplaceWith (node) {
      +  canReplaceWith (node, ignorePeers = []) {
           if (node.name !== this.name)
             return false
       
      +    if (node.packageName !== this.packageName)
      +      return false
      +
      +    ignorePeers = new Set(ignorePeers)
      +
           // gather up all the deps of this node and that are only depended
           // upon by deps of this node.  those ones don't count, since
           // they'll be replaced if this node is replaced anyway.
           const depSet = gatherDepSet([this], e => e.to !== this && e.valid)
       
           for (const edge of this.edgesIn) {
      +      // when replacing peer sets, we need to be able to replace the entire
      +      // peer group, which means we ignore incoming edges from other peers
      +      // within the replacement set.
      +      const ignored = !this.isTop &&
      +        edge.from.parent === this.parent &&
      +        edge.peer &&
      +        ignorePeers.has(edge.from.name)
      +      if (ignored)
      +        continue
      +
             // only care about edges that don't originate from this node
             if (!depSet.has(edge.from) && !edge.satisfiedBy(node))
               return false
      @@ -896,8 +916,8 @@ class Node {
           return true
         }
       
      -  canReplace (node) {
      -    return node.canReplaceWith(this)
      +  canReplace (node, ignorePeers) {
      +    return node.canReplaceWith(this, ignorePeers)
         }
       
         // return true if it's safe to remove this node, because anything that
      @@ -1174,7 +1194,7 @@ class Node {
         }
       
         get target () {
      -    return null
      +    return this
         }
       
         set target (n) {
      @@ -1197,11 +1217,25 @@ class Node {
           return this.isTop ? this : this.parent.top
         }
       
      +  get isFsTop () {
      +    return !this.fsParent
      +  }
      +
      +  get fsTop () {
      +    return this.isFsTop ? this : this.fsParent.fsTop
      +  }
      +
         get resolveParent () {
           return this.parent || this.fsParent
         }
       
         resolve (name) {
      +    /* istanbul ignore next - should be impossible,
      +     * but I keep doing this mistake in tests */
      +    debug(() => {
      +      if (typeof name !== 'string' || !name)
      +        throw new Error('non-string passed to Node.resolve')
      +    })
           const mine = this.children.get(name)
           if (mine)
             return mine
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/peer-entry-sets.js b/deps/npm/node_modules/@npmcli/arborist/lib/peer-entry-sets.js
      new file mode 100644
      index 00000000000000..11f9a431607ec0
      --- /dev/null
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/peer-entry-sets.js
      @@ -0,0 +1,72 @@
      +// Given a node in a tree, return all of the peer dependency sets that
      +// it is a part of, with the entry (top or non-peer) edges into the sets
      +// identified.
      +//
      +// With this information, we can determine whether it is appropriate to
      +// replace the entire peer set with another (and remove the old one),
      +// push the set deeper into the tree, and so on.
      +//
      +// Returns a Map of { edge => Set(peerNodes) },
      +
      +const peerEntrySets = node => {
      +  // this is the union of all peer groups that the node is a part of
      +  // later, we identify all of the entry edges, and create a set of
      +  // 1 or more overlapping sets that this node is a part of.
      +  const unionSet = new Set([node])
      +  for (const node of unionSet) {
      +    for (const edge of node.edgesOut.values()) {
      +      if (edge.valid && edge.peer && edge.to)
      +        unionSet.add(edge.to)
      +    }
      +    for (const edge of node.edgesIn) {
      +      if (edge.valid && edge.peer)
      +        unionSet.add(edge.from)
      +    }
      +  }
      +  const entrySets = new Map()
      +  for (const peer of unionSet) {
      +    for (const edge of peer.edgesIn) {
      +      // if not valid, it doesn't matter anyway.  either it's been previously
      +      // overridden, or it's the thing we're interested in replacing.
      +      if (!edge.valid)
      +        continue
      +      // this is the entry point into the peer set
      +      if (!edge.peer || edge.from.isTop) {
      +        // get the subset of peer brought in by this peer entry edge
      +        const sub = new Set([peer])
      +        for (const peer of sub) {
      +          for (const edge of peer.edgesOut.values()) {
      +            if (edge.valid && edge.peer && edge.to)
      +              sub.add(edge.to)
      +          }
      +        }
      +        // if this subset does not include the node we are focused on,
      +        // then it is not relevant for our purposes.  Example:
      +        //
      +        // a -> (b, c, d)
      +        // b -> PEER(d) b -> d -> e -> f <-> g
      +        // c -> PEER(f, h) c -> (f <-> g, h -> g)
      +        // d -> PEER(e) d -> e -> f <-> g
      +        // e -> PEER(f)
      +        // f -> PEER(g)
      +        // g -> PEER(f)
      +        // h -> PEER(g)
      +        //
      +        // The unionSet(e) will include c, but we don't actually care about
      +        // it.  We only expanded to the edge of the peer nodes in order to
      +        // find the entry edges that caused the inclusion of peer sets
      +        // including (e), so we want:
      +        //   Map{
      +        //     Edge(a->b) => Set(b, d, e, f, g)
      +        //     Edge(a->d) => Set(d, e, f, g)
      +        //   }
      +        if (sub.has(node))
      +          entrySets.set(edge, sub)
      +      }
      +    }
      +  }
      +
      +  return entrySets
      +}
      +
      +module.exports = peerEntrySets
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/peer-set.js b/deps/npm/node_modules/@npmcli/arborist/lib/peer-set.js
      deleted file mode 100644
      index 727814e1de3f09..00000000000000
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/peer-set.js
      +++ /dev/null
      @@ -1,25 +0,0 @@
      -// when we have to dupe a set of peer dependencies deeper into the tree in
      -// order to make room for a dep that would otherwise conflict, we use
      -// this to get the set of all deps that have to be checked to ensure
      -// nothing is locking them into the current location.
      -//
      -// this is different in its semantics from an "optional set" (ie, the nodes
      -// that should be removed if an optional dep fails), because in this case,
      -// we specifically intend to include deps in the peer set that have
      -// dependants outside the set.
      -const peerSet = node => {
      -  const set = new Set([node])
      -  for (const node of set) {
      -    for (const edge of node.edgesOut.values()) {
      -      if (edge.valid && edge.peer && edge.to)
      -        set.add(edge.to)
      -    }
      -    for (const edge of node.edgesIn) {
      -      if (edge.valid && edge.peer)
      -        set.add(edge.from)
      -    }
      -  }
      -  return set
      -}
      -
      -module.exports = peerSet
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js b/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js
      new file mode 100644
      index 00000000000000..913b2ba6c2bc73
      --- /dev/null
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js
      @@ -0,0 +1,536 @@
      +// Given a dep, a node that depends on it, and the edge representing that
      +// dependency, place the dep somewhere in the node's tree, and all of its
      +// peer dependencies.
      +//
      +// Handles all of the tree updating needed to place the dep, including
      +// removing replaced nodes, pruning now-extraneous or invalidated nodes,
      +// and saves a set of what was placed and what needs re-evaluation as
      +// a result.
      +
      +const log = require('proc-log')
      +const deepestNestingTarget = require('./deepest-nesting-target.js')
      +const CanPlaceDep = require('./can-place-dep.js')
      +const {
      +  KEEP,
      +  CONFLICT,
      +} = CanPlaceDep
      +const debug = require('./debug.js')
      +
      +const gatherDepSet = require('./gather-dep-set.js')
      +const peerEntrySets = require('./peer-entry-sets.js')
      +
      +class PlaceDep {
      +  constructor (options) {
      +    const {
      +      dep,
      +      edge,
      +      parent = null,
      +    } = options
      +    this.name = edge.name
      +    this.dep = dep
      +    this.edge = edge
      +    this.canPlace = null
      +
      +    this.target = null
      +    this.placed = null
      +
      +    // inherit all these fields from the parent to ensure consistency.
      +    const {
      +      preferDedupe,
      +      force,
      +      explicitRequest,
      +      updateNames,
      +      auditReport,
      +      legacyBundling,
      +      strictPeerDeps,
      +      legacyPeerDeps,
      +      globalStyle,
      +    } = parent || options
      +    Object.assign(this, {
      +      preferDedupe,
      +      force,
      +      explicitRequest,
      +      updateNames,
      +      auditReport,
      +      legacyBundling,
      +      strictPeerDeps,
      +      legacyPeerDeps,
      +      globalStyle,
      +    })
      +
      +    this.children = []
      +    this.parent = parent
      +    this.peerConflict = null
      +
      +    this.checks = new Map()
      +
      +    this.place()
      +  }
      +
      +  place () {
      +    const {
      +      edge,
      +      dep,
      +      preferDedupe,
      +      globalStyle,
      +      legacyBundling,
      +      explicitRequest,
      +      updateNames,
      +      checks,
      +    } = this
      +
      +    // nothing to do if the edge is fine as it is
      +    if (edge.to &&
      +        !edge.error &&
      +        !explicitRequest &&
      +        !updateNames.includes(edge.name) &&
      +        !this.isVulnerable(edge.to))
      +      return
      +
      +    // walk up the tree until we hit either a top/root node, or a place
      +    // where the dep is not a peer dep.
      +    const start = this.getStartNode()
      +
      +    let canPlace = null
      +    let canPlaceSelf = null
      +    for (const target of start.ancestry()) {
      +      // if the current location has a peerDep on it, then we can't place here
      +      // this is pretty rare to hit, since we always prefer deduping peers,
      +      // and the getStartNode will start us out above any peers from the
      +      // thing that depends on it.  but we could hit it with something like:
      +      //
      +      // a -> (b@1, c@1)
      +      // +-- c@1
      +      // +-- b -> PEEROPTIONAL(v) (c@2)
      +      //     +-- c@2 -> (v)
      +      //
      +      // So we check if we can place v under c@2, that's fine.
      +      // Then we check under b, and can't, because of the optional peer dep.
      +      // but we CAN place it under a, so the correct thing to do is keep
      +      // walking up the tree.
      +      const targetEdge = target.edgesOut.get(edge.name)
      +      if (!target.isTop && targetEdge && targetEdge.peer)
      +        continue
      +
      +      const cpd = new CanPlaceDep({
      +        dep,
      +        edge,
      +        // note: this sets the parent's canPlace as the parent of this
      +        // canPlace, but it does NOT add this canPlace to the parent's
      +        // children.  This way, we can know that it's a peer dep, and
      +        // get the top edge easily, while still maintaining the
      +        // tree of checks that factored into the original decision.
      +        parent: this.parent && this.parent.canPlace,
      +        target,
      +        preferDedupe,
      +        explicitRequest: this.explicitRequest,
      +      })
      +      checks.set(target, cpd)
      +
      +      // It's possible that a "conflict" is a conflict among the *peers* of
      +      // a given node we're trying to place, but there actually is no current
      +      // node.  Eg,
      +      // root -> (a, b)
      +      // a -> PEER(c)
      +      // b -> PEER(d)
      +      // d -> PEER(c@2)
      +      // We place (a), and get a peer of (c) along with it.
      +      // then we try to place (b), and get CONFLICT in the check, because
      +      // of the conflicting peer from (b)->(d)->(c@2).  In that case, we
      +      // should treat (b) and (d) as OK, and place them in the last place
      +      // where they did not themselves conflict, and skip c@2 if conflict
      +      // is ok by virtue of being forced or not ours and not strict.
      +      if (cpd.canPlaceSelf !== CONFLICT)
      +        canPlaceSelf = cpd
      +
      +      // we found a place this can go, along with all its peer friends.
      +      // we break when we get the first conflict
      +      if (cpd.canPlace !== CONFLICT)
      +        canPlace = cpd
      +      else
      +        break
      +
      +      // if it's a load failure, just plop it in the first place attempted,
      +      // since we're going to crash the build or prune it out anyway.
      +      // but, this will frequently NOT be a successful canPlace, because
      +      // it'll have no version or other information.
      +      if (dep.errors.length)
      +        break
      +
      +      // nest packages like npm v1 and v2
      +      // very disk-inefficient
      +      if (legacyBundling)
      +        break
      +
      +      // when installing globally, or just in global style, we never place
      +      // deps above the first level.
      +      if (globalStyle) {
      +        const rp = target.resolveParent
      +        if (rp && rp.isProjectRoot)
      +          break
      +      }
      +    }
      +
      +    Object.assign(this, {
      +      canPlace,
      +      canPlaceSelf,
      +    })
      +    this.current = edge.to
      +
      +    // if we can't find a target, that means that the last place checked,
      +    // and all the places before it, had a conflict.
      +    if (!canPlace) {
      +      // if not forced, or it's our dep, or strictPeerDeps is set, then
      +      // this is an ERESOLVE error.
      +      if (!this.conflictOk)
      +        return this.failPeerConflict()
      +
      +      // ok!  we're gonna allow the conflict, but we should still warn
      +      // if we have a current, then we treat CONFLICT as a KEEP.
      +      // otherwise, we just skip it.  Only warn on the one that actually
      +      // could not be placed somewhere.
      +      if (!canPlaceSelf) {
      +        this.warnPeerConflict()
      +        return
      +      }
      +
      +      this.canPlace = canPlaceSelf
      +    }
      +
      +    // now we have a target, a tree of CanPlaceDep results for the peer group,
      +    // and we are ready to go
      +    this.placeInTree()
      +  }
      +
      +  placeInTree () {
      +    const {
      +      dep,
      +      canPlace,
      +      edge,
      +    } = this
      +
      +    /* istanbul ignore next */
      +    if (!canPlace) {
      +      debug(() => {
      +        throw new Error('canPlace not set, but trying to place in tree')
      +      })
      +      return
      +    }
      +
      +    const { target } = canPlace
      +
      +    log.silly(
      +      'placeDep',
      +      target.location || 'ROOT',
      +      `${dep.name}@${dep.version}`,
      +      canPlace.description,
      +      `for: ${this.edge.from.package._id || this.edge.from.location}`,
      +      `want: ${edge.spec || '*'}`
      +    )
      +
      +    const placementType = canPlace.canPlace === CONFLICT
      +      ? canPlace.canPlaceSelf
      +      : canPlace.canPlace
      +
      +    // if we're placing in the tree with --force, we can get here even though
      +    // it's a conflict.  Treat it as a KEEP, but warn and move on.
      +    if (placementType === KEEP) {
      +      // this was an overridden peer dep
      +      if (edge.peer && !edge.valid)
      +        this.warnPeerConflict()
      +
      +      // if we get a KEEP in a update scenario, then we MAY have something
      +      // already duplicating this unnecessarily!  For example:
      +      // ```
      +      // root (dep: y@1)
      +      // +-- x (dep: y@1.1)
      +      // |   +-- y@1.1.0 (replacing with 1.1.2, got KEEP at the root)
      +      // +-- y@1.1.2 (updated already from 1.0.0)
      +      // ```
      +      // Now say we do `reify({update:['y']})`, and the latest version is
      +      // 1.1.2, which we now have in the root.  We'll try to place y@1.1.2
      +      // first in x, then in the root, ending with KEEP, because we already
      +      // have it.  In that case, we ought to REMOVE the nm/x/nm/y node, because
      +      // it is an unnecessary duplicate.
      +      this.pruneDedupable(target)
      +      return
      +    }
      +
      +    // XXX if we are replacing SOME of a peer entry group, we will need to
      +    // remove any that are not being replaced and will now be invalid, and
      +    // re-evaluate them deeper into the tree.
      +
      +    const virtualRoot = dep.parent
      +    this.placed = new dep.constructor({
      +      name: dep.name,
      +      pkg: dep.package,
      +      resolved: dep.resolved,
      +      integrity: dep.integrity,
      +      legacyPeerDeps: this.legacyPeerDeps,
      +      error: dep.errors[0],
      +      ...(dep.isLink ? { target: dep.target, realpath: dep.target.path } : {}),
      +    })
      +
      +    this.oldDep = target.children.get(this.name)
      +    if (this.oldDep)
      +      this.replaceOldDep()
      +    else
      +      this.placed.parent = target
      +
      +    // if it's an overridden peer dep, warn about it
      +    if (edge.peer && !this.placed.satisfies(edge))
      +      this.warnPeerConflict()
      +
      +    // If the edge is not an error, then we're updating something, and
      +    // MAY end up putting a better/identical node further up the tree in
      +    // a way that causes an unnecessary duplication.  If so, remove the
      +    // now-unnecessary node.
      +    if (edge.valid && edge.to && edge.to !== this.placed)
      +      this.pruneDedupable(edge.to, false)
      +
      +    // in case we just made some duplicates that can be removed,
      +    // prune anything deeper in the tree that can be replaced by this
      +    for (const node of target.root.inventory.query('name', this.name)) {
      +      if (node.isDescendantOf(target) && !node.isTop) {
      +        this.pruneDedupable(node, false)
      +        // only walk the direct children of the ones we kept
      +        if (node.root === target.root) {
      +          for (const kid of node.children.values())
      +            this.pruneDedupable(kid, false)
      +        }
      +      }
      +    }
      +
      +    // also place its unmet or invalid peer deps at this location
      +    // loop through any peer deps from the thing we just placed, and place
      +    // those ones as well.  it's safe to do this with the virtual nodes,
      +    // because we're copying rather than moving them out of the virtual root,
      +    // otherwise they'd be gone and the peer set would change throughout
      +    // this loop.
      +    for (const peerEdge of this.placed.edgesOut.values()) {
      +      if (peerEdge.valid || !peerEdge.peer || peerEdge.overridden)
      +        continue
      +
      +      const peer = virtualRoot.children.get(peerEdge.name)
      +
      +      // Note: if the virtualRoot *doesn't* have the peer, then that means
      +      // it's an optional peer dep.  If it's not being properly met (ie,
      +      // peerEdge.valid is false), then this is likely heading for an
      +      // ERESOLVE error, unless it can walk further up the tree.
      +      if (!peer)
      +        continue
      +
      +      // overridden peerEdge, just accept what's there already
      +      if (!peer.satisfies(peerEdge))
      +        continue
      +
      +      this.children.push(new PlaceDep({
      +        parent: this,
      +        dep: peer,
      +        node: this.placed,
      +        edge: peerEdge,
      +      }))
      +    }
      +  }
      +
      +  replaceOldDep () {
      +    // XXX handle replacing an entire peer group?
      +    // what about cases where we need to push some other peer groups deeper
      +    // into the tree?  all the tree updating should be done here, and track
      +    // all the things that we add and remove, so that we can know what
      +    // to re-evaluate.
      +
      +    // if we're replacing, we should also remove any nodes for edges that
      +    // are now invalid, and where this (or its deps) is the only dependent,
      +    // and also recurse on that pruning.  Otherwise leaving that dep node
      +    // around can result in spurious conflicts pushing nodes deeper into
      +    // the tree than needed in the case of cycles that will be removed
      +    // later anyway.
      +    const oldDeps = []
      +    for (const [name, edge] of this.oldDep.edgesOut.entries()) {
      +      if (!this.placed.edgesOut.has(name) && edge.to)
      +        oldDeps.push(...gatherDepSet([edge.to], e => e.to !== edge.to))
      +    }
      +    this.placed.replace(this.oldDep)
      +    this.pruneForReplacement(this.placed, oldDeps)
      +  }
      +
      +  pruneForReplacement (node, oldDeps) {
      +    // gather up all the now-invalid/extraneous edgesOut, as long as they are
      +    // only depended upon by the old node/deps
      +    const invalidDeps = new Set([...node.edgesOut.values()]
      +      .filter(e => e.to && !e.valid).map(e => e.to))
      +    for (const dep of oldDeps) {
      +      const set = gatherDepSet([dep], e => e.to !== dep && e.valid)
      +      for (const dep of set)
      +        invalidDeps.add(dep)
      +    }
      +
      +    // ignore dependency edges from the node being replaced, but
      +    // otherwise filter the set down to just the set with no
      +    // dependencies from outside the set, except the node in question.
      +    const deps = gatherDepSet(invalidDeps, edge =>
      +      edge.from !== node && edge.to !== node && edge.valid)
      +
      +    // now just delete whatever's left, because it's junk
      +    for (const dep of deps)
      +      dep.root = null
      +  }
      +
      +  // prune all the nodes in a branch of the tree that can be safely removed
      +  // This is only the most basic duplication detection; it finds if there
      +  // is another satisfying node further up the tree, and if so, dedupes.
      +  // Even in legacyBundling mode, we do this amount of deduplication.
      +  pruneDedupable (node, descend = true) {
      +    if (node.canDedupe(this.preferDedupe)) {
      +      // gather up all deps that have no valid edges in from outside
      +      // the dep set, except for this node we're deduping, so that we
      +      // also prune deps that would be made extraneous.
      +      const deps = gatherDepSet([node], e => e.to !== node && e.valid)
      +      for (const node of deps)
      +        node.root = null
      +      return
      +    }
      +    if (descend) {
      +      // sort these so that they're deterministically ordered
      +      // otherwise, resulting tree shape is dependent on the order
      +      // in which they happened to be resolved.
      +      const nodeSort = (a, b) => a.location.localeCompare(b.location, 'en')
      +
      +      const children = [...node.children.values()].sort(nodeSort)
      +      for (const child of children)
      +        this.pruneDedupable(child)
      +      const fsChildren = [...node.fsChildren].sort(nodeSort)
      +      for (const topNode of fsChildren) {
      +        const children = [...topNode.children.values()].sort(nodeSort)
      +        for (const child of children)
      +          this.pruneDedupable(child)
      +      }
      +    }
      +  }
      +
      +  get conflictOk () {
      +    return this.force || (!this.isMine && !this.strictPeerDeps)
      +  }
      +
      +  get isMine () {
      +    const { edge } = this.top
      +    const { from: node } = edge
      +
      +    if (node.isWorkspace || node.isProjectRoot)
      +      return true
      +
      +    if (!edge.peer)
      +      return false
      +
      +    // re-entry case.  check if any non-peer edges come from the project,
      +    // or any entryEdges on peer groups are from the root.
      +    let hasPeerEdges = false
      +    for (const edge of node.edgesIn) {
      +      if (edge.peer) {
      +        hasPeerEdges = true
      +        continue
      +      }
      +      if (edge.from.isWorkspace || edge.from.isProjectRoot)
      +        return true
      +    }
      +    if (hasPeerEdges) {
      +      for (const edge of peerEntrySets(node).keys()) {
      +        if (edge.from.isWorkspace || edge.from.isProjectRoot)
      +          return true
      +      }
      +    }
      +
      +    return false
      +  }
      +
      +  warnPeerConflict () {
      +    this.edge.overridden = true
      +    const expl = this.explainPeerConflict()
      +    log.warn('ERESOLVE', 'overriding peer dependency', expl)
      +  }
      +
      +  failPeerConflict () {
      +    const expl = this.explainPeerConflict()
      +    throw Object.assign(new Error('could not resolve'), expl)
      +  }
      +
      +  explainPeerConflict () {
      +    const { edge, dep } = this.top
      +    const { from: node } = edge
      +    const curNode = node.resolve(edge.name)
      +
      +    const expl = {
      +      code: 'ERESOLVE',
      +      edge: edge.explain(),
      +      dep: dep.explain(edge),
      +    }
      +
      +    if (this.parent) {
      +      // this is the conflicted peer
      +      expl.current = curNode && curNode.explain(edge)
      +      expl.peerConflict = this.current && this.current.explain(this.edge)
      +    } else {
      +      expl.current = curNode && curNode.explain()
      +      if (this.canPlaceSelf && this.canPlaceSelf.canPlaceSelf !== CONFLICT) {
      +        // failed while checking for a child dep
      +        const cps = this.canPlaceSelf
      +        for (const peer of cps.conflictChildren) {
      +          if (peer.current) {
      +            expl.peerConflict = {
      +              current: peer.current.explain(),
      +              peer: peer.dep.explain(peer.edge),
      +            }
      +            break
      +          }
      +        }
      +      } else {
      +        expl.peerConflict = {
      +          current: this.current && this.current.explain(),
      +          peer: this.dep.explain(this.edge),
      +        }
      +      }
      +    }
      +
      +    const {
      +      strictPeerDeps,
      +      force,
      +      isMine,
      +    } = this
      +    Object.assign(expl, {
      +      strictPeerDeps,
      +      force,
      +      isMine,
      +    })
      +
      +    // XXX decorate more with this.canPlace and this.canPlaceSelf,
      +    // this.checks, this.children, walk over conflicted peers, etc.
      +    return expl
      +  }
      +
      +  getStartNode () {
      +    // if we are a peer, then we MUST be at least as shallow as the
      +    // peer dependent
      +    const from = this.parent ? this.parent.getStartNode() : this.edge.from
      +    return deepestNestingTarget(from, this.name)
      +  }
      +
      +  get top () {
      +    return this.parent ? this.parent.top : this
      +  }
      +
      +  isVulnerable (node) {
      +    return this.auditReport && this.auditReport.isVulnerable(node)
      +  }
      +
      +  get allChildren () {
      +    const set = new Set(this.children)
      +    for (const child of set) {
      +      for (const grandchild of child.children)
      +        set.add(grandchild)
      +    }
      +    return [...set]
      +  }
      +}
      +
      +module.exports = PlaceDep
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/printable.js b/deps/npm/node_modules/@npmcli/arborist/lib/printable.js
      index ce764071dc62aa..4aa2fffd104b4a 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/printable.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/printable.js
      @@ -31,6 +31,10 @@ class ArboristNode {
             this.bundled = true
           if (tree.inDepBundle)
             this.bundler = tree.getBundler().location
      +    if (tree.isProjectRoot)
      +      this.isProjectRoot = true
      +    if (tree.isWorkspace)
      +      this.isWorkspace = true
           const bd = tree.package && tree.package.bundleDependencies
           if (bd && bd.length)
             this.bundleDependencies = bd
      @@ -107,6 +111,8 @@ class Edge {
           this.spec = edge.spec || '*'
           if (edge.error)
             this.error = edge.error
      +    if (edge.overridden)
      +      this.overridden = edge.overridden
         }
       }
       
      @@ -122,6 +128,8 @@ class EdgeOut extends Edge {
             this.to ? ' -> ' + this.to : ''
           }${
             this.error ? ' ' + this.error : ''
      +    }${
      +      this.overridden ? ' overridden' : ''
           } }`
         }
       }
      @@ -136,6 +144,8 @@ class EdgeIn extends Edge {
         [util.inspect.custom] () {
           return `{ ${this.from || '""'} ${this.type} ${this.name}@${this.spec}${
             this.error ? ' ' + this.error : ''
      +    }${
      +      this.overridden ? ' overridden' : ''
           } }`
         }
       }
      diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/shrinkwrap.js b/deps/npm/node_modules/@npmcli/arborist/lib/shrinkwrap.js
      index b251539a94c902..ebbe004de72d66 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/lib/shrinkwrap.js
      +++ b/deps/npm/node_modules/@npmcli/arborist/lib/shrinkwrap.js
      @@ -183,8 +183,10 @@ const assertNoNewer = async (path, data, lockTime, dir = path, seen = null) => {
               await assertNoNewer(path, data, lockTime, child, seen)
             else if (ent.isSymbolicLink()) {
               const target = resolve(parent, await readlink(child))
      -        const tstat = await stat(target).catch(() => null)
      +        const tstat = await stat(target).catch(
      +          /* istanbul ignore next - windows */ () => null)
               seen.add(relpath(path, child))
      +        /* istanbul ignore next - windows cannot do this */
               if (tstat && tstat.isDirectory() && !seen.has(relpath(path, target)))
                 await assertNoNewer(path, data, lockTime, target, seen)
             }
      @@ -802,7 +804,7 @@ class Shrinkwrap {
           if (this.tree) {
             if (this.yarnLock)
               this.yarnLock.fromTree(this.tree)
      -      const root = Shrinkwrap.metaFromNode(this.tree.target || this.tree, this.path)
      +      const root = Shrinkwrap.metaFromNode(this.tree.target, this.path)
             this.data.packages = {}
             if (Object.keys(root).length)
               this.data.packages[''] = root
      @@ -864,7 +866,7 @@ class Shrinkwrap {
           const spec = !edge ? rSpec
             : npa.resolve(node.name, edge.spec, edge.from.realpath)
       
      -    if (node.target)
      +    if (node.isLink)
             lock.version = `file:${relpath(this.path, node.realpath)}`
           else if (spec && (spec.type === 'file' || spec.type === 'remote'))
             lock.version = spec.saveSpec
      @@ -888,7 +890,7 @@ class Shrinkwrap {
           // when we didn't resolve to git, file, or dir, and didn't request
           // git, file, dir, or remote, then the resolved value is necessary.
           if (node.resolved &&
      -        !node.target &&
      +        !node.isLink &&
               rSpec.type !== 'git' &&
               rSpec.type !== 'file' &&
               rSpec.type !== 'directory' &&
      @@ -917,7 +919,7 @@ class Shrinkwrap {
               lock.optional = true
           }
       
      -    const depender = node.target || node
      +    const depender = node.target
           if (depender.edgesOut.size > 0) {
             if (node !== this.tree) {
               lock.requires = [...depender.edgesOut.entries()].reduce((set, [k, v]) => {
      @@ -942,7 +944,7 @@ class Shrinkwrap {
           }
       
           // now we walk the children, putting them in the 'dependencies' object
      -    const {children} = node.target || node
      +    const {children} = node.target
           if (!children.size)
             delete lock.dependencies
           else {
      diff --git a/deps/npm/node_modules/@npmcli/arborist/package.json b/deps/npm/node_modules/@npmcli/arborist/package.json
      index 138d6ec25b4c2d..56046eaa5f3578 100644
      --- a/deps/npm/node_modules/@npmcli/arborist/package.json
      +++ b/deps/npm/node_modules/@npmcli/arborist/package.json
      @@ -1,6 +1,6 @@
       {
         "name": "@npmcli/arborist",
      -  "version": "2.6.4",
      +  "version": "2.8.0",
         "description": "Manage node_modules trees",
         "dependencies": {
           "@npmcli/installed-package-contents": "^1.0.7",
      @@ -16,19 +16,22 @@
           "common-ancestor-path": "^1.0.1",
           "json-parse-even-better-errors": "^2.3.1",
           "json-stringify-nice": "^1.1.4",
      +    "mkdirp": "^1.0.4",
           "mkdirp-infer-owner": "^2.0.0",
           "npm-install-checks": "^4.0.0",
      -    "npm-package-arg": "^8.1.0",
      +    "npm-package-arg": "^8.1.5",
           "npm-pick-manifest": "^6.1.0",
           "npm-registry-fetch": "^11.0.0",
      -    "pacote": "^11.2.6",
      +    "pacote": "^11.3.5",
           "parse-conflict-json": "^1.1.1",
           "proc-log": "^1.0.0",
           "promise-all-reject-late": "^1.0.0",
           "promise-call-limit": "^1.0.1",
           "read-package-json-fast": "^2.0.2",
           "readdir-scoped-modules": "^1.1.0",
      +    "rimraf": "^3.0.2",
           "semver": "^7.3.5",
      +    "ssri": "^8.0.1",
           "tar": "^6.1.0",
           "treeverse": "^1.0.4",
           "walk-up-path": "^1.0.0"
      @@ -50,7 +53,7 @@
           "test-only": "tap",
           "posttest": "npm run lint",
           "snap": "tap",
      -    "postsnap": "npm run lint",
      +    "postsnap": "npm run lintfix",
           "test-proxy": "ARBORIST_TEST_PROXY=1 tap --snapshot",
           "preversion": "npm test",
           "postversion": "npm publish",
      diff --git a/deps/npm/node_modules/@npmcli/git/lib/errors.js b/deps/npm/node_modules/@npmcli/git/lib/errors.js
      new file mode 100644
      index 00000000000000..25b2b9f9fd6a6a
      --- /dev/null
      +++ b/deps/npm/node_modules/@npmcli/git/lib/errors.js
      @@ -0,0 +1,36 @@
      +
      +const maxRetry = 3
      +
      +class GitError extends Error {
      +  shouldRetry () {
      +    return false
      +  }
      +}
      +
      +class GitConnectionError extends GitError {
      +  constructor (message) {
      +    super('A git connection error occurred')
      +  }
      +
      +  shouldRetry (number) {
      +    return number < maxRetry
      +  }
      +}
      +
      +class GitPathspecError extends GitError {
      +  constructor (message) {
      +    super('The git reference could not be found')
      +  }
      +}
      +
      +class GitUnknownError extends GitError {
      +  constructor (message) {
      +    super('An unknown git error occurred')
      +  }
      +}
      +
      +module.exports = {
      +  GitConnectionError,
      +  GitPathspecError,
      +  GitUnknownError
      +}
      diff --git a/deps/npm/node_modules/@npmcli/git/lib/index.js b/deps/npm/node_modules/@npmcli/git/lib/index.js
      index 50fd889b89b5ad..20d7cfd01cfd12 100644
      --- a/deps/npm/node_modules/@npmcli/git/lib/index.js
      +++ b/deps/npm/node_modules/@npmcli/git/lib/index.js
      @@ -4,5 +4,6 @@ module.exports = {
         spawn: require('./spawn.js'),
         is: require('./is.js'),
         find: require('./find.js'),
      -  isClean: require('./is-clean.js')
      +  isClean: require('./is-clean.js'),
      +  errors: require('./errors.js')
       }
      diff --git a/deps/npm/node_modules/@npmcli/git/lib/make-error.js b/deps/npm/node_modules/@npmcli/git/lib/make-error.js
      new file mode 100644
      index 00000000000000..043a8e6e95181e
      --- /dev/null
      +++ b/deps/npm/node_modules/@npmcli/git/lib/make-error.js
      @@ -0,0 +1,33 @@
      +const {
      +  GitConnectionError,
      +  GitPathspecError,
      +  GitUnknownError
      +} = require('./errors.js')
      +
      +const connectionErrorRe = new RegExp([
      +  'remote error: Internal Server Error',
      +  'The remote end hung up unexpectedly',
      +  'Connection timed out',
      +  'Operation timed out',
      +  'Failed to connect to .* Timed out',
      +  'Connection reset by peer',
      +  'SSL_ERROR_SYSCALL',
      +  'The requested URL returned error: 503'
      +].join('|'))
      +
      +const missingPathspecRe = /pathspec .* did not match any file\(s\) known to git/
      +
      +function makeError (er) {
      +  const message = er.stderr
      +  let gitEr
      +  if (connectionErrorRe.test(message)) {
      +    gitEr = new GitConnectionError(message)
      +  } else if (missingPathspecRe.test(message)) {
      +    gitEr = new GitPathspecError(message)
      +  } else {
      +    gitEr = new GitUnknownError(message)
      +  }
      +  return Object.assign(gitEr, er)
      +}
      +
      +module.exports = makeError
      diff --git a/deps/npm/node_modules/@npmcli/git/lib/should-retry.js b/deps/npm/node_modules/@npmcli/git/lib/should-retry.js
      deleted file mode 100644
      index 8082bb5d7c6e71..00000000000000
      --- a/deps/npm/node_modules/@npmcli/git/lib/should-retry.js
      +++ /dev/null
      @@ -1,17 +0,0 @@
      -const transientErrors = [
      -  'remote error: Internal Server Error',
      -  'The remote end hung up unexpectedly',
      -  'Connection timed out',
      -  'Operation timed out',
      -  'Failed to connect to .* Timed out',
      -  'Connection reset by peer',
      -  'SSL_ERROR_SYSCALL',
      -  'The requested URL returned error: 503'
      -].join('|')
      -
      -const transientErrorRe = new RegExp(transientErrors)
      -
      -const maxRetry = 3
      -
      -module.exports = (error, number) =>
      -  transientErrorRe.test(error) && (number < maxRetry)
      diff --git a/deps/npm/node_modules/@npmcli/git/lib/spawn.js b/deps/npm/node_modules/@npmcli/git/lib/spawn.js
      index 337164a9a012dc..1c89a4c53cf86a 100644
      --- a/deps/npm/node_modules/@npmcli/git/lib/spawn.js
      +++ b/deps/npm/node_modules/@npmcli/git/lib/spawn.js
      @@ -1,6 +1,6 @@
       const spawn = require('@npmcli/promise-spawn')
       const promiseRetry = require('promise-retry')
      -const shouldRetry = require('./should-retry.js')
      +const makeError = require('./make-error.js')
       const whichGit = require('./which.js')
       const makeOpts = require('./opts.js')
       const procLog = require('./proc-log.js')
      @@ -33,10 +33,11 @@ module.exports = (gitArgs, opts = {}) => {
       
           return spawn(gitPath, args, makeOpts(opts))
             .catch(er => {
      -        if (!shouldRetry(er.stderr, number)) {
      -          throw er
      +        const gitError = makeError(er)
      +        if (!gitError.shouldRetry(number)) {
      +          throw gitError
               }
      -        retry(er)
      +        retry(gitError)
             })
         }, retry)
       }
      diff --git a/deps/npm/node_modules/@npmcli/git/package.json b/deps/npm/node_modules/@npmcli/git/package.json
      index 0fe94686ece20c..9475da5007a7dc 100644
      --- a/deps/npm/node_modules/@npmcli/git/package.json
      +++ b/deps/npm/node_modules/@npmcli/git/package.json
      @@ -1,6 +1,6 @@
       {
         "name": "@npmcli/git",
      -  "version": "2.0.9",
      +  "version": "2.1.0",
         "main": "lib/index.js",
         "files": [
           "lib/*.js"
      diff --git a/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js b/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js
      index 41f8a3d215ee14..a2acea156ee6f5 100644
      --- a/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js
      +++ b/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js
      @@ -48,6 +48,7 @@ const KEEP_RESPONSE_HEADERS = [
       // return an object containing all metadata to be written to the index
       const getMetadata = (request, response, options) => {
         const metadata = {
      +    time: Date.now(),
           url: request.url,
           reqHeaders: {},
           resHeaders: {},
      @@ -112,9 +113,18 @@ const _policy = Symbol('policy')
       
       class CacheEntry {
         constructor ({ entry, request, response, options }) {
      -    this.entry = entry
      +    if (entry) {
      +      this.key = entry.key
      +      this.entry = entry
      +      // previous versions of this module didn't write an explicit timestamp in
      +      // the metadata, so fall back to the entry's timestamp. we can't use the
      +      // entry timestamp to determine staleness because cacache will update it
      +      // when it verifies its data
      +      this.entry.metadata.time = this.entry.metadata.time || this.entry.time
      +    } else
      +      this.key = cacheKey(request)
      +
           this.options = options
      -    this.key = entry ? entry.key : cacheKey(request)
       
           // these properties are behind getters that lazily evaluate
           this[_request] = request
      @@ -340,13 +350,25 @@ class CacheEntry {
                   const content = await cacache.get.byDigest(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
                   body.end(content)
                 } catch (err) {
      +            if (err.code === 'EINTEGRITY')
      +              await cacache.rm.content(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
      +            if (err.code === 'ENOENT' || err.code === 'EINTEGRITY')
      +              await CacheEntry.invalidate(this.request, this.options)
                   body.emit('error', err)
                 }
               }
             } else {
               onResume = () => {
                 const cacheStream = cacache.get.stream.byDigest(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
      -          cacheStream.on('error', (err) => body.emit('error', err))
      +          cacheStream.on('error', async (err) => {
      +            cacheStream.pause()
      +            if (err.code === 'EINTEGRITY')
      +              await cacache.rm.content(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
      +            if (err.code === 'ENOENT' || err.code === 'EINTEGRITY')
      +              await CacheEntry.invalidate(this.request, this.options)
      +            body.emit('error', err)
      +            cacheStream.resume()
      +          })
                 cacheStream.pipe(body)
               }
             }
      @@ -368,7 +390,7 @@ class CacheEntry {
           response.headers.set('x-local-cache-key', encodeURIComponent(this.key))
           response.headers.set('x-local-cache-mode', shouldBuffer ? 'buffer' : 'stream')
           response.headers.set('x-local-cache-status', status)
      -    response.headers.set('x-local-cache-time', new Date(this.entry.time).toUTCString())
      +    response.headers.set('x-local-cache-time', new Date(this.entry.metadata.time).toUTCString())
           return response
         }
       
      diff --git a/deps/npm/node_modules/make-fetch-happen/lib/cache/policy.js b/deps/npm/node_modules/make-fetch-happen/lib/cache/policy.js
      index 189dce80ee68ed..e0959f64ddf9df 100644
      --- a/deps/npm/node_modules/make-fetch-happen/lib/cache/policy.js
      +++ b/deps/npm/node_modules/make-fetch-happen/lib/cache/policy.js
      @@ -67,7 +67,7 @@ class CachePolicy {
             // this is necessary because the CacheSemantics constructor forces
             // the value to Date.now() which means a policy created from a
             // cache entry is likely to always identify itself as stale
      -      this.policy._responseTime = this.entry.time
      +      this.policy._responseTime = this.entry.metadata.time
           }
         }
       
      diff --git a/deps/npm/node_modules/make-fetch-happen/lib/remote.js b/deps/npm/node_modules/make-fetch-happen/lib/remote.js
      index e37f39de845f38..7e4ed24edb5304 100644
      --- a/deps/npm/node_modules/make-fetch-happen/lib/remote.js
      +++ b/deps/npm/node_modules/make-fetch-happen/lib/remote.js
      @@ -14,6 +14,7 @@ const RETRY_ERRORS = [
         'ECONNREFUSED', // remote host refused to open connection
         'EADDRINUSE', // failed to bind to a local port (proxy?)
         'ETIMEDOUT', // someone in the transaction is WAY TOO SLOW
      +  'ERR_SOCKET_TIMEOUT', // same as above, but this one comes from agentkeepalive
         // Known codes we do NOT retry on:
         // ENOTFOUND (getaddrinfo failure. Either bad hostname, or offline)
       ]
      diff --git a/deps/npm/node_modules/make-fetch-happen/package.json b/deps/npm/node_modules/make-fetch-happen/package.json
      index 44330998bb02f7..e4a26a9cd94dfc 100644
      --- a/deps/npm/node_modules/make-fetch-happen/package.json
      +++ b/deps/npm/node_modules/make-fetch-happen/package.json
      @@ -1,6 +1,6 @@
       {
         "name": "make-fetch-happen",
      -  "version": "9.0.3",
      +  "version": "9.0.4",
         "description": "Opinionated, caching, retrying fetch client",
         "main": "lib/index.js",
         "files": [
      diff --git a/deps/npm/node_modules/mime-db/HISTORY.md b/deps/npm/node_modules/mime-db/HISTORY.md
      index ff9438ee9c075b..672d414ca3782e 100644
      --- a/deps/npm/node_modules/mime-db/HISTORY.md
      +++ b/deps/npm/node_modules/mime-db/HISTORY.md
      @@ -1,3 +1,9 @@
      +1.49.0 / 2021-07-26
      +===================
      +
      +  * Add extension `.trig` to `application/trig`
      +  * Add new upstream MIME types
      +
       1.48.0 / 2021-05-30
       ===================
       
      diff --git a/deps/npm/node_modules/mime-db/db.json b/deps/npm/node_modules/mime-db/db.json
      index 067e0ce8151a4d..911b0f865b7048 100644
      --- a/deps/npm/node_modules/mime-db/db.json
      +++ b/deps/npm/node_modules/mime-db/db.json
      @@ -777,6 +777,7 @@
           "extensions": ["mads"]
         },
         "application/manifest+json": {
      +    "source": "iana",
           "charset": "UTF-8",
           "compressible": true,
           "extensions": ["webmanifest"]
      @@ -896,6 +897,9 @@
         "application/mipc": {
           "source": "iana"
         },
      +  "application/missing-blocks+cbor-seq": {
      +    "source": "iana"
      +  },
         "application/mmt-aei+xml": {
           "source": "iana",
           "compressible": true,
      @@ -1062,6 +1066,10 @@
           "source": "iana",
           "extensions": ["oxps"]
         },
      +  "application/p21+zip": {
      +    "source": "iana",
      +    "compressible": false
      +  },
         "application/p2p-overlay+xml": {
           "source": "iana",
           "compressible": true,
      @@ -1640,7 +1648,8 @@
           "source": "iana"
         },
         "application/trig": {
      -    "source": "iana"
      +    "source": "iana",
      +    "extensions": ["trig"]
         },
         "application/ttml+xml": {
           "source": "iana",
      @@ -2053,6 +2062,12 @@
           "source": "iana",
           "extensions": ["atx"]
         },
      +  "application/vnd.apache.arrow.file": {
      +    "source": "iana"
      +  },
      +  "application/vnd.apache.arrow.stream": {
      +    "source": "iana"
      +  },
         "application/vnd.apache.thrift.binary": {
           "source": "iana"
         },
      @@ -4288,6 +4303,9 @@
           "compressible": true,
           "extensions": ["osm"]
         },
      +  "application/vnd.opentimestamps.ots": {
      +    "source": "iana"
      +  },
         "application/vnd.openxmlformats-officedocument.custom-properties+xml": {
           "source": "iana",
           "compressible": true
      @@ -4819,6 +4837,9 @@
         "application/vnd.renlearn.rlprint": {
           "source": "iana"
         },
      +  "application/vnd.resilient.logic": {
      +    "source": "iana"
      +  },
         "application/vnd.restful+json": {
           "source": "iana",
           "compressible": true
      @@ -5283,6 +5304,10 @@
         "application/vnd.verimatrix.vcas": {
           "source": "iana"
         },
      +  "application/vnd.veritone.aion+json": {
      +    "source": "iana",
      +    "compressible": true
      +  },
         "application/vnd.veryant.thin": {
           "source": "iana"
         },
      @@ -7401,6 +7426,16 @@
           "source": "iana",
           "extensions": ["obj"]
         },
      +  "model/step+zip": {
      +    "source": "iana",
      +    "compressible": false,
      +    "extensions": ["stpz"]
      +  },
      +  "model/step-xml+zip": {
      +    "source": "iana",
      +    "compressible": false,
      +    "extensions": ["stpxz"]
      +  },
         "model/stl": {
           "source": "iana",
           "extensions": ["stl"]
      @@ -8298,6 +8333,9 @@
         "video/vp8": {
           "source": "iana"
         },
      +  "video/vp9": {
      +    "source": "iana"
      +  },
         "video/webm": {
           "source": "apache",
           "compressible": false,
      diff --git a/deps/npm/node_modules/mime-db/package.json b/deps/npm/node_modules/mime-db/package.json
      index d4395a727b8888..e546efa728fd18 100644
      --- a/deps/npm/node_modules/mime-db/package.json
      +++ b/deps/npm/node_modules/mime-db/package.json
      @@ -1,7 +1,7 @@
       {
         "name": "mime-db",
         "description": "Media Type Database",
      -  "version": "1.48.0",
      +  "version": "1.49.0",
         "contributors": [
           "Douglas Christopher Wilson ",
           "Jonathan Ong  (http://jongleberry.com)",
      @@ -22,8 +22,8 @@
           "bluebird": "3.7.2",
           "co": "4.6.0",
           "cogent": "1.0.1",
      -    "csv-parse": "4.15.4",
      -    "eslint": "7.27.0",
      +    "csv-parse": "4.16.0",
      +    "eslint": "7.31.0",
           "eslint-config-standard": "15.0.1",
           "eslint-plugin-import": "2.23.4",
           "eslint-plugin-markdown": "2.2.0",
      @@ -31,7 +31,7 @@
           "eslint-plugin-promise": "5.1.0",
           "eslint-plugin-standard": "4.1.0",
           "gnode": "0.1.2",
      -    "mocha": "8.4.0",
      +    "mocha": "9.0.3",
           "nyc": "15.1.0",
           "raw-body": "2.4.1",
           "stream-to-array": "2.3.0"
      diff --git a/deps/npm/node_modules/mime-types/HISTORY.md b/deps/npm/node_modules/mime-types/HISTORY.md
      index 19e45a15fcc7f4..977ffbb15d8657 100644
      --- a/deps/npm/node_modules/mime-types/HISTORY.md
      +++ b/deps/npm/node_modules/mime-types/HISTORY.md
      @@ -1,3 +1,10 @@
      +2.1.32 / 2021-07-27
      +===================
      +
      +  * deps: mime-db@1.49.0
      +    - Add extension `.trig` to `application/trig`
      +    - Add new upstream MIME types
      +
       2.1.31 / 2021-06-01
       ===================
       
      diff --git a/deps/npm/node_modules/mime-types/package.json b/deps/npm/node_modules/mime-types/package.json
      index a271000ec92389..7567acd5508dff 100644
      --- a/deps/npm/node_modules/mime-types/package.json
      +++ b/deps/npm/node_modules/mime-types/package.json
      @@ -1,7 +1,7 @@
       {
         "name": "mime-types",
         "description": "The ultimate javascript content-type utility.",
      -  "version": "2.1.31",
      +  "version": "2.1.32",
         "contributors": [
           "Douglas Christopher Wilson ",
           "Jeremiah Senkpiel  (https://searchbeam.jit.su)",
      @@ -14,17 +14,17 @@
         ],
         "repository": "jshttp/mime-types",
         "dependencies": {
      -    "mime-db": "1.48.0"
      +    "mime-db": "1.49.0"
         },
         "devDependencies": {
      -    "eslint": "7.27.0",
      +    "eslint": "7.31.0",
           "eslint-config-standard": "14.1.1",
           "eslint-plugin-import": "2.23.4",
           "eslint-plugin-markdown": "2.2.0",
           "eslint-plugin-node": "11.1.0",
           "eslint-plugin-promise": "5.1.0",
           "eslint-plugin-standard": "4.1.0",
      -    "mocha": "8.4.0",
      +    "mocha": "9.0.3",
           "nyc": "15.1.0"
         },
         "files": [
      diff --git a/deps/npm/node_modules/minipass-fetch/lib/index.js b/deps/npm/node_modules/minipass-fetch/lib/index.js
      index d6ed57942e80f4..2ffcba85105540 100644
      --- a/deps/npm/node_modules/minipass-fetch/lib/index.js
      +++ b/deps/npm/node_modules/minipass-fetch/lib/index.js
      @@ -94,6 +94,19 @@ const fetch = (url, opts) => {
           }
       
           req.on('error', er => {
      +      // if a 'response' event is emitted before the 'error' event, then by the
      +      // time this handler is run it's too late to reject the Promise for the
      +      // response. instead, we forward the error event to the response stream
      +      // so that the error will surface to the user when they try to consume
      +      // the body. this is done as a side effect of aborting the request except
      +      // for in windows, where we must forward the event manually, otherwise
      +      // there is no longer a ref'd socket attached to the request and the
      +      // stream never ends so the event loop runs out of work and the process
      +      // exits without warning.
      +      // coverage skipped here due to the difficulty in testing
      +      // istanbul ignore next
      +      if (req.res)
      +        req.res.emit('error', er)
             reject(new FetchError(`request to ${request.url} failed, reason: ${
               er.message}`, 'system', er))
             finalize()
      @@ -286,8 +299,16 @@ const fetch = (url, opts) => {
       
       
             // for br
      -      if (codings == 'br' && typeof zlib.BrotliDecompress === 'function') {
      -        const decoder = new zlib.BrotliDecompress()
      +      if (codings == 'br') {
      +        // ignoring coverage so tests don't have to fake support (or lack of) for brotli
      +        // istanbul ignore next
      +        try {
      +          var decoder = new zlib.BrotliDecompress()
      +        } catch (err) {
      +          reject(err)
      +          finalize()
      +          return
      +        }
               // exceedingly rare that the stream would have an error,
               // but just in case we proxy it to the stream in use.
               body.on('error', /* istanbul ignore next */ er => decoder.emit('error', er)).pipe(decoder)
      diff --git a/deps/npm/node_modules/minipass-fetch/lib/request.js b/deps/npm/node_modules/minipass-fetch/lib/request.js
      index c5208a7fc1300a..173f415d18e7b4 100644
      --- a/deps/npm/node_modules/minipass-fetch/lib/request.js
      +++ b/deps/npm/node_modules/minipass-fetch/lib/request.js
      @@ -77,6 +77,7 @@ class Request extends Body {
             crl,
             dhparam,
             ecdhCurve,
      +      family,
             honorCipherOrder,
             key,
             passphrase,
      @@ -101,6 +102,7 @@ class Request extends Body {
             crl,
             dhparam,
             ecdhCurve,
      +      family,
             honorCipherOrder,
             key,
             passphrase,
      @@ -208,6 +210,7 @@ class Request extends Body {
             crl,
             dhparam,
             ecdhCurve,
      +      family,
             honorCipherOrder,
             key,
             passphrase,
      @@ -234,6 +237,7 @@ class Request extends Body {
             crl,
             dhparam,
             ecdhCurve,
      +      family,
             honorCipherOrder,
             key,
             passphrase,
      diff --git a/deps/npm/node_modules/minipass-fetch/package.json b/deps/npm/node_modules/minipass-fetch/package.json
      index df48f372a60796..64dab7816bd120 100644
      --- a/deps/npm/node_modules/minipass-fetch/package.json
      +++ b/deps/npm/node_modules/minipass-fetch/package.json
      @@ -1,6 +1,6 @@
       {
         "name": "minipass-fetch",
      -  "version": "1.3.3",
      +  "version": "1.3.4",
         "description": "An implementation of window.fetch in Node.js using Minipass streams",
         "license": "MIT",
         "main": "lib/index.js",
      diff --git a/deps/npm/node_modules/pacote/lib/fetcher.js b/deps/npm/node_modules/pacote/lib/fetcher.js
      index d488e88ff72369..69dd025b7bd98e 100644
      --- a/deps/npm/node_modules/pacote/lib/fetcher.js
      +++ b/deps/npm/node_modules/pacote/lib/fetcher.js
      @@ -119,6 +119,13 @@ class FetcherBase {
             '--no-progress',
             '--no-save',
             '--no-audit',
      +      // override any omit settings from the environment
      +      '--include=dev',
      +      '--include=peer',
      +      '--include=optional',
      +      // we need the actual things, not just the lockfile
      +      '--no-package-lock-only',
      +      '--no-dry-run',
           ]
         }
       
      @@ -430,6 +437,7 @@ class FetcherBase {
           return {
             cwd,
             noChmod: true,
      +      noMtime: true,
             filter: (name, entry) => {
               if (/Link$/.test(entry.type))
                 return false
      diff --git a/deps/npm/node_modules/pacote/lib/git.js b/deps/npm/node_modules/pacote/lib/git.js
      index 973e13ea9be43d..18f42547bb3ac9 100644
      --- a/deps/npm/node_modules/pacote/lib/git.js
      +++ b/deps/npm/node_modules/pacote/lib/git.js
      @@ -85,6 +85,9 @@ class GitFetcher extends Fetcher {
         [_resolvedFromHosted] (hosted) {
           return this[_resolvedFromRepo](hosted.https && hosted.https())
             .catch(er => {
      +        // Throw early since we know pathspec errors will fail again if retried
      +        if (er instanceof git.errors.GitPathspecError)
      +          throw er
               const ssh = hosted.sshurl && hosted.sshurl()
               // no fallthrough if we can't fall through or have https auth
               if (!ssh || hosted.auth)
      @@ -260,9 +263,11 @@ class GitFetcher extends Fetcher {
         // is present, otherwise ssh if the hosted type provides it
         [_cloneHosted] (ref, tmp) {
           const hosted = this.spec.hosted
      -    const https = hosted.https()
           return this[_cloneRepo](hosted.https({ noCommittish: true }), ref, tmp)
             .catch(er => {
      +        // Throw early since we know pathspec errors will fail again if retried
      +        if (er instanceof git.errors.GitPathspecError)
      +          throw er
               const ssh = hosted.sshurl && hosted.sshurl({ noCommittish: true })
               // no fallthrough if we can't fall through or have https auth
               if (!ssh || hosted.auth)
      diff --git a/deps/npm/node_modules/pacote/package.json b/deps/npm/node_modules/pacote/package.json
      index 7472c6eeab0cc8..437bb8f79e1d88 100644
      --- a/deps/npm/node_modules/pacote/package.json
      +++ b/deps/npm/node_modules/pacote/package.json
      @@ -1,6 +1,6 @@
       {
         "name": "pacote",
      -  "version": "11.3.4",
      +  "version": "11.3.5",
         "description": "JavaScript package downloader",
         "author": "Isaac Z. Schlueter  (https://izs.me)",
         "bin": {
      @@ -33,7 +33,7 @@
           "git"
         ],
         "dependencies": {
      -    "@npmcli/git": "^2.0.1",
      +    "@npmcli/git": "^2.1.0",
           "@npmcli/installed-package-contents": "^1.0.6",
           "@npmcli/promise-spawn": "^1.2.0",
           "@npmcli/run-script": "^1.8.2",
      diff --git a/deps/npm/node_modules/socks/typings/common/receiveBuffer.d.ts b/deps/npm/node_modules/socks/typings/common/receivebuffer.d.ts
      similarity index 100%
      rename from deps/npm/node_modules/socks/typings/common/receiveBuffer.d.ts
      rename to deps/npm/node_modules/socks/typings/common/receivebuffer.d.ts
      diff --git a/deps/npm/package.json b/deps/npm/package.json
      index 73b03991026e1c..15835f331e2613 100644
      --- a/deps/npm/package.json
      +++ b/deps/npm/package.json
      @@ -1,5 +1,5 @@
       {
      -  "version": "7.19.1",
      +  "version": "7.20.3",
         "name": "npm",
         "description": "a package manager for JavaScript",
         "workspaces": [
      @@ -53,7 +53,7 @@
           "./package.json": "./package.json"
         },
         "dependencies": {
      -    "@npmcli/arborist": "^2.6.4",
      +    "@npmcli/arborist": "^2.8.0",
           "@npmcli/ci-detect": "^1.2.0",
           "@npmcli/config": "^2.2.0",
           "@npmcli/package-json": "^1.0.1",
      @@ -88,7 +88,7 @@
           "libnpmsearch": "^3.1.1",
           "libnpmteam": "^2.0.3",
           "libnpmversion": "^1.2.1",
      -    "make-fetch-happen": "^9.0.3",
      +    "make-fetch-happen": "^9.0.4",
           "minipass": "^3.1.3",
           "minipass-pipeline": "^1.2.4",
           "mkdirp": "^1.0.4",
      @@ -104,7 +104,7 @@
           "npm-user-validate": "^1.0.1",
           "npmlog": "~4.1.2",
           "opener": "^1.5.2",
      -    "pacote": "^11.3.3",
      +    "pacote": "^11.3.5",
           "parse-conflict-json": "^1.1.1",
           "qrcode-terminal": "^0.12.0",
           "read": "~1.0.7",
      @@ -193,7 +193,7 @@
           "write-file-atomic"
         ],
         "devDependencies": {
      -    "eslint": "^7.26.0",
      +    "eslint": "^7.30.0",
           "eslint-plugin-import": "^2.23.4",
           "eslint-plugin-node": "^11.1.0",
           "eslint-plugin-promise": "^5.1.0",
      diff --git a/deps/npm/tap-snapshots/smoke-tests/index.js.test.cjs b/deps/npm/tap-snapshots/smoke-tests/index.js.test.cjs
      index 89c0cb20b5e367..0a79e38cdfa031 100644
      --- a/deps/npm/tap-snapshots/smoke-tests/index.js.test.cjs
      +++ b/deps/npm/tap-snapshots/smoke-tests/index.js.test.cjs
      @@ -26,10 +26,10 @@ All commands:
           edit, exec, explain, explore, find-dupes, fund, get, help,
           hook, init, install, install-ci-test, install-test, link,
           ll, login, logout, ls, org, outdated, owner, pack, ping,
      -    prefix, profile, prune, publish, rebuild, repo, restart,
      -    root, run-script, search, set, set-script, shrinkwrap, star,
      -    stars, start, stop, team, test, token, uninstall, unpublish,
      -    unstar, update, version, view, whoami
      +    pkg, prefix, profile, prune, publish, rebuild, repo,
      +    restart, root, run-script, search, set, set-script,
      +    shrinkwrap, star, stars, start, stop, team, test, token,
      +    uninstall, unpublish, unstar, update, version, view, whoami
       
       Specify configs in the ini-formatted file:
           {CWD}/smoke-tests/tap-testdir-index/.npmrc
      @@ -482,6 +482,89 @@ abbrev     1.0.4   1.1.1   1.1.1  node_modules/abbrev  project
       
       `
       
      +exports[`smoke-tests/index.js TAP npm pkg > should have expected npm pkg delete modified package.json result 1`] = `
      +{
      +  "name": "project",
      +  "version": "1.0.0",
      +  "description": "",
      +  "main": "index.js",
      +  "scripts": {
      +    "test": "echo /"Error: no test specified/" && exit 1",
      +    "hello": "echo Hello"
      +  },
      +  "keywords": [],
      +  "author": "",
      +  "license": "ISC",
      +  "dependencies": {
      +    "abbrev": "^1.0.4"
      +  }
      +}
      +
      +`
      +
      +exports[`smoke-tests/index.js TAP npm pkg > should have expected npm pkg set modified package.json result 1`] = `
      +{
      +  "name": "project",
      +  "version": "1.0.0",
      +  "description": "",
      +  "main": "index.js",
      +  "scripts": {
      +    "test": "echo /"Error: no test specified/" && exit 1",
      +    "hello": "echo Hello"
      +  },
      +  "keywords": [],
      +  "author": "",
      +  "license": "ISC",
      +  "dependencies": {
      +    "abbrev": "^1.0.4"
      +  },
      +  "tap": {
      +    "test-env": [
      +      "LC_ALL=sk"
      +    ]
      +  }
      +}
      +
      +`
      +
      +exports[`smoke-tests/index.js TAP npm pkg > should have expected pkg delete output 1`] = `
      +
      +`
      +
      +exports[`smoke-tests/index.js TAP npm pkg > should have expected pkg get output 1`] = `
      +"ISC"
      +
      +`
      +
      +exports[`smoke-tests/index.js TAP npm pkg > should have expected pkg set output 1`] = `
      +
      +`
      +
      +exports[`smoke-tests/index.js TAP npm pkg > should print package.json contents 1`] = `
      +{
      +  "name": "project",
      +  "version": "1.0.0",
      +  "description": "",
      +  "ma",
      +  "scripts": {
      +    "test": "echo /"Error: no test specified/" && exit 1",
      +    "hello": "echo Hello"
      +  },
      +  "keywords": [],
      +  "author": "",
      +  "license": "ISC",
      +  "dependencies": {
      +    "abbrev": "^1.0.4"
      +  },
      +  "tap": {
      +    "test-env": [
      +      "LC_ALL=sk"
      +    ]
      +  }
      +}
      +
      +`
      +
       exports[`smoke-tests/index.js TAP npm prefix > should have expected prefix output 1`] = `
       {CWD}/smoke-tests/tap-testdir-index/project
       
      diff --git a/deps/npm/tap-snapshots/test/lib/config.js.test.cjs b/deps/npm/tap-snapshots/test/lib/config.js.test.cjs
      index 84418ec2e816d2..a094bd32d56dfc 100644
      --- a/deps/npm/tap-snapshots/test/lib/config.js.test.cjs
      +++ b/deps/npm/tap-snapshots/test/lib/config.js.test.cjs
      @@ -5,7 +5,7 @@
        * Make sure to inspect the output below.  Do not ignore changes!
        */
       'use strict'
      -exports[`test/lib/config.js TAP config edit --global > should write global config file 1`] = `
      +exports[`test/lib/config.js TAP config edit --location=global > should write global config file 1`] = `
       ;;;;
       ; npm globalconfig file: /etc/npmrc
       ; this is a simple ini-formatted file
      @@ -92,8 +92,8 @@ cat = true
       chai = true 
       dog = true 
       editor = "vi" 
      -global = false 
       json = false 
      +location = "user"
       long = false 
       
       ; node bin location = /path/to/node
      @@ -116,8 +116,8 @@ cat = true
       chai = true 
       dog = true 
       editor = "vi" 
      -global = false 
       json = false 
      +location = "user"
       long = true
       `
       
      @@ -128,8 +128,8 @@ cat = true
       chai = true 
       dog = true 
       editor = "vi" 
      -global = false 
       json = false 
      +location = "user"
       long = false 
       
       ; node bin location = /path/to/node
      @@ -145,9 +145,9 @@ cat = true
       chai = true 
       dog = true 
       editor = "vi" 
      -global = false 
       init.author.name = "Bar" 
       json = false 
      +location = "user"
       long = false 
       
       ; "user" config from ~/.npmrc
      diff --git a/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs b/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs
      index 3575783a644b2f..8cf2e2837e2954 100644
      --- a/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs
      +++ b/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs
      @@ -84,7 +84,7 @@ Usage:
       npm bugs []
       
       Options:
      -[--browser|--browser ] [--registry ]
      +[--no-browser|--browser ] [--registry ]
       
       alias: issues
       
      @@ -120,7 +120,7 @@ Usage:
       npm ci
       
       Options:
      -[--ignore-scripts] [--script-shell ]
      +[--no-audit] [--ignore-scripts] [--script-shell ]
       
       aliases: clean-install, ic, install-clean, isntall-clean
       
      @@ -151,7 +151,8 @@ npm config list [--json]
       npm config edit
       
       Options:
      -[--json] [-g|--global] [--editor ] [-l|--long]
      +[--json] [-g|--global] [--editor ] [-L|--location ]
      +[-l|--long]
       
       alias: c
       
      @@ -167,9 +168,9 @@ Usage:
       npm dedupe
       
       Options:
      -[--global-style] [--legacy-bundling] [--strict-peer-deps] [--package-lock]
      +[--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock]
       [--omit  [--omit  ...]] [--ignore-scripts]
      -[--audit] [--bin-links] [--fund] [--dry-run]
      +[--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -239,7 +240,7 @@ Usage:
       npm docs [ [ ...]]
       
       Options:
      -[--browser|--browser ] [--registry ]
      +[--no-browser|--browser ] [--registry ]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -337,9 +338,9 @@ Usage:
       npm find-dupes
       
       Options:
      -[--global-style] [--legacy-bundling] [--strict-peer-deps] [--package-lock]
      +[--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock]
       [--omit  [--omit  ...]] [--ignore-scripts]
      -[--audit] [--bin-links] [--fund]
      +[--no-audit] [--no-bin-links] [--no-fund]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -355,7 +356,7 @@ Usage:
       npm fund [[<@scope>/]]
       
       Options:
      -[--json] [--browser|--browser ] [--unicode]
      +[--json] [--no-browser|--browser ] [--unicode]
       [-w|--workspace  [-w|--workspace  ...]]
       [--which ]
       
      @@ -446,9 +447,9 @@ npm install /
       Options:
       [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer]
       [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling]
      -[--strict-peer-deps] [--package-lock]
      +[--strict-peer-deps] [--no-package-lock]
       [--omit  [--omit  ...]] [--ignore-scripts]
      -[--audit] [--bin-links] [--fund] [--dry-run]
      +[--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -466,7 +467,7 @@ Usage:
       npm install-ci-test
       
       Options:
      -[--ignore-scripts] [--script-shell ]
      +[--no-audit] [--ignore-scripts] [--script-shell ]
       
       alias: cit
       
      @@ -493,9 +494,9 @@ npm install-test /
       Options:
       [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer]
       [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling]
      -[--strict-peer-deps] [--package-lock]
      +[--strict-peer-deps] [--no-package-lock]
       [--omit  [--omit  ...]] [--ignore-scripts]
      -[--audit] [--bin-links] [--fund] [--dry-run]
      +[--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -516,9 +517,9 @@ npm link [<@scope>/][@]
       Options:
       [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer]
       [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling]
      -[--strict-peer-deps] [--package-lock]
      +[--strict-peer-deps] [--no-package-lock]
       [--omit  [--omit  ...]] [--ignore-scripts]
      -[--audit] [--bin-links] [--fund] [--dry-run]
      +[--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -678,6 +679,24 @@ Options:
       Run "npm help ping" for more info
       `
       
      +exports[`test/lib/load-all-commands.js TAP load each command pkg > must match snapshot 1`] = `
      +npm pkg
      +
      +Manages your package.json
      +
      +Usage:
      +npm pkg set = [= ...]
      +npm pkg get [ [ ...]]
      +npm pkg delete  [ ...]
      +
      +Options:
      +[-f|--force] [--json]
      +[-w|--workspace  [-w|--workspace  ...]]
      +[-ws|--workspaces]
      +
      +Run "npm help pkg" for more info
      +`
      +
       exports[`test/lib/load-all-commands.js TAP load each command prefix > must match snapshot 1`] = `
       npm prefix
       
      @@ -750,7 +769,7 @@ Usage:
       npm rebuild [[<@scope>/][@] ...]
       
       Options:
      -[-g|--global] [--bin-links] [--ignore-scripts]
      +[-g|--global] [--no-bin-links] [--ignore-scripts]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -768,7 +787,7 @@ Usage:
       npm repo [ [ ...]]
       
       Options:
      -[--browser|--browser ]
      +[--no-browser|--browser ]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -830,7 +849,7 @@ Usage:
       npm search [search terms ...]
       
       Options:
      -[-l|--long] [--json] [--color|--color ] [-p|--parseable]
      +[-l|--long] [--json] [--color|--no-color|--color always] [-p|--parseable]
       [--no-description] [--searchopts ] [--searchexclude ]
       [--registry ] [--prefer-online] [--prefer-offline] [--offline]
       
      @@ -1041,8 +1060,8 @@ npm update [...]
       
       Options:
       [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps]
      -[--package-lock] [--omit  [--omit  ...]]
      -[--ignore-scripts] [--audit] [--bin-links] [--fund] [--dry-run]
      +[--no-package-lock] [--omit  [--omit  ...]]
      +[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
       
      @@ -1060,7 +1079,7 @@ Usage:
       npm version [ | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]
       
       Options:
      -[--allow-same-version] [--commit-hooks] [--git-tag-version] [--json]
      +[--allow-same-version] [--no-commit-hooks] [--no-git-tag-version] [--json]
       [--preid prerelease-id] [--sign-git-tag]
       [-w|--workspace  [-w|--workspace  ...]]
       [-ws|--workspaces]
      diff --git a/deps/npm/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs
      index 832f8560125a3d..971580792048b4 100644
      --- a/deps/npm/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs
      +++ b/deps/npm/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs
      @@ -158,6 +158,7 @@ Object {
           "diff",
           "dist-tag",
           "ping",
      +    "pkg",
           "test",
           "stop",
           "start",
      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 12df9ec89f6f72..01b137b8af54ab 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
      @@ -81,6 +81,7 @@ Array [
         "legacy-peer-deps",
         "link",
         "local-address",
      +  "location",
         "loglevel",
         "logs-max",
         "long",
      @@ -218,9 +219,10 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for audit
       * Default: true
       * Type: Boolean
       
      -When "true" submit audit reports alongside \`npm install\` runs to the default
      -registry and all registries configured for scopes. See the documentation for
      -[\`npm audit\`](/commands/npm-audit) for details on what is submitted.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes. See the
      +documentation for [\`npm audit\`](/commands/npm-audit) for details on what is
      +submitted.
       `
       
       exports[`test/lib/utils/config/definitions.js TAP > config description for audit-level 1`] = `
      @@ -648,6 +650,7 @@ mistakes, unnecessary performance degradation, and malicious input.
       * Allow unpublishing all versions of a published package.
       * Allow conflicting peerDependencies to be installed in the root project.
       * Implicitly set \`--yes\` during \`npm init\`.
      +* Allow clobbering existing values in \`npm pkg\`
       
       If you don't have a clear idea of what you want to do, it is strongly
       recommended that you do not use this option!
      @@ -949,6 +952,9 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for json
       
       Whether or not to output JSON data, rather than the normal output.
       
      +* In \`npm pkg set\` it enables parsing set values with JSON.parse() before
      +  saving them to your \`package.json\`.
      +
       Not supported by all npm commands.
       `
       
      @@ -1019,6 +1025,16 @@ The IP address of the local interface to use when making connections to the
       npm registry. Must be IPv4 in versions of Node prior to 0.12.
       `
       
      +exports[`test/lib/utils/config/definitions.js TAP > config description for location 1`] = `
      +#### \`location\`
      +
      +* Default: "user" unless \`--global\` is passed, which will also set this value
      +  to "global"
      +* Type: "global", "user", or "project"
      +
      +When passed to \`npm config\` this refers to which config file to use.
      +`
      +
       exports[`test/lib/utils/config/definitions.js TAP > config description for loglevel 1`] = `
       #### \`loglevel\`
       
      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 daa071b642e944..8487b45174cc39 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
      @@ -49,9 +49,10 @@ to the same value as the current version.
       * Default: true
       * Type: Boolean
       
      -When "true" submit audit reports alongside \`npm install\` runs to the default
      -registry and all registries configured for scopes. See the documentation for
      -[\`npm audit\`](/commands/npm-audit) for details on what is submitted.
      +When "true" submit audit reports alongside the current npm command to the
      +default registry and all registries configured for scopes. See the
      +documentation for [\`npm audit\`](/commands/npm-audit) for details on what is
      +submitted.
       
       #### \`audit-level\`
       
      @@ -374,6 +375,7 @@ mistakes, unnecessary performance degradation, and malicious input.
       * Allow unpublishing all versions of a published package.
       * Allow conflicting peerDependencies to be installed in the root project.
       * Implicitly set \`--yes\` during \`npm init\`.
      +* Allow clobbering existing values in \`npm pkg\`
       
       If you don't have a clear idea of what you want to do, it is strongly
       recommended that you do not use this option!
      @@ -573,6 +575,9 @@ number, if not already set in package.json.
       
       Whether or not to output JSON data, rather than the normal output.
       
      +* In \`npm pkg set\` it enables parsing set values with JSON.parse() before
      +  saving them to your \`package.json\`.
      +
       Not supported by all npm commands.
       
       #### \`key\`
      @@ -632,6 +637,14 @@ Used with \`npm ls\`, limiting output to only those packages that are linked.
       The IP address of the local interface to use when making connections to the
       npm registry. Must be IPv4 in versions of Node prior to 0.12.
       
      +#### \`location\`
      +
      +* Default: "user" unless \`--global\` is passed, which will also set this value
      +  to "global"
      +* Type: "global", "user", or "project"
      +
      +When passed to \`npm config\` this refers to which config file to use.
      +
       #### \`loglevel\`
       
       * Default: "notice"
      diff --git a/deps/npm/tap-snapshots/test/lib/utils/config/index.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/config/index.js.test.cjs
      index 1e5ca232452e02..f1cba9264ee2ff 100644
      --- a/deps/npm/tap-snapshots/test/lib/utils/config/index.js.test.cjs
      +++ b/deps/npm/tap-snapshots/test/lib/utils/config/index.js.test.cjs
      @@ -64,6 +64,9 @@ Object {
         "l": Array [
           "--long",
         ],
      +  "L": Array [
      +    "--location",
      +  ],
         "local": Array [
           "--no-global",
         ],
      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 7b02dbd9aaa650..8adb33c395df75 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
      @@ -1289,6 +1289,29 @@ Object {
       }
       `
       
      +exports[`test/lib/utils/error-message.js TAP just simple messages > must match snapshot 23`] = `
      +Object {
      +  "detail": Array [
      +    Array [
      +      "network",
      +      String(
      +        This is a problem related to network connectivity.
      +        In most cases you are behind a proxy or have bad network settings.
      +
      +        If you are behind a proxy, please make sure that the
      +        'proxy' config is set properly.  See: 'npm help config'
      +      ),
      +    ],
      +  ],
      +  "summary": Array [
      +    Array [
      +      "network",
      +      "foo",
      +    ],
      +  ],
      +}
      +`
      +
       exports[`test/lib/utils/error-message.js TAP just simple messages > must match snapshot 3`] = `
       Object {
         "detail": 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 8cea8ee17e5ead..eb383c104a6744 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
      @@ -6,15 +6,15 @@
        */
       'use strict'
       exports[`test/lib/utils/exit-handler.js TAP handles unknown error > should have expected log contents for unknown error 1`] = `
      -0 verbose stack Error: ERROR
      -1 verbose cwd {CWD}
      -2 verbose Foo 1.0.0
      -3 verbose argv "/node" "{CWD}/test/lib/utils/exit-handler.js"
      -4 verbose node v1.0.0
      -5 verbose npm  v1.0.0
      -6 error foo code ERROR
      -7 error foo ERR ERROR
      -8 error foo ERR ERROR
      -9 verbose exit 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
       
       `
      diff --git a/deps/npm/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs
      index 4c84aaca4ceebe..354081d1103196 100644
      --- a/deps/npm/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs
      +++ b/deps/npm/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs
      @@ -215,6 +215,142 @@ to accept an incorrect (and potentially broken) dependency resolution.
       See \${REPORT} for a full report.
       `
       
      +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > explain with color, depth of 2 1`] = `
      +While resolving: eslint-plugin-react@7.24.0
      +Found: eslint@6.8.0
      +node_modules/eslint
      +  dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project
      +  3 more (@typescript-eslint/parser, ...)
      +
      +Could not resolve dependency:
      +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Conflicting peer dependency: eslint@7.31.0
      +node_modules/eslint
      +  peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1
      +  node_modules/eslint-plugin-eslint-plugin
      +    dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +`
      +
      +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > explain with no color, depth of 6 1`] = `
      +While resolving: eslint-plugin-react@7.24.0
      +Found: eslint@6.8.0
      +node_modules/eslint
      +  dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project
      +  peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0
      +  node_modules/@typescript-eslint/parser
      +    dev @typescript-eslint/parser@"^2.34.0" from the root project
      +  peer eslint@"^5.16.0 || ^6.8.0 || ^7.2.0" from eslint-config-airbnb-base@14.2.1
      +  node_modules/eslint-config-airbnb-base
      +    dev eslint-config-airbnb-base@"^14.2.1" from the root project
      +  1 more (eslint-plugin-import)
      +
      +Could not resolve dependency:
      +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Conflicting peer dependency: eslint@7.31.0
      +node_modules/eslint
      +  peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1
      +  node_modules/eslint-plugin-eslint-plugin
      +    dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +`
      +
      +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report 1`] = `
      +# npm resolution error report
      +
      +\${TIME}
      +
      +While resolving: eslint-plugin-react@7.24.0
      +Found: eslint@6.8.0
      +node_modules/eslint
      +  dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project
      +  peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0
      +  node_modules/@typescript-eslint/parser
      +    dev @typescript-eslint/parser@"^2.34.0" from the root project
      +  peer eslint@"^5.16.0 || ^6.8.0 || ^7.2.0" from eslint-config-airbnb-base@14.2.1
      +  node_modules/eslint-config-airbnb-base
      +    dev eslint-config-airbnb-base@"^14.2.1" from the root project
      +  peer eslint@"^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" from eslint-plugin-import@2.23.4
      +  node_modules/eslint-plugin-import
      +    dev eslint-plugin-import@"^2.23.4" from the root project
      +    peer eslint-plugin-import@"^2.22.1" from eslint-config-airbnb-base@14.2.1
      +    node_modules/eslint-config-airbnb-base
      +      dev eslint-config-airbnb-base@"^14.2.1" from the root project
      +
      +Could not resolve dependency:
      +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Conflicting peer dependency: eslint@7.31.0
      +node_modules/eslint
      +  peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1
      +  node_modules/eslint-plugin-eslint-plugin
      +    dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Fix the upstream dependency conflict, or retry
      +this command with --force, or --legacy-peer-deps
      +to accept an incorrect (and potentially broken) dependency resolution.
      +
      +Raw JSON explanation object:
      +
      +{
      +  "name": "eslint-plugin case",
      +  "json": true
      +}
      +
      +`
      +
      +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with color 1`] = `
      +While resolving: eslint-plugin-react@7.24.0
      +Found: eslint@6.8.0
      +node_modules/eslint
      +  dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project
      +  peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0
      +  node_modules/@typescript-eslint/parser
      +    dev @typescript-eslint/parser@"^2.34.0" from the root project
      +  2 more (eslint-config-airbnb-base, eslint-plugin-import)
      +
      +Could not resolve dependency:
      +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Conflicting peer dependency: eslint@7.31.0
      +node_modules/eslint
      +  peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1
      +  node_modules/eslint-plugin-eslint-plugin
      +    dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Fix the upstream dependency conflict, or retry
      +this command with --force, or --legacy-peer-deps
      +to accept an incorrect (and potentially broken) dependency resolution.
      +
      +See \${REPORT} for a full report.
      +`
      +
      +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with no color 1`] = `
      +While resolving: eslint-plugin-react@7.24.0
      +Found: eslint@6.8.0
      +node_modules/eslint
      +  dev eslint@"^3 || ^4 || ^5 || ^6 || ^7" from the root project
      +  peer eslint@"^5.0.0 || ^6.0.0" from @typescript-eslint/parser@2.34.0
      +  node_modules/@typescript-eslint/parser
      +    dev @typescript-eslint/parser@"^2.34.0" from the root project
      +  2 more (eslint-config-airbnb-base, eslint-plugin-import)
      +
      +Could not resolve dependency:
      +dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Conflicting peer dependency: eslint@7.31.0
      +node_modules/eslint
      +  peer eslint@"^7.0.0" from eslint-plugin-eslint-plugin@3.5.1
      +  node_modules/eslint-plugin-eslint-plugin
      +    dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project
      +
      +Fix the upstream dependency conflict, or retry
      +this command with --force, or --legacy-peer-deps
      +to accept an incorrect (and potentially broken) dependency resolution.
      +
      +See \${REPORT} for a full report.
      +`
      +
       exports[`test/lib/utils/explain-eresolve.js TAP gatsby > explain with color, depth of 2 1`] = `
       While resolving: gatsby-recipes@0.2.31
       Found: ink@3.0.0-7
      @@ -433,6 +569,9 @@ See \${REPORT} for a full report.
       
       exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > explain with color, depth of 2 1`] = `
       While resolving: eslint@7.22.0
      +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      +node_modules/eslint-plugin-jsdoc
      +  dev eslint-plugin-jsdoc@"^22.1.0" from the root project
       
       Could not resolve dependency:
       peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      @@ -442,6 +581,9 @@ Could not resolve dependency:
       
       exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > explain with no color, depth of 6 1`] = `
       While resolving: eslint@7.22.0
      +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      +node_modules/eslint-plugin-jsdoc
      +  dev eslint-plugin-jsdoc@"^22.1.0" from the root project
       
       Could not resolve dependency:
       peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      @@ -455,6 +597,9 @@ exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge
       \${TIME}
       
       While resolving: eslint@7.22.0
      +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      +node_modules/eslint-plugin-jsdoc
      +  dev eslint-plugin-jsdoc@"^22.1.0" from the root project
       
       Could not resolve dependency:
       peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      @@ -476,6 +621,9 @@ Raw JSON explanation object:
       
       exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with color 1`] = `
       While resolving: eslint@7.22.0
      +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      +node_modules/eslint-plugin-jsdoc
      +  dev eslint-plugin-jsdoc@"^22.1.0" from the root project
       
       Could not resolve dependency:
       peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      @@ -491,6 +639,9 @@ See \${REPORT} for a full report.
       
       exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with no color 1`] = `
       While resolving: eslint@7.22.0
      +Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      +node_modules/eslint-plugin-jsdoc
      +  dev eslint-plugin-jsdoc@"^22.1.0" from the root project
       
       Could not resolve dependency:
       peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0
      diff --git a/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs
      index 3987f6a732da55..17df1aa1f58ede 100644
      --- a/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs
      +++ b/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs
      @@ -26,10 +26,10 @@ All commands:
           edit, exec, explain, explore, find-dupes, fund, get, help,
           hook, init, install, install-ci-test, install-test, link,
           ll, login, logout, ls, org, outdated, owner, pack, ping,
      -    prefix, profile, prune, publish, rebuild, repo, restart,
      -    root, run-script, search, set, set-script, shrinkwrap, star,
      -    stars, start, stop, team, test, token, uninstall, unpublish,
      -    unstar, update, version, view, whoami
      +    pkg, prefix, profile, prune, publish, rebuild, repo,
      +    restart, root, run-script, search, set, set-script,
      +    shrinkwrap, star, stars, start, stop, team, test, token,
      +    uninstall, unpublish, unstar, update, version, view, whoami
       
       Specify configs in the ini-formatted file:
           /some/config/file/.npmrc
      @@ -62,10 +62,10 @@ All commands:
           edit, exec, explain, explore, find-dupes, fund, get, help,
           hook, init, install, install-ci-test, install-test, link,
           ll, login, logout, ls, org, outdated, owner, pack, ping,
      -    prefix, profile, prune, publish, rebuild, repo, restart,
      -    root, run-script, search, set, set-script, shrinkwrap, star,
      -    stars, start, stop, team, test, token, uninstall, unpublish,
      -    unstar, update, version, view, whoami
      +    pkg, prefix, profile, prune, publish, rebuild, repo,
      +    restart, root, run-script, search, set, set-script,
      +    shrinkwrap, star, stars, start, stop, team, test, token,
      +    uninstall, unpublish, unstar, update, version, view, whoami
       
       Specify configs in the ini-formatted file:
           /some/config/file/.npmrc
      @@ -98,10 +98,10 @@ All commands:
           edit, exec, explain, explore, find-dupes, fund, get, help,
           hook, init, install, install-ci-test, install-test, link,
           ll, login, logout, ls, org, outdated, owner, pack, ping,
      -    prefix, profile, prune, publish, rebuild, repo, restart,
      -    root, run-script, search, set, set-script, shrinkwrap, star,
      -    stars, start, stop, team, test, token, uninstall, unpublish,
      -    unstar, update, version, view, whoami
      +    pkg, prefix, profile, prune, publish, rebuild, repo,
      +    restart, root, run-script, search, set, set-script,
      +    shrinkwrap, star, stars, start, stop, team, test, token,
      +    uninstall, unpublish, unstar, update, version, view, whoami
       
       Specify configs in the ini-formatted file:
           /some/config/file/.npmrc
      @@ -134,10 +134,10 @@ All commands:
           edit, exec, explain, explore, find-dupes, fund, get, help,
           hook, init, install, install-ci-test, install-test, link,
           ll, login, logout, ls, org, outdated, owner, pack, ping,
      -    prefix, profile, prune, publish, rebuild, repo, restart,
      -    root, run-script, search, set, set-script, shrinkwrap, star,
      -    stars, start, stop, team, test, token, uninstall, unpublish,
      -    unstar, update, version, view, whoami
      +    pkg, prefix, profile, prune, publish, rebuild, repo,
      +    restart, root, run-script, search, set, set-script,
      +    shrinkwrap, star, stars, start, stop, team, test, token,
      +    uninstall, unpublish, unstar, update, version, view, whoami
       
       Specify configs in the ini-formatted file:
           /some/config/file/.npmrc
      @@ -235,7 +235,7 @@ All commands:
                           npm bugs []
                           
                           Options:
      -                    [--browser|--browser ] [--registry ]
      +                    [--no-browser|--browser ] [--registry ]
                           
                           alias: issues
                           
      @@ -267,7 +267,7 @@ All commands:
                           npm ci
                           
                           Options:
      -                    [--ignore-scripts] [--script-shell ]
      +                    [--no-audit] [--ignore-scripts] [--script-shell ]
                           
                           aliases: clean-install, ic, install-clean, isntall-clean
                           
      @@ -294,7 +294,8 @@ All commands:
                           npm config edit
                           
                           Options:
      -                    [--json] [-g|--global] [--editor ] [-l|--long]
      +                    [--json] [-g|--global] [--editor ] [-L|--location ]
      +                    [-l|--long]
                           
                           alias: c
                           
      @@ -308,9 +309,9 @@ All commands:
                           npm dedupe
                           
                           Options:
      -                    [--global-style] [--legacy-bundling] [--strict-peer-deps] [--package-lock]
      +                    [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock]
                           [--omit  [--omit  ...]] [--ignore-scripts]
      -                    [--audit] [--bin-links] [--fund] [--dry-run]
      +                    [--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -372,7 +373,7 @@ All commands:
                           npm docs [ [ ...]]
                           
                           Options:
      -                    [--browser|--browser ] [--registry ]
      +                    [--no-browser|--browser ] [--registry ]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -458,9 +459,9 @@ All commands:
                           npm find-dupes
                           
                           Options:
      -                    [--global-style] [--legacy-bundling] [--strict-peer-deps] [--package-lock]
      +                    [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock]
                           [--omit  [--omit  ...]] [--ignore-scripts]
      -                    [--audit] [--bin-links] [--fund]
      +                    [--no-audit] [--no-bin-links] [--no-fund]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -474,7 +475,7 @@ All commands:
                           npm fund [[<@scope>/]]
                           
                           Options:
      -                    [--json] [--browser|--browser ] [--unicode]
      +                    [--json] [--no-browser|--browser ] [--unicode]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [--which ]
                           
      @@ -555,9 +556,9 @@ All commands:
                           Options:
                           [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer]
                           [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling]
      -                    [--strict-peer-deps] [--package-lock]
      +                    [--strict-peer-deps] [--no-package-lock]
                           [--omit  [--omit  ...]] [--ignore-scripts]
      -                    [--audit] [--bin-links] [--fund] [--dry-run]
      +                    [--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -573,7 +574,7 @@ All commands:
                           npm install-ci-test
                           
                           Options:
      -                    [--ignore-scripts] [--script-shell ]
      +                    [--no-audit] [--ignore-scripts] [--script-shell ]
                           
                           alias: cit
                           
      @@ -598,9 +599,9 @@ All commands:
                           Options:
                           [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer]
                           [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling]
      -                    [--strict-peer-deps] [--package-lock]
      +                    [--strict-peer-deps] [--no-package-lock]
                           [--omit  [--omit  ...]] [--ignore-scripts]
      -                    [--audit] [--bin-links] [--fund] [--dry-run]
      +                    [--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -619,9 +620,9 @@ All commands:
                           Options:
                           [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer]
                           [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling]
      -                    [--strict-peer-deps] [--package-lock]
      +                    [--strict-peer-deps] [--no-package-lock]
                           [--omit  [--omit  ...]] [--ignore-scripts]
      -                    [--audit] [--bin-links] [--fund] [--dry-run]
      +                    [--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -762,6 +763,22 @@ All commands:
                           
                           Run "npm help ping" for more info
       
      +    pkg             npm pkg
      +
      +                    Manages your package.json
      +
      +                    Usage:
      +                    npm pkg set = [= ...]
      +                    npm pkg get [ [ ...]]
      +                    npm pkg delete  [ ...]
      +
      +                    Options:
      +                    [-f|--force] [--json]
      +                    [-w|--workspace  [-w|--workspace  ...]]
      +                    [-ws|--workspaces]
      +
      +                    Run "npm help pkg" for more info
      +
           prefix          npm prefix
                           
                           Display prefix
      @@ -825,7 +842,7 @@ All commands:
                           npm rebuild [[<@scope>/][@] ...]
                           
                           Options:
      -                    [-g|--global] [--bin-links] [--ignore-scripts]
      +                    [-g|--global] [--no-bin-links] [--ignore-scripts]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -841,7 +858,7 @@ All commands:
                           npm repo [ [ ...]]
                           
                           Options:
      -                    [--browser|--browser ]
      +                    [--no-browser|--browser ]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -895,7 +912,7 @@ All commands:
                           npm search [search terms ...]
                           
                           Options:
      -                    [-l|--long] [--json] [--color|--color ] [-p|--parseable]
      +                    [-l|--long] [--json] [--color|--no-color|--color always] [-p|--parseable]
                           [--no-description] [--searchopts ] [--searchexclude ]
                           [--registry ] [--prefer-online] [--prefer-offline] [--offline]
                           
      @@ -1078,8 +1095,8 @@ All commands:
                           
                           Options:
                           [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps]
      -                    [--package-lock] [--omit  [--omit  ...]]
      -                    [--ignore-scripts] [--audit] [--bin-links] [--fund] [--dry-run]
      +                    [--no-package-lock] [--omit  [--omit  ...]]
      +                    [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
                           
      @@ -1095,7 +1112,7 @@ All commands:
                           npm version [ | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]
                           
                           Options:
      -                    [--allow-same-version] [--commit-hooks] [--git-tag-version] [--json]
      +                    [--allow-same-version] [--no-commit-hooks] [--no-git-tag-version] [--json]
                           [--preid prerelease-id] [--sign-git-tag]
                           [-w|--workspace  [-w|--workspace  ...]]
                           [-ws|--workspaces]
      diff --git a/deps/npm/tap-snapshots/test/lib/utils/update-notifier.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/update-notifier.js.test.cjs
      index 91228650d47de7..157390997d7936 100644
      --- a/deps/npm/tap-snapshots/test/lib/utils/update-notifier.js.test.cjs
      +++ b/deps/npm/tap-snapshots/test/lib/utils/update-notifier.js.test.cjs
      @@ -6,11 +6,11 @@
        */
       'use strict'
       exports[`test/lib/utils/update-notifier.js TAP notification situations major to current > color 1`] = `
      -
      -New major version of npm available! 122.420.69 -> 123.420.69
      -Changelog: https://github.com/npm/cli/releases/tag/v123.420.69
      -Run npm install -g npm@123.420.69 to update!
      -
      +
      +New major version of npm available! 122.420.69 -> 123.420.69
      +Changelog: https://github.com/npm/cli/releases/tag/v123.420.69
      +Run npm install -g npm@123.420.69 to update!
      +
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations major to current > no color 1`] = `
      @@ -22,11 +22,11 @@ Run \`npm install -g npm@123.420.69\` to update!
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations minor to current > color 1`] = `
      -
      -New minor version of npm available! 123.419.69 -> 123.420.69
      -Changelog: https://github.com/npm/cli/releases/tag/v123.420.69
      -Run npm install -g npm@123.420.69 to update!
      -
      +
      +New minor version of npm available! 123.419.69 -> 123.420.69
      +Changelog: https://github.com/npm/cli/releases/tag/v123.420.69
      +Run npm install -g npm@123.420.69 to update!
      +
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations minor to current > no color 1`] = `
      @@ -38,11 +38,11 @@ Run \`npm install -g npm@123.420.69\` to update!
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations minor to next version > color 1`] = `
      -
      -New minor version of npm available! 123.420.70 -> 123.421.70
      -Changelog: https://github.com/npm/cli/releases/tag/v123.421.70
      -Run npm install -g npm@123.421.70 to update!
      -
      +
      +New minor version of npm available! 123.420.70 -> 123.421.70
      +Changelog: https://github.com/npm/cli/releases/tag/v123.421.70
      +Run npm install -g npm@123.421.70 to update!
      +
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations minor to next version > no color 1`] = `
      @@ -54,11 +54,11 @@ Run \`npm install -g npm@123.421.70\` to update!
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations new beta available > color 1`] = `
      -
      -New prerelease version of npm available! 124.0.0-beta.0 -> 124.0.0-beta.99999
      -Changelog: https://github.com/npm/cli/releases/tag/v124.0.0-beta.99999
      -Run npm install -g npm@124.0.0-beta.99999 to update!
      -
      +
      +New prerelease version of npm available! 124.0.0-beta.0 -> 124.0.0-beta.99999
      +Changelog: https://github.com/npm/cli/releases/tag/v124.0.0-beta.99999
      +Run npm install -g npm@124.0.0-beta.99999 to update!
      +
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations new beta available > no color 1`] = `
      @@ -70,11 +70,11 @@ Run \`npm install -g npm@124.0.0-beta.99999\` to update!
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations patch to current > color 1`] = `
      -
      -New patch version of npm available! 123.420.68 -> 123.420.69
      -Changelog: https://github.com/npm/cli/releases/tag/v123.420.69
      -Run npm install -g npm@123.420.69 to update!
      -
      +
      +New patch version of npm available! 123.420.68 -> 123.420.69
      +Changelog: https://github.com/npm/cli/releases/tag/v123.420.69
      +Run npm install -g npm@123.420.69 to update!
      +
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations patch to current > no color 1`] = `
      @@ -86,11 +86,11 @@ Run \`npm install -g npm@123.420.69\` to update!
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations patch to next version > color 1`] = `
      -
      -New patch version of npm available! 123.421.69 -> 123.421.70
      -Changelog: https://github.com/npm/cli/releases/tag/v123.421.70
      -Run npm install -g npm@123.421.70 to update!
      -
      +
      +New patch version of npm available! 123.421.69 -> 123.421.70
      +Changelog: https://github.com/npm/cli/releases/tag/v123.421.70
      +Run npm install -g npm@123.421.70 to update!
      +
       `
       
       exports[`test/lib/utils/update-notifier.js TAP notification situations patch to next version > no color 1`] = `
      diff --git a/deps/npm/test/fixtures/eresolve-explanations.js b/deps/npm/test/fixtures/eresolve-explanations.js
      index b6ccac7d3d6275..c34424c7f857ac 100644
      --- a/deps/npm/test/fixtures/eresolve-explanations.js
      +++ b/deps/npm/test/fixtures/eresolve-explanations.js
      @@ -35,43 +35,45 @@ module.exports = {
             ],
           },
           peerConflict: {
      -      name: '@isaacs/peer-dep-cycle-c',
      -      version: '1.0.0',
      -      whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' },
      -      location: 'node_modules/@isaacs/peer-dep-cycle-c',
      -      dependents: [
      -        {
      -          type: 'peer',
      -          name: '@isaacs/peer-dep-cycle-c',
      -          spec: '1',
      -          from: {
      -            name: '@isaacs/peer-dep-cycle-b',
      -            version: '1.0.0',
      -            whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' },
      -            location: 'node_modules/@isaacs/peer-dep-cycle-b',
      -            dependents: [
      -              {
      -                type: 'peer',
      -                name: '@isaacs/peer-dep-cycle-b',
      -                spec: '1',
      -                from: {
      -                  name: '@isaacs/peer-dep-cycle-a',
      -                  version: '1.0.0',
      -                  location: 'node_modules/@isaacs/peer-dep-cycle-a',
      -                  dependents: [
      -                    {
      -                      type: 'prod',
      -                      name: '@isaacs/peer-dep-cycle-a',
      -                      spec: '1.x',
      -                      from: { location: '/some/project' },
      -                    },
      -                  ],
      +      peer: {
      +        name: '@isaacs/peer-dep-cycle-c',
      +        version: '1.0.0',
      +        whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' },
      +        location: 'node_modules/@isaacs/peer-dep-cycle-c',
      +        dependents: [
      +          {
      +            type: 'peer',
      +            name: '@isaacs/peer-dep-cycle-c',
      +            spec: '1',
      +            from: {
      +              name: '@isaacs/peer-dep-cycle-b',
      +              version: '1.0.0',
      +              whileInstalling: { name: '@isaacs/peer-dep-cycle-a', version: '1.0.0' },
      +              location: 'node_modules/@isaacs/peer-dep-cycle-b',
      +              dependents: [
      +                {
      +                  type: 'peer',
      +                  name: '@isaacs/peer-dep-cycle-b',
      +                  spec: '1',
      +                  from: {
      +                    name: '@isaacs/peer-dep-cycle-a',
      +                    version: '1.0.0',
      +                    location: 'node_modules/@isaacs/peer-dep-cycle-a',
      +                    dependents: [
      +                      {
      +                        type: 'prod',
      +                        name: '@isaacs/peer-dep-cycle-a',
      +                        spec: '1.x',
      +                        from: { location: '/some/project' },
      +                      },
      +                    ],
      +                  },
                       },
      -              },
      -            ],
      +              ],
      +            },
                 },
      -        },
      -      ],
      +        ],
      +      },
           },
           strictPeerDeps: true,
         },
      @@ -373,4 +375,185 @@ module.exports = {
           strictPeerDeps: false,
           force: false,
         },
      +
      +  'eslint-plugin case': {
      +    code: 'ERESOLVE',
      +    edge: {
      +      type: 'dev',
      +      name: 'eslint-plugin-eslint-plugin',
      +      spec: '^3.1.0',
      +      error: 'MISSING',
      +      from: {
      +        location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +      },
      +    },
      +    dep: {
      +      name: 'eslint-plugin-eslint-plugin',
      +      version: '3.5.1',
      +      whileInstalling: {
      +        name: 'eslint-plugin-react',
      +        version: '7.24.0',
      +        path: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +      },
      +      location: 'node_modules/eslint-plugin-eslint-plugin',
      +      isWorkspace: false,
      +      dependents: [
      +        {
      +          type: 'dev',
      +          name: 'eslint-plugin-eslint-plugin',
      +          spec: '^3.1.0',
      +          error: 'MISSING',
      +          from: {
      +            location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +          },
      +        },
      +      ],
      +    },
      +    current: null,
      +    peerConflict: {
      +      current: {
      +        name: 'eslint',
      +        version: '6.8.0',
      +        location: 'node_modules/eslint',
      +        isWorkspace: false,
      +        dependents: [
      +          {
      +            type: 'dev',
      +            name: 'eslint',
      +            spec: '^3 || ^4 || ^5 || ^6 || ^7',
      +            from: {
      +              location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +            },
      +          },
      +          {
      +            type: 'peer',
      +            name: 'eslint',
      +            spec: '^5.0.0 || ^6.0.0',
      +            from: {
      +              name: '@typescript-eslint/parser',
      +              version: '2.34.0',
      +              location: 'node_modules/@typescript-eslint/parser',
      +              isWorkspace: false,
      +              dependents: [
      +                {
      +                  type: 'dev',
      +                  name: '@typescript-eslint/parser',
      +                  spec: '^2.34.0',
      +                  from: {
      +                    location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +                  },
      +                },
      +              ],
      +            },
      +          },
      +          {
      +            type: 'peer',
      +            name: 'eslint',
      +            spec: '^5.16.0 || ^6.8.0 || ^7.2.0',
      +            from: {
      +              name: 'eslint-config-airbnb-base',
      +              version: '14.2.1',
      +              location: 'node_modules/eslint-config-airbnb-base',
      +              isWorkspace: false,
      +              dependents: [
      +                {
      +                  type: 'dev',
      +                  name: 'eslint-config-airbnb-base',
      +                  spec: '^14.2.1',
      +                  from: {
      +                    location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +                  },
      +                },
      +              ],
      +            },
      +          },
      +          {
      +            type: 'peer',
      +            name: 'eslint',
      +            spec: '^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0',
      +            from: {
      +              name: 'eslint-plugin-import',
      +              version: '2.23.4',
      +              location: 'node_modules/eslint-plugin-import',
      +              isWorkspace: false,
      +              dependents: [
      +                {
      +                  type: 'dev',
      +                  name: 'eslint-plugin-import',
      +                  spec: '^2.23.4',
      +                  from: {
      +                    location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +                  },
      +                },
      +                {
      +                  type: 'peer',
      +                  name: 'eslint-plugin-import',
      +                  spec: '^2.22.1',
      +                  from: {
      +                    name: 'eslint-config-airbnb-base',
      +                    version: '14.2.1',
      +                    location: 'node_modules/eslint-config-airbnb-base',
      +                    isWorkspace: false,
      +                    dependents: [
      +                      {
      +                        type: 'dev',
      +                        name: 'eslint-config-airbnb-base',
      +                        spec: '^14.2.1',
      +                        from: {
      +                          location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +                        },
      +                      },
      +                    ],
      +                  },
      +                },
      +              ],
      +            },
      +          },
      +        ],
      +      },
      +      peer: {
      +        name: 'eslint',
      +        version: '7.31.0',
      +        whileInstalling: {
      +          name: 'eslint-plugin-react',
      +          version: '7.24.0',
      +          path: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +        },
      +        location: 'node_modules/eslint',
      +        isWorkspace: false,
      +        dependents: [
      +          {
      +            type: 'peer',
      +            name: 'eslint',
      +            spec: '^7.0.0',
      +            from: {
      +              name: 'eslint-plugin-eslint-plugin',
      +              version: '3.5.1',
      +              whileInstalling: {
      +                name: 'eslint-plugin-react',
      +                version: '7.24.0',
      +                path: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +              },
      +              location: 'node_modules/eslint-plugin-eslint-plugin',
      +              isWorkspace: false,
      +              dependents: [
      +                {
      +                  type: 'dev',
      +                  name: 'eslint-plugin-eslint-plugin',
      +                  spec: '^3.1.0',
      +                  error: 'MISSING',
      +                  from: {
      +                    location: '/Users/isaacs/dev/npm/arborist/fixtures/eslint-plugin-react',
      +                  },
      +                },
      +              ],
      +            },
      +          },
      +        ],
      +      },
      +    },
      +    strictPeerDeps: false,
      +    force: false,
      +    isMine: true,
      +  },
       }
      diff --git a/deps/npm/test/fixtures/mock-npm.js b/deps/npm/test/fixtures/mock-npm.js
      index 1de080eb10b4a8..e3be10b4b9aa3f 100644
      --- a/deps/npm/test/fixtures/mock-npm.js
      +++ b/deps/npm/test/fixtures/mock-npm.js
      @@ -1,20 +1,19 @@
       const npmlog = require('npmlog')
      -const perf = require('../../lib/utils/perf.js')
      -perf.reset()
       const procLog = require('../../lib/utils/proc-log-listener.js')
       procLog.reset()
       
       const realLog = {}
      -for (const level of ['silly', 'verbose', 'timing', 'notice', 'warn', 'error'])
      +for (const level in npmlog.levels)
         realLog[level] = npmlog[level]
       
       const { title, execPath } = process
       
       const RealMockNpm = (t, otherMocks = {}) => {
         t.teardown(() => {
      -    for (const level of ['silly', 'verbose', 'timing', 'notice', 'warn', 'error'])
      +    npm.perfStop()
      +    npmlog.record.length = 0
      +    for (const level in npmlog.levels)
             npmlog[level] = realLog[level]
      -    perf.reset()
           procLog.reset()
           process.title = title
           process.execPath = execPath
      @@ -33,9 +32,14 @@ const RealMockNpm = (t, otherMocks = {}) => {
             })
           })
         }
      -  for (const level of ['silly', 'verbose', 'timing', 'notice', 'warn', 'error']) {
      +  for (const level in npmlog.levels) {
           npmlog[level] = (...msg) => {
             logs.push([level, ...msg])
      +
      +      const l = npmlog.level
      +      npmlog.level = 'silent'
      +      realLog[level](...msg)
      +      npmlog.level = l
           }
         }
         npm.output = (...msg) => outputs.push(msg)
      diff --git a/deps/npm/test/lib/config.js b/deps/npm/test/lib/config.js
      index 6c04293137af9e..8a1e7d85e09aa3 100644
      --- a/deps/npm/test/lib/config.js
      +++ b/deps/npm/test/lib/config.js
      @@ -47,8 +47,8 @@ const defaults = {
       const cliConfig = {
         editor: 'vi',
         json: false,
      +  location: 'user',
         long: false,
      -  global: false,
         cat: true,
         chai: true,
         dog: true,
      @@ -198,8 +198,8 @@ t.test('config list --json', t => {
             {
               editor: 'vi',
               json: true,
      +        location: 'user',
               long: false,
      -        global: false,
               cat: true,
               chai: true,
               dog: true,
      @@ -265,7 +265,7 @@ t.test('config delete multiple key', t => {
         })
       })
       
      -t.test('config delete key --global', t => {
      +t.test('config delete key --location=global', t => {
         t.plan(4)
       
         npm.config.delete = (key, where) => {
      @@ -277,13 +277,13 @@ t.test('config delete key --global', t => {
           t.equal(where, 'global', 'should save global config post-delete')
         }
       
      -  cliConfig.global = true
      +  cliConfig.location = 'global'
         config.exec(['delete', 'foo'], (err) => {
      -    t.error(err, 'npm config delete key --global')
      +    t.error(err, 'npm config delete key --location=global')
         })
       
         t.teardown(() => {
      -    cliConfig.global = false
      +    cliConfig.location = 'user'
           delete npm.config.delete
           delete npm.config.save
         })
      @@ -419,7 +419,7 @@ t.test('config set invalid key', t => {
         })
       })
       
      -t.test('config set key --global', t => {
      +t.test('config set key --location=global', t => {
         t.plan(5)
       
         npm.config.set = (key, val, where) => {
      @@ -432,13 +432,13 @@ t.test('config set key --global', t => {
           t.equal(where, 'global', 'should save global config')
         }
       
      -  cliConfig.global = true
      +  cliConfig.location = 'global'
         config.exec(['set', 'foo', 'bar'], (err) => {
      -    t.error(err, 'npm config set key --global')
      +    t.error(err, 'npm config set key --location=global')
         })
       
         t.teardown(() => {
      -    cliConfig.global = false
      +    cliConfig.location = 'user'
           delete npm.config.set
           delete npm.config.save
         })
      @@ -583,10 +583,10 @@ sign-git-commit=true`
         })
       })
       
      -t.test('config edit --global', t => {
      +t.test('config edit --location=global', t => {
         t.plan(6)
       
      -  cliConfig.global = true
      +  cliConfig.location = 'global'
         const npmrc = 'init.author.name=Foo'
         npm.config.data.set('global', {
           source: '/etc/npmrc',
      @@ -626,7 +626,7 @@ t.test('config edit --global', t => {
         })
       
         t.teardown(() => {
      -    cliConfig.global = false
      +    cliConfig.location = 'user'
           npm.config.data.delete('user')
           delete npm.config.save
         })
      diff --git a/deps/npm/test/lib/link.js b/deps/npm/test/lib/link.js
      index 736d18cab99068..96f689892ff83b 100644
      --- a/deps/npm/test/lib/link.js
      +++ b/deps/npm/test/lib/link.js
      @@ -30,7 +30,7 @@ const printLinks = async (opts) => {
         const linkedItems = [...tree.inventory.values()]
           .sort((a, b) => a.pkgid.localeCompare(b.pkgid, 'en'))
         for (const item of linkedItems) {
      -    if (item.target)
      +    if (item.isLink)
             res += `${item.path} -> ${item.target.path}\n`
         }
         return res
      diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js
      index 291a58955ceedd..03bb46d8d8451c 100644
      --- a/deps/npm/test/lib/npm.js
      +++ b/deps/npm/test/lib/npm.js
      @@ -476,3 +476,28 @@ t.test('set process.title', t => {
       
         t.end()
       })
      +
      +t.test('timings', t => {
      +  const { npm, logs } = mockNpm(t)
      +  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',
      +      '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()
      +})
      diff --git a/deps/npm/test/lib/pkg.js b/deps/npm/test/lib/pkg.js
      new file mode 100644
      index 00000000000000..688df6859054af
      --- /dev/null
      +++ b/deps/npm/test/lib/pkg.js
      @@ -0,0 +1,737 @@
      +const { resolve } = require('path')
      +const { readFileSync } = require('fs')
      +const t = require('tap')
      +const { fake: mockNpm } = require('../fixtures/mock-npm')
      +
      +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}')
      +}
      +
      +t.cleanSnapshot = (str) => redactCwd(str)
      +
      +let OUTPUT = ''
      +const config = {
      +  global: false,
      +  force: false,
      +  'pkg-cast': 'string',
      +}
      +const npm = mockNpm({
      +  localPrefix: t.testdirName,
      +  config,
      +  output: (str) => {
      +    OUTPUT += str
      +  },
      +})
      +
      +const Pkg = require('../../lib/pkg.js')
      +const pkg = new Pkg(npm)
      +
      +const readPackageJson = (path) => {
      +  path = path || npm.localPrefix
      +  return JSON.parse(readFileSync(resolve(path, 'package.json'), 'utf8'))
      +}
      +
      +t.afterEach(() => {
      +  config.global = false
      +  config.json = false
      +  npm.localPrefix = t.testdirName
      +  OUTPUT = ''
      +})
      +
      +t.test('no args', t => {
      +  pkg.exec([], err => {
      +    t.match(
      +      err,
      +      { code: 'EUSAGE' },
      +      'should throw usage error'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('no global mode', t => {
      +  config.global = true
      +  pkg.exec(['get', 'foo'], err => {
      +    t.match(
      +      err,
      +      { code: 'EPKGGLOBAL' },
      +      'should throw no global mode error'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('get no args', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.1.1',
      +    }),
      +  })
      +
      +  pkg.exec(['get'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      JSON.parse(OUTPUT),
      +      {
      +        name: 'foo',
      +        version: '1.1.1',
      +      },
      +      'should print package.json content'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('get single arg', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.1.1',
      +    }),
      +  })
      +
      +  pkg.exec(['get', 'version'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      JSON.parse(OUTPUT),
      +      '1.1.1',
      +      'should print retrieved package.json field'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('get nested arg', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.1.1',
      +      scripts: {
      +        test: 'node test.js',
      +      },
      +    }),
      +  })
      +
      +  pkg.exec(['get', 'scripts.test'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      JSON.parse(OUTPUT),
      +      'node test.js',
      +      'should print retrieved nested field'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('get array field', t => {
      +  const files = [
      +    'index.js',
      +    'cli.js',
      +  ]
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.1.1',
      +      files,
      +    }),
      +  })
      +
      +  pkg.exec(['get', 'files'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      JSON.parse(OUTPUT),
      +      files,
      +      'should print retrieved array field'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('get array item', t => {
      +  const files = [
      +    'index.js',
      +    'cli.js',
      +  ]
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.1.1',
      +      files,
      +    }),
      +  })
      +
      +  pkg.exec(['get', 'files[0]'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      JSON.parse(OUTPUT),
      +      'index.js',
      +      'should print retrieved array field'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('get array nested items notation', t => {
      +  const contributors = [
      +    {
      +      name: 'Ruy',
      +      url: 'http://example.com/ruy',
      +    },
      +    {
      +      name: 'Gar',
      +      url: 'http://example.com/gar',
      +    },
      +  ]
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.1.1',
      +      contributors,
      +    }),
      +  })
      +
      +  pkg.exec(['get', 'contributors.name'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      JSON.parse(OUTPUT),
      +      {
      +        'contributors[0].name': 'Ruy',
      +        'contributors[1].name': 'Gar',
      +      },
      +      'should print json result containing matching results'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('set no args', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({ name: 'foo' }),
      +  })
      +  pkg.exec(['set'], err => {
      +    t.match(
      +      err,
      +      { code: 'EPKGSET' },
      +      'should throw an error if no args'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('set missing value', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({ name: 'foo' }),
      +  })
      +  pkg.exec(['set', 'key='], err => {
      +    t.match(
      +      err,
      +      { code: 'EPKGSET' },
      +      'should throw an error if missing value'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('set missing key', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({ name: 'foo' }),
      +  })
      +  pkg.exec(['set', '=value'], err => {
      +    t.match(
      +      err,
      +      { code: 'EPKGSET' },
      +      'should throw an error if missing key'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('set single field', t => {
      +  const json = {
      +    name: 'foo',
      +    version: '1.1.1',
      +  }
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify(json),
      +  })
      +
      +  pkg.exec(['set', 'description=Awesome stuff'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      readPackageJson(),
      +      {
      +        ...json,
      +        description: 'Awesome stuff',
      +      },
      +      'should add single field to package.json'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('push to array syntax', t => {
      +  const json = {
      +    name: 'foo',
      +    version: '1.1.1',
      +    keywords: [
      +      'foo',
      +    ],
      +  }
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify(json),
      +  })
      +
      +  pkg.exec(['set', 'keywords[]=bar', 'keywords[]=baz'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      readPackageJson(),
      +      {
      +        ...json,
      +        keywords: [
      +          'foo',
      +          'bar',
      +          'baz',
      +        ],
      +      },
      +      'should append to arrays using empty bracket syntax'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('set multiple fields', t => {
      +  const json = {
      +    name: 'foo',
      +    version: '1.1.1',
      +  }
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify(json),
      +  })
      +
      +  pkg.exec(['set', 'bin.foo=foo.js', 'scripts.test=node test.js'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      readPackageJson(),
      +      {
      +        ...json,
      +        bin: {
      +          foo: 'foo.js',
      +        },
      +        scripts: {
      +          test: 'node test.js',
      +        },
      +      },
      +      'should add single field to package.json'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('set = separate value', t => {
      +  const json = {
      +    name: 'foo',
      +    version: '1.1.1',
      +  }
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify(json),
      +  })
      +
      +  pkg.exec(['set', 'tap[test-env][0]=LC_ALL=sk'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      readPackageJson(),
      +      {
      +        ...json,
      +        tap: {
      +          'test-env': [
      +            'LC_ALL=sk',
      +          ],
      +        },
      +      },
      +      'should add single field to package.json'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('set --json', async t => {
      +  config.json = true
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.1.1',
      +    }),
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.exec(['set', 'private=true'], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        readPackageJson(),
      +        {
      +          name: 'foo',
      +          version: '1.1.1',
      +          private: true,
      +        },
      +        'should add boolean field to package.json'
      +      )
      +      res()
      +    })
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.exec(['set', 'tap.timeout=60'], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        readPackageJson(),
      +        {
      +          name: 'foo',
      +          version: '1.1.1',
      +          private: true,
      +          tap: {
      +            timeout: 60,
      +          },
      +        },
      +        'should add number field to package.json'
      +      )
      +      res()
      +    })
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.exec(['set', 'foo={ "bar": { "baz": "BAZ" } }'], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        readPackageJson(),
      +        {
      +          name: 'foo',
      +          version: '1.1.1',
      +          private: true,
      +          tap: {
      +            timeout: 60,
      +          },
      +          foo: {
      +            bar: {
      +              baz: 'BAZ',
      +            },
      +          },
      +        },
      +        'should add object field to package.json'
      +      )
      +      res()
      +    })
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.exec(['set', 'workspaces=["packages/*"]'], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        readPackageJson(),
      +        {
      +          name: 'foo',
      +          version: '1.1.1',
      +          private: true,
      +          workspaces: [
      +            'packages/*',
      +          ],
      +          tap: {
      +            timeout: 60,
      +          },
      +          foo: {
      +            bar: {
      +              baz: 'BAZ',
      +            },
      +          },
      +        },
      +        'should add object field to package.json'
      +      )
      +      res()
      +    })
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.exec(['set', 'description="awesome"'], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        readPackageJson(),
      +        {
      +          name: 'foo',
      +          version: '1.1.1',
      +          description: 'awesome',
      +          private: true,
      +          workspaces: [
      +            'packages/*',
      +          ],
      +          tap: {
      +            timeout: 60,
      +          },
      +          foo: {
      +            bar: {
      +              baz: 'BAZ',
      +            },
      +          },
      +        },
      +        'should add object field to package.json'
      +      )
      +      res()
      +    })
      +  })
      +})
      +
      +t.test('delete no args', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({ name: 'foo' }),
      +  })
      +  pkg.exec(['delete'], err => {
      +    t.match(
      +      err,
      +      { code: 'EPKGDELETE' },
      +      'should throw an error if deleting no args'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('delete invalid key', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({ name: 'foo' }),
      +  })
      +  pkg.exec(['delete', ''], err => {
      +    t.match(
      +      err,
      +      { code: 'EPKGDELETE' },
      +      'should throw an error if deleting invalid args'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('delete single field', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.0.0',
      +    }),
      +  })
      +  pkg.exec(['delete', 'version'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      readPackageJson(),
      +      {
      +        name: 'foo',
      +      },
      +      'should delete single field from package.json'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('delete multiple field', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.0.0',
      +      description: 'awesome',
      +    }),
      +  })
      +  pkg.exec(['delete', 'version', 'description'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      readPackageJson(),
      +      {
      +        name: 'foo',
      +      },
      +      'should delete multiple fields from package.json'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('delete nested field', t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'foo',
      +      version: '1.0.0',
      +      info: {
      +        foo: {
      +          bar: [
      +            {
      +              baz: 'deleteme',
      +            },
      +          ],
      +        },
      +      },
      +    }),
      +  })
      +  pkg.exec(['delete', 'info.foo.bar[0].baz'], err => {
      +    if (err)
      +      throw err
      +
      +    t.strictSame(
      +      readPackageJson(),
      +      {
      +        name: 'foo',
      +        version: '1.0.0',
      +        info: {
      +          foo: {
      +            bar: [
      +              {},
      +            ],
      +          },
      +        },
      +      },
      +      'should delete nested fields from package.json'
      +    )
      +
      +    t.end()
      +  })
      +})
      +
      +t.test('workspaces', async t => {
      +  npm.localPrefix = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'root',
      +      version: '1.0.0',
      +      workspaces: [
      +        'packages/*',
      +      ],
      +    }),
      +    packages: {
      +      a: {
      +        'package.json': JSON.stringify({
      +          name: 'a',
      +          version: '1.0.0',
      +        }),
      +      },
      +      b: {
      +        'package.json': JSON.stringify({
      +          name: 'b',
      +          version: '1.2.3',
      +        }),
      +      },
      +    },
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.execWorkspaces(['get', 'name', 'version'], [], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        JSON.parse(OUTPUT),
      +        {
      +          a: {
      +            name: 'a',
      +            version: '1.0.0',
      +          },
      +          b: {
      +            name: 'b',
      +            version: '1.2.3',
      +          },
      +        },
      +        'should return expected result for configured workspaces'
      +      )
      +      res()
      +    })
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.execWorkspaces(['set', 'funding=http://example.com'], [], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        readPackageJson(resolve(npm.localPrefix, 'packages/a')),
      +        {
      +          name: 'a',
      +          version: '1.0.0',
      +          funding: 'http://example.com',
      +        },
      +        'should add field to workspace a'
      +      )
      +
      +      t.strictSame(
      +        readPackageJson(resolve(npm.localPrefix, 'packages/b')),
      +        {
      +          name: 'b',
      +          version: '1.2.3',
      +          funding: 'http://example.com',
      +        },
      +        'should add field to workspace b'
      +      )
      +      res()
      +    })
      +  })
      +
      +  await new Promise((res, rej) => {
      +    pkg.execWorkspaces(['delete', 'version'], [], err => {
      +      if (err)
      +        rej(err)
      +
      +      t.strictSame(
      +        readPackageJson(resolve(npm.localPrefix, 'packages/a')),
      +        {
      +          name: 'a',
      +          funding: 'http://example.com',
      +        },
      +        'should delete version field from workspace a'
      +      )
      +
      +      t.strictSame(
      +        readPackageJson(resolve(npm.localPrefix, 'packages/b')),
      +        {
      +          name: 'b',
      +          funding: 'http://example.com',
      +        },
      +        'should delete version field from workspace b'
      +      )
      +      res()
      +    })
      +  })
      +})
      diff --git a/deps/npm/test/lib/publish.js b/deps/npm/test/lib/publish.js
      index 56590478fc1ae4..4aa3e5592751e0 100644
      --- a/deps/npm/test/lib/publish.js
      +++ b/deps/npm/test/lib/publish.js
      @@ -762,3 +762,103 @@ t.test('private workspaces', (t) => {
       
         t.end()
       })
      +
      +t.test('runs correct lifecycle scripts', t => {
      +  const testDir = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'my-cool-pkg',
      +      version: '1.0.0',
      +      scripts: {
      +        prepublishOnly: 'echo test prepublishOnly',
      +        prepublish: 'echo test prepublish', // should NOT run this one
      +        publish: 'echo test publish',
      +        postpublish: 'echo test postpublish',
      +      },
      +    }, null, 2),
      +  })
      +
      +  const scripts = []
      +  const Publish = t.mock('../../lib/publish.js', {
      +    '@npmcli/run-script': (args) => {
      +      scripts.push(args)
      +    },
      +    '../../lib/utils/tar.js': {
      +      getContents: () => ({
      +        id: 'someid',
      +      }),
      +      logTar: () => {
      +        t.pass('logTar is called')
      +      },
      +    },
      +    libnpmpublish: {
      +      publish: () => {
      +        t.pass('publish called')
      +      },
      +    },
      +  })
      +  const npm = mockNpm({
      +    output: () => {
      +      t.pass('output is called')
      +    },
      +  })
      +  npm.config.getCredentialsByURI = (uri) => {
      +    t.same(uri, npm.config.get('registry'), 'gets credentials for expected registry')
      +    return { token: 'some.registry.token' }
      +  }
      +  const publish = new Publish(npm)
      +  publish.exec([testDir], (er) => {
      +    if (er)
      +      throw er
      +    t.same(
      +      scripts.map(s => s.event),
      +      ['prepublishOnly', 'publish', 'postpublish'],
      +      'runs only expected scripts, in order'
      +    )
      +    t.end()
      +  })
      +})
      +
      +t.test('does not run scripts on --ignore-scripts', t => {
      +  const testDir = t.testdir({
      +    'package.json': JSON.stringify({
      +      name: 'my-cool-pkg',
      +      version: '1.0.0',
      +    }, null, 2),
      +  })
      +
      +  const Publish = t.mock('../../lib/publish.js', {
      +    '@npmcli/run-script': () => {
      +      t.fail('should not call run-script')
      +    },
      +    '../../lib/utils/tar.js': {
      +      getContents: () => ({
      +        id: 'someid',
      +      }),
      +      logTar: () => {
      +        t.pass('logTar is called')
      +      },
      +    },
      +    libnpmpublish: {
      +      publish: () => {
      +        t.pass('publish called')
      +      },
      +    },
      +  })
      +  const npm = mockNpm({
      +    config: { 'ignore-scripts': true },
      +    output: () => {
      +      t.pass('output is called')
      +    },
      +  })
      +  npm.config.getCredentialsByURI = (uri) => {
      +    t.same(uri, npm.config.get('registry'), 'gets credentials for expected registry')
      +    return { token: 'some.registry.token' }
      +  }
      +  const publish = new Publish(npm)
      +  publish.exec([testDir], (er) => {
      +    if (er)
      +      throw er
      +    t.pass('got to callback')
      +    t.end()
      +  })
      +})
      diff --git a/deps/npm/test/lib/utils/config/definition.js b/deps/npm/test/lib/utils/config/definition.js
      index 45f4c977a77a03..a17a1a09a2240b 100644
      --- a/deps/npm/test/lib/utils/config/definition.js
      +++ b/deps/npm/test/lib/utils/config/definition.js
      @@ -95,6 +95,13 @@ t.test('basic definition', async t => {
           description: 'test description',
         })
         t.equal(hasShort.usage, '-t|--key ')
      +  const multiHasShort = new Definition('key', {
      +    default: 'test default',
      +    short: 't',
      +    type: [null, String],
      +    description: 'test description',
      +  })
      +  t.equal(multiHasShort.usage, '-t|--key ')
         const hardCodedTypes = new Definition('key', {
           default: 'test default',
           type: ['string1', 'string2'],
      diff --git a/deps/npm/test/lib/utils/config/definitions.js b/deps/npm/test/lib/utils/config/definitions.js
      index 8724f0e3bd3ebd..63d9bbd195ab28 100644
      --- a/deps/npm/test/lib/utils/config/definitions.js
      +++ b/deps/npm/test/lib/utils/config/definitions.js
      @@ -463,7 +463,7 @@ t.test('search options', t => {
         t.end()
       })
       
      -t.test('noProxy', t => {
      +t.test('noProxy - array', t => {
         const obj = { noproxy: ['1.2.3.4,2.3.4.5', '3.4.5.6'] }
         const flat = {}
         definitions.noproxy.flatten('noproxy', obj, flat)
      @@ -471,6 +471,14 @@ t.test('noProxy', t => {
         t.end()
       })
       
      +t.test('noProxy - string', t => {
      +  const obj = { noproxy: '1.2.3.4,2.3.4.5,3.4.5.6' }
      +  const flat = {}
      +  definitions.noproxy.flatten('noproxy', obj, flat)
      +  t.strictSame(flat, { noProxy: '1.2.3.4,2.3.4.5,3.4.5.6' })
      +  t.end()
      +})
      +
       t.test('maxSockets', t => {
         const obj = { maxsockets: 123 }
         const flat = {}
      @@ -797,3 +805,26 @@ t.test('save-exact', t => {
         t.strictSame(flat, { savePrefix: '~1.2.3' })
         t.end()
       })
      +
      +t.test('location', t => {
      +  const obj = {
      +    global: true,
      +    location: 'user',
      +  }
      +  const flat = {}
      +  definitions.location.flatten('location', obj, flat)
      +  // global = true sets location in both places to global
      +  t.strictSame(flat, { location: 'global' })
      +  t.strictSame(obj, { global: true, location: 'global' })
      +
      +  obj.global = false
      +  obj.location = 'user'
      +  delete flat.global
      +  delete flat.location
      +
      +  definitions.location.flatten('location', obj, flat)
      +  // global = false leaves location unaltered
      +  t.strictSame(flat, { location: 'user' })
      +  t.strictSame(obj, { global: false, location: 'user' })
      +  t.end()
      +})
      diff --git a/deps/npm/test/lib/utils/error-message.js b/deps/npm/test/lib/utils/error-message.js
      index 4f94645a4542d2..3fdfb8cc250898 100644
      --- a/deps/npm/test/lib/utils/error-message.js
      +++ b/deps/npm/test/lib/utils/error-message.js
      @@ -97,6 +97,7 @@ t.test('just simple messages', t => {
           'ETOOMANYARGS',
           'ETARGET',
           'E403',
      +    'ERR_SOCKET_TIMEOUT',
         ]
         t.plan(codes.length)
         codes.forEach(code => {
      diff --git a/deps/npm/test/lib/utils/exit-handler.js b/deps/npm/test/lib/utils/exit-handler.js
      index 06014b67a97548..981ac9a32b6845 100644
      --- a/deps/npm/test/lib/utils/exit-handler.js
      +++ b/deps/npm/test/lib/utils/exit-handler.js
      @@ -1,13 +1,12 @@
       /* eslint-disable no-extend-native */
       /* eslint-disable no-global-assign */
      -const EventEmitter = require('events')
      -const writeFileAtomic = require('write-file-atomic')
       const t = require('tap')
      +const EventEmitter = require('events')
      +const os = require('os')
      +const fs = require('fs')
      +const path = require('path')
       
      -// NOTE: Although these unit tests may look like the rest on the surface,
      -// they are in fact very special due to the amount of things hooking directly
      -// to global process and variables defined in the module scope. That makes
      -// for tests that are very interdependent and their order are important.
      +const { real: mockNpm } = require('../../fixtures/mock-npm')
       
       // generic error to be used in tests
       const err = Object.assign(new Error('ERROR'), { code: 'ERROR' })
      @@ -23,69 +22,23 @@ const redactCwd = (path) => {
       
       t.cleanSnapshot = (str) => redactCwd(str)
       
      -// internal modules mocks
       const cacheFolder = t.testdir({})
      -const config = {
      -  values: {
      -    cache: cacheFolder,
      -    timing: true,
      -  },
      -  loaded: true,
      -  updateNotification: null,
      -  get (key) {
      -    return this.values[key]
      -  },
      -}
      -
      -const npm = {
      -  version: '1.0.0',
      -  config,
      -  shelloutCommands: ['exec', 'run-script'],
      -}
      +const logFile = path.resolve(cacheFolder, '_logs', 'expecteddate-debug.log')
      +const timingFile = path.resolve(cacheFolder, '_timing.json')
       
      -const npmlog = {
      -  disableProgress: () => null,
      -  log (level, ...args) {
      -    this.record.push({
      -      id: this.record.length,
      -      level,
      -      message: args.reduce((res, i) => `${res} ${i.message ? i.message : i}`, ''),
      -      prefix: level !== 'verbose' ? 'foo' : '',
      -    })
      -  },
      -  error (...args) {
      -    this.log('error', ...args)
      -  },
      -  info (...args) {
      -    this.log('info', ...args)
      -  },
      -  level: 'silly',
      -  levels: {
      -    silly: 0,
      -    verbose: 1,
      -    info: 2,
      -    error: 3,
      -    silent: 4,
      -  },
      -  notice (...args) {
      -    this.log('notice', ...args)
      -  },
      -  record: [],
      -  verbose (...args) {
      -    this.log('verbose', ...args)
      -  },
      -}
      +const { npm } = mockNpm(t)
       
      -// overrides OS type/release for cross platform snapshots
      -const os = require('os')
      -os.type = () => 'Foo'
      -os.release = () => '1.0.0'
      +t.before(async () => {
      +  npm.version = '1.0.0'
      +  await npm.load()
      +  npm.config.set('cache', cacheFolder)
      +})
       
      -// bootstrap tap before cutting off process ref
      -t.test('ok', (t) => {
      +t.test('bootstrap tap before cutting off process ref', (t) => {
         t.ok('ok')
         t.end()
       })
      +
       // cut off process from script so that it won't quit the test runner
       // while trying to run through the myriad of cases
       const _process = process
      @@ -95,9 +48,11 @@ process = Object.assign(
           argv: ['/node', ..._process.argv.slice(1)],
           cwd: _process.cwd,
           env: _process.env,
      -    exit () {},
      -    exitCode: 0,
           version: 'v1.0.0',
      +    exit: (code) => {
      +      process.exitCode = code || process.exitCode || 0
      +      process.emit('exit', process.exitCode)
      +    },
           stdout: { write (_, cb) {
             cb()
           } },
      @@ -105,19 +60,40 @@ process = Object.assign(
           hrtime: _process.hrtime,
         }
       )
      -// needs to put process back in its place
      -// in order for tap to exit properly
      +
      +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
      -  npmlog.record.length = 0
      +  npm.log.record.length = 0
      +  delete process.exitCode
       })
       
       const mocks = {
      -  npmlog,
         '../../../lib/utils/error-message.js': (err) => ({
           ...err,
           summary: [['ERR', err.message]],
      @@ -125,102 +101,57 @@ const mocks = {
         }),
       }
       
      -let exitHandler = t.mock('../../../lib/utils/exit-handler.js', mocks)
      +const exitHandler = t.mock('../../../lib/utils/exit-handler.js', mocks)
       exitHandler.setNpm(npm)
       
      -t.test('default exit code', (t) => {
      -  t.plan(1)
      -
      -  // manually simulate timing handlers
      -  process.emit('timing', 'foo', 1)
      -  process.emit('timing', 'foo', 2)
      -
      -  // generates logfile name with mocked date
      -  const _toISOString = Date.prototype.toISOString
      -  Date.prototype.toISOString = () => 'expecteddate'
      -
      -  npmlog.level = 'silent'
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    t.equal(code, 1, 'should default to error code 1')
      -  }
      -
      -  // skip console.error logs
      -  const _error = console.error
      -  console.error = () => null
      -
      +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()
      +})
       
      -  t.teardown(() => {
      -    npmlog.level = 'silly'
      -    process.exit = _exit
      -    console.error = _error
      -    Date.prototype.toISOString = _toISOString
      -  })
      +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', (t) => {
         t.plan(2)
       
      -  const _toISOString = Date.prototype.toISOString
      -  Date.prototype.toISOString = () => 'expecteddate'
      -
      -  const sync = writeFileAtomic.sync
      -  writeFileAtomic.sync = (filename, content) => {
      -    t.equal(
      -      redactCwd(filename),
      -      '{CWD}/test/lib/utils/tap-testdir-exit-handler/_logs/expecteddate-debug.log',
      -      'should use expected log filename'
      -    )
      -    t.matchSnapshot(
      -      content,
      -      'should have expected log contents for unknown error'
      -    )
      -  }
      -
      -  exitHandler(err)
      +  npm.log.level = 'notice'
       
      -  t.teardown(() => {
      -    writeFileAtomic.sync = sync
      -    Date.prototype.toISOString = _toISOString
      +  process.once('timeEnd', (msg) => {
      +    t.equal(msg, 'npm', 'should trigger timeEnd for npm')
         })
      +
      +  exitHandler(err)
      +  const logData = fs.readFileSync(logFile, 'utf8')
      +  t.matchSnapshot(
      +    logData,
      +    'should have expected log contents for unknown error'
      +  )
         t.end()
       })
       
      -t.test('npm.config not ready', (t) => {
      +t.test('fail to write logfile', (t) => {
         t.plan(1)
       
      -  config.loaded = false
      -
      -  const _error = console.error
      -  console.error = (msg) => {
      -    t.match(
      -      msg,
      -      /Error: Exit prior to config file resolving./,
      -      'should exit with config error msg'
      -    )
      -  }
      -
      -  exitHandler()
      -
         t.teardown(() => {
      -    console.error = _error
      -    config.loaded = true
      +    npm.config.set('cache', cacheFolder)
         })
      -})
      -
      -t.test('fail to write logfile', (t) => {
      -  t.plan(1)
       
         const badDir = t.testdir({
           _logs: 'is a file',
         })
       
      -  config.values.cache = badDir
      -
      -  t.teardown(() => {
      -    config.values.cache = cacheFolder
      -  })
      +  npm.config.set('cache', badDir)
       
         t.doesNotThrow(
           () => exitHandler(err),
      @@ -231,241 +162,166 @@ t.test('fail to write logfile', (t) => {
       t.test('console.log output using --json', (t) => {
         t.plan(1)
       
      -  config.values.json = true
      -
      -  const _error = console.error
      -  console.error = (jsonOutput) => {
      -    t.same(
      -      JSON.parse(jsonOutput),
      -      {
      -        error: {
      -          code: 'EBADTHING', // should default error code to E[A-Z]+
      -          summary: 'Error: EBADTHING Something happened',
      -          detail: 'Error: EBADTHING Something happened',
      -        },
      -      },
      -      'should output expected json output'
      -    )
      -  }
      -
      -  exitHandler(new Error('Error: EBADTHING Something happened'))
      -
      +  npm.config.set('json', true)
         t.teardown(() => {
      -    console.error = _error
      -    delete config.values.json
      +    npm.config.set('json', false)
         })
      +
      +  exitHandler(new Error('Error: EBADTHING Something happened'))
      +  t.same(
      +    JSON.parse(errors[0]),
      +    {
      +      error: {
      +        code: 'EBADTHING', // should default error code to E[A-Z]+
      +        summary: 'Error: EBADTHING Something happened',
      +        detail: 'Error: EBADTHING Something happened',
      +      },
      +    },
      +    'should output expected json output'
      +  )
       })
       
       t.test('throw a non-error obj', (t) => {
      -  t.plan(3)
      +  t.plan(2)
       
         const weirdError = {
           code: 'ESOMETHING',
           message: 'foo bar',
         }
       
      -  const _logError = npmlog.error
      -  npmlog.error = (title, err) => {
      -    t.equal(title, 'weird error', 'should name it a weird error')
      -    t.same(err, weirdError, 'should log given weird error')
      -  }
      -
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    t.equal(code, 1, 'should exit with code 1')
      -  }
      -
      -  exitHandler(weirdError)
      -
      -  t.teardown(() => {
      -    process.exit = _exit
      -    npmlog.error = _logError
      +  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.test('throw a string error', (t) => {
      -  t.plan(3)
      -
      +  t.plan(2)
         const error = 'foo bar'
       
      -  const _logError = npmlog.error
      -  npmlog.error = (title, err) => {
      -    t.equal(title, '', 'should have an empty name ref')
      -    t.same(err, 'foo bar', 'should log string error')
      -  }
      -
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    t.equal(code, 1, 'should exit with code 1')
      -  }
      -
      -  exitHandler(error)
      -
      -  t.teardown(() => {
      -    process.exit = _exit
      -    npmlog.error = _logError
      +  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' }
      +  )
       })
       
       t.test('update notification', (t) => {
      -  t.plan(2)
      -
         const updateMsg = 'you should update npm!'
         npm.updateNotification = updateMsg
      -
      -  const _notice = npmlog.notice
      -  npmlog.notice = (prefix, msg) => {
      -    t.equal(prefix, '', 'should have no prefix')
      -    t.equal(msg, updateMsg, 'should show update message')
      -  }
      -
      -  exitHandler(err)
      +  npm.log.level = 'silent'
       
         t.teardown(() => {
      -    npmlog.notice = _notice
           delete npm.updateNotification
         })
      +
      +  exitHandler()
      +  t.match(
      +    npm.log.record.find(r => r.level === 'notice'),
      +    { message: 'you should update npm!' }
      +  )
      +  t.end()
       })
       
      -t.test('on exit handler', (t) => {
      -  t.plan(2)
      +t.test('npm.config not ready', (t) => {
      +  t.plan(1)
       
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    t.equal(code, 1, 'should default to error code 1')
      -  }
      +  const { npm: unloaded } = mockNpm(t)
       
      -  process.once('timeEnd', (msg) => {
      -    t.equal(msg, 'npm', 'should trigger timeEnd for npm')
      +  t.teardown(() => {
      +    exitHandler.setNpm(npm)
         })
       
      -  // skip console.error logs
      -  const _error = console.error
      -  console.error = () => null
      +  exitHandler.setNpm(unloaded)
       
      -  process.emit('exit', 1)
      -
      -  t.teardown(() => {
      -    console.error = _error
      -    process.exit = _exit
      -  })
      +  exitHandler()
      +  t.match(
      +    errors[0],
      +    /Error: Exit prior to config file resolving./,
      +    'should exit with config error msg'
      +  )
      +  t.end()
       })
       
      -t.test('it worked', (t) => {
      -  t.plan(2)
      +t.test('timing', (t) => {
      +  npm.config.set('timing', true)
       
      -  config.values.timing = false
      -
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    process.exit = _exit
      -    t.notOk(code, 'should exit with no code')
      +  t.teardown(() => {
      +    fs.unlinkSync(timingFile)
      +    npm.config.set('timing', false)
      +  })
       
      -    const _info = npmlog.info
      -    npmlog.info = (msg) => {
      -      npmlog.info = _info
      -      t.equal(msg, 'ok', 'should log ok if "it worked"')
      -    }
      +  exitHandler()
      +  const timingData = JSON.parse(fs.readFileSync(timingFile, 'utf8'))
      +  t.match(timingData, { version: '1.0.0', 'config:load:defaults': Number })
      +  t.end()
      +})
       
      -    process.emit('exit', 0)
      -  }
      +t.test('timing - with error', (t) => {
      +  npm.config.set('timing', true)
       
         t.teardown(() => {
      -    process.exit = _exit
      -    config.values.timing = true
      +    fs.unlinkSync(timingFile)
      +    npm.config.set('timing', false)
         })
       
      -  exitHandler()
      +  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)
       
      -  exitHandler = t.mock('../../../lib/utils/exit-handler.js', mocks)
      -  exitHandler.setNpm(npm)
      -
      -  npmlog.level = 'silent'
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    t.equal(code, 127, 'should use set errno')
      -  }
      -
      +  process.once('exit', code => {
      +    t.equal(code, 127, 'should set exitCode from errno')
      +  })
         exitHandler(Object.assign(
           new Error('Error with errno'),
           {
             errno: 127,
           }
         ))
      -
      -  t.teardown(() => {
      -    npmlog.level = 'silly'
      -    process.exit = _exit
      -  })
       })
       
      -t.test('uses exitCode as code if using a number', (t) => {
      +t.test('uses code from number', (t) => {
         t.plan(1)
       
      -  exitHandler = t.mock('../../../lib/utils/exit-handler.js', mocks)
      -  exitHandler.setNpm(npm)
      -
      -  npmlog.level = 'silent'
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    t.equal(code, 404, 'should use code if a number')
      -  }
      -
      +  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,
           }
         ))
      -
      -  t.teardown(() => {
      -    npmlog.level = 'silly'
      -    process.exit = _exit
      -  })
       })
       
       t.test('call exitHandler with no error', (t) => {
         t.plan(1)
      -
      -  exitHandler = t.mock('../../../lib/utils/exit-handler.js', mocks)
      -  exitHandler.setNpm(npm)
      -
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    t.equal(code, undefined, 'should exit with code undefined')
      -  }
      -
      -  t.teardown(() => {
      -    process.exit = _exit
      +  process.once('exit', code => {
      +    t.equal(code, 0, 'should end up with exitCode 0 (default)')
         })
      -
      -  exitHandler()
      -})
      -
      -t.test('exit handler called twice', (t) => {
      -  t.plan(2)
      -
      -  const _verbose = npmlog.verbose
      -  npmlog.verbose = (key, value) => {
      -    t.equal(key, 'stack', 'should log stack in verbose level')
      -    t.match(
      -      value,
      -      /Error: Exit handler called more than once./,
      -      'should have expected error msg'
      -    )
      -    npmlog.verbose = _verbose
      -  }
      -
         exitHandler()
       })
       
       t.test('defaults to log error msg if stack is missing', (t) => {
      -  t.plan(1)
      +  const { npm: unloaded } = mockNpm(t)
       
      +  t.teardown(() => {
      +    exitHandler.setNpm(npm)
      +  })
      +
      +  exitHandler.setNpm(unloaded)
         const noStackErr = Object.assign(
           new Error('Error with no stack'),
           {
      @@ -475,89 +331,63 @@ t.test('defaults to log error msg if stack is missing', (t) => {
         )
         delete noStackErr.stack
       
      -  npm.config.loaded = false
      -
      -  const _error = console.error
      -  console.error = (msg) => {
      -    console.error = _error
      -    npm.config.loaded = true
      -    t.equal(msg, 'Error with no stack', 'should use error msg')
      -  }
      -
         exitHandler(noStackErr)
      +  t.equal(errors[0], 'Error with no stack', 'should use error msg')
      +  t.end()
       })
       
       t.test('exits cleanly when emitting exit event', (t) => {
         t.plan(1)
       
      -  npmlog.level = 'silent'
      -  const _exit = process.exit
      -  process.exit = (code) => {
      -    process.exit = _exit
      -    t.same(code, null, 'should exit with code null')
      -  }
      -
      -  t.teardown(() => {
      -    process.exit = _exit
      -    npmlog.level = 'silly'
      -  })
      -
      +  npm.log.level = 'silent'
         process.emit('exit')
      +  t.match(
      +    npm.log.record.find(r => r.level === 'info'),
      +    { prefix: 'ok', message: '' }
      +  )
      +  t.end()
       })
       
       t.test('do no fancy handling for shellouts', t => {
      -  const { exit } = process
         const { command } = npm
      -  const { log } = npmlog
         const LOG_RECORD = []
      +  npm.command = 'exec'
      +
         t.teardown(() => {
      -    npmlog.log = log
      -    process.exit = exit
           npm.command = command
         })
      -
      -  npmlog.log = function (level, ...args) {
      -    log.call(this, level, ...args)
      -    LOG_RECORD.push(npmlog.record[npmlog.record.length - 1])
      -  }
      -
      -  npm.command = 'exec'
      -
      -  let EXPECT_EXIT = 0
      -  process.exit = code => {
      -    t.equal(code, EXPECT_EXIT, 'got expected exit code')
      -    EXPECT_EXIT = 0
      -  }
         t.beforeEach(() => LOG_RECORD.length = 0)
       
      -  const loudNoises = () => LOG_RECORD
      +  const loudNoises = () => npm.log.record
           .filter(({ level }) => ['warn', 'error'].includes(level))
       
         t.test('shellout with a numeric error code', t => {
      -    EXPECT_EXIT = 5
      +    t.plan(2)
      +    process.once('exit', code => {
      +      t.equal(code, 5, 'got expected exit code')
      +    })
           exitHandler(Object.assign(new Error(), { code: 5 }))
      -    t.equal(EXPECT_EXIT, 0, 'called process.exit')
      -    // should log no warnings or errors, verbose/silly is fine.
           t.strictSame(loudNoises(), [], 'no noisy warnings')
      -    t.end()
         })
       
         t.test('shellout without a numeric error code (something in npm)', t => {
      -    EXPECT_EXIT = 1
      +    t.plan(2)
      +    process.once('exit', code => {
      +      t.equal(code, 1, 'got expected exit code')
      +    })
           exitHandler(Object.assign(new Error(), { code: 'banana stand' }))
      -    t.equal(EXPECT_EXIT, 0, 'called process.exit')
           // 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 => {
      -    EXPECT_EXIT = 1
      +    t.plan(2)
      +    process.once('exit', code => {
      +      t.equal(code, 1, 'got expected exit code')
      +    })
           exitHandler(Object.assign(new Error(), { code: 0 }))
      -    t.equal(EXPECT_EXIT, 0, 'called process.exit')
      -    // should log some warnings and errors, because something weird happened
           t.strictNotSame(loudNoises(), [], 'bring the noise')
      -    t.end()
         })
       
         t.end()
      diff --git a/deps/npm/test/lib/utils/perf.js b/deps/npm/test/lib/utils/perf.js
      deleted file mode 100644
      index 840dcb6e32399b..00000000000000
      --- a/deps/npm/test/lib/utils/perf.js
      +++ /dev/null
      @@ -1,38 +0,0 @@
      -const t = require('tap')
      -const logs = []
      -const npmlog = require('npmlog')
      -npmlog.silly = (...msg) => logs.push(['silly', ...msg])
      -npmlog.timing = (...msg) => logs.push(['timing', ...msg])
      -
      -t.test('time some stuff', t => {
      -  const timings = {}
      -  process.on('timing', (name, value) => {
      -    timings[name] = (timings[name] || 0) + value
      -  })
      -  require('../../../lib/utils/perf.js')
      -  process.emit('time', 'foo')
      -  process.emit('time', 'bar')
      -  setTimeout(() => {
      -    process.emit('timeEnd', 'foo')
      -    process.emit('timeEnd', 'bar')
      -    process.emit('time', 'foo')
      -    setTimeout(() => {
      -      process.emit('timeEnd', 'foo')
      -      process.emit('timeEnd', 'baz')
      -      t.match(logs, [
      -        ['timing', 'foo', /Completed in [0-9]+ms/],
      -        ['timing', 'bar', /Completed in [0-9]+ms/],
      -        ['timing', 'foo', /Completed in [0-9]+ms/],
      -        [
      -          'silly',
      -          'timing',
      -          "Tried to end timer that doesn't exist:",
      -          'baz',
      -        ],
      -      ])
      -      t.match(timings, { foo: Number, bar: Number })
      -      t.equal(timings.foo > timings.bar, true, 'foo should be > bar')
      -      t.end()
      -    }, 100)
      -  }, 100)
      -})
      diff --git a/deps/npm/test/lib/utils/queryable.js b/deps/npm/test/lib/utils/queryable.js
      new file mode 100644
      index 00000000000000..bde3ea66238f28
      --- /dev/null
      +++ b/deps/npm/test/lib/utils/queryable.js
      @@ -0,0 +1,965 @@
      +const { inspect } = require('util')
      +const t = require('tap')
      +const Queryable = require('../../../lib/utils/queryable.js')
      +
      +t.test('retrieve single nested property', async t => {
      +  const fixture = {
      +    foo: {
      +      bar: 'bar',
      +      baz: 'baz',
      +    },
      +    lorem: {
      +      ipsum: 'ipsum',
      +    },
      +  }
      +  const q = new Queryable(fixture)
      +  const query = 'foo.bar'
      +  t.strictSame(q.query(query), { [query]: 'bar' },
      +    'should retrieve property value when querying for dot-sep name')
      +})
      +
      +t.test('query', async t => {
      +  const fixture = {
      +    o: 'o',
      +    single: [
      +      'item',
      +    ],
      +    w: [
      +      'a',
      +      'b',
      +      'c',
      +    ],
      +    list: [
      +      {
      +        name: 'first',
      +      },
      +      {
      +        name: 'second',
      +      },
      +    ],
      +    foo: {
      +      bar: 'bar',
      +      baz: 'baz',
      +    },
      +    lorem: {
      +      ipsum: 'ipsum',
      +      dolor: [
      +        'a',
      +        'b',
      +        'c',
      +        {
      +          sit: [
      +            'amet',
      +          ],
      +        },
      +      ],
      +    },
      +    a: [
      +      [
      +        [
      +          {
      +            b: [
      +              [
      +                {
      +                  c: 'd',
      +                },
      +              ],
      +            ],
      +          },
      +        ],
      +      ],
      +    ],
      +  }
      +  const q = new Queryable(fixture)
      +  t.strictSame(
      +    q.query(['foo.baz', 'lorem.dolor[0]']),
      +    {
      +      'foo.baz': 'baz',
      +      'lorem.dolor[0]': 'a',
      +    },
      +    'should retrieve property values when querying for multiple dot-sep names')
      +  t.strictSame(
      +    q.query('lorem.dolor[3].sit[0]'),
      +    {
      +      'lorem.dolor[3].sit[0]': 'amet',
      +    },
      +    'should retrieve property from nested array items')
      +  t.strictSame(
      +    q.query('a[0][0][0].b[0][0].c'),
      +    {
      +      'a[0][0][0].b[0][0].c': 'd',
      +    },
      +    'should retrieve property from deep nested array items')
      +  t.strictSame(
      +    q.query('o'),
      +    {
      +      o: 'o',
      +    },
      +    'should retrieve single level property value')
      +  t.strictSame(
      +    q.query('list.name'),
      +    {
      +      'list[0].name': 'first',
      +      'list[1].name': 'second',
      +    },
      +    'should automatically expand arrays')
      +  t.strictSame(
      +    q.query(['list.name']),
      +    {
      +      'list[0].name': 'first',
      +      'list[1].name': 'second',
      +    },
      +    'should automatically expand multiple arrays')
      +  t.strictSame(
      +    q.query('w'),
      +    {
      +      w: ['a', 'b', 'c'],
      +    },
      +    'should return arrays')
      +  t.strictSame(
      +    q.query('single'),
      +    {
      +      single: 'item',
      +    },
      +    'should return single item')
      +  t.strictSame(
      +    q.query('missing'),
      +    undefined,
      +    'should return undefined')
      +  t.strictSame(
      +    q.query('missing[bar]'),
      +    undefined,
      +    'should return undefined also')
      +  t.throws(() => q.query('lorem.dolor[]'),
      +    { code: 'EINVALIDSYNTAX' },
      +    'should throw if using empty brackets notation'
      +  )
      +  t.throws(() => q.query('lorem.dolor[].sit[0]'),
      +    { code: 'EINVALIDSYNTAX' },
      +    'should throw if using nested empty brackets notation'
      +  )
      +
      +  const qq = new Queryable({
      +    foo: {
      +      bar: 'bar',
      +    },
      +  })
      +  t.strictSame(
      +    qq.query(''),
      +    {
      +      '': {
      +        foo: {
      +          bar: 'bar',
      +        },
      +      },
      +    },
      +    'should return an object with results in an empty key'
      +  )
      +})
      +
      +t.test('missing key', async t => {
      +  const fixture = {
      +    foo: {
      +      bar: 'bar',
      +    },
      +  }
      +  const q = new Queryable(fixture)
      +  const query = 'foo.missing'
      +  t.equal(q.query(query), undefined,
      +    'should retrieve no results')
      +})
      +
      +t.test('no data object', async t => {
      +  t.throws(
      +    () => new Queryable(),
      +    { code: 'ENOQUERYABLEOBJ' },
      +    'should throw ENOQUERYABLEOBJ error'
      +  )
      +  t.throws(
      +    () => new Queryable(1),
      +    { code: 'ENOQUERYABLEOBJ' },
      +    'should throw ENOQUERYABLEOBJ error'
      +  )
      +})
      +
      +t.test('get values', async t => {
      +  const q = new Queryable({
      +    foo: {
      +      bar: 'bar',
      +    },
      +  })
      +  t.equal(q.get('foo.bar'), 'bar', 'should retrieve value')
      +  t.equal(q.get('missing'), undefined, 'should return undefined')
      +})
      +
      +t.test('set property values', async t => {
      +  const fixture = {
      +    foo: {
      +      bar: 'bar',
      +    },
      +  }
      +  const q = new Queryable(fixture)
      +  q.set('foo.baz', 'baz')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +        baz: 'baz',
      +      },
      +    },
      +    'should add new property and its assigned value'
      +  )
      +  q.set('foo[lorem.ipsum]', 'LOREM IPSUM')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +        baz: 'baz',
      +        'lorem.ipsum': 'LOREM IPSUM',
      +      },
      +    },
      +    'should be able to set square brackets props'
      +  )
      +  q.set('a.b[c.d]', 'omg')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +        baz: 'baz',
      +        'lorem.ipsum': 'LOREM IPSUM',
      +      },
      +      a: {
      +        b: {
      +          'c.d': 'omg',
      +        },
      +      },
      +    },
      +    'should be able to nest square brackets props'
      +  )
      +  q.set('a.b[e][f.g][1.0.0]', 'multiple')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +        baz: 'baz',
      +        'lorem.ipsum': 'LOREM IPSUM',
      +      },
      +      a: {
      +        b: {
      +          'c.d': 'omg',
      +          e: {
      +            'f.g': {
      +              '1.0.0': 'multiple',
      +            },
      +          },
      +        },
      +      },
      +    },
      +    'should be able to nest multiple square brackets props'
      +  )
      +  q.set('a.b[e][f.g][2.0.0].author.name', 'Ruy Adorno')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +        baz: 'baz',
      +        'lorem.ipsum': 'LOREM IPSUM',
      +      },
      +      a: {
      +        b: {
      +          'c.d': 'omg',
      +          e: {
      +            'f.g': {
      +              '1.0.0': 'multiple',
      +              '2.0.0': {
      +                author: {
      +                  name: 'Ruy Adorno',
      +                },
      +              },
      +            },
      +          },
      +        },
      +      },
      +    },
      +    'should be able to use dot-sep notation after square bracket props'
      +  )
      +  q.set('a.b[e][f.g][2.0.0].author[url]', 'https://npmjs.com')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +        baz: 'baz',
      +        'lorem.ipsum': 'LOREM IPSUM',
      +      },
      +      a: {
      +        b: {
      +          'c.d': 'omg',
      +          e: {
      +            'f.g': {
      +              '1.0.0': 'multiple',
      +              '2.0.0': {
      +                author: {
      +                  name: 'Ruy Adorno',
      +                  url: 'https://npmjs.com',
      +                },
      +              },
      +            },
      +          },
      +        },
      +      },
      +    },
      +    'should be able to have multiple, separated, square brackets props'
      +  )
      +  q.set('a.b[e][f.g][2.0.0].author[foo][bar].lorem.ipsum[dolor][sit][amet].omg', 'O_O')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +        baz: 'baz',
      +        'lorem.ipsum': 'LOREM IPSUM',
      +      },
      +      a: {
      +        b: {
      +          'c.d': 'omg',
      +          e: {
      +            'f.g': {
      +              '1.0.0': 'multiple',
      +              '2.0.0': {
      +                author: {
      +                  name: 'Ruy Adorno',
      +                  url: 'https://npmjs.com',
      +                  foo: {
      +                    bar: {
      +                      lorem: {
      +                        ipsum: {
      +                          dolor: {
      +                            sit: {
      +                              amet: {
      +                                omg: 'O_O',
      +                              },
      +                            },
      +                          },
      +                        },
      +                      },
      +                    },
      +                  },
      +                },
      +              },
      +            },
      +          },
      +        },
      +      },
      +    },
      +    'many many times...'
      +  )
      +  t.throws(
      +    () => q.set('foo.bar.nest', 'should throw'),
      +    { code: 'EOVERRIDEVALUE' },
      +    'should throw if trying to override a literal value with an object'
      +  )
      +  q.set('foo.bar.nest', 'use the force!', { force: true })
      +  t.strictSame(
      +    q.toJSON().foo,
      +    {
      +      bar: {
      +        nest: 'use the force!',
      +      },
      +      baz: 'baz',
      +      'lorem.ipsum': 'LOREM IPSUM',
      +    },
      +    'should allow overriding literal values when using force option'
      +  )
      +
      +  const qq = new Queryable({})
      +  qq.set('foo.bar.baz', 'BAZ')
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: {
      +        bar: {
      +          baz: 'BAZ',
      +        },
      +      },
      +    },
      +    'should add new props to qq object'
      +  )
      +  qq.set('foo.bar.bario', 'bario')
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: {
      +        bar: {
      +          baz: 'BAZ',
      +          bario: 'bario',
      +        },
      +      },
      +    },
      +    'should add new props to a previously existing object'
      +  )
      +  qq.set('lorem', 'lorem')
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: {
      +        bar: {
      +          baz: 'BAZ',
      +          bario: 'bario',
      +        },
      +      },
      +      lorem: 'lorem',
      +    },
      +    'should append new props added to object later'
      +  )
      +  qq.set('foo.bar[foo.bar]', 'foo.bar.with.dots')
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: {
      +        bar: {
      +          'foo.bar': 'foo.bar.with.dots',
      +          baz: 'BAZ',
      +          bario: 'bario',
      +        },
      +      },
      +      lorem: 'lorem',
      +    },
      +    'should append new props added to object later'
      +  )
      +})
      +
      +t.test('set arrays', async t => {
      +  const q = new Queryable({})
      +
      +  q.set('foo[1]', 'b')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: [
      +        undefined,
      +        'b',
      +      ],
      +    },
      +    'should be able to set items in an array using index references'
      +  )
      +
      +  q.set('foo[0]', 'a')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: [
      +        'a',
      +        'b',
      +      ],
      +    },
      +    'should be able to set a previously missing item to an array'
      +  )
      +
      +  q.set('foo[2]', 'c')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: [
      +        'a',
      +        'b',
      +        'c',
      +      ],
      +    },
      +    'should be able to append more items to an array'
      +  )
      +
      +  q.set('foo[2]', 'C')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: [
      +        'a',
      +        'b',
      +        'C',
      +      ],
      +    },
      +    'should be able to override array items'
      +  )
      +
      +  t.throws(
      +    () => q.set('foo[2].bar', 'bar'),
      +    { code: 'EOVERRIDEVALUE' },
      +    'should throw if trying to override an array literal item with an obj'
      +  )
      +
      +  q.set('foo[2].bar', 'bar', { force: true })
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: [
      +        'a',
      +        'b',
      +        { bar: 'bar' },
      +      ],
      +    },
      +    'should be able to override an array string item with an obj'
      +  )
      +
      +  q.set('foo[3].foo', 'surprise surprise, another foo')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: [
      +        'a',
      +        'b',
      +        { bar: 'bar' },
      +        {
      +          foo: 'surprise surprise, another foo',
      +        },
      +      ],
      +    },
      +    'should be able to append more items to an array'
      +  )
      +
      +  q.set('foo[3].foo', 'FOO')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: [
      +        'a',
      +        'b',
      +        { bar: 'bar' },
      +        {
      +          foo: 'FOO',
      +        },
      +      ],
      +    },
      +    'should be able to override property of an obj inside an array'
      +  )
      +
      +  const qq = new Queryable({})
      +  qq.set('foo[0].bar[1].baz.bario[0][0][0]', 'something')
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: [
      +        {
      +          bar: [
      +            undefined,
      +            {
      +              baz: {
      +                bario: [[['something']]],
      +              },
      +            },
      +          ],
      +        },
      +      ],
      +    },
      +    'should append as many arrays as necessary'
      +  )
      +  qq.set('foo[0].bar[1].baz.bario[0][1][0]', 'something else')
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: [
      +        {
      +          bar: [
      +            undefined,
      +            {
      +              baz: {
      +                bario: [[
      +                  ['something'],
      +                  ['something else'],
      +                ]],
      +              },
      +            },
      +          ],
      +        },
      +      ],
      +    },
      +    'should append as many arrays as necessary'
      +  )
      +  qq.set('foo', null)
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: null,
      +    },
      +    'should be able to set a value to null'
      +  )
      +  qq.set('foo.bar', 'bar')
      +  t.strictSame(
      +    qq.toJSON(),
      +    {
      +      foo: {
      +        bar: 'bar',
      +      },
      +    },
      +    'should be able to replace a null value with properties'
      +  )
      +
      +  const qqq = new Queryable({
      +    arr: [
      +      'a',
      +      'b',
      +    ],
      +  })
      +
      +  qqq.set('arr[]', 'c')
      +  t.strictSame(
      +    qqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +        'c',
      +      ],
      +    },
      +    'should be able to append to array using empty bracket notation'
      +  )
      +
      +  qqq.set('arr[].foo', 'foo')
      +  t.strictSame(
      +    qqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +        'c',
      +        {
      +          foo: 'foo',
      +        },
      +      ],
      +    },
      +    'should be able to append objects to array using empty bracket notation'
      +  )
      +
      +  qqq.set('arr[].bar.name', 'BAR')
      +  t.strictSame(
      +    qqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +        'c',
      +        {
      +          foo: 'foo',
      +        },
      +        {
      +          bar: {
      +            name: 'BAR',
      +          },
      +        },
      +      ],
      +    },
      +    'should be able to append more objects to array using empty brackets'
      +  )
      +
      +  qqq.set('foo.bar.baz[].lorem.ipsum', 'something')
      +  t.strictSame(
      +    qqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +        'c',
      +        {
      +          foo: 'foo',
      +        },
      +        {
      +          bar: {
      +            name: 'BAR',
      +          },
      +        },
      +      ],
      +      foo: {
      +        bar: {
      +          baz: [
      +            {
      +              lorem: {
      +                ipsum: 'something',
      +              },
      +            },
      +          ],
      +        },
      +      },
      +    },
      +    'should be able to append to array using empty brackets in nested objs'
      +  )
      +
      +  qqq.set('foo.bar.baz[].lorem.array[]', 'new item')
      +  t.strictSame(
      +    qqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +        'c',
      +        {
      +          foo: 'foo',
      +        },
      +        {
      +          bar: {
      +            name: 'BAR',
      +          },
      +        },
      +      ],
      +      foo: {
      +        bar: {
      +          baz: [
      +            {
      +              lorem: {
      +                ipsum: 'something',
      +              },
      +            },
      +            {
      +              lorem: {
      +                array: [
      +                  'new item',
      +                ],
      +              },
      +            },
      +          ],
      +        },
      +      },
      +    },
      +    'should be able to append to array using empty brackets in nested objs'
      +  )
      +
      +  const qqqq = new Queryable({
      +    arr: [
      +      'a',
      +      'b',
      +    ],
      +  })
      +  t.throws(
      +    () => qqqq.set('arr.foo', 'foo'),
      +    { code: 'ENOADDPROP' },
      +    'should throw an override error'
      +  )
      +
      +  qqqq.set('arr.foo', 'foo', { force: true })
      +  t.strictSame(
      +    qqqq.toJSON(),
      +    {
      +      arr: {
      +        0: 'a',
      +        1: 'b',
      +        foo: 'foo',
      +      },
      +    },
      +    'should be able to override arrays with objects when using force=true'
      +  )
      +
      +  qqqq.set('bar[]', 'item', { force: true })
      +  t.strictSame(
      +    qqqq.toJSON(),
      +    {
      +      arr: {
      +        0: 'a',
      +        1: 'b',
      +        foo: 'foo',
      +      },
      +      bar: [
      +        'item',
      +      ],
      +    },
      +    'should be able to create new array with item when using force=true'
      +  )
      +
      +  qqqq.set('bar[]', 'something else', { force: true })
      +  t.strictSame(
      +    qqqq.toJSON(),
      +    {
      +      arr: {
      +        0: 'a',
      +        1: 'b',
      +        foo: 'foo',
      +      },
      +      bar: [
      +        'item',
      +        'something else',
      +      ],
      +    },
      +    'should be able to append items to arrays when using force=true'
      +  )
      +
      +  const qqqqq = new Queryable({
      +    arr: [
      +      null,
      +    ],
      +  })
      +  qqqqq.set('arr[]', 'b')
      +  t.strictSame(
      +    qqqqq.toJSON(),
      +    {
      +      arr: [
      +        null,
      +        'b',
      +      ],
      +    },
      +    'should be able to append items with empty items'
      +  )
      +  qqqqq.set('arr[0]', 'a')
      +  t.strictSame(
      +    qqqqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +      ],
      +    },
      +    'should be able to replace empty items in an array'
      +  )
      +  qqqqq.set('lorem.ipsum', 3)
      +  t.strictSame(
      +    qqqqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +      ],
      +      lorem: {
      +        ipsum: 3,
      +      },
      +    },
      +    'should be able to replace empty items in an array'
      +  )
      +  t.throws(
      +    () => qqqqq.set('lorem[]', 4),
      +    { code: 'ENOAPPEND' },
      +    'should throw error if using empty square bracket in an non-array item'
      +  )
      +  qqqqq.set('lorem[0]', 3)
      +  t.strictSame(
      +    qqqqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +      ],
      +      lorem: {
      +        0: 3,
      +        ipsum: 3,
      +      },
      +    },
      +    'should be able add indexes as props when finding an object'
      +  )
      +  qqqqq.set('lorem.1', 3)
      +  t.strictSame(
      +    qqqqq.toJSON(),
      +    {
      +      arr: [
      +        'a',
      +        'b',
      +      ],
      +      lorem: {
      +        0: 3,
      +        1: 3,
      +        ipsum: 3,
      +      },
      +    },
      +    'should be able add numeric props to an obj'
      +  )
      +})
      +
      +t.test('delete values', async t => {
      +  const q = new Queryable({
      +    foo: {
      +      bar: {
      +        lorem: 'lorem',
      +      },
      +    },
      +  })
      +  q.delete('foo.bar.lorem')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        bar: {},
      +      },
      +    },
      +    'should delete queried item'
      +  )
      +  q.delete('foo')
      +  t.strictSame(
      +    q.toJSON(),
      +    {},
      +    'should delete nested items'
      +  )
      +  q.set('foo.a.b.c[0]', 'value')
      +  q.delete('foo.a.b.c[0]')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        a: {
      +          b: {
      +            c: [],
      +          },
      +        },
      +      },
      +    },
      +    'should delete array item'
      +  )
      +  // creates an array that has an implicit empty first item
      +  q.set('foo.a.b.c[1][0].foo.bar[0][0]', 'value')
      +  q.delete('foo.a.b.c[1]')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      foo: {
      +        a: {
      +          b: {
      +            c: [null],
      +          },
      +        },
      +      },
      +    },
      +    'should delete array item'
      +  )
      +})
      +
      +t.test('logger', async t => {
      +  const q = new Queryable({})
      +  q.set('foo.bar[0].baz', 'baz')
      +  t.strictSame(
      +    inspect(q, { depth: 10 }),
      +    inspect({
      +      foo: {
      +        bar: [
      +          {
      +            baz: 'baz',
      +          },
      +        ],
      +      },
      +    }, { depth: 10 }),
      +    'should retrieve expected data'
      +  )
      +})
      +
      +t.test('bracket lovers', async t => {
      +  const q = new Queryable({})
      +  q.set('[iLoveBrackets]', 'seriously?')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      '[iLoveBrackets]': 'seriously?',
      +    },
      +    'should be able to set top-level props using square brackets notation'
      +  )
      +
      +  t.equal(q.get('[iLoveBrackets]'), 'seriously?',
      +    'should bypass square bracket in top-level properties')
      +
      +  q.set('[0]', '-.-')
      +  t.strictSame(
      +    q.toJSON(),
      +    {
      +      '[iLoveBrackets]': 'seriously?',
      +      '[0]': '-.-',
      +    },
      +    'any top-level item can not be parsed with square bracket notation'
      +  )
      +})