diff --git a/.editorconfig b/.editorconfig index 4a6b8a6375311b..3a416e87aba4db 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,7 @@ indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true +quote_type = single [vcbuild.bat] end_of_line = crlf diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 6c25e775d34a1e..14aed9bfddfdc3 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -24,7 +24,7 @@ jobs: - name: Environment Information run: npx envinfo - name: Lint addon docs - run: NODE=$(which node) make lint-addon-docs + run: NODE=$(command -v node) make lint-addon-docs lint-cpp: runs-on: ubuntu-latest steps: @@ -50,7 +50,7 @@ jobs: - name: Lint docs run: | echo "::add-matcher::.github/workflows/remark-lint-problem-matcher.json" - NODE=$(which node) make lint-md + NODE=$(command -v node) make lint-md lint-js: runs-on: ubuntu-latest steps: @@ -62,7 +62,7 @@ jobs: - name: Environment Information run: npx envinfo - name: Lint JavaScript files - run: NODE=$(which node) make lint-js + run: NODE=$(command -v node) make lint-js lint-py: runs-on: ubuntu-latest steps: @@ -76,7 +76,7 @@ jobs: - name: Lint Python run: | make lint-py-build || true - NODE=$(which node) make lint-py + NODE=$(command -v node) make lint-py lint-codeowners: runs-on: ubuntu-latest diff --git a/.github/workflows/misc.yml b/.github/workflows/misc.yml index 4ee135c5ebc43e..1444dff7262819 100644 --- a/.github/workflows/misc.yml +++ b/.github/workflows/misc.yml @@ -23,7 +23,7 @@ jobs: - name: Environment Information run: npx envinfo - name: Build - run: NODE=$(which node) make doc-only + run: NODE=$(command -v node) make doc-only - uses: actions/upload-artifact@v1 with: name: docs diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index 5c5f2b2a1953b8..08e6e91e8f4fbd 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -25,6 +25,6 @@ jobs: - name: Environment Information run: npx envinfo - name: Build - run: make build-ci -j8 V=1 CONFIG_FLAGS="--error-on-warn --experimental-quic" + run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn --experimental-quic" - name: Test - run: make run-ci -j8 V=1 TEST_CI_ARGS="-p actions" + run: make run-ci -j2 V=1 TEST_CI_ARGS="-p actions" diff --git a/BSDmakefile b/BSDmakefile index b2f36fa28720f1..3994ab9efd9a4d 100644 --- a/BSDmakefile +++ b/BSDmakefile @@ -3,7 +3,7 @@ FLAGS=${.MAKEFLAGS:C/\-J ([0-9]+,?)+//W} all: .DEFAULT .DEFAULT: - @which gmake > /dev/null 2>&1 ||\ + @command -v gmake > /dev/null 2>&1 ||\ (echo "GMake is required for node.js to build.\ Install and try again" && exit 1) @gmake ${.FLAGS} ${.TARGETS} diff --git a/BUILDING.md b/BUILDING.md index 6452e3ebd780fa..1d26ec520a8f7d 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -113,6 +113,7 @@ platforms. This is true regardless of entries in the table below. | Windows | x64, x86 | Windows Server 2012 (not R2) | Experimental | | | Windows | arm64 | >= Windows 10 | Tier 2 (compiling) / Experimental (running) | | | macOS | x64 | >= 10.13 | Tier 1 | | +| macOS | arm64 | >= 11 | Experimental | | | SmartOS | x64 | >= 18 | Tier 2 | | | AIX | ppc64be >=power7 | >= 7.2 TL02 | Tier 2 | | | FreeBSD | x64 | >= 11 | Experimental | Downgraded as of Node.js 12 [7](#fn7) | diff --git a/CHANGELOG.md b/CHANGELOG.md index d3d003ba375792..cbe9ccfd7f5019 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,8 @@ release. -15.2.1
+15.3.0
+15.2.1
15.2.0
15.1.0
15.0.1
diff --git a/Makefile b/Makefile index 7db5b3320f6181..6379f06a2e0b6d 100644 --- a/Makefile +++ b/Makefile @@ -65,8 +65,8 @@ V ?= 0 available-node = \ if [ -x $(PWD)/$(NODE) ] && [ -e $(PWD)/$(NODE) ]; then \ $(PWD)/$(NODE) $(1); \ - elif [ -x `which node` ] && [ -e `which node` ] && [ `which node` ]; then \ - `which node` $(1); \ + elif [ -x `command -v node` ] && [ -e `command -v node` ] && [ `command -v node` ]; then \ + `command -v node` $(1); \ else \ echo "No available node, cannot run \"node $(1)\""; \ exit 1; \ @@ -898,7 +898,7 @@ BINARYNAME=$(TARNAME)-$(PLATFORM)-$(ARCH) endif BINARYTAR=$(BINARYNAME).tar # OSX doesn't have xz installed by default, http://macpkg.sourceforge.net/ -HAS_XZ ?= $(shell which xz > /dev/null 2>&1; [ $$? -eq 0 ] && echo 1 || echo 0) +HAS_XZ ?= $(shell command -v xz > /dev/null 2>&1; [ $$? -eq 0 ] && echo 1 || echo 0) # Supply SKIP_XZ=1 to explicitly skip .tar.xz creation SKIP_XZ ?= 0 XZ = $(shell [ $(HAS_XZ) -eq 1 -a $(SKIP_XZ) -eq 0 ] && echo 1 || echo 0) @@ -1383,7 +1383,7 @@ lint-clean: $(RM) tools/.*lintstamp $(RM) .eslintcache -HAS_DOCKER ?= $(shell which docker > /dev/null 2>&1; [ $$? -eq 0 ] && echo 1 || echo 0) +HAS_DOCKER ?= $(shell command -v docker > /dev/null 2>&1; [ $$? -eq 0 ] && echo 1 || echo 0) ifeq ($(HAS_DOCKER), 1) DOCKER_COMMAND ?= docker run -it -v $(PWD):/node diff --git a/README.md b/README.md index 2d0e58655810a9..b8d5c4c09d2ec9 100644 --- a/README.md +++ b/README.md @@ -402,8 +402,6 @@ For information about the governance of the Node.js project, see **Santiago Gimeno** <santiago.gimeno@gmail.com> * [seishun](https://github.com/seishun) - **Nikolai Vavilov** <vvnicholas@gmail.com> -* [shigeki](https://github.com/shigeki) - -**Shigeki Ohtsu** <ohtsu@ohtsu.org> (he/him) * [shisama](https://github.com/shisama) - **Masashi Hirano** <shisama07@gmail.com> (he/him) * [silverwind](https://github.com/silverwind) - @@ -547,6 +545,8 @@ For information about the governance of the Node.js project, see **Sam Roberts** <vieuxtech@gmail.com> * [sebdeckers](https://github.com/sebdeckers) - **Sebastiaan Deckers** <sebdeckers83@gmail.com> +* [shigeki](https://github.com/shigeki) - +**Shigeki Ohtsu** <ohtsu@ohtsu.org> (he/him) * [stefanmb](https://github.com/stefanmb) - **Stefan Budeanu** <stefan@budeanu.com> * [tellnes](https://github.com/tellnes) - diff --git a/android-configure b/android-configure index a7cb2b9c8b4a78..e3f4a721827e84 100755 --- a/android-configure +++ b/android-configure @@ -50,8 +50,8 @@ esac HOST_OS="linux" HOST_ARCH="x86_64" -export CC_host=$(which gcc) -export CXX_host=$(which g++) +export CC_host=$(command -v gcc) +export CXX_host=$(command -v g++) host_gcc_version=$($CC_host --version | grep gcc | awk '{print $NF}') major=$(echo $host_gcc_version | awk -F . '{print $1}') diff --git a/benchmark/fs/bench-statSync-failure.js b/benchmark/fs/bench-statSync-failure.js new file mode 100644 index 00000000000000..82cb24c09f4af2 --- /dev/null +++ b/benchmark/fs/bench-statSync-failure.js @@ -0,0 +1,28 @@ +'use strict'; + +const common = require('../common'); +const fs = require('fs'); +const path = require('path'); + +const bench = common.createBenchmark(main, { + n: [1e6], + statSyncType: ['throw', 'noThrow'] +}); + + +function main({ n, statSyncType }) { + const arg = path.join(__dirname, 'non.existent'); + + bench.start(); + for (let i = 0; i < n; i++) { + if (statSyncType === 'noThrow') { + fs.statSync(arg, { throwIfNoEntry: false }); + } else { + try { + fs.statSync(arg); + } catch { + } + } + } + bench.end(n); +} diff --git a/benchmark/napi/function_args/binding.cc b/benchmark/napi/function_args/binding.cc index 2c54dd424d405d..078fe0ee3ea767 100644 --- a/benchmark/napi/function_args/binding.cc +++ b/benchmark/napi/function_args/binding.cc @@ -123,7 +123,9 @@ void CallWithArguments(const FunctionCallbackInfo& args) { } } -void Initialize(Local target) { +void Initialize(Local target, + Local module, + void* data) { NODE_SET_METHOD(target, "callWithString", CallWithString); NODE_SET_METHOD(target, "callWithLongString", CallWithString); diff --git a/benchmark/napi/function_call/binding.cc b/benchmark/napi/function_call/binding.cc index 289a94ac3ecc88..570f96f41ec458 100644 --- a/benchmark/napi/function_call/binding.cc +++ b/benchmark/napi/function_call/binding.cc @@ -7,7 +7,9 @@ void Hello(const v8::FunctionCallbackInfo& args) { args.GetReturnValue().Set(c++); } -void Initialize(v8::Local target) { +void Initialize(v8::Local target, + v8::Local module, + void* data) { NODE_SET_METHOD(target, "hello", Hello); } diff --git a/common.gypi b/common.gypi index 4745bb5ac77639..fc74558f2cbffe 100644 --- a/common.gypi +++ b/common.gypi @@ -36,7 +36,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.17', + 'v8_embedder_string': '-node.22', ##### V8 defaults for Node.js ##### diff --git a/configure b/configure index 07581d9c5a4ff1..ca2cd8aa9e6358 100755 --- a/configure +++ b/configure @@ -10,6 +10,7 @@ command -v python3.8 >/dev/null && exec python3.8 "$0" "$@" command -v python3.7 >/dev/null && exec python3.7 "$0" "$@" command -v python3.6 >/dev/null && exec python3.6 "$0" "$@" command -v python3.5 >/dev/null && exec python3.5 "$0" "$@" +command -v python3 >/dev/null && exec python3 "$0" "$@" command -v python2.7 >/dev/null && exec python2.7 "$0" "$@" exec python "$0" "$@" ''' "$0" "$@" diff --git a/configure.py b/configure.py index eb78598d9d32f0..50994c8c2772e2 100755 --- a/configure.py +++ b/configure.py @@ -3,7 +3,7 @@ import json import sys import errno -import optparse +import argparse import os import pipes import pprint @@ -41,7 +41,7 @@ from gyp_node import run_gyp # parse our options -parser = optparse.OptionParser() +parser = argparse.ArgumentParser() valid_os = ('win', 'mac', 'solaris', 'freebsd', 'openbsd', 'linux', 'android', 'aix', 'cloudabi') @@ -57,113 +57,125 @@ icu_versions = json.load(f) # create option groups -shared_optgroup = optparse.OptionGroup(parser, "Shared libraries", +shared_optgroup = parser.add_argument_group("Shared libraries", "Flags that allows you to control whether you want to build against " "built-in dependencies or its shared representations. If necessary, " "provide multiple libraries with comma.") -intl_optgroup = optparse.OptionGroup(parser, "Internationalization", +intl_optgroup = parser.add_argument_group("Internationalization", "Flags that lets you enable i18n features in Node.js as well as which " "library you want to build against.") -http2_optgroup = optparse.OptionGroup(parser, "HTTP2", +http2_optgroup = parser.add_argument_group("HTTP2", "Flags that allows you to control HTTP2 features in Node.js") # Options should be in alphabetical order but keep --prefix at the top, # that's arguably the one people will be looking for most. -parser.add_option('--prefix', +parser.add_argument('--prefix', action='store', dest='prefix', default='/usr/local', - help='select the install prefix [default: %default]') + help='select the install prefix [default: %(default)s]') -parser.add_option('--coverage', +parser.add_argument('--coverage', action='store_true', dest='coverage', + default=None, help='Build node with code coverage enabled') -parser.add_option('--debug', +parser.add_argument('--debug', action='store_true', dest='debug', + default=None, help='also build debug build') -parser.add_option('--debug-node', +parser.add_argument('--debug-node', action='store_true', dest='debug_node', + default=None, help='build the Node.js part of the binary with debugging symbols') -parser.add_option('--dest-cpu', +parser.add_argument('--dest-cpu', action='store', dest='dest_cpu', choices=valid_arch, help='CPU architecture to build for ({0})'.format(', '.join(valid_arch))) -parser.add_option('--cross-compiling', +parser.add_argument('--cross-compiling', action='store_true', dest='cross_compiling', default=None, help='force build to be considered as cross compiled') -parser.add_option('--no-cross-compiling', +parser.add_argument('--no-cross-compiling', action='store_false', dest='cross_compiling', default=None, help='force build to be considered as NOT cross compiled') -parser.add_option('--dest-os', +parser.add_argument('--dest-os', action='store', dest='dest_os', choices=valid_os, help='operating system to build for ({0})'.format(', '.join(valid_os))) -parser.add_option('--error-on-warn', +parser.add_argument('--error-on-warn', action='store_true', dest='error_on_warn', + default=None, help='Turn compiler warnings into errors for node core sources.') -parser.add_option('--experimental-quic', +parser.add_argument('--experimental-quic', action='store_true', dest='experimental_quic', + default=None, help='enable experimental quic support') -parser.add_option('--gdb', +parser.add_argument('--gdb', action='store_true', dest='gdb', + default=None, help='add gdb support') -parser.add_option('--no-ifaddrs', +parser.add_argument('--no-ifaddrs', action='store_true', dest='no_ifaddrs', + default=None, help='use on deprecated SunOS systems that do not support ifaddrs.h') -parser.add_option("--fully-static", +parser.add_argument("--fully-static", action="store_true", dest="fully_static", + default=None, help="Generate an executable without external dynamic libraries. This " "will not work on OSX when using the default compilation environment") -parser.add_option("--partly-static", +parser.add_argument("--partly-static", action="store_true", dest="partly_static", + default=None, help="Generate an executable with libgcc and libstdc++ libraries. This " "will not work on OSX when using the default compilation environment") -parser.add_option("--enable-pgo-generate", +parser.add_argument("--enable-pgo-generate", action="store_true", dest="enable_pgo_generate", + default=None, help="Enable profiling with pgo of a binary. This feature is only available " "on linux with gcc and g++ 5.4.1 or newer.") -parser.add_option("--enable-pgo-use", +parser.add_argument("--enable-pgo-use", action="store_true", dest="enable_pgo_use", + default=None, help="Enable use of the profile generated with --enable-pgo-generate. This " "feature is only available on linux with gcc and g++ 5.4.1 or newer.") -parser.add_option("--enable-lto", +parser.add_argument("--enable-lto", action="store_true", dest="enable_lto", + default=None, help="Enable compiling with lto of a binary. This feature is only available " "on linux with gcc and g++ 5.4.1 or newer.") -parser.add_option("--link-module", +parser.add_argument("--link-module", action="append", dest="linked_module", help="Path to a JS file to be bundled in the binary as a builtin. " @@ -171,334 +183,355 @@ "e.g. /root/x/y.js will be referenced via require('root/x/y'). " "Can be used multiple times") -parser.add_option('--openssl-default-cipher-list', +parser.add_argument('--openssl-default-cipher-list', action='store', dest='openssl_default_cipher_list', help='Use the specified cipher list as the default cipher list') -parser.add_option("--openssl-no-asm", +parser.add_argument("--openssl-no-asm", action="store_true", dest="openssl_no_asm", + default=None, help="Do not build optimized assembly for OpenSSL") -parser.add_option('--openssl-fips', +parser.add_argument('--openssl-fips', action='store', dest='openssl_fips', help='Build OpenSSL using FIPS canister .o file in supplied folder') -parser.add_option('--openssl-is-fips', +parser.add_argument('--openssl-is-fips', action='store_true', dest='openssl_is_fips', + default=None, help='specifies that the OpenSSL library is FIPS compatible') -parser.add_option('--openssl-use-def-ca-store', +parser.add_argument('--openssl-use-def-ca-store', action='store_true', dest='use_openssl_ca_store', + default=None, help='Use OpenSSL supplied CA store instead of compiled-in Mozilla CA copy.') -parser.add_option('--openssl-system-ca-path', +parser.add_argument('--openssl-system-ca-path', action='store', dest='openssl_system_ca_path', help='Use the specified path to system CA (PEM format) in addition to ' 'the OpenSSL supplied CA store or compiled-in Mozilla CA copy.') -parser.add_option('--experimental-http-parser', +parser.add_argument('--experimental-http-parser', action='store_true', dest='experimental_http_parser', + default=None, help='(no-op)') -shared_optgroup.add_option('--shared-http-parser', +shared_optgroup.add_argument('--shared-http-parser', action='store_true', dest='shared_http_parser', + default=None, help='link to a shared http_parser DLL instead of static linking') -shared_optgroup.add_option('--shared-http-parser-includes', +shared_optgroup.add_argument('--shared-http-parser-includes', action='store', dest='shared_http_parser_includes', help='directory containing http_parser header files') -shared_optgroup.add_option('--shared-http-parser-libname', +shared_optgroup.add_argument('--shared-http-parser-libname', action='store', dest='shared_http_parser_libname', default='http_parser', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-http-parser-libpath', +shared_optgroup.add_argument('--shared-http-parser-libpath', action='store', dest='shared_http_parser_libpath', help='a directory to search for the shared http_parser DLL') -shared_optgroup.add_option('--shared-libuv', +shared_optgroup.add_argument('--shared-libuv', action='store_true', dest='shared_libuv', + default=None, help='link to a shared libuv DLL instead of static linking') -shared_optgroup.add_option('--shared-libuv-includes', +shared_optgroup.add_argument('--shared-libuv-includes', action='store', dest='shared_libuv_includes', help='directory containing libuv header files') -shared_optgroup.add_option('--shared-libuv-libname', +shared_optgroup.add_argument('--shared-libuv-libname', action='store', dest='shared_libuv_libname', default='uv', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-libuv-libpath', +shared_optgroup.add_argument('--shared-libuv-libpath', action='store', dest='shared_libuv_libpath', help='a directory to search for the shared libuv DLL') -shared_optgroup.add_option('--shared-nghttp2', +shared_optgroup.add_argument('--shared-nghttp2', action='store_true', dest='shared_nghttp2', + default=None, help='link to a shared nghttp2 DLL instead of static linking') -shared_optgroup.add_option('--shared-nghttp2-includes', +shared_optgroup.add_argument('--shared-nghttp2-includes', action='store', dest='shared_nghttp2_includes', help='directory containing nghttp2 header files') -shared_optgroup.add_option('--shared-nghttp2-libname', +shared_optgroup.add_argument('--shared-nghttp2-libname', action='store', dest='shared_nghttp2_libname', default='nghttp2', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-nghttp2-libpath', +shared_optgroup.add_argument('--shared-nghttp2-libpath', action='store', dest='shared_nghttp2_libpath', help='a directory to search for the shared nghttp2 DLLs') -shared_optgroup.add_option('--shared-ngtcp2', +shared_optgroup.add_argument('--shared-ngtcp2', action='store_true', dest='shared_ngtcp2', + default=None, help='link to a shared ngtcp2 DLL instead of static linking') -shared_optgroup.add_option('--shared-ngtcp2-includes', +shared_optgroup.add_argument('--shared-ngtcp2-includes', action='store', dest='shared_ngtcp2_includes', help='directory containing ngtcp2 header files') -shared_optgroup.add_option('--shared-ngtcp2-libname', +shared_optgroup.add_argument('--shared-ngtcp2-libname', action='store', dest='shared_ngtcp2_libname', default='ngtcp2', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-ngtcp2-libpath', +shared_optgroup.add_argument('--shared-ngtcp2-libpath', action='store', dest='shared_ngtcp2_libpath', help='a directory to search for the shared ngtcp2 DLLs') -shared_optgroup.add_option('--shared-nghttp3', +shared_optgroup.add_argument('--shared-nghttp3', action='store_true', dest='shared_nghttp3', + default=None, help='link to a shared nghttp3 DLL instead of static linking') -shared_optgroup.add_option('--shared-nghttp3-includes', +shared_optgroup.add_argument('--shared-nghttp3-includes', action='store', dest='shared_nghttp3_includes', help='directory containing nghttp3 header files') -shared_optgroup.add_option('--shared-nghttp3-libname', +shared_optgroup.add_argument('--shared-nghttp3-libname', action='store', dest='shared_nghttp3_libname', default='nghttp3', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-nghttp3-libpath', +shared_optgroup.add_argument('--shared-nghttp3-libpath', action='store', dest='shared_nghttp3_libpath', help='a directory to search for the shared nghttp3 DLLs') -shared_optgroup.add_option('--shared-openssl', +shared_optgroup.add_argument('--shared-openssl', action='store_true', dest='shared_openssl', + default=None, help='link to a shared OpenSSl DLL instead of static linking') -shared_optgroup.add_option('--shared-openssl-includes', +shared_optgroup.add_argument('--shared-openssl-includes', action='store', dest='shared_openssl_includes', help='directory containing OpenSSL header files') -shared_optgroup.add_option('--shared-openssl-libname', +shared_optgroup.add_argument('--shared-openssl-libname', action='store', dest='shared_openssl_libname', default='crypto,ssl', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-openssl-libpath', +shared_optgroup.add_argument('--shared-openssl-libpath', action='store', dest='shared_openssl_libpath', help='a directory to search for the shared OpenSSL DLLs') -shared_optgroup.add_option('--shared-zlib', +shared_optgroup.add_argument('--shared-zlib', action='store_true', dest='shared_zlib', + default=None, help='link to a shared zlib DLL instead of static linking') -shared_optgroup.add_option('--shared-zlib-includes', +shared_optgroup.add_argument('--shared-zlib-includes', action='store', dest='shared_zlib_includes', help='directory containing zlib header files') -shared_optgroup.add_option('--shared-zlib-libname', +shared_optgroup.add_argument('--shared-zlib-libname', action='store', dest='shared_zlib_libname', default='z', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-zlib-libpath', +shared_optgroup.add_argument('--shared-zlib-libpath', action='store', dest='shared_zlib_libpath', help='a directory to search for the shared zlib DLL') -shared_optgroup.add_option('--shared-brotli', +shared_optgroup.add_argument('--shared-brotli', action='store_true', dest='shared_brotli', + default=None, help='link to a shared brotli DLL instead of static linking') -shared_optgroup.add_option('--shared-brotli-includes', +shared_optgroup.add_argument('--shared-brotli-includes', action='store', dest='shared_brotli_includes', help='directory containing brotli header files') -shared_optgroup.add_option('--shared-brotli-libname', +shared_optgroup.add_argument('--shared-brotli-libname', action='store', dest='shared_brotli_libname', default='brotlidec,brotlienc', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-brotli-libpath', +shared_optgroup.add_argument('--shared-brotli-libpath', action='store', dest='shared_brotli_libpath', help='a directory to search for the shared brotli DLL') -shared_optgroup.add_option('--shared-cares', +shared_optgroup.add_argument('--shared-cares', action='store_true', dest='shared_cares', + default=None, help='link to a shared cares DLL instead of static linking') -shared_optgroup.add_option('--shared-cares-includes', +shared_optgroup.add_argument('--shared-cares-includes', action='store', dest='shared_cares_includes', help='directory containing cares header files') -shared_optgroup.add_option('--shared-cares-libname', +shared_optgroup.add_argument('--shared-cares-libname', action='store', dest='shared_cares_libname', default='cares', - help='alternative lib name to link to [default: %default]') + help='alternative lib name to link to [default: %(default)s]') -shared_optgroup.add_option('--shared-cares-libpath', +shared_optgroup.add_argument('--shared-cares-libpath', action='store', dest='shared_cares_libpath', help='a directory to search for the shared cares DLL') -parser.add_option_group(shared_optgroup) +parser.add_argument_group(shared_optgroup) -parser.add_option('--systemtap-includes', +parser.add_argument('--systemtap-includes', action='store', dest='systemtap_includes', help='directory containing systemtap header files') -parser.add_option('--tag', +parser.add_argument('--tag', action='store', dest='tag', help='custom build tag') -parser.add_option('--release-urlbase', +parser.add_argument('--release-urlbase', action='store', dest='release_urlbase', help='Provide a custom URL prefix for the `process.release` properties ' '`sourceUrl` and `headersUrl`. When compiling a release build, this ' 'will default to https://nodejs.org/download/release/') -parser.add_option('--enable-d8', +parser.add_argument('--enable-d8', action='store_true', dest='enable_d8', - help=optparse.SUPPRESS_HELP) # Unsupported, undocumented. + default=None, + help=argparse.SUPPRESS) # Unsupported, undocumented. -parser.add_option('--enable-trace-maps', +parser.add_argument('--enable-trace-maps', action='store_true', dest='trace_maps', + default=None, help='Enable the --trace-maps flag in V8 (use at your own risk)') -parser.add_option('--experimental-enable-pointer-compression', +parser.add_argument('--experimental-enable-pointer-compression', action='store_true', dest='enable_pointer_compression', + default=None, help='[Experimental] Enable V8 pointer compression (limits max heap to 4GB and breaks ABI compatibility)') -parser.add_option('--v8-options', +parser.add_argument('--v8-options', action='store', dest='v8_options', help='v8 options to pass, see `node --v8-options` for examples.') -parser.add_option('--with-ossfuzz', +parser.add_argument('--with-ossfuzz', action='store_true', dest='ossfuzz', + default=None, help='Enables building of fuzzers. This command should be run in an OSS-Fuzz Docker image.') -parser.add_option('--with-arm-float-abi', +parser.add_argument('--with-arm-float-abi', action='store', dest='arm_float_abi', choices=valid_arm_float_abi, help='specifies which floating-point ABI to use ({0}).'.format( ', '.join(valid_arm_float_abi))) -parser.add_option('--with-arm-fpu', +parser.add_argument('--with-arm-fpu', action='store', dest='arm_fpu', choices=valid_arm_fpu, - help='ARM FPU mode ({0}) [default: %default]'.format( + help='ARM FPU mode ({0}) [default: %(default)s]'.format( ', '.join(valid_arm_fpu))) -parser.add_option('--with-mips-arch-variant', +parser.add_argument('--with-mips-arch-variant', action='store', dest='mips_arch_variant', default='r2', choices=valid_mips_arch, - help='MIPS arch variant ({0}) [default: %default]'.format( + help='MIPS arch variant ({0}) [default: %(default)s]'.format( ', '.join(valid_mips_arch))) -parser.add_option('--with-mips-fpu-mode', +parser.add_argument('--with-mips-fpu-mode', action='store', dest='mips_fpu_mode', default='fp32', choices=valid_mips_fpu, - help='MIPS FPU mode ({0}) [default: %default]'.format( + help='MIPS FPU mode ({0}) [default: %(default)s]'.format( ', '.join(valid_mips_fpu))) -parser.add_option('--with-mips-float-abi', +parser.add_argument('--with-mips-float-abi', action='store', dest='mips_float_abi', default='hard', choices=valid_mips_float_abi, - help='MIPS floating-point ABI ({0}) [default: %default]'.format( + help='MIPS floating-point ABI ({0}) [default: %(default)s]'.format( ', '.join(valid_mips_float_abi))) -parser.add_option('--with-dtrace', +parser.add_argument('--with-dtrace', action='store_true', dest='with_dtrace', + default=None, help='build with DTrace (default is true on sunos and darwin)') -parser.add_option('--with-etw', +parser.add_argument('--with-etw', action='store_true', dest='with_etw', + default=None, help='build with ETW (default is true on Windows)') -parser.add_option('--use-largepages', +parser.add_argument('--use-largepages', action='store_true', dest='node_use_large_pages', + default=None, help='This option has no effect. --use-largepages is now a runtime option.') -parser.add_option('--use-largepages-script-lld', +parser.add_argument('--use-largepages-script-lld', action='store_true', dest='node_use_large_pages_script_lld', + default=None, help='This option has no effect. --use-largepages is now a runtime option.') -parser.add_option('--use-section-ordering-file', +parser.add_argument('--use-section-ordering-file', action='store', dest='node_section_ordering_info', default='', @@ -506,42 +539,42 @@ 'Node.js be linked using the gold linker. The gold linker must have ' + 'version 1.2 or greater.') -intl_optgroup.add_option('--with-intl', +intl_optgroup.add_argument('--with-intl', action='store', dest='with_intl', default='full-icu', choices=valid_intl_modes, - help='Intl mode (valid choices: {0}) [default: %default]'.format( + help='Intl mode (valid choices: {0}) [default: %(default)s]'.format( ', '.join(valid_intl_modes))) -intl_optgroup.add_option('--without-intl', +intl_optgroup.add_argument('--without-intl', action='store_const', dest='with_intl', const='none', help='Disable Intl, same as --with-intl=none (disables inspector)') -intl_optgroup.add_option('--with-icu-path', +intl_optgroup.add_argument('--with-icu-path', action='store', dest='with_icu_path', help='Path to icu.gyp (ICU i18n, Chromium version only.)') icu_default_locales='root,en' -intl_optgroup.add_option('--with-icu-locales', +intl_optgroup.add_argument('--with-icu-locales', action='store', dest='with_icu_locales', default=icu_default_locales, help='Comma-separated list of locales for "small-icu". "root" is assumed. ' - '[default: %default]') + '[default: %(default)s]') -intl_optgroup.add_option('--with-icu-source', +intl_optgroup.add_argument('--with-icu-source', action='store', dest='with_icu_source', help='Intl mode: optional local path to icu/ dir, or path/URL of ' 'the icu4c source archive. ' 'v%d.x or later recommended.' % icu_versions['minimum_icu']) -intl_optgroup.add_option('--with-icu-default-data-dir', +intl_optgroup.add_argument('--with-icu-default-data-dir', action='store', dest='with_icu_default_data_dir', help='Path to the icuXXdt{lb}.dat file. If unspecified, ICU data will ' @@ -549,159 +582,179 @@ '--icu-data-dir runtime argument is used. This option has effect ' 'only when Node.js is built with --with-intl=small-icu.') -parser.add_option('--with-ltcg', +parser.add_argument('--with-ltcg', action='store_true', dest='with_ltcg', + default=None, help='Use Link Time Code Generation. This feature is only available on Windows.') -parser.add_option('--without-node-snapshot', +parser.add_argument('--without-node-snapshot', action='store_true', dest='without_node_snapshot', + default=None, help='Turn off V8 snapshot integration. Currently experimental.') -parser.add_option('--without-node-code-cache', +parser.add_argument('--without-node-code-cache', action='store_true', dest='without_node_code_cache', + default=None, help='Turn off V8 Code cache integration.') -intl_optgroup.add_option('--download', +intl_optgroup.add_argument('--download', action='store', dest='download_list', help=nodedownload.help()) -intl_optgroup.add_option('--download-path', +intl_optgroup.add_argument('--download-path', action='store', dest='download_path', default='deps', - help='Download directory [default: %default]') + help='Download directory [default: %(default)s]') -parser.add_option_group(intl_optgroup) +parser.add_argument_group(intl_optgroup) -parser.add_option('--debug-lib', +parser.add_argument('--debug-lib', action='store_true', dest='node_debug_lib', + default=None, help='build lib with DCHECK macros') -http2_optgroup.add_option('--debug-nghttp2', +http2_optgroup.add_argument('--debug-nghttp2', action='store_true', dest='debug_nghttp2', + default=None, help='build nghttp2 with DEBUGBUILD (default is false)') -parser.add_option_group(http2_optgroup) +parser.add_argument_group(http2_optgroup) -parser.add_option('--without-dtrace', +parser.add_argument('--without-dtrace', action='store_true', dest='without_dtrace', + default=None, help='build without DTrace') -parser.add_option('--without-etw', +parser.add_argument('--without-etw', action='store_true', dest='without_etw', + default=None, help='build without ETW') -parser.add_option('--without-npm', +parser.add_argument('--without-npm', action='store_true', dest='without_npm', + default=None, help='do not install the bundled npm (package manager)') # Dummy option for backwards compatibility -parser.add_option('--without-report', +parser.add_argument('--without-report', action='store_true', dest='unused_without_report', - help=optparse.SUPPRESS_HELP) + default=None, + help=argparse.SUPPRESS) -parser.add_option('--with-snapshot', +parser.add_argument('--with-snapshot', action='store_true', dest='unused_with_snapshot', - help=optparse.SUPPRESS_HELP) + default=None, + help=argparse.SUPPRESS) -parser.add_option('--without-snapshot', +parser.add_argument('--without-snapshot', action='store_true', dest='unused_without_snapshot', - help=optparse.SUPPRESS_HELP) + default=None, + help=argparse.SUPPRESS) -parser.add_option('--without-siphash', +parser.add_argument('--without-siphash', action='store_true', dest='without_siphash', - help=optparse.SUPPRESS_HELP) + default=None, + help=argparse.SUPPRESS) # End dummy list. -parser.add_option('--without-ssl', +parser.add_argument('--without-ssl', action='store_true', dest='without_ssl', + default=None, help='build without SSL (disables crypto, https, inspector, etc.)') -parser.add_option('--without-node-options', +parser.add_argument('--without-node-options', action='store_true', dest='without_node_options', + default=None, help='build without NODE_OPTIONS support') -parser.add_option('--ninja', +parser.add_argument('--ninja', action='store_true', dest='use_ninja', + default=None, help='generate build files for use with Ninja') -parser.add_option('--enable-asan', +parser.add_argument('--enable-asan', action='store_true', dest='enable_asan', + default=None, help='compile for Address Sanitizer to find memory bugs') -parser.add_option('--enable-static', +parser.add_argument('--enable-static', action='store_true', dest='enable_static', + default=None, help='build as static library') -parser.add_option('--no-browser-globals', +parser.add_argument('--no-browser-globals', action='store_true', dest='no_browser_globals', + default=None, help='do not export browser globals like setTimeout, console, etc. ' + '(This mode is not officially supported for regular applications)') -parser.add_option('--without-inspector', +parser.add_argument('--without-inspector', action='store_true', dest='without_inspector', + default=None, help='disable the V8 inspector protocol') -parser.add_option('--shared', +parser.add_argument('--shared', action='store_true', dest='shared', + default=None, help='compile shared library for embedding node in another project. ' + '(This mode is not officially supported for regular applications)') -parser.add_option('--without-v8-platform', +parser.add_argument('--without-v8-platform', action='store_true', dest='without_v8_platform', default=False, help='do not initialize v8 platform during node.js startup. ' + '(This mode is not officially supported for regular applications)') -parser.add_option('--without-bundled-v8', +parser.add_argument('--without-bundled-v8', action='store_true', dest='without_bundled_v8', default=False, help='do not use V8 includes from the bundled deps folder. ' + '(This mode is not officially supported for regular applications)') -parser.add_option('--verbose', +parser.add_argument('--verbose', action='store_true', dest='verbose', default=False, help='get more output from this script') -parser.add_option('--v8-non-optimized-debug', +parser.add_argument('--v8-non-optimized-debug', action='store_true', dest='v8_non_optimized_debug', default=False, help='compile V8 with minimal optimizations and with runtime checks') -parser.add_option('--v8-with-dchecks', +parser.add_argument('--v8-with-dchecks', action='store_true', dest='v8_with_dchecks', default=False, help='compile V8 with debug checks and runtime debugging features enabled') -parser.add_option('--v8-lite-mode', +parser.add_argument('--v8-lite-mode', action='store_true', dest='v8_lite_mode', default=False, @@ -709,25 +762,26 @@ 'memory footprint, but also implies no just-in-time compilation ' + 'support, thus much slower execution)') -parser.add_option('--v8-enable-object-print', +parser.add_argument('--v8-enable-object-print', action='store_true', dest='v8_enable_object_print', default=True, help='compile V8 with auxiliar functions for native debuggers') -parser.add_option('--node-builtin-modules-path', +parser.add_argument('--node-builtin-modules-path', action='store', dest='node_builtin_modules_path', default=False, help='node will load builtin modules from disk instead of from binary') # Create compile_commands.json in out/Debug and out/Release. -parser.add_option('-C', +parser.add_argument('-C', action='store_true', dest='compile_commands_json', - help=optparse.SUPPRESS_HELP) + default=None, + help=argparse.SUPPRESS) -(options, args) = parser.parse_args() +(options, args) = parser.parse_known_args() # Expand ~ in the install prefix now, it gets written to multiple files. options.prefix = os.path.expanduser(options.prefix or '') diff --git a/deps/npm/.eslintrc.json b/deps/npm/.eslintrc.json index 6232a8f82187ff..139716eefd85a0 100644 --- a/deps/npm/.eslintrc.json +++ b/deps/npm/.eslintrc.json @@ -133,7 +133,7 @@ "no-shadow-restricted-names": "error", "no-sparse-arrays": "error", "no-tabs": "error", - "no-template-curly-in-string": "error", + "no-template-curly-in-string": "off", "no-this-before-super": "error", "no-throw-literal": "off", "no-trailing-spaces": "error", diff --git a/deps/npm/AUTHORS b/deps/npm/AUTHORS index 4209517f2a0ff8..6dfd49d38bef4e 100644 --- a/deps/npm/AUTHORS +++ b/deps/npm/AUTHORS @@ -730,3 +730,8 @@ Michele Azzolari foxxyz Dr Jan Tojnar +Jason Attwood +Vlad GURDIGA +Sébastien Puech +Jannis Hell +Hollow Man diff --git a/deps/npm/CHANGELOG.md b/deps/npm/CHANGELOG.md index 49d44ab10a09e0..6ac63cfba3336d 100644 --- a/deps/npm/CHANGELOG.md +++ b/deps/npm/CHANGELOG.md @@ -1,3 +1,181 @@ +## 7.0.14 (2020-11-23) + +### DEPENDENCIES +* [`09d21ab90`](https://github.com/npm/cli/commit/09d21ab903dcfebdfd446b8b29ad46c425b6510e) + `@npmcli/run-script@1.8.1` + - fix a regression in how scripts are escaped + +## 7.0.13 (2020-11-20) + +### BUG FIXES +* [`5fc56b6db`](https://github.com/npm/cli/commit/5fc56b6dbcc7d7d1463a761abb67d2fc16ad3657) + [npm/statusboard#174](https://github.com/npm/statusboard/issues/174) + [#2204](https://github.com/npm/cli/issues/2204) + fix npm unstar command + ([@ruyadorno](https://github.com/ruyadorno)) +* [`7842b4d4d`](https://github.com/npm/cli/commit/7842b4d4dca1e076b0d26d554f9dce67484cd7be) + [npm/statusboard#182](https://github.com/npm/statusboard/issues/182) + [#2205](https://github.com/npm/cli/issues/2205) + fix npm version usage output + ([@ruyadorno](https://github.com/ruyadorno)) +* [`a0adbf9f8`](https://github.com/npm/cli/commit/a0adbf9f8f77531fcf81ae31bbc7102698765ee3) + [#2206](https://github.com/npm/cli/issues/2206) + [#2213](https://github.com/npm/cli/issues/2213) + fix: fix flatOptions usage in npm init + ([@ruyadorno](https://github.com/ruyadorno)) + +### DEPENDENCIES + +* [`3daaf000a`](https://github.com/npm/cli/commit/3daaf000aee0ba81af855977d7011850e79099e6) + `@npmcli/arborist@1.0.12` + - fixes some windows specific bugs in how paths are handled and compared + +### DOCUMENTATION + +* [`084a7b6ad`](https://github.com/npm/cli/commit/084a7b6ad6eaf9f2d92eb05da93e745f5357cce2) + [#2210](https://github.com/npm/cli/issues/2210) + docs: Fix typo + ([@HollowMan6](https://github.com/HollowMan6)) + +## 7.0.12 (2020-11-17) + +### BUG FIXES + +* [`7b89576bd`](https://github.com/npm/cli/commit/7b89576bd1fa557a312a841afa66b895558d1b12) + [#2174](https://github.com/npm/cli/issues/2174) + fix running empty scripts with `npm run-script` + ([@nlf](https://github.com/nlf)) +* [`bc9afb195`](https://github.com/npm/cli/commit/bc9afb195f5aad7c06bc96049c0f00dc8e752dee) + [#2002](https://github.com/npm/cli/issues/2002) + [#2184](https://github.com/npm/cli/issues/2184) + Preserve builtin conf when installing npm globally + ([@isaacs](https://github.com/isaacs)) + +### DEPENDENCIES + +* [`b74c05d88`](https://github.com/npm/cli/commit/b74c05d88dc48fabef031ea66ffaa4e548845655) + `@npmcli/run-script@1.8.0` + * fix windows command-line argument escaping + +### DOCUMENTATION + +* [`4e522fdc9`](https://github.com/npm/cli/commit/4e522fdc917bc85af2ca8ff7669a0178e2f35123) + [#2179](https://github.com/npm/cli/issues/2179) + remove mention to --parseable option from `npm audit` docs + ([@Primajin](https://github.com/Primajin)) + +## 7.0.11 (2020-11-13) + +### DEPENDENCIES + +* [`629a667a9`](https://github.com/npm/cli/commit/629a667a9b30b0b870075da965606979622a5e2e) + `eslint@7.13.0` +* [`de9891bd2`](https://github.com/npm/cli/commit/de9891bd2a16fe890ff5cfb140c7b1209aeac0de) + `eslint-plugin-standard@4.1.0` +* [`c3e7aa31c`](https://github.com/npm/cli/commit/c3e7aa31c565dfe21cd1f55a8433bfbcf58aa289) + [#2123](https://github.com/npm/cli/issues/2123) + [#1957](https://github.com/npm/cli/issues/1957) + `@npmcli/arborist@1.0.11` + +### BUG FIXES + +* [`a8aa38513`](https://github.com/npm/cli/commit/a8aa38513ad5c4ad44e6bb3e1499bfc40c31e213) + [#2134](https://github.com/npm/cli/issues/2134) + [#2156](https://github.com/npm/cli/issues/2156) + Fix `cannot read property length of undefined` in `ERESOLVE` explanation code + ([@isaacs](https://github.com/isaacs)) +* [`1dbf0f9bb`](https://github.com/npm/cli/commit/1dbf0f9bb26ba70f4c6d0a807701d7652c31d7d4) + [#2150](https://github.com/npm/cli/issues/2150) + [#2155](https://github.com/npm/cli/issues/2155) + send json errors to stderr, not stdout + ([@isaacs](https://github.com/isaacs)) +* [`fd1d7a21b`](https://github.com/npm/cli/commit/fd1d7a21b247bb35d112c51ff8d8a06fd83c8b44) + [#1927](https://github.com/npm/cli/issues/1927) + [#2154](https://github.com/npm/cli/issues/2154) + Set process.title a bit more usefully + ([@isaacs](https://github.com/isaacs)) +* [`2a80c67ef`](https://github.com/npm/cli/commit/2a80c67ef8c12c3d9d254f5be6293a6461067d99) + [#2008](https://github.com/npm/cli/issues/2008) + [#2153](https://github.com/npm/cli/issues/2153) + Support legacy auth tokens for registries that use them + ([@ruyadorno](https://github.com/ruyadorno)) +* [`786e36404`](https://github.com/npm/cli/commit/786e36404068fd51657ddac766e066a98754edbf) + [#2017](https://github.com/npm/cli/issues/2017) + [#2159](https://github.com/npm/cli/issues/2159) + pass all options to Arborist for `npm ci` + ([@darcyclarke](https://github.com/darcyclarke)) +* [`b47ada7d1`](https://github.com/npm/cli/commit/b47ada7d1623e9ee586ee0cf781ee3ac5ea3c223) + [#2161](https://github.com/npm/cli/issues/2161) + fixed typo + ([@scarabedore](https://github.com/scarabedore)) + +## 7.0.10 (2020-11-10) + +### DOCUMENTATION + +* [`e48badb03`](https://github.com/npm/cli/commit/e48badb03058286a557584d7319db4143049cc6b) + [#2148](https://github.com/npm/cli/issues/2148) + Fix link in documentation + ([@gurdiga](https://github.com/gurdiga)) + +### BUG FIXES + +* [`8edbbdc70`](https://github.com/npm/cli/commit/8edbbdc706694fa32f52d0991c76ae9f207b7bbc) + [#1972](https://github.com/npm/cli/issues/1972) + Support exec auto pick bin when all bin is alias + ([@dr-js](https://github.com/dr-js)) + +### DEPENDENCIES + +* [`04a3e8c10`](https://github.com/npm/cli/commit/04a3e8c10c3f38e1c7a35976d77c2929bdc39868) + [#1962](https://github.com/npm/cli/issues/1962) + `@npmcli/arborist@1.0.10`: + * prevent self-assignment of parent/fsParent + * Support update options in global package space + +## 7.0.9 (2020-11-06) + +### BUG FIXES + +* [`96a0d2802`](https://github.com/npm/cli/commit/96a0d2802d3e619c6ea47290f5c460edfe94070a) + default the 'start' script when server.js present + ([@isaacs](https://github.com/isaacs)) +* [`7716e423e`](https://github.com/npm/cli/commit/7716e423ee92a81730c0dfe5b9ecb4bb41a3f947) + [#2075](https://github.com/npm/cli/issues/2075) + [#2071](https://github.com/npm/cli/issues/2071) print the registry when + using 'npm login' ([@Wicked7000](https://github.com/Wicked7000)) +* [`7046fe10c`](https://github.com/npm/cli/commit/7046fe10c5035ac57246a31ca8a6b09e3f5562bf) + [#2122](https://github.com/npm/cli/issues/2122) tests for `npm cache` + command ([@nlf](https://github.com/nlf)) + +### DEPENDENCIES + +* [`74325f53b`](https://github.com/npm/cli/commit/74325f53b9d813b0e42203c037189418fad2f64a) + [#2124](https://github.com/npm/cli/issues/2124) + `@npmcli/run-script@1.7.5`: + * Export the `isServerPackage` method + * Proxy signals to and from foreground child processes +* [`0e58e6f6b`](https://github.com/npm/cli/commit/0e58e6f6b8f0cd62294642a502c17561aaf46553) + [#1984](https://github.com/npm/cli/issues/1984) + [#2079](https://github.com/npm/cli/issues/2079) + [#1923](https://github.com/npm/cli/issues/1923) + [#606](https://github.com/npm/cli/issues/606) + [#2031](https://github.com/npm/cli/issues/2031) `@npmcli/arborist@1.0.9`: + * Process deps for all link nodes + * Use junctions instead of symlinks + * Use @npmcli/move-file instead of fs.rename +* [`1dad328a1`](https://github.com/npm/cli/commit/1dad328a17d93def7799545596b4eba9833b35aa) + [#1865](https://github.com/npm/cli/issues/1865) + [#2106](https://github.com/npm/cli/issues/2106) + [#2084](https://github.com/npm/cli/issues/2084) `pacote@11.1.13`: + * Properly set the installation command for `prepare` scripts when + installing git/dir deps +* [`e090d706c`](https://github.com/npm/cli/commit/e090d706ca637d4df96d28bff1660590aa3f3b62) + [#2097](https://github.com/npm/cli/issues/2097) `libnpmversion@1.0.7`: + * Do not crash when the package.json file lacks a 'version' field +* [`8fa541a10`](https://github.com/npm/cli/commit/8fa541a10dbdc09376175db7a378cc9b33e8b17b) + `cmark-gfm@0.8.4` + ## 7.0.8 (2020-11-03) ### DOCUMENTATION diff --git a/deps/npm/docs/content/commands/npm-audit.md b/deps/npm/docs/content/commands/npm-audit.md index 645ab87b157e17..2c0a8f58047ca2 100644 --- a/deps/npm/docs/content/commands/npm-audit.md +++ b/deps/npm/docs/content/commands/npm-audit.md @@ -7,8 +7,8 @@ description: Run a security audit ### Synopsis ```bash -npm audit [--json|--parseable|--audit-level=(low|moderate|high|critical)] -npm audit fix [--force|--package-lock-only|--dry-run] +npm audit [--json] [--production] [--audit-level=(low|moderate|high|critical)] +npm audit fix [--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)] common options: [--production] [--only=(dev|prod)] ``` diff --git a/deps/npm/docs/content/commands/npm-exec.md b/deps/npm/docs/content/commands/npm-exec.md index 38fb1bf25af4be..c9de9933be3a55 100644 --- a/deps/npm/docs/content/commands/npm-exec.md +++ b/deps/npm/docs/content/commands/npm-exec.md @@ -54,7 +54,8 @@ the package specifier provided as the first positional argument according to the following heuristic: - If the package has a single entry in its `bin` field in `package.json`, - then that command will be used. + or if all entries are aliases of the same command, then that command + will be used. - If the package has multiple `bin` entries, and one of them matches the unscoped portion of the `name` field, then that command will be used. - If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/content/commands/npm-explain.md b/deps/npm/docs/content/commands/npm-explain.md index a68bd7d1c252f9..fe7485d61acd8b 100644 --- a/deps/npm/docs/content/commands/npm-explain.md +++ b/deps/npm/docs/content/commands/npm-explain.md @@ -56,7 +56,7 @@ node_modules/nyc/node_modules/find-up #### json * Default: false -* Type: Bolean +* Type: Boolean Show information in JSON format. diff --git a/deps/npm/docs/content/commands/npx.md b/deps/npm/docs/content/commands/npx.md index a5522c66e85aa4..625ac3d8cd6025 100644 --- a/deps/npm/docs/content/commands/npx.md +++ b/deps/npm/docs/content/commands/npx.md @@ -8,9 +8,9 @@ description: Run a command from a local or remote npm package ```bash npm exec -- [@] [args...] -npm exec -p [@] -- [args...] +npm exec --package=[@] -- [args...] npm exec -c ' [args...]' -npm exec -p foo -c ' [args...]' +npm exec --package=foo -c ' [args...]' npx [@] [args...] npx -p [@] [args...] @@ -19,7 +19,8 @@ npx -p [@] -c ' [args...]' alias: npm x, npx --p --package= (may be specified multiple times) +--package= (may be specified multiple times) +-p is a shorthand for --package only when using npx executable -c --call= (may not be mixed with positional arguments) ``` @@ -29,9 +30,9 @@ This command allows you to run an arbitrary command from an npm package (either one installed locally, or fetched remotely), in a similar context as running it via `npm run`. -Whatever packages are specified by the `--package` or `-p` option will be +Whatever packages are specified by the `--package` option will be provided in the `PATH` of the executed command, along with any locally -installed package executables. The `--package` or `-p` option may be +installed package executables. The `--package` option may be specified multiple times, to execute the supplied command in an environment where all specified packages are available. @@ -47,13 +48,14 @@ only be considered a match if they have the exact same name and version as the local dependency. If no `-c` or `--call` option is provided, then the positional arguments -are used to generate the command string. If no `-p` or `--package` options +are used to generate the command string. If no `--package` options are provided, then npm will attempt to determine the executable name from the package specifier provided as the first positional argument according to the following heuristic: - If the package has a single entry in its `bin` field in `package.json`, - then that command will be used. + or if all entries are aliases of the same command, then that command + will be used. - If the package has multiple `bin` entries, and one of them matches the unscoped portion of the `name` field, then that command will be used. - If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/content/using-npm/developers.md b/deps/npm/docs/content/using-npm/developers.md index d42c759d42cf1e..7e47b76f65aaf2 100644 --- a/deps/npm/docs/content/using-npm/developers.md +++ b/deps/npm/docs/content/using-npm/developers.md @@ -109,7 +109,7 @@ create an empty `.npmignore` file to override it. Like `git`, `npm` looks for `.npmignore` and `.gitignore` files in all subdirectories of your package, not only the root directory. -`.npmignore` files follow the [same pattern rules](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#Ignoring-Files) +`.npmignore` files follow the [same pattern rules](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#_ignoring) as `.gitignore` files: * Blank lines or lines starting with `#` are ignored. diff --git a/deps/npm/docs/content/using-npm/scripts.md b/deps/npm/docs/content/using-npm/scripts.md index f86f9e88bc9ddf..c111aa3f3ab533 100644 --- a/deps/npm/docs/content/using-npm/scripts.md +++ b/deps/npm/docs/content/using-npm/scripts.md @@ -6,7 +6,7 @@ description: How npm handles the "scripts" field ### Description -The `"scripts"` property of of your `package.json` file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running `npm run-script ` or `npm run ` for short. *Pre* and *post* commands with matching names will be run for those as well (e.g. `premyscript`, `myscript`, `postmyscript`). Scripts from dependencies can be run with `npm explore -- npm run `. +The `"scripts"` property of your `package.json` file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running `npm run-script ` or `npm run ` for short. *Pre* and *post* commands with matching names will be run for those as well (e.g. `premyscript`, `myscript`, `postmyscript`). Scripts from dependencies can be run with `npm explore -- npm run `. ### Pre & Post Scripts diff --git a/deps/npm/docs/output/commands/npm-audit.html b/deps/npm/docs/output/commands/npm-audit.html index 4dd59417e82713..4482f6608999f2 100644 --- a/deps/npm/docs/output/commands/npm-audit.html +++ b/deps/npm/docs/output/commands/npm-audit.html @@ -145,8 +145,8 @@

Table of contents

Synopsis

-
npm audit [--json|--parseable|--audit-level=(low|moderate|high|critical)]
-npm audit fix [--force|--package-lock-only|--dry-run]
+
npm audit [--json] [--production] [--audit-level=(low|moderate|high|critical)]
+npm audit fix [--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)]
 
 common options: [--production] [--only=(dev|prod)]
 
diff --git a/deps/npm/docs/output/commands/npm-exec.html b/deps/npm/docs/output/commands/npm-exec.html index 6bd59f7a8ed674..6e50a1cb9af9dd 100644 --- a/deps/npm/docs/output/commands/npm-exec.html +++ b/deps/npm/docs/output/commands/npm-exec.html @@ -186,7 +186,8 @@

Description

to the following heuristic:

  • If the package has a single entry in its bin field in package.json, -then that command will be used.
  • +or if all entries are aliases of the same command, then that command +will be used.
  • If the package has multiple bin entries, and one of them matches the unscoped portion of the name field, then that command will be used.
  • If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/output/commands/npm-explain.html b/deps/npm/docs/output/commands/npm-explain.html index 009332da9f2540..53007485746405 100644 --- a/deps/npm/docs/output/commands/npm-explain.html +++ b/deps/npm/docs/output/commands/npm-explain.html @@ -183,7 +183,7 @@

    Configuration

    json

    • Default: false
    • -
    • Type: Bolean
    • +
    • Type: Boolean

    Show information in JSON format.

    See Also

    diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index 55722b8f1ce325..0891ac81e5a760 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -156,7 +156,7 @@

    Description

    limit 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.0.8 /path/to/npm
    +
        npm@7.0.14 /path/to/npm
         └─┬ init-package-json@0.0.4
           └── promzard@0.1.5
     
    diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html index e3f5ce28afc480..bae6ef6e803442 100644 --- a/deps/npm/docs/output/commands/npm.html +++ b/deps/npm/docs/output/commands/npm.html @@ -148,7 +148,7 @@

    Table of contents

    npm <command> [args]
     

    Version

    -

    7.0.8

    +

    7.0.14

    Description

    npm is the package manager for the Node JavaScript platform. It puts modules in place so that node can find them, and manages dependency diff --git a/deps/npm/docs/output/commands/npx.html b/deps/npm/docs/output/commands/npx.html index 61194a0aa31f12..36aad9f701fe8e 100644 --- a/deps/npm/docs/output/commands/npx.html +++ b/deps/npm/docs/output/commands/npx.html @@ -146,9 +146,9 @@

    Table of contents

    Synopsis

    npm exec -- <pkg>[@<version>] [args...]
    -npm exec -p <pkg>[@<version>] -- <cmd> [args...]
    +npm exec --package=<pkg>[@<version>] -- <cmd> [args...]
     npm exec -c '<cmd> [args...]'
    -npm exec -p foo -c '<cmd> [args...]'
    +npm exec --package=foo -c '<cmd> [args...]'
     
     npx <pkg>[@<specifier>] [args...]
     npx -p <pkg>[@<specifier>] <cmd> [args...]
    @@ -157,16 +157,17 @@ 

    Table of contents

    alias: npm x, npx --p <pkg> --package=<pkg> (may be specified multiple times) +--package=<pkg> (may be specified multiple times) +-p is a shorthand for --package only when using npx executable -c <cmd> --call=<cmd> (may not be mixed with positional arguments)

    Description

    This command allows you to run an arbitrary command from an npm package (either one installed locally, or fetched remotely), in a similar context as running it via npm run.

    -

    Whatever packages are specified by the --package or -p option will be +

    Whatever packages are specified by the --package option will be provided in the PATH of the executed command, along with any locally -installed package executables. The --package or -p option may be +installed package executables. The --package option may be specified multiple times, to execute the supplied command in an environment where all specified packages are available.

    If any requested packages are not present in the local project @@ -179,13 +180,14 @@

    Description

    only be considered a match if they have the exact same name and version as the local dependency.

    If no -c or --call option is provided, then the positional arguments -are used to generate the command string. If no -p or --package options +are used to generate the command string. If no --package options are provided, then npm will attempt to determine the executable name from the package specifier provided as the first positional argument according to the following heuristic:

    • If the package has a single entry in its bin field in package.json, -then that command will be used.
    • +or if all entries are aliases of the same command, then that command +will be used.
    • If the package has multiple bin entries, and one of them matches the unscoped portion of the name field, then that command will be used.
    • If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/output/using-npm/developers.html b/deps/npm/docs/output/using-npm/developers.html index c0e7d4b95c558c..ae547d4f520ec5 100644 --- a/deps/npm/docs/output/using-npm/developers.html +++ b/deps/npm/docs/output/using-npm/developers.html @@ -238,7 +238,7 @@

      Keeping files out of your pa create an empty .npmignore file to override it. Like git, npm looks for .npmignore and .gitignore files in all subdirectories of your package, not only the root directory.

      -

      .npmignore files follow the same pattern rules +

      .npmignore files follow the same pattern rules as .gitignore files:

      • Blank lines or lines starting with # are ignored.
      • diff --git a/deps/npm/docs/output/using-npm/scripts.html b/deps/npm/docs/output/using-npm/scripts.html index dc9d952142dfd9..8d0ad5090789ef 100644 --- a/deps/npm/docs/output/using-npm/scripts.html +++ b/deps/npm/docs/output/using-npm/scripts.html @@ -145,7 +145,7 @@

        Table of contents

        Description

        -

        The "scripts" property of of your package.json file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running npm run-script <stage> or npm run <stage> for short. Pre and post commands with matching names will be run for those as well (e.g. premyscript, myscript, postmyscript). Scripts from dependencies can be run with npm explore <pkg> -- npm run <stage>.

        +

        The "scripts" property of your package.json file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running npm run-script <stage> or npm run <stage> for short. Pre and post commands with matching names will be run for those as well (e.g. premyscript, myscript, postmyscript). Scripts from dependencies can be run with npm explore <pkg> -- npm run <stage>.

        Pre & Post Scripts

        To create “pre” or “post” scripts for any scripts defined in the "scripts" section of the package.json, simply create another script with a matching name and add “pre” or “post” to the beginning of them.

        {
        diff --git a/deps/npm/lib/adduser.js b/deps/npm/lib/adduser.js
        index 895a677c019de3..5017f57a8ae906 100644
        --- a/deps/npm/lib/adduser.js
        +++ b/deps/npm/lib/adduser.js
        @@ -4,6 +4,7 @@ const log = require('npmlog')
         const npm = require('./npm.js')
         const output = require('./utils/output.js')
         const usageUtil = require('./utils/usage.js')
        +const replaceInfo = require('./utils/replace-info.js')
         const authTypes = {
           legacy: require('./auth/legacy.js'),
           oauth: require('./auth/oauth.js'),
        @@ -57,6 +58,8 @@ const adduser = async (args) => {
         
           log.disableProgress()
         
        +  log.notice('', `Log in on ${replaceInfo(registry)}`)
        +
           const { message, newCreds } = await auth({
             creds,
             registry,
        diff --git a/deps/npm/lib/audit.js b/deps/npm/lib/audit.js
        index e77beab1eff61e..cb8ab5b3a43f5d 100644
        --- a/deps/npm/lib/audit.js
        +++ b/deps/npm/lib/audit.js
        @@ -2,7 +2,7 @@ const Arborist = require('@npmcli/arborist')
         const auditReport = require('npm-audit-report')
         const npm = require('./npm.js')
         const output = require('./utils/output.js')
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         const auditError = require('./utils/audit-error.js')
         
         const audit = async args => {
        @@ -14,7 +14,7 @@ const audit = async args => {
           const fix = args[0] === 'fix'
           await arb.audit({ fix })
           if (fix)
        -    reifyOutput(arb)
        +    await reifyFinish(arb)
           else {
             // will throw if there's an error, because this is an audit command
             auditError(arb.auditReport)
        diff --git a/deps/npm/lib/cache.js b/deps/npm/lib/cache.js
        index bf788043ab6e68..30d6aef863ac29 100644
        --- a/deps/npm/lib/cache.js
        +++ b/deps/npm/lib/cache.js
        @@ -22,10 +22,11 @@ const usage = usageUtil('cache',
         const completion = (opts, cb) => {
           const argv = opts.conf.argv.remain
           if (argv.length === 2)
        -    return cb(null, ['add', 'clean'])
        +    return cb(null, ['add', 'clean', 'verify'])
         
           // TODO - eventually...
           switch (argv[2]) {
        +    case 'verify':
             case 'clean':
             case 'add':
               return cb(null, [])
        @@ -40,11 +41,11 @@ const cache = async (args) => {
             case 'rm': case 'clear': case 'clean':
               return await clean(args)
             case 'add':
        -      return await add(args, npm.prefix)
        +      return await add(args)
             case 'verify': case 'check':
               return await verify()
             default:
        -      throw usage
        +      throw Object.assign(new Error(usage), { code: 'EUSAGE' })
           }
         }
         
        @@ -77,22 +78,21 @@ with --force.`)
         // npm cache add  
         // npm cache add 
         // npm cache add 
        -const add = async (args, where) => {
        +const add = async (args) => {
           const usage = 'Usage:\n' +
             '    npm cache add \n' +
             '    npm cache add @\n' +
             '    npm cache add \n' +
             '    npm cache add \n'
           log.silly('cache add', 'args', args)
        -  const spec = args[0] +
        +  const spec = args[0] && args[0] +
             (args[1] === undefined || args[1] === null ? '' : `@${args[1]}`)
         
        -  log.verbose('cache add', 'spec', spec)
           if (!spec)
        -    throw new Error(usage)
        +    throw Object.assign(new Error(usage), { code: 'EUSAGE' })
         
        -  log.silly('cache add', 'parsed spec', spec)
        -  const opts = { ...npm.flatOptions, where }
        +  log.silly('cache add', 'spec', spec)
        +  const opts = { ...npm.flatOptions }
         
           // we ask pacote for the thing, and then just throw the data
           // away so that it tee-pipes it into the cache like it does
        @@ -109,7 +109,7 @@ const verify = async () => {
             ? `~${cache.substr(process.env.HOME.length)}`
             : cache
           const stats = await cacache.verify(cache)
        -  output(`Cache verified and compressed (${prefix}):`)
        +  output(`Cache verified and compressed (${prefix})`)
           output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`)
           stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`)
           stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`)
        diff --git a/deps/npm/lib/ci.js b/deps/npm/lib/ci.js
        index a72e1c0cffba61..1255fbc2646fd4 100644
        --- a/deps/npm/lib/ci.js
        +++ b/deps/npm/lib/ci.js
        @@ -1,7 +1,7 @@
         const util = require('util')
         const Arborist = require('@npmcli/arborist')
         const rimraf = util.promisify(require('rimraf'))
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         
         const log = require('npmlog')
         const npm = require('./npm.js')
        @@ -34,8 +34,8 @@ const ci = async () => {
             rimraf(`${where}/node_modules/*`, { glob: { dot: true, nosort: true, silent: true } }),
           ])
           // npm ci should never modify the lockfile or package.json
        -  await arb.reify({ save: false })
        -  reifyOutput(arb)
        +  await arb.reify({ ...npm.flatOptions, save: false })
        +  await reifyFinish(arb)
         }
         
         module.exports = Object.assign(cmd, { completion, usage })
        diff --git a/deps/npm/lib/cli.js b/deps/npm/lib/cli.js
        index f06abcd186f966..910b674eaa790f 100644
        --- a/deps/npm/lib/cli.js
        +++ b/deps/npm/lib/cli.js
        @@ -1,5 +1,7 @@
         // Separated out for easier unit testing
         module.exports = (process) => {
        +  // set it here so that regardless of what happens later, we don't
        +  // leak any private CLI configs to other programs
           process.title = 'npm'
         
           const {
        diff --git a/deps/npm/lib/dedupe.js b/deps/npm/lib/dedupe.js
        index a08c9f3f8f3349..fe8243e21e43d2 100644
        --- a/deps/npm/lib/dedupe.js
        +++ b/deps/npm/lib/dedupe.js
        @@ -2,7 +2,7 @@
         const npm = require('./npm.js')
         const Arborist = require('@npmcli/arborist')
         const usageUtil = require('./utils/usage.js')
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         
         const usage = usageUtil('dedupe', 'npm dedupe')
         const completion = require('./utils/completion/none.js')
        @@ -18,7 +18,7 @@ const dedupe = async (args) => {
             dryRun,
           })
           await arb.dedupe(npm.flatOptions)
        -  reifyOutput(arb)
        +  await reifyFinish(arb)
         }
         
         module.exports = Object.assign(cmd, { usage, completion })
        diff --git a/deps/npm/lib/exec.js b/deps/npm/lib/exec.js
        index 088a7c00eba314..6bcaf838ed327e 100644
        --- a/deps/npm/lib/exec.js
        +++ b/deps/npm/lib/exec.js
        @@ -226,15 +226,15 @@ const manifestMissing = (tree, mani) => {
         
         const getBinFromManifest = mani => {
           // if we have a bin matching (unscoped portion of) packagename, use that
        -  // otherwise if there's 1 bin, use that,
        +  // otherwise if there's 1 bin or all bin value is the same (alias), use that,
           // otherwise fail
        -  const bins = Object.entries(mani.bin || {})
        -  if (bins.length === 1)
        -    return bins[0][0]
        +  const bin = mani.bin || {}
        +  if (new Set(Object.values(bin)).size === 1)
        +    return Object.keys(bin)[0]
         
           // XXX probably a util to parse this better?
           const name = mani.name.replace(/^@[^/]+\//, '')
        -  if (mani.bin && mani.bin[name])
        +  if (bin[name])
             return name
         
           // XXX need better error message
        diff --git a/deps/npm/lib/init.js b/deps/npm/lib/init.js
        index e805a2eda7796c..ac49f54a7954d4 100644
        --- a/deps/npm/lib/init.js
        +++ b/deps/npm/lib/init.js
        @@ -1,11 +1,11 @@
        -// initialize a package.json file
        -
        -const usageUtil = require('./utils/usage.js')
        -const completion = require('./utils/completion/none.js')
        +'use strict'
         
        +const initJson = require('init-package-json')
         const npa = require('npm-package-arg')
        +
         const npm = require('./npm.js')
        -const initJson = require('init-package-json')
        +const usageUtil = require('./utils/usage.js')
        +const completion = require('./utils/completion/none.js')
         const output = require('./utils/output.js')
         
         const usage = usageUtil(
        @@ -43,7 +43,6 @@ const init = async args => {
               }
             }
             npm.config.set('package', [])
        -    npm.flatOptions = { ...npm.flatOptions, package: [] }
             return new Promise((res, rej) => {
               npm.commands.exec([packageName, ...args.slice(1)], er => er ? rej(er) : res())
             })
        @@ -78,11 +77,12 @@ const init = async args => {
                 npm.log.warn('init', 'canceled')
                 return res()
               }
        -      npm.log.info('init', 'written successfully')
               if (er)
                 rej(er)
        -      else
        +      else {
        +        npm.log.info('init', 'written successfully')
                 res(data)
        +      }
             })
           })
         }
        diff --git a/deps/npm/lib/install.js b/deps/npm/lib/install.js
        index 5f04fcd4f9d6be..f621c85c23e1e2 100644
        --- a/deps/npm/lib/install.js
        +++ b/deps/npm/lib/install.js
        @@ -6,13 +6,15 @@ const util = require('util')
         const readdir = util.promisify(fs.readdir)
         const npm = require('./npm.js')
         const usageUtil = require('./utils/usage.js')
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         const log = require('npmlog')
         const { resolve, join } = require('path')
         const Arborist = require('@npmcli/arborist')
         const runScript = require('@npmcli/run-script')
         
        -const install = async (args, cb) => {
        +const cmd = async (args, cb) => install(args).then(() => cb()).catch(cb)
        +
        +const install = async args => {
           // the /path/to/node_modules/..
           const globalTop = resolve(npm.globalDir, '..')
           const { ignoreScripts, global: isGlobalInstall } = npm.flatOptions
        @@ -34,38 +36,33 @@ const install = async (args, cb) => {
             path: where,
           })
         
        -  try {
        -    await arb.reify({
        -      ...npm.flatOptions,
        -      add: args,
        -    })
        -    if (!args.length && !isGlobalInstall && !ignoreScripts) {
        -      const { scriptShell } = npm.flatOptions
        -      const scripts = [
        -        'preinstall',
        -        'install',
        -        'postinstall',
        -        'prepublish', // XXX should we remove this finally??
        -        'preprepare',
        -        'prepare',
        -        'postprepare',
        -      ]
        -      for (const event of scripts) {
        -        await runScript({
        -          path: where,
        -          args: [],
        -          scriptShell,
        -          stdio: 'inherit',
        -          stdioString: true,
        -          event,
        -        })
        -      }
        +  await arb.reify({
        +    ...npm.flatOptions,
        +    add: args,
        +  })
        +  if (!args.length && !isGlobalInstall && !ignoreScripts) {
        +    const { scriptShell } = npm.flatOptions
        +    const scripts = [
        +      'preinstall',
        +      'install',
        +      'postinstall',
        +      'prepublish', // XXX should we remove this finally??
        +      'preprepare',
        +      'prepare',
        +      'postprepare',
        +    ]
        +    for (const event of scripts) {
        +      await runScript({
        +        path: where,
        +        args: [],
        +        scriptShell,
        +        stdio: 'inherit',
        +        stdioString: true,
        +        event,
        +      })
             }
        -    reifyOutput(arb)
        -    cb()
        -  } catch (er) {
        -    cb(er)
           }
        +  await reifyFinish(arb)
         }
         
         const usage = usageUtil(
        @@ -144,4 +141,4 @@ const completion = async (opts, cb) => {
           cb()
         }
         
        -module.exports = Object.assign(install, { usage, completion })
        +module.exports = Object.assign(cmd, { usage, completion })
        diff --git a/deps/npm/lib/link.js b/deps/npm/lib/link.js
        index d7303fd086cdd9..bee44d43a7ff62 100644
        --- a/deps/npm/lib/link.js
        +++ b/deps/npm/lib/link.js
        @@ -10,7 +10,7 @@ const semver = require('semver')
         
         const npm = require('./npm.js')
         const usageUtil = require('./utils/usage.js')
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         
         const completion = (opts, cb) => {
           const dir = npm.globalDir
        @@ -122,7 +122,7 @@ const linkInstall = async args => {
             add: names.map(l => `file:${resolve(globalTop, 'node_modules', l)}`),
           })
         
        -  reifyOutput(localArb)
        +  await reifyFinish(localArb)
         }
         
         const linkPkg = async () => {
        @@ -133,7 +133,7 @@ const linkPkg = async () => {
             global: true,
           })
           await arb.reify({ add: [`file:${npm.prefix}`] })
        -  reifyOutput(arb)
        +  await reifyFinish(arb)
         }
         
         module.exports = Object.assign(cmd, { completion, usage })
        diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js
        index d6eab9674fe186..4430b80539d031 100644
        --- a/deps/npm/lib/npm.js
        +++ b/deps/npm/lib/npm.js
        @@ -54,6 +54,7 @@ const _runCmd = Symbol('_runCmd')
         const _load = Symbol('_load')
         const _flatOptions = Symbol('_flatOptions')
         const _tmpFolder = Symbol('_tmpFolder')
        +const _title = Symbol('_title')
         const npm = module.exports = new class extends EventEmitter {
           constructor () {
             super()
        @@ -75,6 +76,7 @@ const npm = module.exports = new class extends EventEmitter {
               defaults,
               shorthands,
             })
        +    this[_title] = process.title
             this.updateNotification = null
           }
         
        @@ -156,6 +158,15 @@ const npm = module.exports = new class extends EventEmitter {
             return this.config.loaded
           }
         
        +  get title () {
        +    return this[_title]
        +  }
        +
        +  set title (t) {
        +    process.title = t
        +    this[_title] = t
        +  }
        +
           async [_load] () {
             const node = await which(process.argv[0]).catch(er => null)
             if (node && node.toUpperCase() !== process.execPath.toUpperCase()) {
        @@ -166,6 +177,15 @@ const npm = module.exports = new class extends EventEmitter {
         
             await this.config.load()
             this.argv = this.config.parsedArgv.remain
        +    // note: this MUST be shorter than the actual argv length, because it
        +    // uses the same memory, so node will truncate it if it's too long.
        +    // if it's a token revocation, then the argv contains a secret, so
        +    // don't show that.  (Regrettable historical choice to put it there.)
        +    // Any other secrets are configs only, so showing only the positional
        +    // args keeps those from being leaked.
        +    const tokrev = deref(this.argv[0]) === 'token' && this.argv[1] === 'revoke'
        +    this.title = tokrev ? 'npm token revoke' + (this.argv[2] ? ' ***' : '')
        +      : ['npm', ...this.argv].join(' ')
         
             this.color = setupLog(this.config, this)
             process.env.COLOR = this.color ? '1' : '0'
        diff --git a/deps/npm/lib/prune.js b/deps/npm/lib/prune.js
        index aa2ed378088e37..ea6ed4108aba28 100644
        --- a/deps/npm/lib/prune.js
        +++ b/deps/npm/lib/prune.js
        @@ -3,7 +3,7 @@ const npm = require('./npm.js')
         const Arborist = require('@npmcli/arborist')
         const usageUtil = require('./utils/usage.js')
         
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         
         const usage = usageUtil('prune',
           'npm prune [[<@scope>/]...] [--production]'
        @@ -19,7 +19,7 @@ const prune = async () => {
             path: where,
           })
           await arb.prune(npm.flatOptions)
        -  reifyOutput(arb)
        +  await reifyFinish(arb)
         }
         
         module.exports = Object.assign(cmd, { usage, completion })
        diff --git a/deps/npm/lib/run-script.js b/deps/npm/lib/run-script.js
        index 4d27e8eed965e8..c095e6decd4032 100644
        --- a/deps/npm/lib/run-script.js
        +++ b/deps/npm/lib/run-script.js
        @@ -1,4 +1,5 @@
         const run = require('@npmcli/run-script')
        +const { isServerPackage } = run
         const npm = require('./npm.js')
         const readJson = require('read-package-json-fast')
         const { resolve } = require('path')
        @@ -45,7 +46,7 @@ const runScript = async (args) => {
         
           pkg.scripts = scripts
         
        -  if (!scripts[event]) {
        +  if (!Object.prototype.hasOwnProperty.call(scripts, event) && !(event === 'start' && await isServerPackage(path))) {
             if (npm.config.get('if-present'))
               return
         
        diff --git a/deps/npm/lib/star.js b/deps/npm/lib/star.js
        index 15beef37352c28..85d14d0e427cda 100644
        --- a/deps/npm/lib/star.js
        +++ b/deps/npm/lib/star.js
        @@ -3,73 +3,75 @@
         const fetch = require('npm-registry-fetch')
         const log = require('npmlog')
         const npa = require('npm-package-arg')
        +
         const npm = require('./npm.js')
         const output = require('./utils/output.js')
        -const usage = require('./utils/usage.js')
        -const getItentity = require('./utils/get-identity')
        +const usageUtil = require('./utils/usage.js')
        +const getIdentity = require('./utils/get-identity')
        +const completion = require('./utils/completion/none.js')
         
        -star.usage = usage(
        +const usage = usageUtil(
           'star',
           'npm star [...]\n' +
           'npm unstar [...]'
         )
         
        -star.completion = function (opts, cb) {
        -  // FIXME: there used to be registry completion here, but it stopped making
        -  // sense somewhere around 50,000 packages on the registry
        -  cb()
        -}
        +const cmd = (args, cb) => star(args).then(() => cb()).catch(cb)
        +
        +const star = async args => {
        +  if (!args.length)
        +    throw new Error(usage)
        +
        +  // if we're unstarring, then show an empty star image
        +  // otherwise, show the full star image
        +  const { unicode } = npm.flatOptions
        +  const unstar = npm.config.get('star.unstar')
        +  const full = unicode ? '\u2605 ' : '(*)'
        +  const empty = unicode ? '\u2606 ' : '( )'
        +  const show = unstar ? empty : full
        +
        +  const pkgs = args.map(npa)
        +  for (const pkg of pkgs) {
        +    const [username, fullData] = await Promise.all([
        +      getIdentity(npm.flatOptions),
        +      fetch.json(pkg.escapedName, {
        +        ...npm.flatOptions,
        +        spec: pkg,
        +        query: { write: true },
        +        preferOnline: true,
        +      }),
        +    ])
         
        -module.exports = star
        -function star (args, cb) {
        -  const opts = npm.flatOptions
        -  return Promise.resolve().then(() => {
        -    if (!args.length)
        -      throw new Error(star.usage)
        -    // if we're unstarring, then show an empty star image
        -    // otherwise, show the full star image
        -    const unstar = /^un/.test(npm.command)
        -    const full = opts.unicode ? '\u2605 ' : '(*)'
        -    const empty = opts.unicode ? '\u2606 ' : '( )'
        -    const show = unstar ? empty : full
        -    return Promise.all(args.map(npa).map(pkg => {
        -      return Promise.all([
        -        getItentity(opts),
        -        fetch.json(pkg.escapedName, {
        -          ...opts,
        -          spec: pkg,
        -          query: { write: true },
        -          preferOnline: true,
        -        }),
        -      ]).then(([username, fullData]) => {
        -        if (!username)
        -          throw new Error('You need to be logged in!')
        -        const body = {
        -          _id: fullData._id,
        -          _rev: fullData._rev,
        -          users: fullData.users || {},
        -        }
        +    if (!username)
        +      throw new Error('You need to be logged in!')
         
        -        if (!unstar) {
        -          log.info('star', 'starring', body._id)
        -          body.users[username] = true
        -          log.verbose('star', 'starring', body)
        -        } else {
        -          delete body.users[username]
        -          log.info('star', 'unstarring', body._id)
        -          log.verbose('star', 'unstarring', body)
        -        }
        -        return fetch.json(pkg.escapedName, {
        -          ...opts,
        -          spec: pkg,
        -          method: 'PUT',
        -          body,
        -        })
        -      }).then(data => {
        -        output(show + ' ' + pkg.name)
        -        log.verbose('star', data)
        -        return data
        -      })
        -    }))
        -  }).then(() => cb(), cb)
        +    const body = {
        +      _id: fullData._id,
        +      _rev: fullData._rev,
        +      users: fullData.users || {},
        +    }
        +
        +    if (!unstar) {
        +      log.info('star', 'starring', body._id)
        +      body.users[username] = true
        +      log.verbose('star', 'starring', body)
        +    } else {
        +      delete body.users[username]
        +      log.info('unstar', 'unstarring', body._id)
        +      log.verbose('unstar', 'unstarring', body)
        +    }
        +
        +    const data = await fetch.json(pkg.escapedName, {
        +      ...npm.flatOptions,
        +      spec: pkg,
        +      method: 'PUT',
        +      body,
        +    })
        +
        +    output(show + ' ' + pkg.name)
        +    log.verbose('star', data)
        +    return data
        +  }
         }
        +
        +module.exports = Object.assign(cmd, { completion, usage })
        diff --git a/deps/npm/lib/uninstall.js b/deps/npm/lib/uninstall.js
        index ec997ae6457ab6..dbaa992f500e05 100644
        --- a/deps/npm/lib/uninstall.js
        +++ b/deps/npm/lib/uninstall.js
        @@ -5,7 +5,7 @@ const npm = require('./npm.js')
         const rpj = require('read-package-json-fast')
         const { resolve } = require('path')
         const usageUtil = require('./utils/usage.js')
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         
         const cmd = (args, cb) => rm(args).then(() => cb()).catch(cb)
         
        @@ -32,7 +32,7 @@ const rm = async args => {
             ...npm.flatOptions,
             rm: args,
           })
        -  reifyOutput(arb)
        +  await reifyFinish(arb)
         }
         
         const usage = usageUtil(
        diff --git a/deps/npm/lib/unstar.js b/deps/npm/lib/unstar.js
        new file mode 100644
        index 00000000000000..5dea5bcab0e9cb
        --- /dev/null
        +++ b/deps/npm/lib/unstar.js
        @@ -0,0 +1,9 @@
        +const { usage, completion } = require('./star.js')
        +const npm = require('./npm.js')
        +
        +const unstar = (args, cb) => {
        +  npm.config.set('star.unstar', true)
        +  return npm.commands.star(args, cb)
        +}
        +
        +module.exports = Object.assign(unstar, { usage, completion })
        diff --git a/deps/npm/lib/update.js b/deps/npm/lib/update.js
        index 791e67e407643a..0a786e30f312e9 100644
        --- a/deps/npm/lib/update.js
        +++ b/deps/npm/lib/update.js
        @@ -4,7 +4,7 @@ const Arborist = require('@npmcli/arborist')
         const log = require('npmlog')
         const npm = require('./npm.js')
         const usageUtil = require('./utils/usage.js')
        -const reifyOutput = require('./utils/reify-output.js')
        +const reifyFinish = require('./utils/reify-finish.js')
         const completion = require('./utils/completion/installed-deep.js')
         
         const usage = usageUtil(
        @@ -32,7 +32,7 @@ const update = async args => {
           })
         
           await arb.reify({ update })
        -  reifyOutput(arb)
        +  await reifyFinish(arb)
         }
         
         module.exports = Object.assign(cmd, { usage, completion })
        diff --git a/deps/npm/lib/utils/cmd-list.js b/deps/npm/lib/utils/cmd-list.js
        index 5c188a8e92ad51..8d8c898d94ae36 100644
        --- a/deps/npm/lib/utils/cmd-list.js
        +++ b/deps/npm/lib/utils/cmd-list.js
        @@ -12,7 +12,6 @@ const shorthands = {
           c: 'config',
           s: 'search',
           se: 'search',
        -  unstar: 'star', // same function
           tst: 'test',
           t: 'test',
           ddp: 'dedupe',
        @@ -88,6 +87,7 @@ const cmdList = [
           'publish',
           'star',
           'stars',
        +  'unstar',
           'adduser',
           'login', // This is an alias for `adduser` but it can be confusing
           'logout',
        diff --git a/deps/npm/lib/utils/config.js b/deps/npm/lib/utils/config.js
        index f9de6e9a79220c..6abb502e205724 100644
        --- a/deps/npm/lib/utils/config.js
        +++ b/deps/npm/lib/utils/config.js
        @@ -52,6 +52,7 @@ const defaults = {
           'always-auth': false,
           audit: true,
           'audit-level': null,
        +  _auth: null,
           'auth-type': 'legacy',
           before: null,
           'bin-links': true,
        @@ -191,6 +192,7 @@ const types = {
           all: Boolean,
           'allow-same-version': Boolean,
           also: [null, 'dev', 'development'],
        +  _auth: [null, String],
           'always-auth': Boolean,
           audit: Boolean,
           'audit-level': ['low', 'moderate', 'high', 'critical', 'none', null],
        diff --git a/deps/npm/lib/utils/error-handler.js b/deps/npm/lib/utils/error-handler.js
        index dc9e2a26bcfa59..476ca9e917b366 100644
        --- a/deps/npm/lib/utils/error-handler.js
        +++ b/deps/npm/lib/utils/error-handler.js
        @@ -182,7 +182,7 @@ const errorHandler = (er) => {
                 detail: messageText(msg.detail),
               },
             }
        -    console.log(JSON.stringify(error, null, 2))
        +    console.error(JSON.stringify(error, null, 2))
           }
         
           exit(typeof er.errno === 'number' ? er.errno : typeof er.code === 'number' ? er.code : 1)
        diff --git a/deps/npm/lib/utils/explain-dep.js b/deps/npm/lib/utils/explain-dep.js
        index 096df97edfda32..ed69a02c143c0b 100644
        --- a/deps/npm/lib/utils/explain-dep.js
        +++ b/deps/npm/lib/utils/explain-dep.js
        @@ -64,7 +64,7 @@ const explainDependents = ({ name, dependents }, depth, color) => {
             const maxLen = 50
             const showNames = []
             for (let i = max; i < dependents.length; i++) {
        -      const { from: { name } } = dependents[i]
        +      const { from: { name = 'the root project' } } = dependents[i]
               len += name.length
               if (len >= maxLen && i < dependents.length - 1) {
                 showNames.push('...')
        diff --git a/deps/npm/lib/utils/flat-options.js b/deps/npm/lib/utils/flat-options.js
        index be62c5a4cdb589..8b6864aa823ff7 100644
        --- a/deps/npm/lib/utils/flat-options.js
        +++ b/deps/npm/lib/utils/flat-options.js
        @@ -50,6 +50,7 @@ const flatten = obj => ({
           alwaysAuth: obj['always-auth'],
           audit: obj.audit,
           auditLevel: obj['audit-level'],
        +  _auth: obj._auth,
           authType: obj['auth-type'],
           ssoType: obj['sso-type'],
           ssoPollFrequency: obj['sso-poll-frequency'],
        diff --git a/deps/npm/lib/utils/reify-finish.js b/deps/npm/lib/utils/reify-finish.js
        new file mode 100644
        index 00000000000000..76dba06cb570c8
        --- /dev/null
        +++ b/deps/npm/lib/utils/reify-finish.js
        @@ -0,0 +1,31 @@
        +const reifyOutput = require('./reify-output.js')
        +const npm = require('../npm.js')
        +const ini = require('ini')
        +const {writeFile} = require('fs').promises
        +const {resolve} = require('path')
        +
        +const reifyFinish = async arb => {
        +  await saveBuiltinConfig(arb)
        +  reifyOutput(arb)
        +}
        +
        +const saveBuiltinConfig = async arb => {
        +  const { options: { global }, actualTree } = arb
        +  if (!global)
        +    return
        +
        +  // if we are using a builtin config, and just installed npm as
        +  // a top-level global package, we have to preserve that config.
        +  const npmNode = actualTree.inventory.get('node_modules/npm')
        +  if (!npmNode)
        +    return
        +
        +  const builtinConf = npm.config.data.get('builtin')
        +  if (builtinConf.loadError)
        +    return
        +
        +  const content = ini.stringify(builtinConf.raw).trim() + '\n'
        +  await writeFile(resolve(npmNode.path, 'npmrc'), content)
        +}
        +
        +module.exports = reifyFinish
        diff --git a/deps/npm/lib/version.js b/deps/npm/lib/version.js
        index 98068490d85b1a..abdd8d552b20ca 100644
        --- a/deps/npm/lib/version.js
        +++ b/deps/npm/lib/version.js
        @@ -1,3 +1,5 @@
        +'use strict'
        +
         const libversion = require('libnpmversion')
         const npm = require('./npm.js')
         const output = require('./utils/output.js')
        @@ -42,7 +44,7 @@ const version = async args => {
                 path: npm.prefix,
               }))
             default:
        -      throw version.usage
        +      throw usage
           }
         }
         
        diff --git a/deps/npm/man/man1/npm-audit.1 b/deps/npm/man/man1/npm-audit.1
        index ebd91e8198d554..cd52afeac38d09 100644
        --- a/deps/npm/man/man1/npm-audit.1
        +++ b/deps/npm/man/man1/npm-audit.1
        @@ -5,8 +5,8 @@
         .P
         .RS 2
         .nf
        -npm audit [\-\-json|\-\-parseable|\-\-audit\-level=(low|moderate|high|critical)]
        -npm audit fix [\-\-force|\-\-package\-lock\-only|\-\-dry\-run]
        +npm audit [\-\-json] [\-\-production] [\-\-audit\-level=(low|moderate|high|critical)]
        +npm audit fix [\-\-force|\-\-package\-lock\-only|\-\-dry\-run|\-\-production|\-\-only=(dev|prod)]
         
         common options: [\-\-production] [\-\-only=(dev|prod)]
         .fi
        diff --git a/deps/npm/man/man1/npm-exec.1 b/deps/npm/man/man1/npm-exec.1
        index 6048388fd6e262..17d436812edba9 100644
        --- a/deps/npm/man/man1/npm-exec.1
        +++ b/deps/npm/man/man1/npm-exec.1
        @@ -53,7 +53,8 @@ to the following heuristic:
         .RS 0
         .IP \(bu 2
         If the package has a single entry in its \fBbin\fP field in \fBpackage\.json\fP,
        -then that command will be used\.
        +or if all entries are aliases of the same command, then that command
        +will be used\.
         .IP \(bu 2
         If the package has multiple \fBbin\fP entries, and one of them matches the
         unscoped portion of the \fBname\fP field, then that command will be used\.
        diff --git a/deps/npm/man/man1/npm-explain.1 b/deps/npm/man/man1/npm-explain.1
        index dfbe283f2bccbf..1c30b568c56173 100644
        --- a/deps/npm/man/man1/npm-explain.1
        +++ b/deps/npm/man/man1/npm-explain.1
        @@ -58,7 +58,7 @@ node_modules/nyc/node_modules/find\-up
         .IP \(bu 2
         Default: false
         .IP \(bu 2
        -Type: Bolean
        +Type: Boolean
         
         .RE
         .P
        diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1
        index afa7913b743853..a99c1d145329c3 100644
        --- a/deps/npm/man/man1/npm-ls.1
        +++ b/deps/npm/man/man1/npm-ls.1
        @@ -22,7 +22,7 @@ For example, running \fBnpm ls promzard\fP in npm's source tree will show:
         .P
         .RS 2
         .nf
        -    npm@7\.0\.8 /path/to/npm
        +    npm@7\.0\.14 /path/to/npm
             └─┬ init\-package\-json@0\.0\.4
               └── promzard@0\.1\.5
         .fi
        diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1
        index 9197f45f0ad022..e55d61f2df28a9 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\.0\.8
        +7\.0\.14
         .SS Description
         .P
         npm is the package manager for the Node JavaScript platform\.  It puts
        diff --git a/deps/npm/man/man1/npx.1 b/deps/npm/man/man1/npx.1
        index 88b597de523502..d87c4a946d592c 100644
        --- a/deps/npm/man/man1/npx.1
        +++ b/deps/npm/man/man1/npx.1
        @@ -6,9 +6,9 @@
         .RS 2
         .nf
         npm exec \-\- [@] [args\.\.\.]
        -npm exec \-p [@] \-\-  [args\.\.\.]
        +npm exec \-\-package=[@] \-\-  [args\.\.\.]
         npm exec \-c ' [args\.\.\.]'
        -npm exec \-p foo \-c ' [args\.\.\.]'
        +npm exec \-\-package=foo \-c ' [args\.\.\.]'
         
         npx [@] [args\.\.\.]
         npx \-p [@]  [args\.\.\.]
        @@ -17,7 +17,8 @@ npx \-p [@] \-c ' [args\.\.\.]'
         
         alias: npm x, npx
         
        -\-p  \-\-package= (may be specified multiple times)
        +\-\-package= (may be specified multiple times)
        +\-p is a shorthand for \-\-package only when using npx executable
         \-c  \-\-call= (may not be mixed with positional arguments)
         .fi
         .RE
        @@ -27,9 +28,9 @@ This command allows you to run an arbitrary command from an npm package
         (either one installed locally, or fetched remotely), in a similar context
         as running it via \fBnpm run\fP\|\.
         .P
        -Whatever packages are specified by the \fB\-\-package\fP or \fB\-p\fP option will be
        +Whatever packages are specified by the \fB\-\-package\fP option will be
         provided in the \fBPATH\fP of the executed command, along with any locally
        -installed package executables\.  The \fB\-\-package\fP or \fB\-p\fP option may be
        +installed package executables\.  The \fB\-\-package\fP option may be
         specified multiple times, to execute the supplied command in an environment
         where all specified packages are available\.
         .P
        @@ -45,14 +46,15 @@ only be considered a match if they have the exact same name and version as
         the local dependency\.
         .P
         If no \fB\-c\fP or \fB\-\-call\fP option is provided, then the positional arguments
        -are used to generate the command string\.  If no \fB\-p\fP or \fB\-\-package\fP options
        +are used to generate the command string\.  If no \fB\-\-package\fP options
         are provided, then npm will attempt to determine the executable name from
         the package specifier provided as the first positional argument according
         to the following heuristic:
         .RS 0
         .IP \(bu 2
         If the package has a single entry in its \fBbin\fP field in \fBpackage\.json\fP,
        -then that command will be used\.
        +or if all entries are aliases of the same command, then that command
        +will be used\.
         .IP \(bu 2
         If the package has multiple \fBbin\fP entries, and one of them matches the
         unscoped portion of the \fBname\fP field, then that command will be used\.
        diff --git a/deps/npm/man/man7/developers.7 b/deps/npm/man/man7/developers.7
        index 9a34bf3edb0505..1af140b44233fb 100644
        --- a/deps/npm/man/man7/developers.7
        +++ b/deps/npm/man/man7/developers.7
        @@ -114,7 +114,7 @@ create an empty \fB\|\.npmignore\fP file to override it\. Like \fBgit\fP, \fBnpm
         for \fB\|\.npmignore\fP and \fB\|\.gitignore\fP files in all subdirectories of your
         package, not only the root directory\.
         .P
        -\fB\|\.npmignore\fP files follow the same pattern rules \fIhttps://git\-scm\.com/book/en/v2/Git\-Basics\-Recording\-Changes\-to\-the\-Repository#Ignoring\-Files\fR
        +\fB\|\.npmignore\fP files follow the same pattern rules \fIhttps://git\-scm\.com/book/en/v2/Git\-Basics\-Recording\-Changes\-to\-the\-Repository#_ignoring\fR
         as \fB\|\.gitignore\fP files:
         .RS 0
         .IP \(bu 2
        diff --git a/deps/npm/man/man7/scripts.7 b/deps/npm/man/man7/scripts.7
        index 522e32cb80e158..2067fe45d92383 100644
        --- a/deps/npm/man/man7/scripts.7
        +++ b/deps/npm/man/man7/scripts.7
        @@ -3,7 +3,7 @@
         \fBscripts\fR \- How npm handles the "scripts" field
         .SS Description
         .P
        -The \fB"scripts"\fP property of of your \fBpackage\.json\fP file supports a number of built\-in scripts and their preset life cycle events as well as arbitrary scripts\. These all can be executed by running \fBnpm run\-script \fP or \fBnpm run \fP for short\. \fIPre\fR and \fIpost\fR commands with matching names will be run for those as well (e\.g\. \fBpremyscript\fP, \fBmyscript\fP, \fBpostmyscript\fP)\. Scripts from dependencies can be run with \fBnpm explore  \-\- npm run \fP\|\.
        +The \fB"scripts"\fP property of your \fBpackage\.json\fP file supports a number of built\-in scripts and their preset life cycle events as well as arbitrary scripts\. These all can be executed by running \fBnpm run\-script \fP or \fBnpm run \fP for short\. \fIPre\fR and \fIpost\fR commands with matching names will be run for those as well (e\.g\. \fBpremyscript\fP, \fBmyscript\fP, \fBpostmyscript\fP)\. Scripts from dependencies can be run with \fBnpm explore  \-\- npm run \fP\|\.
         .SS Pre & Post Scripts
         .P
         To create "pre" or "post" scripts for any scripts defined in the \fB"scripts"\fP section of the \fBpackage\.json\fP, simply create another script \fIwith a matching name\fR and add "pre" or "post" to the beginning of them\.
        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 54a6ff33751a1f..579d5740da4f75 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
        @@ -7,6 +7,10 @@ const semver = require('semver')
         const promiseCallLimit = require('promise-call-limit')
         const getPeerSet = require('../peer-set.js')
         const realpath = require('../../lib/realpath.js')
        +const walkUpPath = require('walk-up-path')
        +const { dirname, resolve } = require('path')
        +const { promisify } = require('util')
        +const readdir = promisify(require('readdir-scoped-modules'))
         
         const debug = require('../debug.js')
         const fromPath = require('../from-path.js')
        @@ -182,8 +186,10 @@ module.exports = cls => class IdealTreeBuilder extends cls {
         
             process.emit('time', 'idealTree')
         
        -    if (!options.add && !options.rm && this[_global])
        -      return Promise.reject(new Error('global requires an add or rm option'))
        +    if (!options.add && !options.rm && !options.update && this[_global]) {
        +      const er = new Error('global requires add, rm, or update option')
        +      return Promise.reject(er)
        +    }
         
             // first get the virtual tree, if possible.  If there's a lockfile, then
             // that defines the ideal tree, unless the root package.json is not
        @@ -305,7 +311,6 @@ module.exports = cls => class IdealTreeBuilder extends cls {
               // cases we don't use a lockfile anyway.
               // Load on a new Arborist object, so the Nodes aren't the same,
               // or else it'll get super confusing when we change them!
        -      // Only have to mapWorkspaces if we didn't get it from actual or virtual
               .then(async root => {
                 if (!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk)
                   await new this.constructor(this.options).loadActual({ root })
        @@ -322,10 +327,10 @@ module.exports = cls => class IdealTreeBuilder extends cls {
           }
         
           [_globalRootNode] () {
        -    const root = this[_rootNodeFromPackage]({})
        +    const root = this[_rootNodeFromPackage]({ dependencies: {} })
             // this is a gross kludge to handle the fact that we don't save
             // metadata on the root node in global installs, because the "root"
        -    // node is something like /usr/local/lib/node_modules.
        +    // node is something like /usr/local/lib.
             const meta = new Shrinkwrap({ path: this.path })
             meta.reset()
             root.meta = meta
        @@ -353,9 +358,19 @@ module.exports = cls => class IdealTreeBuilder extends cls {
             // If we have a list of package names to update, and we know it's
             // going to update them wherever they are, add any paths into those
             // named nodes to the buildIdealTree queue.
        -    if (this[_updateNames].length)
        +    if (!this[_global] && this[_updateNames].length)
               this[_queueNamedUpdates]()
         
        +    // global updates only update the globalTop nodes, but we need to know
        +    // that they're there, and not reinstall the world unnecessarily.
        +    if (this[_global] && (this[_updateAll] || this[_updateNames].length)) {
        +      const nm = resolve(this.path, 'node_modules')
        +      for (const name of await readdir(nm)) {
        +        if (this[_updateAll] || this[_updateNames].includes(name))
        +          this.idealTree.package.dependencies[name] = '*'
        +      }
        +    }
        +
             if (this.auditReport && this.auditReport.size > 0)
               this[_queueVulnDependents](options)
         
        @@ -563,7 +578,8 @@ module.exports = cls => class IdealTreeBuilder extends cls {
             const { meta, inventory } = this.idealTree
             const ancient = meta.ancientLockfile
             const old = meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)
        -    if (inventory.size === 0 || !(ancient || old && this[_complete]))
        +
        +    if (inventory.size === 0 || !ancient && !(old && this[_complete]))
               return
         
             // if the lockfile is from node v5 or earlier, then we'll have to reload
        @@ -604,6 +620,10 @@ This is a one-time fix-up, please be patient...
               })
             }
             await promiseCallLimit(queue)
        +    // yes, yes, this isn't the "original" version, but now that it's been
        +    // upgraded, we need to make sure we don't do the work to upgrade it
        +    // again, since it's now as new as can be.
        +    meta.originalLockfileVersion = 2
             this.finishTracker('idealTree:inflate')
             process.emit('timeEnd', 'idealTree:inflate')
           }
        @@ -790,6 +810,11 @@ This is a one-time fix-up, please be patient...
             }
             await Promise.all(promises)
         
        +    for (const { to } of node.edgesOut.values()) {
        +      if (to && to.isLink)
        +        this[_linkNodes].add(to)
        +    }
        +
             return this[_buildDepStep]()
           }
         
        @@ -1065,14 +1090,22 @@ This is a one-time fix-up, please be patient...
         
             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)
        +      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) {
        @@ -1144,7 +1177,7 @@ This is a one-time fix-up, please be patient...
               const oldDeps = []
               for (const [name, edge] of oldChild.edgesOut.entries()) {
                 if (!newDep.edgesOut.has(name) && edge.to)
        -          oldDeps.push(edge.to)
        +          oldDeps.push(...gatherDepSet([edge.to], e => e.to !== edge.to))
               }
               newDep.replace(oldChild)
               this[_pruneForReplacement](newDep, oldDeps)
        @@ -1245,14 +1278,17 @@ This is a one-time fix-up, please be patient...
             // 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)
        -      invalidDeps.add(dep)
        +    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.from !== node && edge.to !== node && edge.valid)
         
             // now just delete whatever's left, because it's junk
             for (const dep of deps)
        @@ -1279,7 +1315,7 @@ This is a one-time fix-up, please be patient...
           // 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 = []) {
        +  [_canPlaceDep] (dep, target, edge, peerEntryEdge = null, peerPath = [], isSource = false) {
             /* istanbul ignore next */
             debug(() => {
               if (!dep)
        @@ -1287,8 +1323,16 @@ This is a one-time fix-up, please be patient...
             })
             const entryEdge = peerEntryEdge || edge
             const source = this[_peerSetSource].get(dep)
        -    const isSource = target === source
        -    const { isRoot, isWorkspace } = source || {}
        +    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 { isRoot, isWorkspace } = isSource ? target : source || {}
             const isMine = isRoot || isWorkspace
         
             // Useful testing thingie right here.
        @@ -1313,7 +1357,7 @@ This is a one-time fix-up, please be patient...
               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)
        +        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
        @@ -1333,7 +1377,7 @@ This is a one-time fix-up, please be patient...
               // 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)
        +        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
        @@ -1401,7 +1445,7 @@ This is a one-time fix-up, please be patient...
                   }
                 }
                 if (canReplace) {
        -          const ret = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath)
        +          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. */
        @@ -1462,14 +1506,14 @@ This is a one-time fix-up, please be patient...
             }
         
             // no objections!  ok to place here
        -    return this[_canPlacePeers](dep, target, edge, OK, peerEntryEdge, peerPath)
        +    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) {
        +  [_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
        @@ -1481,7 +1525,7 @@ This is a one-time fix-up, please be patient...
               if (!peerEdge.peer || !peerEdge.to)
                 continue
               const peer = peerEdge.to
        -      const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, entryEdge, peerPath)
        +      const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, entryEdge, peerPath, isSource)
               if (canPlacePeer !== CONFLICT)
                 continue
         
        @@ -1514,34 +1558,35 @@ This is a one-time fix-up, please be patient...
         
               const external = /^\.\.(\/|$)/.test(loc)
         
        -      if (external && !this[_follow]) {
        -        // outside the root, somebody else's problem, ignore it
        -        continue
        -      }
        -
               if (!link.target.parent && !link.target.fsParent) {
        -        // the fsParent MUST be some node in the tree, possibly the root.
        -        // find it by walking up.  Note that this is where its deps may
        -        // end up being installed, if possible.
        -        const parts = loc.split('/')
        -        for (let p = parts.length - 1; p > -1; p--) {
        -          const path = parts.slice(0, p).join('/')
        -          if (!path && external)
        -            break
        +        // the fsParent likely some node in the tree, possibly the root,
        +        // unless it is external.  find it by walking up.  Note that this
        +        // is where its deps may end up being installed, if possible.
        +        for (const p of walkUpPath(dirname(realpath))) {
        +          const path = relpath(this.path, p)
                   const node = !path ? this.idealTree
                     : this.idealTree.inventory.get(path)
                   if (node) {
                     link.target.fsParent = node
                     this.addTracker('idealTree', link.target.name, link.target.location)
                     this[_depsQueue].push(link.target)
        -            p = -1
        +            break
                   }
                 }
               }
         
        -      // didn't find a parent for it, but we're filling in external
        -      // link targets, so go ahead and process it.
        -      if (this[_follow] && !link.target.parent && !link.target.fsParent) {
        +      // outside the root, somebody else's problem, ignore it
        +      if (external && !this[_follow])
        +        continue
        +
        +      // didn't find a parent for it or it has not been seen yet
        +      // so go ahead and process it.
        +      const unseenLink = (link.target.parent || link.target.fsParent)
        +        && !this[_depsSeen].has(link.target)
        +      if (this[_follow]
        +        && !link.target.parent
        +        && !link.target.fsParent
        +        || unseenLink) {
                 this.addTracker('idealTree', link.target.name, link.target.location)
                 this[_depsQueue].push(link.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 219b6378f13baa..22ce9cc8fc1b4e 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
        @@ -1,6 +1,6 @@
         // mix-in implementing the loadActual method
         
        -const {relative, dirname, resolve, join} = require('path')
        +const {relative, dirname, resolve, join, normalize} = require('path')
         
         const rpj = require('read-package-json-fast')
         const {promisify} = require('util')
        @@ -209,7 +209,7 @@ module.exports = cls => class ActualLoader extends cls {
               // soldier on if read-package-json raises an error
               .then(pkg => [pkg, null], error => [null, error])
               .then(([pkg, error]) => {
        -        return this[path === real ? _newNode : _newLink]({
        +        return this[normalize(path) === real ? _newNode : _newLink]({
                   legacyPeerDeps: this.legacyPeerDeps,
                   path,
                   realpath: real,
        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 14c96092753fc9..e335bdadd45413 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
        @@ -185,12 +185,6 @@ module.exports = cls => class VirtualLoader extends cls {
           // links is the set of metadata, and nodes is the map of non-Link nodes
           // Set the targets to nodes in the set, if we have them (we might not)
           async [resolveLinks] (links, nodes) {
        -    // now we've loaded the root, and all real nodes
        -    // link up the links
        -    const {meta} = this.virtualTree
        -    const {loadedFromDisk, originalLockfileVersion} = meta
        -    const oldLockfile = loadedFromDisk && !(originalLockfileVersion >= 2)
        -
             for (const [location, meta] of links.entries()) {
               const targetPath = resolve(this.path, meta.resolved)
               const targetLoc = relpath(this.path, targetPath)
        @@ -198,27 +192,31 @@ module.exports = cls => class VirtualLoader extends cls {
               const link = this[loadLink](location, targetLoc, target, meta)
               nodes.set(location, link)
               nodes.set(targetLoc, link.target)
        -      // legacy shrinkwraps do not store all the info we need for the target.
        -      // if we're loading from disk, and have a link in place, we need to
        -      // look in that actual folder (or at least try to) in order to get
        -      // the dependencies of the link target and load it properly.
        -      if (oldLockfile) {
        -        const pj = link.realpath + '/package.json'
        -        const pkg = await rpj(pj).catch(() => null)
        -        if (pkg)
        -          link.target.package = pkg
        -      }
        +
        +      // we always need to read the package.json for link targets
        +      // because they can be changed by the local user
        +      const pj = link.realpath + '/package.json'
        +      const pkg = await rpj(pj).catch(() => null)
        +      if (pkg)
        +        link.target.package = pkg
             }
           }
         
           [assignParentage] (nodes) {
             for (const [location, node] of nodes) {
        +      // Skip assignment of parentage for the root package
        +      if (!location)
        +        continue
               const { path, name } = node
               for (const p of walkUp(dirname(path))) {
                 const ploc = relpath(this.path, p)
                 const parent = nodes.get(ploc)
                 if (!parent)
                   continue
        +        // Safety check: avoid self-assigning nodes as their own parents
        +        /* istanbul ignore if - should be obviated by parentage skip check */
        +        if (parent === node)
        +          continue
         
                 const locTest = `${ploc}/node_modules/${name}`.replace(/^\//, '')
                 const ptype = location === locTest
        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 57ecf071fbaff6..92943554b474e5 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
        @@ -10,10 +10,10 @@ const {dirname, resolve, relative} = require('path')
         const {depth: dfwalk} = require('treeverse')
         const fs = require('fs')
         const {promisify} = require('util')
        -const rename = promisify(fs.rename)
         const symlink = promisify(fs.symlink)
         const writeFile = promisify(fs.writeFile)
         const mkdirp = require('mkdirp-infer-owner')
        +const moveFile = require('@npmcli/move-file')
         const rimraf = promisify(require('rimraf'))
         const packageContents = require('@npmcli/installed-package-contents')
         
        @@ -60,6 +60,7 @@ const _rollbackRetireShallowNodes = Symbol.for('rollbackRetireShallowNodes')
         const _rollbackCreateSparseTree = Symbol.for('rollbackCreateSparseTree')
         const _rollbackMoveBackRetiredUnchanged = Symbol.for('rollbackMoveBackRetiredUnchanged')
         const _saveIdealTree = Symbol.for('saveIdealTree')
        +const _saveLockFile = Symbol('saveLockFile')
         const _copyIdealToActual = Symbol('copyIdealToActual')
         const _addOmitsToTrashList = Symbol('addOmitsToTrashList')
         const _packageLockOnly = Symbol('packageLockOnly')
        @@ -172,7 +173,7 @@ module.exports = cls => class Reifier extends cls {
               ignoreMissing: true,
               global: true,
               filter: (node, kid) => !node.isRoot ? true
        -      : this[_explicitRequests].has(kid),
        +      : (node.edgesOut.has(kid) || this[_explicitRequests].has(kid)),
             } : { ignoreMissing: true }
         
             if (!this[_global]) {
        @@ -182,7 +183,9 @@ module.exports = cls => class Reifier extends cls {
         
             // the global install space tends to have a lot of stuff in it.  don't
             // load all of it, just what we care about.  we won't be saving a
        -    // hidden lockfile in there anyway.
        +    // hidden lockfile in there anyway.  Note that we have to load ideal
        +    // BEFORE loading actual, so that the actualOpt can use the
        +    // explicitRequests which is set during buildIdealTree
             return this.buildIdealTree(bitOpt)
               .then(() => this.loadActual(actualOpt))
               .then(() => process.emit('timeEnd', 'reify:loadTrees'))
        @@ -251,7 +254,7 @@ module.exports = cls => class Reifier extends cls {
           }
         
           [_renamePath] (from, to, didMkdirp = false) {
        -    return rename(from, to)
        +    return moveFile(from, to)
               .catch(er => {
                 // Occasionally an expected bin file might not exist in the package,
                 // or a shim/symlink might have been moved aside.  If we've already
        @@ -261,7 +264,7 @@ module.exports = cls => class Reifier extends cls {
                   return didMkdirp ? null : mkdirp(dirname(to)).then(() =>
                     this[_renamePath](from, to, true))
                 } else if (er.code === 'EEXIST')
        -          return rimraf(to).then(() => rename(from, to))
        +          return rimraf(to).then(() => moveFile(from, to))
                 else
                   throw er
               })
        @@ -427,7 +430,7 @@ module.exports = cls => class Reifier extends cls {
             const dir = dirname(node.path)
             const target = node.realpath
             const rel = relative(dir, target)
        -    return symlink(rel, node.path, 'dir')
        +    return symlink(rel, node.path, 'junction')
           }
         
           [_warnDeprecated] (node) {
        @@ -436,23 +439,29 @@ module.exports = cls => class Reifier extends cls {
               this.log.warn('deprecated', `${_id}: ${deprecated}`)
           }
         
        -  [_loadAncientPackageDetails] (node) {
        +  async [_loadAncientPackageDetails] (node, forceReload = false) {
             // If we're loading from a v1 lockfile, load details from the package.json
             // that weren't recorded in the old format.
             const {meta} = this.idealTree
             const ancient = meta.ancientLockfile
             const old = meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)
        +
             // already replaced with the manifest if it's truly ancient
        -    if (old && !ancient) {
        +    if (node.path && (forceReload || (old && !ancient))) {
               // XXX should have a shared location where package.json is read,
               // so we don't ever read the same pj more than necessary.
        -      return rpj(node.path + '/package.json').then(pkg => {
        +      let pkg
        +      try {
        +        pkg = await rpj(node.path + '/package.json')
        +      } catch (err) {}
        +
        +      if (pkg) {
                 node.package.bin = pkg.bin
                 node.package.os = pkg.os
                 node.package.cpu = pkg.cpu
                 node.package.engines = pkg.engines
                 meta.add(node)
        -      })
        +      }
             }
           }
         
        @@ -839,12 +848,28 @@ module.exports = cls => class Reifier extends cls {
               format: (this[_formatPackageLock] && format) ? format
               : this[_formatPackageLock],
             }
        +
             return Promise.all([
        -      this[_usePackageLock] && this.idealTree.meta.save(saveOpt),
        +      this[_saveLockFile](saveOpt),
               writeFile(pj, json),
             ]).then(() => process.emit('timeEnd', 'reify:save'))
           }
         
        +  async [_saveLockFile] (saveOpt) {
        +    if (!this[_usePackageLock])
        +      return
        +
        +    const { meta } = this.idealTree
        +
        +    // might have to update metadata for bins and stuff that gets lost
        +    if (meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)) {
        +      for (const node of this.idealTree.inventory.values())
        +        await this[_loadAncientPackageDetails](node, true)
        +    }
        +
        +    return meta.save(saveOpt)
        +  }
        +
           [_copyIdealToActual] () {
             // save the ideal's meta as a hidden lockfile after we actualize it
             this.idealTree.meta.filename =
        diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/dep-valid.js b/deps/npm/node_modules/@npmcli/arborist/lib/dep-valid.js
        index 0e92ed4f058850..78661fea12b096 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/dep-valid.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/dep-valid.js
        @@ -112,7 +112,7 @@ const tarballValid = (child, requested, requestor) => {
             return false
         
           if (child.resolved)
        -    return child.resolved === `file:${requested.fetchSpec}`
        +    return child.resolved.replace(/\\/g, '/') === `file:${requested.fetchSpec.replace(/\\/g, '/')}`
         
           // if we have a legacy mutated package.json file.  we can't be 100%
           // sure that it resolved to the same file, but if it was the same
        diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/node.js b/deps/npm/node_modules/@npmcli/arborist/lib/node.js
        index a783ce9c975722..7381211ae37e8e 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/node.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/node.js
        @@ -35,6 +35,7 @@ const {normalize} = require('read-package-json-fast')
         const {getPaths: getBinPaths} = require('bin-links')
         const npa = require('npm-package-arg')
         const debug = require('./debug.js')
        +const gatherDepSet = require('./gather-dep-set.js')
         
         const {resolve, relative, dirname, basename} = require('path')
         const _package = Symbol('_package')
        @@ -112,8 +113,8 @@ class Node {
               throw new TypeError('could not detect node name from path or package')
         
             // should be equal if not a link
        -    this.path = path
        -    this.realpath = !this.isLink ? this.path : realpath
        +    this.path = path && resolve(path)
        +    this.realpath = !this.isLink ? this.path : resolve(realpath)
         
             this.resolved = resolved || null
             if (!this.resolved) {
        @@ -566,13 +567,32 @@ class Node {
             }
         
             debug(() => {
        -      if (!this.fsParent && this.realpath.indexOf(fsParent.realpath) !== 0)
        -        throw new Error('attempting to set fsParent improperly')
        +      if (fsParent === this)
        +        throw new Error('setting node to its own fsParent')
        +
        +      if (fsParent.realpath === this.realpath)
        +        throw new Error('setting fsParent to same path')
        +
        +      // the initial set MUST be an actual walk-up from the realpath
        +      // subsequent sets will re-root on the new fsParent's path.
        +      if (!this[_fsParent] && this.realpath.indexOf(fsParent.realpath) !== 0) {
        +        throw Object.assign(new Error('setting fsParent improperly'), {
        +          path: this.path,
        +          realpath: this.realpath,
        +          fsParent: {
        +            path: fsParent.path,
        +            realpath: fsParent.realpath,
        +          },
        +        })
        +      }
         
               if (fsParent.isLink)
        -        throw new Error('attempting to set fsParent to link node')
        +        throw new Error('setting fsParent to link node')
             })
         
        +    if (this === fsParent || fsParent.realpath === this.realpath)
        +      return
        +
             // prune off the original location, so we don't leave edges lying around
             if (current)
               this.fsParent = null
        @@ -621,8 +641,14 @@ class Node {
             if (node.name !== this.name)
               return false
         
        +    // 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) {
        -      if (!edge.satisfiedBy(node))
        +      // only care about edges that don't originate from this node
        +      if (!depSet.has(edge.from) && !edge.satisfiedBy(node))
                 return false
             }
         
        @@ -731,6 +757,9 @@ class Node {
           set parent (parent) {
             const oldParent = this[_parent]
         
        +    if (this === parent)
        +      return
        +
             // link nodes can't contain children directly.
             // children go under the link target.
             if (parent) {
        diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/yarn-lock.js b/deps/npm/node_modules/@npmcli/arborist/lib/yarn-lock.js
        index 17dbc235cda566..14c7691f1bd42c 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/yarn-lock.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/yarn-lock.js
        @@ -79,7 +79,7 @@ class YarnLock {
             const METADATA = /^ {2}[^\s]+ .+$/
             this.entries = new Map()
             this.current = null
        -    const linere = /([^\n]*)\n/gm
        +    const linere = /([^\r\n]*)\r?\n/gm
             let match
             let lineNum = 0
             if (!/\n$/.test(data))
        diff --git a/deps/npm/node_modules/@npmcli/arborist/package.json b/deps/npm/node_modules/@npmcli/arborist/package.json
        index fe72f409c4a457..e6e93fb67cec9a 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/package.json
        +++ b/deps/npm/node_modules/@npmcli/arborist/package.json
        @@ -1,14 +1,15 @@
         {
           "name": "@npmcli/arborist",
        -  "version": "1.0.8",
        +  "version": "1.0.12",
           "description": "Manage node_modules trees",
           "dependencies": {
             "@npmcli/installed-package-contents": "^1.0.5",
             "@npmcli/map-workspaces": "^1.0.1",
             "@npmcli/metavuln-calculator": "^1.0.0",
        +    "@npmcli/move-file": "^1.0.1",
             "@npmcli/name-from-folder": "^1.0.1",
             "@npmcli/node-gyp": "^1.0.0",
        -    "@npmcli/run-script": "^1.7.2",
        +    "@npmcli/run-script": "^1.8.0",
             "bin-links": "^2.2.1",
             "cacache": "^15.0.3",
             "common-ancestor-path": "^1.0.1",
        @@ -37,7 +38,7 @@
             "minify-registry-metadata": "^2.1.0",
             "mutate-fs": "^2.1.1",
             "require-inject": "^1.4.4",
        -    "tap": "^14.10.7",
        +    "tap": "^14.11.0",
             "tcompare": "^3.0.4"
           },
           "scripts": {
        @@ -68,6 +69,7 @@
             "node-arg": [
               "--unhandled-rejections=strict"
             ],
        +    "after": "test/fixtures/cleanup.js",
             "coverage-map": "map.js",
             "esm": false,
             "timeout": "120"
        diff --git a/deps/npm/node_modules/@npmcli/run-script/lib/make-spawn-args.js b/deps/npm/node_modules/@npmcli/run-script/lib/make-spawn-args.js
        index 181be8493f3343..4c38b9401ddf06 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/lib/make-spawn-args.js
        +++ b/deps/npm/node_modules/@npmcli/run-script/lib/make-spawn-args.js
        @@ -3,6 +3,24 @@ const isWindows = require('./is-windows.js')
         const setPATH = require('./set-path.js')
         const {resolve} = require('path')
         const npm_config_node_gyp = require.resolve('node-gyp/bin/node-gyp.js')
        +const { quoteForShell, ShellString, ShellStringText, ShellStringUnquoted } = require('puka')
        +
        +const escapeCmd = cmd => {
        +  const result = []
        +  const parsed = ShellString.sh([cmd])
        +  for (const child of parsed.children) {
        +    if (child instanceof ShellStringText) {
        +      const children = child.contents.filter(segment => segment !== null).map(segment => quoteForShell(segment, false, isWindows && 'win32'))
        +      result.push(...children)
        +    } else if (child instanceof ShellStringUnquoted) {
        +      result.push(child.value)
        +    } else {
        +      result.push(isWindows ? '&' : ';')
        +    }
        +  }
        +
        +  return result.join('')
        +}
         
         const makeSpawnArgs = options => {
           const {
        @@ -16,7 +34,7 @@ const makeSpawnArgs = options => {
           } = options
         
           const isCmd = /(?:^|\\)cmd(?:\.exe)?$/i.test(scriptShell)
        -  const args = isCmd ? ['/d', '/s', '/c', `"${cmd}"`] : ['-c', cmd]
        +  const args = isCmd ? ['/d', '/s', '/c', escapeCmd(cmd)] : ['-c', cmd]
         
           const spawnOpts = {
             env: setPATH(path, {
        diff --git a/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js b/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js
        index 5980376f558f42..ccde173e014f6c 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js
        +++ b/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js
        @@ -6,7 +6,8 @@ const signalManager = require('./signal-manager.js')
         const isServerPackage = require('./is-server-package.js')
         
         // you wouldn't like me when I'm angry...
        -const bruce = (id, event, cmd) => `\n> ${id ? id + ' ' : ''}${event}\n> ${cmd}\n`
        +const bruce = (id, event, cmd) =>
        +  `\n> ${id ? id + ' ' : ''}${event}\n> ${cmd.trim().replace(/\n/g, '\n> ')}\n`
         
         const runScriptPkg = async options => {
           const {
        @@ -20,6 +21,9 @@ const runScriptPkg = async options => {
             stdioString = false,
             // note: only used when stdio:inherit
             banner = true,
        +    // how long to wait for a process.kill signal
        +    // only exposed here so that we can make the test go a bit faster.
        +    signalTimeout = 500,
           } = options
         
           const {scripts = {}, gypfile} = pkg
        @@ -68,7 +72,17 @@ const runScriptPkg = async options => {
           if (p.stdin)
             p.stdin.end()
         
        -  return p
        +  return p.catch(er => {
        +    const { signal } = er
        +    if (stdio === 'inherit' && signal) {
        +      process.kill(process.pid, signal)
        +      // just in case we don't die, reject after 500ms
        +      // this also keeps the node process open long enough to actually
        +      // get the signal, rather than terminating gracefully.
        +      return new Promise((res, rej) => setTimeout(() => rej(er), signalTimeout))
        +    } else
        +      throw er
        +  })
         }
         
         module.exports = runScriptPkg
        diff --git a/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js b/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js
        index 3be39b0ba8076f..af33d2113f9ef0 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js
        +++ b/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js
        @@ -1,6 +1,7 @@
         const rpj = require('read-package-json-fast')
         const runScriptPkg = require('./run-script-pkg.js')
         const validateOptions = require('./validate-options.js')
        +const isServerPackage = require('./is-server-package.js')
         
         const runScript = options => {
           validateOptions(options)
        @@ -9,4 +10,4 @@ const runScript = options => {
             : rpj(path + '/package.json').then(pkg => runScriptPkg({...options, pkg}))
         }
         
        -module.exports = runScript
        +module.exports = Object.assign(runScript, { isServerPackage })
        diff --git a/deps/npm/node_modules/@npmcli/run-script/lib/set-path.js b/deps/npm/node_modules/@npmcli/run-script/lib/set-path.js
        index dfa8001b7743dd..d7bd2c2886b355 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/lib/set-path.js
        +++ b/deps/npm/node_modules/@npmcli/run-script/lib/set-path.js
        @@ -1,6 +1,8 @@
         const {resolve, dirname} = require('path')
         const isWindows = require('./is-windows.js')
        -const nodeGypPath = resolve(__dirname, 'node-gyp-bin')
        +// the path here is relative, even though it does not need to be
        +// in order to make the posix tests pass in windows
        +const nodeGypPath = resolve(__dirname, '../lib/node-gyp-bin')
         
         // Windows typically calls its PATH environ 'Path', but this is not
         // guaranteed, nor is it guaranteed to be the only one.  Merge them
        diff --git a/deps/npm/node_modules/@npmcli/run-script/package.json b/deps/npm/node_modules/@npmcli/run-script/package.json
        index 5ec3bb5b66876e..7adb5c76d82cc1 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/package.json
        +++ b/deps/npm/node_modules/@npmcli/run-script/package.json
        @@ -1,6 +1,6 @@
         {
           "name": "@npmcli/run-script",
        -  "version": "1.7.4",
        +  "version": "1.8.1",
           "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)",
           "author": "Isaac Z. Schlueter  (https://izs.me)",
           "license": "ISC",
        @@ -32,6 +32,7 @@
             "@npmcli/promise-spawn": "^1.3.0",
             "infer-owner": "^1.0.4",
             "node-gyp": "^7.1.0",
        +    "puka": "^1.0.1",
             "read-package-json-fast": "^1.1.3"
           },
           "files": [
        diff --git a/deps/npm/node_modules/libnpmversion/lib/version.js b/deps/npm/node_modules/libnpmversion/lib/version.js
        index ee02fb7ffb9d0a..309b9c2b9504f0 100644
        --- a/deps/npm/node_modules/libnpmversion/lib/version.js
        +++ b/deps/npm/node_modules/libnpmversion/lib/version.js
        @@ -34,7 +34,7 @@ module.exports = async (newversion, opts) => {
           } = opts
         
           const { valid, clean, inc } = semver
        -  const current = pkg.version
        +  const current = pkg.version || '0.0.0'
           const currentClean = clean(current)
         
           const newV = valid(newversion, { loose: true }) ? clean(newversion, { loose: true })
        diff --git a/deps/npm/node_modules/libnpmversion/package.json b/deps/npm/node_modules/libnpmversion/package.json
        index 856e36da6d564d..d7e8d5fa586476 100644
        --- a/deps/npm/node_modules/libnpmversion/package.json
        +++ b/deps/npm/node_modules/libnpmversion/package.json
        @@ -1,6 +1,6 @@
         {
           "name": "libnpmversion",
        -  "version": "1.0.6",
        +  "version": "1.0.7",
           "main": "lib/index.js",
           "files": [
             "lib/*.js"
        diff --git a/deps/npm/node_modules/pacote/lib/fetcher.js b/deps/npm/node_modules/pacote/lib/fetcher.js
        index 01058acb2bfef7..5142bb280a70c7 100644
        --- a/deps/npm/node_modules/pacote/lib/fetcher.js
        +++ b/deps/npm/node_modules/pacote/lib/fetcher.js
        @@ -91,18 +91,11 @@ class FetcherBase {
         
             // command to run 'prepare' scripts on directories and git dirs
             // To use pacote with yarn, for example, set npmBin to 'yarn'
        -    // and npmInstallCmd to ['add'], and npmCliConfig with yarn's equivalents.
        +    // and npmCliConfig with yarn's equivalents.
             this.npmBin = opts.npmBin || 'npm'
         
             // command to install deps for preparing
        -    this.npmInstallCmd = opts.npmInstallCmd || [
        -      'install',
        -      '--only=dev',
        -      '--prod',
        -      '--ignore-prepublish',
        -      '--no-progress',
        -      '--no-save',
        -    ]
        +    this.npmInstallCmd = opts.npmInstallCmd || [ 'install' ]
         
             // XXX fill more of this in based on what we know from this.opts
             // we explicitly DO NOT fill in --tag, though, since we are often
        @@ -113,7 +106,10 @@ class FetcherBase {
               `--prefer-offline=${!!this.preferOffline}`,
               `--prefer-online=${!!this.preferOnline}`,
               `--offline=${!!this.offline}`,
        -      `--before=${this.before ? this.before.toISOString() : ''}`,
        +      ...(this.before ? [`--before=${this.before.toISOString()}`] : []),
        +      '--no-progress',
        +      '--no-save',
        +      '--no-audit',
             ]
           }
         
        diff --git a/deps/npm/node_modules/pacote/package.json b/deps/npm/node_modules/pacote/package.json
        index 7f38a193f7cb94..bef19b66228a66 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.1.12",
        +  "version": "11.1.13",
           "description": "JavaScript package downloader",
           "author": "Isaac Z. Schlueter  (https://izs.me)",
           "bin": {
        @@ -47,7 +47,7 @@
             "minipass": "^3.1.3",
             "mkdirp": "^1.0.3",
             "npm-package-arg": "^8.0.1",
        -    "npm-packlist": "^2.1.0",
        +    "npm-packlist": "^2.1.4",
             "npm-pick-manifest": "^6.0.0",
             "npm-registry-fetch": "^9.0.0",
             "promise-retry": "^1.1.1",
        diff --git a/deps/npm/node_modules/puka/CHANGELOG.md b/deps/npm/node_modules/puka/CHANGELOG.md
        new file mode 100644
        index 00000000000000..781b81295a4a7f
        --- /dev/null
        +++ b/deps/npm/node_modules/puka/CHANGELOG.md
        @@ -0,0 +1,31 @@
        +# Changelog
        +All notable changes to this project will be documented in this file.
        +
        +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
        +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
        +
        +## [1.0.1](https://gitlab.com/rhendric/puka/-/compare/v1.0.0...v1.0.1) - 2020-05-16
        +
        +### Fixed
        +
        +- Add more carets to win32 command arguments ([45965ca](https://gitlab.com/rhendric/puka/-/commit/45965ca60fcc518082e0b085d8e81f3f3279ffb4))
        +
        +    As previously documented and implemented, Puka assumed that all programs
        +    are batch files for the purpose of multi-escaping commands that appear
        +    in pipelines. However, regardless of whether a command is in a pipeline,
        +    one extra layer of escaping is needed if the command invokes a batch
        +    file, which Puka was not producing. This only applies to the arguments
        +    to the command, not to the batch file path, nor to paths used in
        +    redirects. (The property-based spawn test which was supposed to catch
        +    such oversights missed this one because it was invoking the Node.js
        +    executable directly, not, as recommended in the documentation, a batch
        +    file.)
        +
        +    Going forward, the caveats described in the documentation continue to
        +    apply: if you are running programs on Windows with Puka, make sure they
        +    are batch files, or you may find arguments are being escaped with too
        +    many carets. As the documentation says, if this causes problems for you,
        +    please open an issue so we can work out the details of what a good
        +    workaround looks like.
        +
        +## [1.0.0](https://gitlab.com/rhendric/puka/-/tags/v1.0.0) - 2017-09-29
        diff --git a/deps/npm/node_modules/puka/LICENSE.txt b/deps/npm/node_modules/puka/LICENSE.txt
        new file mode 100644
        index 00000000000000..0141196a593376
        --- /dev/null
        +++ b/deps/npm/node_modules/puka/LICENSE.txt
        @@ -0,0 +1,18 @@
        +Copyright 2017 Ryan Hendrickson 
        +
        +Permission is hereby granted, free of charge, to any person obtaining a copy of
        +this software and associated documentation files (the "Software"), to deal in
        +the Software without restriction, including without limitation the rights to
        +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
        +the Software, and to permit persons to whom the Software is furnished to do so,
        +subject to the following conditions:
        +
        +The above copyright notice and this permission notice shall be included in all
        +copies or substantial portions of the Software.
        +
        +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
        +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
        +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
        +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
        +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
        diff --git a/deps/npm/node_modules/puka/README.md b/deps/npm/node_modules/puka/README.md
        new file mode 100644
        index 00000000000000..edbda4d3a29fb9
        --- /dev/null
        +++ b/deps/npm/node_modules/puka/README.md
        @@ -0,0 +1,411 @@
        +# Puka
        +
        +[![GitLab CI pipeline status](https://gitlab.com/rhendric/puka/badges/master/pipeline.svg)](https://gitlab.com/rhendric/puka/commits/master) [![AppVeyor build status](https://img.shields.io/appveyor/ci/rhendric/puka.svg?label=windows%20tests)](https://ci.appveyor.com/project/rhendric/puka) [![Codecov status](https://img.shields.io/codecov/c/gl/rhendric/puka.svg)](https://codecov.io/gl/rhendric/puka)
        +
        +Puka is a cross-platform library for safely passing strings through shells.
        +
        +#### Contents
        +
        +-   [Introduction](#introduction)
        +    -   [Why would I use Puka?](#why-would-i-use-puka)
        +    -   [How do I use Puka?](#how-do-i-use-puka)
        +    -   [What's the catch?](#whats-the-catch)
        +-   [API Documentation](#api-documentation)
        +    -   [Basic API](#basic-api)
        +        -   [sh](#sh)
        +        -   [unquoted](#unquoted)
        +    -   [Advanced API](#advanced-api)
        +        -   [quoteForShell](#quoteforshell)
        +        -   [quoteForCmd](#quoteforcmd)
        +        -   [quoteForSh](#quoteforsh)
        +        -   [ShellString](#shellstring)
        +    -   [Secret API](#secret-api)
        +-   [The sh DSL](#the-sh-dsl)
        +    -   [Syntax](#syntax)
        +    -   [Semantics](#semantics)
        +        -   [Types of placeholders](#types-of-placeholders)
        +
        +## Introduction
        +
        +### Why would I use Puka?
        +
        +When launching a child process from Node, you have a choice between launching
        +directly from the operating system (as with [child_process.spawn](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options),
        +if you don't use the `{ shell: true }` option), and running the command through
        +a shell (as with [child_process.exec](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)).
        +Using a shell gives you more power, such as the ability to chain multiple
        +commands together or use redirection, but you have to construct your command as
        +a single string instead of using an array of arguments. And doing that can be
        +buggy (if not dangerous) if you don't take care to quote any arguments
        +correctly for the shell you're targeting, _and_ the quoting has to be done
        +differently on Windows and non-Windows shells.
        +
        +Puka solves that problem by giving you a simple and platform-agnostic way to
        +build shell commands with arguments that pass through your shell unaltered and
        +with no unsafe side effects, **whether you are running on Windows or a
        +Unix-based OS**.
        +
        +### How do I use Puka?
        +
        +Puka gives you an `sh` function intended for tagging
        +[template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals),
        +which quotes (if necessary) any values interpolated into the template. A simple
        +example:
        +
        +```javascript
        +const { sh } = require('puka');
        +const { execSync } = require('child_process');
        +
        +const arg = 'file with spaces.txt';
        +execSync(sh`some-command ${arg}`);
        +```
        +
        +But Puka supports more than this! See [the `sh` DSL documentation](#the-sh-dsl)
        +for a detailed description of all the features currently supported.
        +
        +### What's the catch?
        +
        +Here are the ones I know about:
        +
        +Puka does _not_ ensure that the actual commands you're running are
        +cross-platform. If you're running npm programs, you generally won't have a
        +problem with that, but if you want to run ``sh`cat file` `` on Windows, you'll
        +need to depend on something like
        +[cash-cat](https://www.npmjs.com/package/cash-cat).
        +
        +I searched for days for a way to quote or escape line breaks in arguments to
        +`cmd.exe`, but couldn't find one (regular `^`-prepending and quotation marks
        +don't seem to cut it). If you know of a way that works, please [open an
        +issue](https://gitlab.com/rhendric/puka/issues/new) to tell me about it! Until
        +then, any line break characters (`\r` or `\n`) in values being interpolated by
        +`sh` will cause an error to be thrown on Windows only.
        +
        +Also on Windows, you may notice quoting mistakes if you run commands that
        +involve invoking a native executable (not a batch file ending in `.cmd` or
        +`.bat`). Unfortunately, batch files require some extra escaping on Windows, and
        +Puka assumes all programs are batch files because npm creates batch file shims
        +for programs it installs (and, if you care about cross-platform, you'll be
        +using npm programs in your commands). If this causes problems for you, please
        +[open an issue](https://gitlab.com/rhendric/puka/issues/new); if your situation
        +is specific enough, there may be workarounds or improvements to Puka to be
        +found.
        +
        +## API Documentation
        +
        +### Basic API
        +
        +
        +
        +
        +#### sh
        +
        +A string template tag for safely constructing cross-platform shell commands.
        +
        +An `sh` template is not actually treated as a literal string to be
        +interpolated; instead, it is a tiny DSL designed to make working with shell
        +strings safe, simple, and straightforward. To get started quickly, see the
        +examples below. [More detailed documentation][1] is available
        +further down.
        +
        +##### Examples
        +
        +```javascript
        +const title = '"this" & "that"';
        +sh`script --title=${title}`; // => "script '--title=\"this\" & \"that\"'"
        +// Note: these examples show results for non-Windows platforms.
        +// On Windows, the above would instead be
        +// 'script ^^^"--title=\\^^^"this\\^^^" ^^^& \\^^^"that\\^^^"^^^"'.
        +
        +const names = ['file1', 'file 2'];
        +sh`rimraf ${names}.txt`; // => "rimraf file1.txt 'file 2.txt'"
        +
        +const cmd1 = ['cat', 'file 1.txt', 'file 2.txt'];
        +const cmd2 = ['use-input', '-abc'];
        +sh`${cmd1}|${cmd2}`; // => "cat 'file 1.txt' 'file 2.txt'|use-input -abc"
        +```
        +
        +Returns **[String][2]** a string formatted for the platform Node is currently
        +running on.
        +
        +#### unquoted
        +
        +This function permits raw strings to be interpolated into a `sh` template.
        +
        +**IMPORTANT**: If you're using Puka due to security concerns, make sure you
        +don't pass any untrusted content to `unquoted`. This may be obvious, but
        +stray punctuation in an `unquoted` section can compromise the safety of the
        +entire shell command.
        +
        +##### Parameters
        +
        +-   `value`  any value (it will be treated as a string)
        +
        +##### Examples
        +
        +```javascript
        +const both = true;
        +sh`foo ${unquoted(both ? '&&' : '||')} bar`; // => 'foo && bar'
        +```
        +
        +### Advanced API
        +
        +If these functions make life easier for you, go ahead and use them; they
        +are just as well supported as the above. But if you aren't certain you
        +need them, you probably don't.
        +
        +
        +#### quoteForShell
        +
        +Quotes a string for injecting into a shell command.
        +
        +This function is exposed for some hypothetical case when the `sh` DSL simply
        +won't do; `sh` is expected to be the more convenient option almost always.
        +Compare:
        +
        +```javascript
        +console.log('cmd' + args.map(a => ' ' + quoteForShell(a)).join(''));
        +console.log(sh`cmd ${args}`); // same as above
        +
        +console.log('cmd' + args.map(a => ' ' + quoteForShell(a, true)).join(''));
        +console.log(sh`cmd "${args}"`); // same as above
        +```
        +
        +Additionally, on Windows, `sh` checks the entire command string for pipes,
        +which subtly change how arguments need to be quoted. If your commands may
        +involve pipes, you are strongly encouraged to use `sh` and not try to roll
        +your own with `quoteForShell`.
        +
        +##### Parameters
        +
        +-   `text` **[String][2]** to be quoted
        +-   `forceQuote` **[Boolean][3]?** whether to always add quotes even if the string
        +    is already safe. Defaults to `false`.
        +-   `platform` **[String][2]?** a value that `process.platform` might take:
        +    `'win32'`, `'linux'`, etc.; determines how the string is to be formatted.
        +    When omitted, effectively the same as `process.platform`.
        +
        +Returns **[String][2]** a string that is safe for the current (or specified)
        +platform.
        +
        +#### quoteForCmd
        +
        +A Windows-specific version of [quoteForShell][4].
        +
        +##### Parameters
        +
        +-   `text` **[String][2]** to be quoted
        +-   `forceQuote` **[Boolean][3]?** whether to always add quotes even if the string
        +    is already safe. Defaults to `false`.
        +
        +#### quoteForSh
        +
        +A Unix-specific version of [quoteForShell][4].
        +
        +##### Parameters
        +
        +-   `text` **[String][2]** to be quoted
        +-   `forceQuote` **[Boolean][3]?** whether to always add quotes even if the string
        +    is already safe. Defaults to `false`.
        +
        +#### ShellString
        +
        +A ShellString represents a shell command after it has been interpolated, but
        +before it has been formatted for a particular platform. ShellStrings are
        +useful if you want to prepare a command for a different platform than the
        +current one, for instance.
        +
        +To create a ShellString, use `ShellString.sh` the same way you would use
        +top-level `sh`.
        +
        +##### toString
        +
        +A method to format a ShellString into a regular String formatted for a
        +particular platform.
        +
        +###### Parameters
        +
        +-   `platform` **[String][2]?** a value that `process.platform` might take:
        +    `'win32'`, `'linux'`, etc.; determines how the string is to be formatted.
        +    When omitted, effectively the same as `process.platform`.
        +
        +Returns **[String][2]**
        +
        +##### sh
        +
        +`ShellString.sh` is a template tag just like `sh`; the only difference is
        +that this function returns a ShellString which has not yet been formatted
        +into a String.
        +
        +Returns **[ShellString][5]**
        +
        +### Secret API
        +
        +Some internals of string formatting have been exposed for the ambitious and
        +brave souls who want to try to extend Puka to handle more shells or custom
        +interpolated values. This ‘secret’ API is partially documented in the code
        +but not here, and the semantic versioning guarantees on this API are bumped
        +down by one level: in other words, minor version releases of Puka can change
        +the secret API in backward-incompatible ways, and patch releases can add or
        +deprecate functionality.
        +
        +If it's not even documented in the code, use at your own risk—no semver
        +guarantees apply.
        +
        +
        +[1]: #the-sh-dsl
        +
        +[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
        +
        +[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
        +
        +[4]: #quoteforshell
        +
        +[5]: #shellstring
        +
        +## The sh DSL
        +
        +### Syntax
        +
        +An `sh` template comprises words, separated by whitespace. Words can contain:
        +
        +-   text, which is composed of any characters that are not whitespace, single or
        +    double quotes, or any of the special characters
        +    ``# $ & ( ) ; < > \ ` |``;
        +-   quotations, which are matching single or double quotes surrounding any
        +    characters other than the delimiting quote; and
        +-   placeholders, using the standard JavaScript template syntax (`${}`).
        +    (Placeholders may also appear inside quotations.)
        +
        +The special characters ``# $ & ( ) ; < > \ ` |``, if unquoted, form their own
        +words.
        +
        +Redirect operators (`<`, `>`, `>>`, `2>`, etc.) receive their own special
        +handling, as do semicolons. Other than these two exceptions, no attempt is made
        +to understand any more sophisticated features of shell syntax.
        +
        +Standard JavaScript escape sequences, such as `\t`, are honored in the template
        +literal, and are treated equivalently to the characters they represent. There
        +is no further mechanism for escaping within the `sh` DSL itself; in particular,
        +if you want to put quotes inside quotes, you have to use interpolation, like
        +this:
        +
        +```javascript
        +sh`echo "${'single = \', double = "'}"` // => "echo 'single = '\\'', double = \"'"
        +```
        +
        +### Semantics
        +
        +Words that do not contain placeholders are emitted mostly verbatim to the
        +output string. Quotations are formatted in the expected style for the target
        +platform (single quotes for Unix, double quotes for Windows) regardless of the
        +quotes used in the template literal—as with JavaScript, single and double quotes
        +are interchangeable, except for the requirement to pair like with like. Unquoted
        +semicolons are translated to ampersands on Windows; all other special characters
        +(as enumerated above), when unquoted, are passed as-is to the output for the
        +shell to interpret.
        +
        +Puka may still quote words not containing the above special characters, if they
        +contain characters that need quoting on the target platform. For example, on
        +Windows, the character `%` is used for variable interpolation in `cmd.exe`, and
        +Puka quotes it on on that platform even if it appears unquoted in the template
        +literal. Consequently, there is no need to be paranoid about quoting anything
        +that doesn't look alphanumeric inside a `sh` template literal, for fear of being
        +burned on a different operating system; anything that matches the definition of
        +‘text’ above will never need manual quoting.
        +
        +#### Types of placeholders
        +
        +##### Strings
        +
        +If a word contains a string placeholder, then the value of the placeholder is
        +interpolated into the word and the entire word, if necessary, is quoted. If
        +the placeholder occurs within quotes, no further quoting is performed:
        +
        +```javascript
        +sh`script --file="${'herp derp'}.txt"`; // => "script --file='herp derp.txt'"
        +```
        +
        +This behavior can be exploited to force consistent quoting, if desired; but
        +both of the examples below are safe on all platforms:
        +
        +```javascript
        +const words = ['oneword', 'two words'];
        +sh`minimal ${words[0]}`; // => "minimal oneword"
        +sh`minimal ${words[1]}`; // => "minimal 'two words'"
        +sh`consistent '${words[0]}'`; // => "consistent 'oneword'"
        +sh`consistent '${words[1]}'`; // => "consistent 'two words'"
        +```
        +
        +##### Arrays and iterables
        +
        +If a word contains a placeholder for an array (or other iterable object), then
        +the entire word is repeated once for each value in the array, separated by
        +spaces. If the array is empty, then the word is not emitted at all, and neither
        +is any leading whitespace.
        +
        +```javascript
        +const files = ['foo', 'bar'];
        +sh`script ${files}`; // => "script foo bar"
        +sh`script --file=${files}`; // => "script --file=foo --file=bar"
        +sh`script --file=${[]}`; // => "script"
        +```
        +
        +Note that, since special characters are their own words, the pipe operator here
        +is not repeated:
        +
        +```javascript
        +const cmd = ['script', 'foo', 'bar'];
        +sh`${cmd}|another-script`; // => "script foo bar|another-script"
        +```
        +
        +Multiple arrays in the same word generate a Cartesian product:
        +
        +```javascript
        +const names = ['foo', 'bar'], exts = ['log', 'txt'];
        +// Same word
        +sh`... ${names}.${exts}`; // => "... foo.log foo.txt bar.log bar.txt"
        +sh`... "${names} ${exts}"`; // => "... 'foo log' 'foo txt' 'bar log' 'bar txt'"
        +
        +// Not the same word (extra space just for emphasis):
        +sh`... ${names}   ${exts}`; // => "... foo bar   log txt"
        +sh`... ${names};${exts}`; // => "... foo bar;log txt"
        +```
        +
        +Finally, if a placeholder appears in the object of a redirect operator, the
        +entire redirect is repeated as necessary:
        +
        +```javascript
        +sh`script > ${['foo', 'bar']}.txt`; // => "script > foo.txt > bar.txt"
        +sh`script > ${[]}.txt`; // => "script"
        +```
        +
        +##### unquoted
        +
        +The `unquoted` function returns a value that will skip being quoted when used
        +in a placeholder, alone or in an array.
        +
        +```javascript
        +const cmd = 'script < input.txt';
        +const fields = ['foo', 'bar'];
        +sh`${unquoted(cmd)} | json ${fields}`; // => "script < input.txt | json foo bar"
        +```
        +
        +##### ShellString
        +
        +If `ShellString.sh` is used to construct an unformatted ShellString, that value
        +can be used in a placeholder to insert the contents of the ShellString into the
        +outer template literal. This is safer than using `unquoted` as in the previous
        +example, but `unquoted` can be used when all you have is a string from another
        +(trusted!) source.
        +
        +```javascript
        +const url = 'http://example.com/data.json?x=1&y=2';
        +const curl = ShellString.sh`curl -L ${url}`;
        +const fields = ['foo', 'bar'];
        +sh`${curl} | json ${fields}`; // => "curl -L 'http://example.com/data.json?x=1&y=2' | json foo bar"
        +```
        +
        +##### Anything else
        +
        +... is treated like a string—namely, a value `x` is equivalent to `'' + x`, if
        +not in one of the above categories.
        diff --git a/deps/npm/node_modules/puka/index.js b/deps/npm/node_modules/puka/index.js
        new file mode 100644
        index 00000000000000..b69e47d7639db9
        --- /dev/null
        +++ b/deps/npm/node_modules/puka/index.js
        @@ -0,0 +1,804 @@
        +'use strict';
        +
        +Object.defineProperty(exports, '__esModule', { value: true });
        +
        +/**
        + * Key a method on your object with this symbol and you can get special
        + * formatting for that value! See ShellStringText, ShellStringUnquoted, or
        + * shellStringSemicolon for examples.
        + * @ignore
        + */
        +const formatSymbol = Symbol('format');
        +/**
        + * This symbol is for implementing advanced behaviors like the need for extra
        + * carets in Windows shell strings that use pipes. If present, it's called in
        + * an earlier phase than formatSymbol, and is passed a mutable context that can
        + * be read during the format phase to influence formatting.
        + * @ignore
        + */
        +const preformatSymbol = Symbol('preformat');
        +
        +// When minimum Node version becomes 6, replace calls to sticky with /.../y and
        +// inline execFrom.
        +let stickySupported = true;
        +try {
        +  new RegExp('', 'y');
        +} catch (e) {
        +  stickySupported = false;
        +}
        +const sticky = stickySupported ? source => new RegExp(source, 'y') : source => new RegExp(`^(?:${source})`);
        +const execFrom = stickySupported ? (re, haystack, index) => (re.lastIndex = index, re.exec(haystack)) : (re, haystack, index) => re.exec(haystack.substr(index));
        +
        +function quoteForCmd(text, forceQuote) {
        +  let caretDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        +  // See the below blog post for an explanation of this function and
        +  // quoteForWin32:
        +  // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
        +  if (!text.length) {
        +    return '""';
        +  }
        +  if (/[\n\r]/.test(text)) {
        +    throw new Error("Line breaks can't be quoted on Windows");
        +  }
        +  const caretEscape = /["%]/.test(text);
        +  text = quoteForWin32(text, forceQuote || !caretEscape && /[&()<>^|]/.test(text));
        +  if (caretEscape) {
        +    // See Win32Context for explanation of what caretDepth is for.
        +    do {
        +      text = text.replace(/[\t "%&()<>^|]/g, '^$&');
        +    } while (caretDepth--);
        +  }
        +  return text;
        +}
        +const quoteForWin32 = (text, forceQuote) => forceQuote || /[\t "]/.test(text) ? `"${text.replace(/\\+(?=$|")/g, '$&$&').replace(/"/g, '\\"')}"` : text;
        +const cmdMetaChars = /[\t\n\r "%&()<>^|]/;
        +class Win32Context {
        +  constructor() {
        +    this.currentScope = newScope(null);
        +    this.scopesByObject = new Map();
        +    this.argDetectState = 0;
        +    this.argSet = new Set();
        +  }
        +  read(text) {
        +    // When cmd.exe executes a batch file, or pipes to or from one, it spawns a
        +    // second copy of itself to run the inner command. This necessitates
        +    // doubling up on carets so that escaped characters survive both cmd.exe
        +    // invocations. See:
        +    // https://stackoverflow.com/questions/8192318/why-does-delayed-expansion-fail-when-inside-a-piped-block-of-code#8194279
        +    // https://ss64.com/nt/syntax-redirection.html
        +    //
        +    // Parentheses can create an additional subshell, requiring additional
        +    // escaping... it's a mess.
        +    //
        +    // So here's what we do about it: we read all unquoted text in a shell
        +    // string and put it through this tiny parser that looks for pipes,
        +    // sequence operators (&, &&, ||), redirects, and parentheses. This can't
        +    // be part of the main Puka parsing, because it can be affected by
        +    // `unquoted(...)` values provided at evaluation time.
        +    //
        +    // Then, after associating each thing that needs to be quoted with a scope
        +    // (via `mark()`), and identifying whether or not it's an argument to a
        +    // command, we can determine the depth of caret escaping required in each
        +    // scope and pass it (via `Formatter::quote()`) to `quoteForCmd()`.
        +    //
        +    // See also `ShellStringText`, which holds the logic for the previous
        +    // paragraph.
        +    const length = text.length;
        +    for (let pos = 0, match; pos < length;) {
        +      while (match = execFrom(reUnimportant, text, pos)) {
        +        if (match[2] == null) {
        +          // (not whitespace)
        +          if (match[1] != null) {
        +            // (>&)
        +            this.argDetectState = this.argDetectState === 0 ? ADS_FLAG_INITIAL_REDIRECT : 0;
        +          } else if (this.argDetectState !== ADS_FLAG_ARGS) {
        +            this.argDetectState |= ADS_FLAG_WORD;
        +          }
        +        } else {
        +          // (whitespace)
        +          if ((this.argDetectState & ADS_FLAG_WORD) !== 0) {
        +            this.argDetectState = ADS_FLAG_ARGS & ~this.argDetectState >> 1;
        +          }
        +        }
        +        pos += match[0].length;
        +      }
        +      if (pos >= length) break;
        +      if (match = execFrom(reSeqOp, text, pos)) {
        +        this.seq();
        +        pos += match[0].length;
        +      } else {
        +        const char = text.charCodeAt(pos);
        +        if (char === CARET) {
        +          pos += 2;
        +        } else if (char === QUOTE) {
        +          // If you were foolish enough to leave a dangling quotation mark in
        +          // an unquoted span... you're likely to have bigger problems than
        +          // incorrect escaping. So we just do the simplest thing of looking for
        +          // the end quote only in this piece of text.
        +          pos += execFrom(reNotQuote, text, pos + 1)[0].length + 2;
        +        } else {
        +          if (char === OPEN_PAREN) {
        +            this.enterScope();
        +          } else if (char === CLOSE_PAREN) {
        +            this.exitScope();
        +          } else if (char === PIPE) {
        +            this.pipe();
        +          } else {
        +            // (char === '<' or '>')
        +            this.argDetectState = this.argDetectState === 0 ? ADS_FLAG_INITIAL_REDIRECT : 0;
        +          }
        +          pos++;
        +        }
        +      }
        +    }
        +  }
        +  enterScope() {
        +    this.currentScope = newScope(this.currentScope);
        +    this.argDetectState = 0;
        +  }
        +  exitScope() {
        +    this.currentScope = this.currentScope.parent || (this.currentScope.parent = newScope(null));
        +    this.argDetectState = ADS_FLAG_ARGS;
        +  }
        +  seq() {
        +    // | binds tighter than sequence operators, so the latter create new sibling
        +    // scopes for future |s to mutate.
        +    this.currentScope = newScope(this.currentScope.parent);
        +    this.argDetectState = 0;
        +  }
        +  pipe() {
        +    this.currentScope.depthDelta = 1;
        +    this.argDetectState = 0;
        +  }
        +  mark(obj) {
        +    this.scopesByObject.set(obj, this.currentScope);
        +    if (this.argDetectState === ADS_FLAG_ARGS) {
        +      this.argSet.add(obj);
        +    } else {
        +      this.argDetectState |= ADS_FLAG_WORD;
        +    }
        +  }
        +  at(obj) {
        +    const scope = this.scopesByObject.get(obj);
        +    return {
        +      depth: getDepth(scope),
        +      isArgument: this.argSet.has(obj),
        +      isNative: scope.isNative
        +    };
        +  }
        +}
        +// These flags span the Win32Context's argument detection state machine. WORD
        +// is set when the context is inside a word that is not an argument (meaning it
        +// is either the first word in the command, or it is the object of a redirect).
        +// ARGS is set when the context has reached the arguments of a command.
        +// INITIAL_REDIRECT tracks the edge case when a redirect occurs before the
        +// first word of the command (if this flag is set, reaching the end of a word
        +// should take the state machine back to 0 instead of setting ADS_FLAG_ARGS).
        +const ADS_FLAG_WORD = 0x1;
        +const ADS_FLAG_ARGS = 0x2;
        +const ADS_FLAG_INITIAL_REDIRECT = 0x4;
        +const getDepth = scope => scope === null ? 0 : scope.depth !== -1 ? scope.depth : scope.depth = getDepth(scope.parent) + scope.depthDelta;
        +const newScope = parent => ({
        +  parent,
        +  depthDelta: 0,
        +  depth: -1,
        +  isNative: false
        +});
        +const CARET = '^'.charCodeAt();
        +const QUOTE = '"'.charCodeAt();
        +const OPEN_PAREN = '('.charCodeAt();
        +const CLOSE_PAREN = ')'.charCodeAt();
        +const PIPE = '|'.charCodeAt();
        +const reNotQuote = sticky('[^"]*');
        +const reSeqOp = sticky('&&?|\\|\\|');
        +const reUnimportant = sticky('(\\d*>&)|[^\\s"$&()<>^|]+|(\\s+)');
        +
        +const quoteForSh = (text, forceQuote) => text.length ? forceQuote || shMetaChars.test(text) ? `'${text.replace(/'/g, "'\\''")}'`.replace(/^(?:'')+(?!$)/, '').replace(/\\'''/g, "\\'") : text : "''";
        +const shMetaChars = /[\t\n\r "#$&'()*;<>?\\`|~]/;
        +
        +/**
        + * To get a Formatter, call `Formatter.for`.
        + *
        + * To create a new Formatter, pass an object to `Formatter.declare`.
        + *
        + * To set the global default Formatter, assign to `Formatter.default`.
        + *
        + * @class
        + * @property {Formatter} default - The Formatter to be used when no platform
        + * is provided—for example, when creating strings with `sh`.
        + * @ignore
        + */
        +function Formatter() {}
        +Object.assign(Formatter,
        +/** @lends Formatter */
        +{
        +  /**
        +   * Gets a Formatter that has been declared for the provided platform, or
        +   * the base `'sh'` formatter if there is no Formatter specific to this
        +   * platform, or the Formatter for the current platform if no specific platform
        +   * is provided.
        +   */
        +  for(platform) {
        +    return platform == null ? Formatter.default || (Formatter.default = Formatter.for(process.platform)) : Formatter._registry.get(platform) || Formatter._registry.get('sh');
        +  },
        +  /**
        +   * Creates a new Formatter or mutates the properties on an existing
        +   * Formatter. The `platform` key on the provided properties object determines
        +   * when the Formatter is retrieved.
        +   */
        +  declare(props) {
        +    const platform = props && props.platform || 'sh';
        +    const existingFormatter = Formatter._registry.get(platform);
        +    const formatter = Object.assign(existingFormatter || new Formatter(), props);
        +    formatter.emptyString === void 0 && (formatter.emptyString = formatter.quote('', true));
        +    existingFormatter || Formatter._registry.set(formatter.platform, formatter);
        +  },
        +  _registry: new Map(),
        +  prototype: {
        +    platform: 'sh',
        +    quote: quoteForSh,
        +    metaChars: shMetaChars,
        +    hasExtraMetaChars: false,
        +    statementSeparator: ';',
        +    createContext() {
        +      return defaultContext;
        +    }
        +  }
        +});
        +const defaultContext = {
        +  at() {}
        +};
        +Formatter.declare();
        +Formatter.declare({
        +  platform: 'win32',
        +  quote(text, forceQuote, opts) {
        +    const caretDepth = opts ? (opts.depth || 0) + (opts.isArgument && !opts.isNative ? 1 : 0) : 0;
        +    return quoteForCmd(text, forceQuote, caretDepth);
        +  },
        +  metaChars: cmdMetaChars,
        +  hasExtraMetaChars: true,
        +  statementSeparator: '&',
        +  createContext(root) {
        +    const context = new this.Context();
        +    root[preformatSymbol](context);
        +    return context;
        +  },
        +  Context: Win32Context
        +});
        +
        +const isObject = any => any === Object(any);
        +function memoize(f) {
        +  const cache = new WeakMap();
        +  return arg => {
        +    let result = cache.get(arg);
        +    if (result === void 0) {
        +      result = f(arg);
        +      cache.set(arg, result);
        +    }
        +    return result;
        +  };
        +}
        +
        +/**
        + * Represents a contiguous span of text that may or must be quoted. The contents
        + * may already contain quoted segments, which will always be quoted. If unquoted
        + * segments also require quoting, the entire span will be quoted together.
        + * @ignore
        + */
        +class ShellStringText {
        +  constructor(contents, untested) {
        +    this.contents = contents;
        +    this.untested = untested;
        +  }
        +  [formatSymbol](formatter, context) {
        +    const unformattedContents = this.contents;
        +    const length = unformattedContents.length;
        +    const contents = new Array(length);
        +    for (let i = 0; i < length; i++) {
        +      const c = unformattedContents[i];
        +      contents[i] = isObject(c) && formatSymbol in c ? c[formatSymbol](formatter) : c;
        +    }
        +    for (let unquoted = true, i = 0; i < length; i++) {
        +      const content = contents[i];
        +      if (content === null) {
        +        unquoted = !unquoted;
        +      } else {
        +        if (unquoted && (formatter.hasExtraMetaChars || this.untested && this.untested.has(i)) && formatter.metaChars.test(content)) {
        +          return formatter.quote(contents.join(''), false, context.at(this));
        +        }
        +      }
        +    }
        +    const parts = [];
        +    for (let quoted = null, i = 0; i < length; i++) {
        +      const content = contents[i];
        +      if (content === null) {
        +        quoted = quoted ? (parts.push(formatter.quote(quoted.join(''), true, context.at(this))), null) : [];
        +      } else {
        +        (quoted || parts).push(content);
        +      }
        +    }
        +    const result = parts.join('');
        +    return result.length ? result : formatter.emptyString;
        +  }
        +  [preformatSymbol](context) {
        +    context.mark(this);
        +  }
        +}
        +
        +/**
        + * Represents a contiguous span of text that will not be quoted.
        + * @ignore
        + */
        +class ShellStringUnquoted {
        +  constructor(value) {
        +    this.value = value;
        +  }
        +  [formatSymbol]() {
        +    return this.value;
        +  }
        +  [preformatSymbol](context) {
        +    context.read(this.value);
        +  }
        +}
        +
        +/**
        + * Represents a semicolon... or an ampersand, on Windows.
        + * @ignore
        + */
        +const shellStringSemicolon = {
        +  [formatSymbol](formatter) {
        +    return formatter.statementSeparator;
        +  },
        +  [preformatSymbol](context) {
        +    context.seq();
        +  }
        +};
        +
        +const PLACEHOLDER = {};
        +const parse = memoize(templateSpans => {
        +  // These are the token types our DSL can recognize. Their values won't escape
        +  // this function.
        +  const TOKEN_TEXT = 0;
        +  const TOKEN_QUOTE = 1;
        +  const TOKEN_SEMI = 2;
        +  const TOKEN_UNQUOTED = 3;
        +  const TOKEN_SPACE = 4;
        +  const TOKEN_REDIRECT = 5;
        +  const result = [];
        +  let placeholderCount = 0;
        +  let prefix = null;
        +  let onlyPrefixOnce = false;
        +  let contents = [];
        +  let quote = 0;
        +  const lastSpan = templateSpans.length - 1;
        +  for (let spanIndex = 0; spanIndex <= lastSpan; spanIndex++) {
        +    const templateSpan = templateSpans[spanIndex];
        +    const posEnd = templateSpan.length;
        +    let tokenStart = 0;
        +    if (spanIndex) {
        +      placeholderCount++;
        +      contents.push(PLACEHOLDER);
        +    }
        +    // For each span, we first do a recognizing pass in which we use regular
        +    // expressions to identify the positions of tokens in the text, and then
        +    // a second pass that actually splits the text into the minimum number of
        +    // substrings necessary.
        +    const recognized = []; // [type1, index1, type2, index2...]
        +    let firstWordBreak = -1;
        +    let lastWordBreak = -1;
        +    {
        +      let pos = 0,
        +          match;
        +      while (pos < posEnd) {
        +        if (quote) {
        +          if (match = execFrom(quote === CHAR_SQUO ? reQuotation1 : reQuotation2, templateSpan, pos)) {
        +            recognized.push(TOKEN_TEXT, pos);
        +            pos += match[0].length;
        +          }
        +          if (pos < posEnd) {
        +            recognized.push(TOKEN_QUOTE, pos++);
        +            quote = 0;
        +          }
        +        } else {
        +          if (match = execFrom(reRedirectOrSpace, templateSpan, pos)) {
        +            firstWordBreak < 0 && (firstWordBreak = pos);
        +            lastWordBreak = pos;
        +            recognized.push(match[1] ? TOKEN_REDIRECT : TOKEN_SPACE, pos);
        +            pos += match[0].length;
        +          }
        +          if (match = execFrom(reText, templateSpan, pos)) {
        +            const setBreaks = match[1] != null;
        +            setBreaks && firstWordBreak < 0 && (firstWordBreak = pos);
        +            recognized.push(setBreaks ? TOKEN_UNQUOTED : TOKEN_TEXT, pos);
        +            pos += match[0].length;
        +            setBreaks && (lastWordBreak = pos);
        +          }
        +          const char = templateSpan.charCodeAt(pos);
        +          if (char === CHAR_SEMI) {
        +            firstWordBreak < 0 && (firstWordBreak = pos);
        +            recognized.push(TOKEN_SEMI, pos++);
        +            lastWordBreak = pos;
        +          } else if (char === CHAR_SQUO || char === CHAR_DQUO) {
        +            recognized.push(TOKEN_QUOTE, pos++);
        +            quote = char;
        +          }
        +        }
        +      }
        +    }
        +    // Word breaks are only important if they separate words with placeholders,
        +    // so we can ignore the first/last break if this is the first/last span.
        +    spanIndex === 0 && (firstWordBreak = -1);
        +    spanIndex === lastSpan && (lastWordBreak = posEnd);
        +    // Here begins the second pass mentioned above. This loop runs one more
        +    // iteration than there are tokens in recognized, because it handles tokens
        +    // on a one-iteration delay; hence the i <= iEnd instead of i < iEnd.
        +    const iEnd = recognized.length;
        +    for (let i = 0, type = -1; i <= iEnd; i += 2) {
        +      let typeNext = -1,
        +          pos;
        +      if (i === iEnd) {
        +        pos = posEnd;
        +      } else {
        +        typeNext = recognized[i];
        +        pos = recognized[i + 1];
        +        // If the next token is space or redirect, but there's another word
        +        // break in this span, then we can handle that token the same way we
        +        // would handle unquoted text because it isn't being attached to a
        +        // placeholder.
        +        typeNext >= TOKEN_SPACE && pos !== lastWordBreak && (typeNext = TOKEN_UNQUOTED);
        +      }
        +      const breakHere = pos === firstWordBreak || pos === lastWordBreak;
        +      if (pos && (breakHere || typeNext !== type)) {
        +        let value = type === TOKEN_QUOTE ? null : type === TOKEN_SEMI ? shellStringSemicolon : templateSpan.substring(tokenStart, pos);
        +        if (type >= TOKEN_SEMI) {
        +          // This branch handles semicolons, unquoted text, spaces, and
        +          // redirects. shellStringSemicolon is already a formatSymbol object;
        +          // the rest need to be wrapped.
        +          type === TOKEN_SEMI || (value = new ShellStringUnquoted(value));
        +          // We don't need to check placeholderCount here like we do below;
        +          // that's only relevant during the first word break of the span, and
        +          // because this iteration of the loop is processing the token that
        +          // was checked for breaks in the previous iteration, it will have
        +          // already been handled. For the same reason, prefix is guaranteed to
        +          // be null.
        +          if (contents.length) {
        +            result.push(new ShellStringText(contents, null));
        +            contents = [];
        +          }
        +          // Only spaces and redirects become prefixes, but not if they've been
        +          // rewritten to unquoted above.
        +          if (type >= TOKEN_SPACE) {
        +            prefix = value;
        +            onlyPrefixOnce = type === TOKEN_SPACE;
        +          } else {
        +            result.push(value);
        +          }
        +        } else {
        +          contents.push(value);
        +        }
        +        tokenStart = pos;
        +      }
        +      if (breakHere) {
        +        if (placeholderCount) {
        +          result.push({
        +            contents,
        +            placeholderCount,
        +            prefix,
        +            onlyPrefixOnce
        +          });
        +        } else {
        +          // There's no prefix to handle in this branch; a prefix prior to this
        +          // span would mean placeholderCount > 0, and a prefix in this span
        +          // can't be created because spaces and redirects get rewritten to
        +          // unquoted before the last word break.
        +          contents.length && result.push(new ShellStringText(contents, null));
        +        }
        +        placeholderCount = 0;
        +        prefix = null;
        +        onlyPrefixOnce = false;
        +        contents = [];
        +      }
        +      type = typeNext;
        +    }
        +  }
        +  if (quote) {
        +    throw new SyntaxError(`String is missing a ${String.fromCharCode(quote)} character`);
        +  }
        +  return result;
        +});
        +const CHAR_SEMI = ';'.charCodeAt();
        +const CHAR_SQUO = "'".charCodeAt();
        +const CHAR_DQUO = '"'.charCodeAt();
        +const reQuotation1 = sticky("[^']+");
        +const reQuotation2 = sticky('[^"]+');
        +const reText = sticky('[^\\s"#$&\'();<>\\\\`|]+|([#$&()\\\\`|]+)');
        +const reRedirectOrSpace = sticky('(\\s*\\d*[<>]+\\s*)|\\s+');
        +
        +class BitSet {
        +  constructor() {
        +    this.vector = new Int32Array(1);
        +  }
        +  has(n) {
        +    return (this.vector[n >>> 5] & 1 << n) !== 0;
        +  }
        +  add(n) {
        +    const i = n >>> 5,
        +          requiredLength = i + 1;
        +    let vector = this.vector,
        +        _vector = vector,
        +        length = _vector.length;
        +    if (requiredLength > length) {
        +      while (requiredLength > (length *= 2));
        +      const oldValues = vector;
        +      vector = new Int32Array(length);
        +      vector.set(oldValues);
        +      this.vector = vector;
        +    }
        +    vector[i] |= 1 << n;
        +  }
        +}
        +
        +function evaluate(template, values) {
        +  values = values.map(toStringishArray);
        +  const children = [];
        +  let valuesStart = 0;
        +  for (let i = 0, iMax = template.length; i < iMax; i++) {
        +    const word = template[i];
        +    if (formatSymbol in word) {
        +      children.push(word);
        +      continue;
        +    }
        +    const contents = word.contents,
        +          placeholderCount = word.placeholderCount,
        +          prefix = word.prefix,
        +          onlyPrefixOnce = word.onlyPrefixOnce;
        +    const kMax = contents.length;
        +    const valuesEnd = valuesStart + placeholderCount;
        +    const tuples = cartesianProduct(values, valuesStart, valuesEnd);
        +    valuesStart = valuesEnd;
        +    for (let j = 0, jMax = tuples.length; j < jMax; j++) {
        +      const needSpace = j > 0;
        +      const tuple = tuples[j];
        +      (needSpace || prefix) && children.push(needSpace && (onlyPrefixOnce || !prefix) ? unquotedSpace : prefix);
        +      let interpolatedContents = [];
        +      let untested = null;
        +      let quoting = false;
        +      let tupleIndex = 0;
        +      for (let k = 0; k < kMax; k++) {
        +        const content = contents[k];
        +        if (content === PLACEHOLDER) {
        +          const value = tuple[tupleIndex++];
        +          if (quoting) {
        +            interpolatedContents.push(value);
        +          } else {
        +            if (isObject(value) && formatSymbol in value) {
        +              if (interpolatedContents.length) {
        +                children.push(new ShellStringText(interpolatedContents, untested));
        +                interpolatedContents = [];
        +                untested = null;
        +              }
        +              children.push(value);
        +            } else {
        +              (untested || (untested = new BitSet())).add(interpolatedContents.length);
        +              interpolatedContents.push(value);
        +            }
        +          }
        +        } else {
        +          interpolatedContents.push(content);
        +          content === null && (quoting = !quoting);
        +        }
        +      }
        +      if (interpolatedContents.length) {
        +        children.push(new ShellStringText(interpolatedContents, untested));
        +      }
        +    }
        +  }
        +  return children;
        +}
        +const primToStringish = value => value == null ? '' + value : value;
        +function toStringishArray(value) {
        +  let array;
        +  switch (true) {
        +    default:
        +      if (isObject(value)) {
        +        if (Array.isArray(value)) {
        +          array = value;
        +          break;
        +        }
        +        if (Symbol.iterator in value) {
        +          array = Array.from(value);
        +          break;
        +        }
        +      }
        +      array = [value];
        +  }
        +  return array.map(primToStringish);
        +}
        +function cartesianProduct(arrs, start, end) {
        +  const size = end - start;
        +  let resultLength = 1;
        +  for (let i = start; i < end; i++) {
        +    resultLength *= arrs[i].length;
        +  }
        +  if (resultLength > 1e6) {
        +    throw new RangeError("Far too many elements to interpolate");
        +  }
        +  const result = new Array(resultLength);
        +  const indices = new Array(size).fill(0);
        +  for (let i = 0; i < resultLength; i++) {
        +    const value = result[i] = new Array(size);
        +    for (let j = 0; j < size; j++) {
        +      value[j] = arrs[j + start][indices[j]];
        +    }
        +    for (let j = size - 1; j >= 0; j--) {
        +      if (++indices[j] < arrs[j + start].length) break;
        +      indices[j] = 0;
        +    }
        +  }
        +  return result;
        +}
        +const unquotedSpace = new ShellStringUnquoted(' ');
        +
        +/**
        + * A ShellString represents a shell command after it has been interpolated, but
        + * before it has been formatted for a particular platform. ShellStrings are
        + * useful if you want to prepare a command for a different platform than the
        + * current one, for instance.
        + *
        + * To create a ShellString, use `ShellString.sh` the same way you would use
        + * top-level `sh`.
        + */
        +class ShellString {
        +  /** @hideconstructor */
        +  constructor(children) {
        +    this.children = children;
        +  }
        +  /**
        +   * `ShellString.sh` is a template tag just like `sh`; the only difference is
        +   * that this function returns a ShellString which has not yet been formatted
        +   * into a String.
        +   * @returns {ShellString}
        +   * @function sh
        +   * @static
        +   * @memberof ShellString
        +   */
        +  static sh(templateSpans) {
        +    for (var _len = arguments.length, values = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
        +      values[_key - 1] = arguments[_key];
        +    }
        +    return new ShellString(evaluate(parse(templateSpans), values));
        +  }
        +  /**
        +   * A method to format a ShellString into a regular String formatted for a
        +   * particular platform.
        +   *
        +   * @param {String} [platform] a value that `process.platform` might take:
        +   * `'win32'`, `'linux'`, etc.; determines how the string is to be formatted.
        +   * When omitted, effectively the same as `process.platform`.
        +   * @returns {String}
        +   */
        +  toString(platform) {
        +    return this[formatSymbol](Formatter.for(platform));
        +  }
        +  [formatSymbol](formatter) {
        +    let context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : formatter.createContext(this);
        +    return this.children.map(child => child[formatSymbol](formatter, context)).join('');
        +  }
        +  [preformatSymbol](context) {
        +    const children = this.children;
        +    for (let i = 0, iMax = children.length; i < iMax; i++) {
        +      const child = children[i];
        +      if (preformatSymbol in child) {
        +        child[preformatSymbol](context);
        +      }
        +    }
        +  }
        +}
        +
        +/**
        + * A Windows-specific version of {@link quoteForShell}.
        + * @param {String} text to be quoted
        + * @param {Boolean} [forceQuote] whether to always add quotes even if the string
        + * is already safe. Defaults to `false`.
        + */
        +
        +/**
        + * A Unix-specific version of {@link quoteForShell}.
        + * @param {String} text to be quoted
        + * @param {Boolean} [forceQuote] whether to always add quotes even if the string
        + * is already safe. Defaults to `false`.
        + */
        +
        +/**
        + * Quotes a string for injecting into a shell command.
        + *
        + * This function is exposed for some hypothetical case when the `sh` DSL simply
        + * won't do; `sh` is expected to be the more convenient option almost always.
        + * Compare:
        + *
        + * ```javascript
        + * console.log('cmd' + args.map(a => ' ' + quoteForShell(a)).join(''));
        + * console.log(sh`cmd ${args}`); // same as above
        + *
        + * console.log('cmd' + args.map(a => ' ' + quoteForShell(a, true)).join(''));
        + * console.log(sh`cmd "${args}"`); // same as above
        + * ```
        + *
        + * Additionally, on Windows, `sh` checks the entire command string for pipes,
        + * which subtly change how arguments need to be quoted. If your commands may
        + * involve pipes, you are strongly encouraged to use `sh` and not try to roll
        + * your own with `quoteForShell`.
        + *
        + * @param {String} text to be quoted
        + * @param {Boolean} [forceQuote] whether to always add quotes even if the string
        + * is already safe. Defaults to `false`.
        + * @param {String} [platform] a value that `process.platform` might take:
        + * `'win32'`, `'linux'`, etc.; determines how the string is to be formatted.
        + * When omitted, effectively the same as `process.platform`.
        + *
        + * @returns {String} a string that is safe for the current (or specified)
        + * platform.
        + */
        +function quoteForShell(text, forceQuote, platform) {
        +  return Formatter.for(platform).quote(text, forceQuote);
        +}
        +
        +/**
        + * A string template tag for safely constructing cross-platform shell commands.
        + *
        + * An `sh` template is not actually treated as a literal string to be
        + * interpolated; instead, it is a tiny DSL designed to make working with shell
        + * strings safe, simple, and straightforward. To get started quickly, see the
        + * examples below. {@link #the-sh-dsl More detailed documentation} is available
        + * further down.
        + *
        + * @name sh
        + * @example
        + * const title = '"this" & "that"';
        + * sh`script --title=${title}`; // => "script '--title=\"this\" & \"that\"'"
        + * // Note: these examples show results for non-Windows platforms.
        + * // On Windows, the above would instead be
        + * // 'script ^^^"--title=\\^^^"this\\^^^" ^^^& \\^^^"that\\^^^"^^^"'.
        + *
        + * const names = ['file1', 'file 2'];
        + * sh`rimraf ${names}.txt`; // => "rimraf file1.txt 'file 2.txt'"
        + *
        + * const cmd1 = ['cat', 'file 1.txt', 'file 2.txt'];
        + * const cmd2 = ['use-input', '-abc'];
        + * sh`${cmd1}|${cmd2}`; // => "cat 'file 1.txt' 'file 2.txt'|use-input -abc"
        + *
        + * @returns {String} - a string formatted for the platform Node is currently
        + * running on.
        + */
        +const sh = function () {
        +  return ShellString.sh.apply(ShellString, arguments).toString();
        +};
        +
        +/**
        + * This function permits raw strings to be interpolated into a `sh` template.
        + *
        + * **IMPORTANT**: If you're using Puka due to security concerns, make sure you
        + * don't pass any untrusted content to `unquoted`. This may be obvious, but
        + * stray punctuation in an `unquoted` section can compromise the safety of the
        + * entire shell command.
        + *
        + * @param value - any value (it will be treated as a string)
        + *
        + * @example
        + * const both = true;
        + * sh`foo ${unquoted(both ? '&&' : '||')} bar`; // => 'foo && bar'
        + */
        +const unquoted = value => new ShellStringUnquoted(value);
        +
        +exports.Formatter = Formatter;
        +exports.ShellString = ShellString;
        +exports.ShellStringText = ShellStringText;
        +exports.ShellStringUnquoted = ShellStringUnquoted;
        +exports.quoteForCmd = quoteForCmd;
        +exports.quoteForSh = quoteForSh;
        +exports.quoteForShell = quoteForShell;
        +exports.sh = sh;
        +exports.shellStringSemicolon = shellStringSemicolon;
        +exports.formatSymbol = formatSymbol;
        +exports.preformatSymbol = preformatSymbol;
        +exports.unquoted = unquoted;
        diff --git a/deps/npm/node_modules/puka/package.json b/deps/npm/node_modules/puka/package.json
        new file mode 100644
        index 00000000000000..41798dc2493b85
        --- /dev/null
        +++ b/deps/npm/node_modules/puka/package.json
        @@ -0,0 +1,38 @@
        +{
        +  "name": "puka",
        +  "version": "1.0.1",
        +  "description": "A cross-platform library for safely passing strings through shells",
        +  "keywords": [
        +    "args",
        +    "arguments",
        +    "cmd",
        +    "command",
        +    "command-line",
        +    "cross-platform",
        +    "escape",
        +    "escaping",
        +    "exec",
        +    "linux",
        +    "mac",
        +    "macos",
        +    "osx",
        +    "quote",
        +    "quoting",
        +    "sh",
        +    "shell",
        +    "spawn",
        +    "unix",
        +    "win",
        +    "win32",
        +    "windows"
        +  ],
        +  "homepage": "https://gitlab.com/rhendric/puka",
        +  "bugs": "https://gitlab.com/rhendric/puka/issues",
        +  "license": "MIT",
        +  "author": "Ryan Hendrickson ",
        +  "repository": "gitlab:rhendric/puka",
        +  "dependencies": {},
        +  "engines": {
        +    "node": ">=4"
        +  }
        +}
        \ No newline at end of file
        diff --git a/deps/npm/package.json b/deps/npm/package.json
        index d0ca0bf91a7dd5..c67b3205a75a8f 100644
        --- a/deps/npm/package.json
        +++ b/deps/npm/package.json
        @@ -1,5 +1,5 @@
         {
        -  "version": "7.0.8",
        +  "version": "7.0.14",
           "name": "npm",
           "description": "a package manager for JavaScript",
           "keywords": [
        @@ -42,10 +42,10 @@
             "./package.json": "./package.json"
           },
           "dependencies": {
        -    "@npmcli/arborist": "^1.0.8",
        +    "@npmcli/arborist": "^1.0.12",
             "@npmcli/ci-detect": "^1.2.0",
             "@npmcli/config": "^1.2.1",
        -    "@npmcli/run-script": "^1.7.4",
        +    "@npmcli/run-script": "^1.8.1",
             "abbrev": "~1.1.1",
             "ansicolors": "~0.3.2",
             "ansistyles": "~0.1.3",
        @@ -76,7 +76,7 @@
             "libnpmpublish": "^4.0.0",
             "libnpmsearch": "^3.0.1",
             "libnpmteam": "^2.0.2",
        -    "libnpmversion": "^1.0.6",
        +    "libnpmversion": "^1.0.7",
             "make-fetch-happen": "^8.0.9",
             "mkdirp": "^1.0.4",
             "mkdirp-infer-owner": "^2.0.0",
        @@ -92,7 +92,7 @@
             "npm-user-validate": "^1.0.1",
             "npmlog": "~4.1.2",
             "opener": "^1.5.2",
        -    "pacote": "^11.1.12",
        +    "pacote": "^11.1.13",
             "parse-conflict-json": "^1.1.1",
             "qrcode-terminal": "^0.12.0",
             "read": "~1.0.7",
        @@ -180,16 +180,16 @@
             "write-file-atomic"
           ],
           "devDependencies": {
        -    "cmark-gfm": "^0.8.3",
        -    "eslint": "^7.12.1",
        +    "cmark-gfm": "^0.8.4",
        +    "eslint": "^7.13.0",
             "eslint-plugin-import": "^2.22.1",
             "eslint-plugin-node": "^11.1.0",
             "eslint-plugin-promise": "^4.2.1",
        -    "eslint-plugin-standard": "^4.0.2",
        +    "eslint-plugin-standard": "^4.1.0",
             "jsdom": "^16.4.0",
             "marked-man": "^0.7.0",
             "require-inject": "^1.4.4",
        -    "tap": "^14.10.8",
        +    "tap": "^14.11.0",
             "yaml": "^1.10.0"
           },
           "scripts": {
        @@ -204,7 +204,7 @@
             "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run test --",
             "posttest": "npm run lint",
             "eslint": "eslint",
        -    "lint": "npm run eslint -- \"lib/**/*.js\"",
        +    "lint": "npm run eslint -- test/lib test/bin \"lib/**/*.js\"",
             "lintfix": "npm run lint -- --fix",
             "prelint": "rimraf test/npm_cache*",
             "resetdeps": "bash scripts/resetdeps.sh"
        diff --git a/deps/npm/scripts/install.sh b/deps/npm/scripts/install.sh
        index 7f66151daea033..4458de87faefbe 100755
        --- a/deps/npm/scripts/install.sh
        +++ b/deps/npm/scripts/install.sh
        @@ -8,7 +8,7 @@
         # shell living at /bin/sh.
         #
         # See this helpful document on writing portable shell scripts:
        -# https://www.gnu.org/s/hello/manual/autoconf/Portable-Shell.html
        +# http://www.gnu.org/s/hello/manual/autoconf/Portable-Shell.html
         #
         # The only shell it won't ever work on is cmd.exe.
         
        @@ -23,32 +23,27 @@ if [ "x$0" = "xsh" ]; then
           if [ $ret -eq 0 ]; then
             (exit 0)
           else
        -    echo "Uninstalling npm-install-$$.sh" >&2
             rm npm-install-$$.sh
        -    echo "Failed to download script" >&2
        +    echo "failed to download script" >&2
             exit $ret
           fi
           sh npm-install-$$.sh
           ret=$?
        -  echo "Uninstalling npm-install-$$.sh" >&2
           rm npm-install-$$.sh
           exit $ret
         fi
         
        -# See what "npm_config_*" things there are in the env,
        -# and make them permanent.
        -# If this fails, it's not such a big deal.
        -configures="`env | grep 'npm_config_' | sed -e 's|^npm_config_||g'`"
        -
        +debug=0
         npm_config_loglevel="error"
         if [ "x$npm_debug" = "x" ]; then
           (exit 0)
         else
        -  echo "Running in debug mode."
        -  echo "Note that this requires bash or zsh."
        +  echo "running in debug mode."
        +  echo "note that this requires bash or zsh."
           set -o xtrace
           set -o pipefail
           npm_config_loglevel="verbose"
        +  debug=1
         fi
         export npm_config_loglevel
         
        @@ -61,33 +56,20 @@ if [ $ret -ne 0 ]; then
           ret=$?
         fi
         if [ $ret -eq 0 ] && [ -x "$node" ]; then
        +  if [ $debug -eq 1 ]; then
        +    echo "found 'node' at: $node"
        +    echo -n "version: "
        +    $node --version
        +    echo ""
        +  fi
           (exit 0)
         else
           echo "npm cannot be installed without node.js." >&2
        -  echo "Install node first, and then try again." >&2
        +  echo "install node first, and then try again." >&2
           echo "" >&2
        -  echo "Maybe node is installed, but not in the PATH?" >&2
        -  echo "Note that running as sudo can change envs." >&2
        -  echo ""
        -  echo "PATH=$PATH" >&2
           exit $ret
         fi
         
        -# set the temp dir
        -TMP="${TMPDIR}"
        -if [ "x$TMP" = "x" ]; then
        -  TMP="/tmp"
        -fi
        -TMP="${TMP}/npm.$$"
        -rm -rf "$TMP" || true
        -mkdir "$TMP"
        -if [ $? -ne 0 ]; then
        -  echo "failed to mkdir $TMP" >&2
        -  exit 1
        -fi
        -
        -BACK="$PWD"
        -
         ret=0
         tar="${TAR}"
         if [ -z "$tar" ]; then
        @@ -99,10 +81,11 @@ if [ -z "$tar" ]; then
         fi
         
         if [ $ret -eq 0 ] && [ -x "$tar" ]; then
        -  echo "tar=$tar"
        -  if [ $tar --version > /dev/null 2>&1 ]; then
        -    echo "version:"
        +  if [ $debug -eq 1 ]; then
        +    echo "found 'tar' at: $tar"
        +    echo -n "version: "
             $tar --version
        +    echo ""
           fi
           ret=$?
         fi
        @@ -110,76 +93,43 @@ fi
         if [ $ret -eq 0 ]; then
           (exit 0)
         else
        -  echo "No suitable tar program found."
        +  echo "this script requires 'tar', please install it and try again."
           exit 1
         fi
         
        -
        -
        -# Try to find a suitable make
        -# If the MAKE environment var is set, use that.
        -# otherwise, try to find gmake, and then make.
        -# If no make is found, then just execute the necessary commands.
        -
        -# XXX For some reason, make is building all the docs every time.  This
        -# is an annoying source of bugs. Figure out why this happens.
        -MAKE=NOMAKE
        -
        -if [ "x$MAKE" = "x" ]; then
        -  make=`which gmake 2>&1`
        -  if [ $? -eq 0 ] && [ -x "$make" ]; then
        -    (exit 0)
        -  else
        -    make=`which make 2>&1`
        -    if [ $? -eq 0 ] && [ -x "$make" ]; then
        -      (exit 0)
        -    else
        -      make=NOMAKE
        -    fi
        +curl=`which curl 2>&1`
        +ret=$?
        +if [ $ret -eq 0 ]; then
        +  if [ $debug -eq 1 ]; then
        +    echo "found 'curl' at: $curl"
        +    echo -n "version: "
        +    $curl --version | head -n 1
        +    echo ""
           fi
        -else
        -  make="$MAKE"
        -fi
        -
        -if [ -x "$make" ]; then
           (exit 0)
         else
        -  # echo "Installing without make. This may fail." >&2
        -  make=NOMAKE
        +  echo "this script requires 'curl', please install it and try again."
        +  exit 1
         fi
         
        -# If there's no bash, then don't even try to clean
        -if [ -x "/bin/bash" ]; then
        -  (exit 0)
        -else
        -  clean="no"
        +# set the temp dir
        +TMP="${TMPDIR}"
        +if [ "x$TMP" = "x" ]; then
        +  TMP="/tmp"
         fi
        -
        -node_version=`"$node" --version 2>&1`
        -ret=$?
        -if [ $ret -ne 0 ]; then
        -  echo "You need node to run this program." >&2
        -  echo "node --version reports: $node_version" >&2
        -  echo "with exit code = $ret" >&2
        -  echo "Please install node before continuing." >&2
        -  exit $ret
        +TMP="${TMP}/npm.$$"
        +rm -rf "$TMP" || true
        +mkdir "$TMP"
        +if [ $? -ne 0 ]; then
        +  echo "failed to mkdir $TMP" >&2
        +  exit 1
         fi
         
        +BACK="$PWD"
        +
         t="${npm_install}"
         if [ -z "$t" ]; then
        -  # switch based on node version.
        -  # note that we can only use strict sh-compatible patterns here.
        -  case $node_version in
        -    0.[01234567].* | v0.[01234567].*)
        -      echo "You are using an outdated and unsupported version of" >&2
        -      echo "node ($node_version).  Please update node and try again." >&2
        -      exit 99
        -      ;;
        -    *)
        -      echo "install npm@latest"
        -      t="latest"
        -      ;;
        -  esac
        +  t="latest"
         fi
         
         # need to echo "" after, because Posix sed doesn't treat EOF
        @@ -201,7 +151,7 @@ if [ "x$url" = "x" ]; then
           fi
         fi
         if [ $ret -ne 0 ]; then
        -  echo "Failed to get tarball url for npm/$t" >&2
        +  echo "failed to get tarball url for npm/$t" >&2
           exit $ret
         fi
         
        @@ -209,37 +159,19 @@ fi
         echo "fetching: $url" >&2
         
         cd "$TMP" \
        -  && curl -SsL "$url" \
        -     | $tar -xzf - \
        -  && cd "$TMP"/* \
        -  && (ret=0
        -      if [ $ret -ne 0 ]; then
        -        echo "Aborted 0.x cleanup.  Exiting." >&2
        -        exit $ret
        -      fi) \
        -  && (if [ "x$configures" = "x" ]; then
        -        (exit 0)
        -      else
        -        echo "./configure $configures"
        -        echo "$configures" > npmrc
        -      fi) \
        -  && (if [ "$make" = "NOMAKE" ]; then
        -        (exit 0)
        -      elif "$make" uninstall install; then
        -        (exit 0)
        -      else
        -        make="NOMAKE"
        -      fi
        -      if [ "$make" = "NOMAKE" ]; then
        -        "$node" bin/npm-cli.js rm npm -gf
        -        "$node" bin/npm-cli.js install -gf $("$node" bin/npm-cli.js pack | tail -1)
        -      fi) \
        +  && curl -SsL -o npm.tgz "$url" \
        +  && $tar -xzf npm.tgz \
        +  && cd "$TMP"/package \
        +  && echo "removing existing npm" \
        +  && "$node" bin/npm-cli.js rm npm -gf --loglevel=silent \
        +  && echo "installing npm@$t" \
        +  && "$node" bin/npm-cli.js install -gf ../npm.tgz \
           && cd "$BACK" \
           && rm -rf "$TMP" \
        -  && echo "It worked"
        +  && echo "successfully installed npm@$t"
         
         ret=$?
         if [ $ret -ne 0 ]; then
        -  echo "It failed" >&2
        +  echo "failed!" >&2
         fi
         exit $ret
        diff --git a/deps/npm/tap-snapshots/test-lib-init.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-init.js-TAP.test.js
        new file mode 100644
        index 00000000000000..25015aab65cb68
        --- /dev/null
        +++ b/deps/npm/tap-snapshots/test-lib-init.js-TAP.test.js
        @@ -0,0 +1,19 @@
        +/* IMPORTANT
        + * This snapshot file is auto-generated, but designed for humans.
        + * It should be checked into source control and tracked carefully.
        + * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
        + * Make sure to inspect the output below.  Do not ignore changes!
        + */
        +'use strict'
        +exports[`test/lib/init.js TAP classic npm init no args > should print helper info 1`] = `
        +This utility will walk you through creating a package.json file.
        +It only covers the most common items, and tries to guess sensible defaults.
        +
        +See \`npm help init\` for definitive documentation on these fields
        +and exactly what they do.
        +
        +Use \`npm install \` afterwards to install a package and
        +save it as a dependency in the package.json file.
        +
        +Press ^C at any time to quit.
        +`
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-cmd-list.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-cmd-list.js-TAP.test.js
        index c77da6b18317dc..36066b57639d47 100644
        --- a/deps/npm/tap-snapshots/test-lib-utils-cmd-list.js-TAP.test.js
        +++ b/deps/npm/tap-snapshots/test-lib-utils-cmd-list.js-TAP.test.js
        @@ -94,7 +94,6 @@ Object {
             "udpate": "update",
             "un": "uninstall",
             "unlink": "uninstall",
        -    "unstar": "star",
             "up": "update",
             "upgrade": "update",
             "urn": "run-script",
        @@ -125,6 +124,7 @@ Object {
             "publish",
             "star",
             "stars",
        +    "unstar",
             "adduser",
             "login",
             "logout",
        @@ -189,7 +189,6 @@ Object {
             "t": "test",
             "tst": "test",
             "un": "uninstall",
        -    "unstar": "star",
             "up": "update",
             "v": "view",
             "why": "explain",
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js
        index 5190a5604a2407..3bdf905d869e6a 100644
        --- a/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js
        +++ b/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js
        @@ -8,6 +8,7 @@
         exports[`test/lib/utils/config.js TAP no process.umask() method > must match snapshot 1`] = `
         Object {
           "defaults": Object {
        +    "_auth": null,
             "access": null,
             "all": false,
             "allow-same-version": false,
        @@ -267,6 +268,10 @@ Object {
             ],
           },
           "types": Object {
        +    "_auth": Array [
        +      null,
        +      "{String TYPE}",
        +    ],
             "access": Array [
               null,
               "restricted",
        @@ -537,6 +542,7 @@ Object {
         exports[`test/lib/utils/config.js TAP no working network interfaces, on windows > must match snapshot 1`] = `
         Object {
           "defaults": Object {
        +    "_auth": null,
             "access": null,
             "all": false,
             "allow-same-version": false,
        @@ -796,6 +802,10 @@ Object {
             ],
           },
           "types": Object {
        +    "_auth": Array [
        +      null,
        +      "{String TYPE}",
        +    ],
             "access": Array [
               null,
               "restricted",
        @@ -1066,6 +1076,7 @@ Object {
         exports[`test/lib/utils/config.js TAP working network interfaces, not windows > must match snapshot 1`] = `
         Object {
           "defaults": Object {
        +    "_auth": null,
             "access": null,
             "all": false,
             "allow-same-version": false,
        @@ -1325,6 +1336,10 @@ Object {
             ],
           },
           "types": Object {
        +    "_auth": Array [
        +      null,
        +      "{String TYPE}",
        +    ],
             "access": Array [
               null,
               "restricted",
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js
        index 48f84e5111821f..54a77bc122b4db 100644
        --- a/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js
        +++ b/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js
        @@ -10,7 +10,7 @@ manydep@1.0.0
           manydep@"1.0.0" from prod-dep@1.2.3
           node_modules/prod-dep
             prod-dep@"1.x" from the root project
        -  6 more (optdep, extra-neos, deep-dev, peer, ...)
        +  7 more (optdep, extra-neos, deep-dev, peer, the root project, ...)
         `
         
         exports[`test/lib/utils/explain-dep.js TAP > ellipses test two 1`] = `
        @@ -18,7 +18,7 @@ manydep@1.0.0
           manydep@"1.0.0" from prod-dep@1.2.3
           node_modules/prod-dep
             prod-dep@"1.x" from the root project
        -  5 more (optdep, extra-neos, deep-dev, peer, a package with a pretty long name)
        +  6 more (optdep, extra-neos, deep-dev, peer, the root project, a package with a pretty long name)
         `
         
         exports[`test/lib/utils/explain-dep.js TAP deepDev > explain color deep 1`] = `
        @@ -90,6 +90,7 @@ exports[`test/lib/utils/explain-dep.js TAP manyDeps > explain color deep 1`] = `
           peer manydep@">1.0.0-beta <1.0.1" from peer@1.0.0 peer
           node_modules/peer
             peer peer@"1.0.0" from the root project
        +  manydep@">1.0.0-beta <1.0.1" from the root project
           manydep@"1" from a package with a pretty long name@1.2.3
           manydep@"1" from another package with a pretty long name@1.2.3
           manydep@"1" from yet another a package with a pretty long name@1.2.3
        @@ -100,7 +101,7 @@ manydep@1.0.0
           manydep@"1.0.0" from prod-dep@1.2.3
           node_modules/prod-dep
             prod-dep@"1.x" from the root project
        -  7 more (optdep, extra-neos, deep-dev, peer, ...)
        +  8 more (optdep, extra-neos, deep-dev, peer, the root project, ...)
         `
         
         exports[`test/lib/utils/explain-dep.js TAP manyDeps > print color 1`] = `
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js
        index 0e6c053b2f452e..6890338a131115 100644
        --- a/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js
        +++ b/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js
        @@ -7,6 +7,7 @@
         'use strict'
         exports[`test/lib/utils/flat-options.js TAP basic > flat options 1`] = `
         Object {
        +  "_auth": undefined,
           "@scope:registry": "@scope:registry",
           "//nerf.dart:_authToken": "//nerf.dart:_authToken",
           "access": "access",
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-reify-finish.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-reify-finish.js-TAP.test.js
        new file mode 100644
        index 00000000000000..a82905a399679a
        --- /dev/null
        +++ b/deps/npm/tap-snapshots/test-lib-utils-reify-finish.js-TAP.test.js
        @@ -0,0 +1,15 @@
        +/* IMPORTANT
        + * This snapshot file is auto-generated, but designed for humans.
        + * It should be checked into source control and tracked carefully.
        + * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
        + * Make sure to inspect the output below.  Do not ignore changes!
        + */
        +'use strict'
        +exports[`test/lib/utils/reify-finish.js TAP should write if everything above passes > written config 1`] = `
        +hasBuiltinConfig=true
        +x=y
        +
        +[nested]
        +foo=bar
        +
        +`
        diff --git a/deps/npm/test/bin/npm-cli.js b/deps/npm/test/bin/npm-cli.js
        index b68d29185873ae..bcca99c8c8fe1f 100644
        --- a/deps/npm/test/bin/npm-cli.js
        +++ b/deps/npm/test/bin/npm-cli.js
        @@ -5,6 +5,6 @@ t.test('loading the bin calls the implementation', t => {
             '../../lib/cli.js': proc => {
               t.equal(proc, process, 'called implementation with process object')
               t.end()
        -    }
        +    },
           })
         })
        diff --git a/deps/npm/test/bin/npx-cli.js b/deps/npm/test/bin/npx-cli.js
        index fc85f636683822..2b7b488297cab2 100644
        --- a/deps/npm/test/bin/npx-cli.js
        +++ b/deps/npm/test/bin/npx-cli.js
        @@ -64,7 +64,7 @@ t.test('use a bunch of deprecated switches and options', t => {
             '--shell-auto-fallback',
             '--ignore-existing',
             '-q',
        -    'foobar'
        +    'foobar',
           ]
         
           const expect = [
        @@ -78,18 +78,18 @@ t.test('use a bunch of deprecated switches and options', t => {
             '--loglevel',
             'warn',
             '--',
        -    'foobar'
        +    'foobar',
           ]
           requireInject(npx, { [cli]: () => {} })
           t.strictSame(process.argv, expect)
           t.strictSame(logs, [
        -    [ 'npx: the --npm argument has been removed.' ],
        -    [ 'npx: the --node-arg argument has been removed.' ],
        -    [ 'npx: the --n argument has been removed.' ],
        -    [ 'npx: the --always-spawn argument has been removed.' ],
        -    [ 'npx: the --shell-auto-fallback argument has been removed.' ],
        -    [ 'npx: the --ignore-existing argument has been removed.' ],
        -    [ 'See `npm help exec` for more information' ]
        +    ['npx: the --npm argument has been removed.'],
        +    ['npx: the --node-arg argument has been removed.'],
        +    ['npx: the --n argument has been removed.'],
        +    ['npx: the --always-spawn argument has been removed.'],
        +    ['npx: the --shell-auto-fallback argument has been removed.'],
        +    ['npx: the --ignore-existing argument has been removed.'],
        +    ['See `npm help exec` for more information'],
           ])
           t.end()
         })
        diff --git a/deps/npm/test/lib/access.js b/deps/npm/test/lib/access.js
        index 5d5a910f94e2fc..3063b6c53263f2 100644
        --- a/deps/npm/test/lib/access.js
        +++ b/deps/npm/test/lib/access.js
        @@ -3,8 +3,8 @@ const requireInject = require('require-inject')
         
         const emptyMock = requireInject('../../lib/access.js', {
           '../../lib/npm.js': {
        -    flatOptions: {}
        -  }
        +    flatOptions: {},
        +  },
         })
         
         test('completion', t => {
        @@ -27,7 +27,7 @@ test('completion', t => {
             'ls-collaborators',
             'edit',
             '2fa-required',
        -    '2fa-not-required'
        +    '2fa-not-required',
           ])
         
           testComp(['npm', 'access', 'grant'], ['read-only', 'read-write'])
        @@ -75,7 +75,7 @@ test('edit', (t) => {
         
           access([
             'edit',
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.match(
               err,
        @@ -89,14 +89,14 @@ test('edit', (t) => {
         test('access public on unscoped package', (t) => {
           const prefix = t.testdir({
             'package.json': JSON.stringify({
        -      name: 'npm-access-public-pkg'
        -    })
        +      name: 'npm-access-public-pkg',
        +    }),
           })
           const access = requireInject('../../lib/access.js', {
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
        -    'public'
        +    'public',
           ], (err) => {
             t.match(
               err,
        @@ -111,10 +111,10 @@ test('access public on scoped package', (t) => {
           t.plan(4)
           const name = '@scoped/npm-access-public-pkg'
           const prefix = t.testdir({
        -    'package.json': JSON.stringify({ name })
        +    'package.json': JSON.stringify({ name }),
           })
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               public: (pkg, { registry }) => {
                 t.equal(pkg, name, 'should use pkg name ref')
                 t.equal(
        @@ -123,17 +123,17 @@ test('access public on scoped package', (t) => {
                   'should forward correct options'
                 )
                 return true
        -      }
        +      },
             },
             '../../lib/npm.js': {
               flatOptions: {
        -        registry: 'https://registry.npmjs.org'
        +        registry: 'https://registry.npmjs.org',
               },
        -      prefix
        -    }
        +      prefix,
        +    },
           })
           access([
        -    'public'
        +    'public',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access public on scoped package')
        @@ -142,13 +142,13 @@ test('access public on scoped package', (t) => {
         
         test('access public on missing package.json', (t) => {
           const prefix = t.testdir({
        -    'node_modules': {}
        +    node_modules: {},
           })
           const access = requireInject('../../lib/access.js', {
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
        -    'public'
        +    'public',
           ], (err) => {
             t.match(
               err,
        @@ -162,13 +162,13 @@ test('access public on missing package.json', (t) => {
         test('access public on invalid package.json', (t) => {
           const prefix = t.testdir({
             'package.json': '{\n',
        -    'node_modules': {}
        +    node_modules: {},
           })
           const access = requireInject('../../lib/access.js', {
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
        -    'public'
        +    'public',
           ], (err) => {
             t.match(
               err,
        @@ -182,14 +182,14 @@ test('access public on invalid package.json', (t) => {
         test('access restricted on unscoped package', (t) => {
           const prefix = t.testdir({
             'package.json': JSON.stringify({
        -      name: 'npm-access-restricted-pkg'
        -    })
        +      name: 'npm-access-restricted-pkg',
        +    }),
           })
           const access = requireInject('../../lib/access.js', {
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
        -    'restricted'
        +    'restricted',
           ], (err) => {
             t.match(
               err,
        @@ -204,10 +204,10 @@ test('access restricted on scoped package', (t) => {
           t.plan(4)
           const name = '@scoped/npm-access-restricted-pkg'
           const prefix = t.testdir({
        -    'package.json': JSON.stringify({ name })
        +    'package.json': JSON.stringify({ name }),
           })
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               restricted: (pkg, { registry }) => {
                 t.equal(pkg, name, 'should use pkg name ref')
                 t.equal(
        @@ -216,17 +216,17 @@ test('access restricted on scoped package', (t) => {
                   'should forward correct options'
                 )
                 return true
        -      }
        +      },
             },
             '../../lib/npm.js': {
               flatOptions: {
        -        registry: 'https://registry.npmjs.org'
        +        registry: 'https://registry.npmjs.org',
               },
        -      prefix
        -    }
        +      prefix,
        +    },
           })
           access([
        -    'restricted'
        +    'restricted',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access restricted on scoped package')
        @@ -235,13 +235,13 @@ test('access restricted on scoped package', (t) => {
         
         test('access restricted on missing package.json', (t) => {
           const prefix = t.testdir({
        -    'node_modules': {}
        +    node_modules: {},
           })
           const access = requireInject('../../lib/access.js', {
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
        -    'restricted'
        +    'restricted',
           ], (err) => {
             t.match(
               err,
        @@ -255,13 +255,13 @@ test('access restricted on missing package.json', (t) => {
         test('access restricted on invalid package.json', (t) => {
           const prefix = t.testdir({
             'package.json': '{\n',
        -    'node_modules': {}
        +    node_modules: {},
           })
           const access = requireInject('../../lib/access.js', {
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
        -    'restricted'
        +    'restricted',
           ], (err) => {
             t.match(
               err,
        @@ -275,21 +275,21 @@ test('access restricted on invalid package.json', (t) => {
         test('access grant read-only', (t) => {
           t.plan(5)
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               grant: (spec, team, permissions) => {
                 t.equal(spec, '@scoped/another', 'should use expected spec')
                 t.equal(team, 'myorg:myteam', 'should use expected team')
                 t.equal(permissions, 'read-only', 'should forward permissions')
                 return true
        -      }
        +      },
             },
        -    '../../lib/npm.js': {}
        +    '../../lib/npm.js': {},
           })
           access([
             'grant',
             'read-only',
             'myorg:myteam',
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access grant read-only')
        @@ -299,21 +299,21 @@ test('access grant read-only', (t) => {
         test('access grant read-write', (t) => {
           t.plan(5)
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               grant: (spec, team, permissions) => {
                 t.equal(spec, '@scoped/another', 'should use expected spec')
                 t.equal(team, 'myorg:myteam', 'should use expected team')
                 t.equal(permissions, 'read-write', 'should forward permissions')
                 return true
        -      }
        +      },
             },
        -    '../../lib/npm.js': {}
        +    '../../lib/npm.js': {},
           })
           access([
             'grant',
             'read-write',
             'myorg:myteam',
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access grant read-write')
        @@ -324,24 +324,24 @@ test('access grant current cwd', (t) => {
           t.plan(5)
           const prefix = t.testdir({
             'package.json': JSON.stringify({
        -      name: 'yargs'
        -    })
        +      name: 'yargs',
        +    }),
           })
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               grant: (spec, team, permissions) => {
                 t.equal(spec, 'yargs', 'should use expected spec')
                 t.equal(team, 'myorg:myteam', 'should use expected team')
                 t.equal(permissions, 'read-write', 'should forward permissions')
                 return true
        -      }
        +      },
             },
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
             'grant',
             'read-write',
        -    'myorg:myteam'
        +    'myorg:myteam',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access grant current cwd')
        @@ -355,7 +355,7 @@ test('access grant others', (t) => {
             'grant',
             'rerere',
             'myorg:myteam',
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.match(
               err,
        @@ -373,7 +373,7 @@ test('access grant missing team args', (t) => {
             'grant',
             'read-only',
             undefined,
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.match(
               err,
        @@ -391,7 +391,7 @@ test('access grant malformed team arg', (t) => {
             'grant',
             'read-only',
             'foo',
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.match(
               err,
        @@ -403,11 +403,9 @@ test('access grant malformed team arg', (t) => {
         })
         
         test('access 2fa-required/2fa-not-required', t => {
        -  let pkg
        -
           t.plan(2)
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               tfaRequired: (spec) => {
                 t.equal(spec, '@scope/pkg', 'should use expected spec')
                 return true
        @@ -415,9 +413,9 @@ test('access 2fa-required/2fa-not-required', t => {
               tfaNotRequired: (spec) => {
                 t.equal(spec, 'unscoped-pkg', 'should use expected spec')
                 return true
        -      }
        +      },
             },
        -    '../../lib/npm.js': {}
        +    '../../lib/npm.js': {},
           })
         
           access(['2fa-required', '@scope/pkg'], er => {
        @@ -434,19 +432,19 @@ test('access 2fa-required/2fa-not-required', t => {
         test('access revoke', (t) => {
           t.plan(4)
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               revoke: (spec, team) => {
                 t.equal(spec, '@scoped/another', 'should use expected spec')
                 t.equal(team, 'myorg:myteam', 'should use expected team')
                 return true
        -      }
        +      },
             },
        -    '../../lib/npm.js': {}
        +    '../../lib/npm.js': {},
           })
           access([
             'revoke',
             'myorg:myteam',
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access revoke')
        @@ -459,7 +457,7 @@ test('access revoke missing team args', (t) => {
           access([
             'revoke',
             undefined,
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.match(
               err,
        @@ -476,7 +474,7 @@ test('access revoke malformed team arg', (t) => {
           access([
             'revoke',
             'foo',
        -    '@scoped/another'
        +    '@scoped/another',
           ], (err) => {
             t.match(
               err,
        @@ -490,18 +488,18 @@ test('access revoke malformed team arg', (t) => {
         test('npm access ls-packages with no team', (t) => {
           t.plan(3)
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               lsPackages: (entity) => {
                 t.equal(entity, 'foo', 'should use expected entity')
                 return {}
        -      }
        +      },
             },
             '../../lib/utils/get-identity.js': () => Promise.resolve('foo'),
             '../../lib/utils/output.js': () => null,
        -    '../../lib/npm.js': {}
        +    '../../lib/npm.js': {},
           })
           access([
        -    'ls-packages'
        +    'ls-packages',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access ls-packages with no team')
        @@ -511,18 +509,18 @@ test('npm access ls-packages with no team', (t) => {
         test('access ls-packages on team', (t) => {
           t.plan(3)
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               lsPackages: (entity) => {
                 t.equal(entity, 'myorg:myteam', 'should use expected entity')
                 return {}
        -      }
        +      },
             },
             '../../lib/utils/output.js': () => null,
        -    '../../lib/npm.js': {}
        +    '../../lib/npm.js': {},
           })
           access([
             'ls-packages',
        -    'myorg:myteam'
        +    'myorg:myteam',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access ls-packages on team')
        @@ -533,21 +531,21 @@ test('access ls-collaborators on current', (t) => {
           t.plan(3)
           const prefix = t.testdir({
             'package.json': JSON.stringify({
        -      name: 'yargs'
        -    })
        +      name: 'yargs',
        +    }),
           })
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               lsCollaborators: (spec) => {
                 t.equal(spec, 'yargs', 'should use expected spec')
                 return {}
        -      }
        +      },
             },
             '../../lib/utils/output.js': () => null,
        -    '../../lib/npm.js': { prefix }
        +    '../../lib/npm.js': { prefix },
           })
           access([
        -    'ls-collaborators'
        +    'ls-collaborators',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access ls-collaborators on current')
        @@ -557,18 +555,18 @@ test('access ls-collaborators on current', (t) => {
         test('access ls-collaborators on spec', (t) => {
           t.plan(3)
           const access = requireInject('../../lib/access.js', {
        -    'libnpmaccess': {
        +    libnpmaccess: {
               lsCollaborators: (spec) => {
                 t.equal(spec, 'yargs', 'should use expected spec')
                 return {}
        -      }
        +      },
             },
             '../../lib/utils/output.js': () => null,
        -    '../../lib/npm.js': {}
        +    '../../lib/npm.js': {},
           })
           access([
             'ls-collaborators',
        -    'yargs'
        +    'yargs',
           ], (err) => {
             t.ifError(err, 'npm access')
             t.ok('should successfully access ls-packages with no team')
        diff --git a/deps/npm/test/lib/adduser.js b/deps/npm/test/lib/adduser.js
        index 4d2233b18ce6c0..4e6a56fc199d60 100644
        --- a/deps/npm/test/lib/adduser.js
        +++ b/deps/npm/test/lib/adduser.js
        @@ -8,11 +8,12 @@ let result = ''
         const _flatOptions = {
           authType: 'legacy',
           registry: 'https://registry.npmjs.org/',
        -  scope: ''
        +  scope: '',
         }
         
         let failSave = false
         let deletedConfig = {}
        +let registryOutput = ''
         let setConfig = {}
         const authDummy = () => Promise.resolve({
           message: 'success',
        @@ -20,55 +21,64 @@ const authDummy = () => Promise.resolve({
             username: 'u',
             password: 'p',
             email: 'u@npmjs.org',
        -    alwaysAuth: false
        -  }
        +    alwaysAuth: false,
        +  },
         })
         
         const deleteMock = (key, where) => {
           deletedConfig = {
             ...deletedConfig,
        -    [key]: where
        +    [key]: where,
           }
         }
         const adduser = requireInject('../../lib/adduser.js', {
           npmlog: {
        -    disableProgress: () => null
        +    disableProgress: () => null,
        +    notice: (_, msg) => {
        +      registryOutput = msg
        +    },
           },
           '../../lib/npm.js': {
             flatOptions: _flatOptions,
             config: {
               delete: deleteMock,
               get (key, where) {
        -        if (!where || where === 'user') {
        +        if (!where || where === 'user')
                   return _flatOptions[key]
        -        }
               },
               getCredentialsByURI,
               async save () {
        -        if (failSave) {
        +        if (failSave)
                   throw new Error('error saving user config')
        -        }
               },
               set (key, value, where) {
                 setConfig = {
                   ...setConfig,
                   [key]: {
                     value,
        -            where
        -          }
        +            where,
        +          },
                 }
               },
        -      setCredentialsByURI
        -    }
        +      setCredentialsByURI,
        +    },
           },
        -  '../../lib/utils/output.js': msg => { result = msg },
        -  '../../lib/auth/legacy.js': authDummy
        +  '../../lib/utils/output.js': msg => {
        +    result = msg
        +  },
        +  '../../lib/auth/legacy.js': authDummy,
         })
         
         test('simple login', (t) => {
           adduser([], (err) => {
             t.ifError(err, 'npm adduser')
         
        +    t.equal(
        +      registryOutput,
        +      'Log in on https://registry.npmjs.org/',
        +      'should have correct message result'
        +    )
        +
             t.deepEqual(
               deletedConfig,
               {
        @@ -80,7 +90,7 @@ test('simple login', (t) => {
                 _authtoken: 'user',
                 _authToken: 'user',
                 '//registry.npmjs.org/:-authtoken': undefined,
        -        '//registry.npmjs.org/:_authToken': 'user'
        +        '//registry.npmjs.org/:_authToken': 'user',
               },
               'should delete token in user config'
             )
        @@ -91,7 +101,7 @@ test('simple login', (t) => {
                 '//registry.npmjs.org/:_password': { value: 'cA==', where: 'user' },
                 '//registry.npmjs.org/:username': { value: 'u', where: 'user' },
                 '//registry.npmjs.org/:email': { value: 'u@npmjs.org', where: 'user' },
        -        '//registry.npmjs.org/:always-auth': { value: false, where: 'user' }
        +        '//registry.npmjs.org/:always-auth': { value: false, where: 'user' },
               },
               'should set expected user configs'
             )
        @@ -102,6 +112,7 @@ test('simple login', (t) => {
               'should output auth success msg'
             )
         
        +    registryOutput = ''
             deletedConfig = {}
             setConfig = {}
             result = ''
        diff --git a/deps/npm/test/lib/audit.js b/deps/npm/test/lib/audit.js
        index 4918cb2fc27110..cc7379394b2adb 100644
        --- a/deps/npm/test/lib/audit.js
        +++ b/deps/npm/test/lib/audit.js
        @@ -5,7 +5,7 @@ const audit = require('../../lib/audit.js')
         t.test('should audit using Arborist', t => {
           let ARB_ARGS = null
           let AUDIT_CALLED = false
        -  let REIFY_OUTPUT_CALLED = false
        +  let REIFY_FINISH_CALLED = false
           let AUDIT_REPORT_CALLED = false
           let OUTPUT_CALLED = false
           let ARB_OBJ = null
        @@ -14,14 +14,14 @@ t.test('should audit using Arborist', t => {
             '../../lib/npm.js': {
               prefix: 'foo',
               flatOptions: {
        -        json: false
        +        json: false,
               },
             },
             'npm-audit-report': () => {
               AUDIT_REPORT_CALLED = true
               return {
                 report: 'there are vulnerabilities',
        -        exitCode: 0
        +        exitCode: 0,
               }
             },
             '@npmcli/arborist': function (args) {
        @@ -32,15 +32,15 @@ t.test('should audit using Arborist', t => {
                 this.auditReport = {}
               }
             },
        -    '../../lib/utils/reify-output.js': arb => {
        -      if (arb !== ARB_OBJ) {
        +    '../../lib/utils/reify-finish.js': arb => {
        +      if (arb !== ARB_OBJ)
                 throw new Error('got wrong object passed to reify-output')
        -      }
        -      REIFY_OUTPUT_CALLED = true
        +
        +      REIFY_FINISH_CALLED = true
             },
             '../../lib/utils/output.js': () => {
               OUTPUT_CALLED = true
        -    }
        +    },
           })
         
           t.test('audit', t => {
        @@ -55,7 +55,7 @@ t.test('should audit using Arborist', t => {
         
           t.test('audit fix', t => {
             audit(['fix'], () => {
        -      t.equal(REIFY_OUTPUT_CALLED, true, 'called reify output')
        +      t.equal(REIFY_FINISH_CALLED, true, 'called reify output')
               t.end()
             })
           })
        @@ -68,12 +68,12 @@ t.test('should audit - json', t => {
             '../../lib/npm.js': {
               prefix: 'foo',
               flatOptions: {
        -        json: true
        +        json: true,
               },
             },
             'npm-audit-report': () => ({
               report: 'there are vulnerabilities',
        -      exitCode: 0
        +      exitCode: 0,
             }),
             '@npmcli/arborist': function () {
               this.audit = () => {
        @@ -81,7 +81,7 @@ t.test('should audit - json', t => {
               }
             },
             '../../lib/utils/reify-output.js': () => {},
        -    '../../lib/utils/output.js': () => {}
        +    '../../lib/utils/output.js': () => {},
           })
         
           audit([], (err) => {
        @@ -100,11 +100,11 @@ t.test('report endpoint error', t => {
                   prefix: 'foo',
                   command: 'audit',
                   flatOptions: {
        -            json
        +            json,
                   },
                   log: {
        -            warn: (...warning) => LOGS.push(warning)
        -          }
        +            warn: (...warning) => LOGS.push(warning),
        +          },
                 },
                 'npm-audit-report': () => {
                   throw new Error('should not call audit report when there are errors')
        @@ -117,25 +117,25 @@ t.test('report endpoint error', t => {
                         method: 'POST',
                         uri: 'https://example.com/',
                         headers: {
        -                  head: ['ers']
        +                  head: ['ers'],
                         },
                         statusCode: 420,
                         body: json ? { nope: 'lol' }
        -                  : Buffer.from('i had a vuln but i eated it lol')
        -              }
        +                : Buffer.from('i had a vuln but i eated it lol'),
        +              },
                     }
                   }
                 },
                 '../../lib/utils/reify-output.js': () => {},
                 '../../lib/utils/output.js': (...msg) => {
                   OUTPUT.push(msg)
        -        }
        +        },
               }
               // have to pass mocks to both to get the npm and output set right
               const auditError = requireInject('../../lib/utils/audit-error.js', mocks)
               const audit = requireInject('../../lib/audit.js', {
                 ...mocks,
        -        '../../lib/utils/audit-error.js': auditError
        +        '../../lib/utils/audit-error.js': auditError,
               })
         
               audit([], (err) => {
        @@ -156,8 +156,8 @@ t.test('report endpoint error', t => {
                       '    "nope": "lol"\n' +
                       '  }\n' +
                       '}'
        -              : 'i had a vuln but i eated it lol'
        -          ]
        +            : 'i had a vuln but i eated it lol',
        +          ],
                 ])
                 t.strictSame(LOGS, [['audit', 'hello, this didnt work']])
                 t.end()
        @@ -170,8 +170,10 @@ t.test('report endpoint error', t => {
         t.test('completion', t => {
           t.test('fix', t => {
             audit.completion({
        -      conf: { argv: { remain: ['npm', 'audit'] } }
        +      conf: { argv: { remain: ['npm', 'audit'] } },
             }, (err, res) => {
        +      if (err)
        +        throw err
               const subcmd = res.pop()
               t.equals('fix', subcmd, 'completes to fix')
               t.end()
        @@ -180,16 +182,17 @@ t.test('completion', t => {
         
           t.test('subcommand fix', t => {
             audit.completion({
        -      conf: { argv: { remain: ['npm', 'audit', 'fix'] } }
        +      conf: { argv: { remain: ['npm', 'audit', 'fix'] } },
             }, (err) => {
        -      t.notOk(err, 'no errors')
        +      if (err)
        +        throw err
               t.end()
             })
           })
         
           t.test('subcommand not recognized', t => {
             audit.completion({
        -      conf: { argv: { remain: ['npm', 'audit', 'repare'] } }
        +      conf: { argv: { remain: ['npm', 'audit', 'repare'] } },
             }, (err) => {
               t.ok(err, 'not recognized')
               t.end()
        diff --git a/deps/npm/test/lib/auth/legacy.js b/deps/npm/test/lib/auth/legacy.js
        index 1607641d8390eb..f926ae13063eae 100644
        --- a/deps/npm/test/lib/auth/legacy.js
        +++ b/deps/npm/test/lib/auth/legacy.js
        @@ -10,20 +10,20 @@ const legacy = requireInject('../../../lib/auth/legacy.js', {
           npmlog: {
             info: (...msgs) => {
               log += msgs.join(' ')
        -    }
        +    },
           },
           'npm-profile': profile,
           '../../../lib/utils/open-url.js': (url, msg, cb) => {
        -    if (url) {
        +    if (url)
               cb()
        -    } else {
        +    else {
               cb(Object.assign(
                 new Error('failed open url'),
                 { code: 'ERROR' }
               ))
             }
           },
        -  '../../../lib/utils/read-user-info.js': read
        +  '../../../lib/utils/read-user-info.js': read,
         })
         
         test('login using username/password with token result', async (t) => {
        @@ -33,16 +33,16 @@ test('login using username/password with token result', async (t) => {
         
           const {
             message,
        -    newCreds
        +    newCreds,
           } = await legacy({
             creds: {
               username: 'u',
               password: 'p',
               email: 'u@npmjs.org',
        -      alwaysAuth: false
        +      alwaysAuth: false,
             },
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           t.equal(
        @@ -74,16 +74,16 @@ test('login using username/password with user info result', async (t) => {
         
           const {
             message,
        -    newCreds
        +    newCreds,
           } = await legacy({
             creds: {
               username: 'u',
               password: 'p',
               email: 'u@npmjs.org',
        -      alwaysAuth: false
        +      alwaysAuth: false,
             },
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           t.equal(
        @@ -98,7 +98,7 @@ test('login using username/password with user info result', async (t) => {
               username: 'u',
               password: 'p',
               email: 'u@npmjs.org',
        -      alwaysAuth: false
        +      alwaysAuth: false,
             },
             'should return used credentials'
           )
        @@ -125,16 +125,16 @@ test('login otp requested', async (t) => {
         
           const {
             message,
        -    newCreds
        +    newCreds,
           } = await legacy({
             creds: {
               username: 'u',
               password: 'p',
               email: 'u@npmjs.org',
        -      alwaysAuth: false
        +      alwaysAuth: false,
             },
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           t.equal(
        @@ -165,10 +165,10 @@ test('login missing basic credential info', async (t) => {
             legacy({
               creds: {
                 username: 'u',
        -        password: 'p'
        +        password: 'p',
               },
               registry: 'https://registry.npmjs.org/',
        -      scope: ''
        +      scope: '',
             }),
             { code: 'ERROR' },
             'should throw server response error'
        @@ -195,16 +195,16 @@ test('create new user when user not found', async (t) => {
         
           const {
             message,
        -    newCreds
        +    newCreds,
           } = await legacy({
             creds: {
               username: 'u',
               password: 'p',
               email: 'u@npmjs.org',
        -      alwaysAuth: false
        +      alwaysAuth: false,
             },
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           t.equal(
        @@ -245,13 +245,13 @@ test('prompts for user info if required', async (t) => {
         
           const {
             message,
        -    newCreds
        +    newCreds,
           } = await legacy({
             creds: {
        -      alwaysAuth: true
        +      alwaysAuth: true,
             },
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           t.equal(
        @@ -272,7 +272,7 @@ test('prompts for user info if required', async (t) => {
               username: 'foo',
               password: 'pass',
               email: 'foo@npmjs.org',
        -      alwaysAuth: true
        +      alwaysAuth: true,
             },
             'should return result from profile.login containing prompt info'
           )
        @@ -309,10 +309,10 @@ test('request otp when creating new user', async (t) => {
               username: 'u',
               password: 'p',
               email: 'u@npmjs.org',
        -      alwaysAuth: false
        +      alwaysAuth: false,
             },
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           log = ''
        @@ -338,10 +338,10 @@ test('unknown error during user creation', async (t) => {
                 username: 'u',
                 password: 'p',
                 email: 'u@npmjs.org',
        -        alwaysAuth: false
        +        alwaysAuth: false,
               },
               registry: 'https://registry.npmjs.org/',
        -      scope: ''
        +      scope: '',
             }),
             { code: 'ERROR' },
             'should throw unknown error'
        @@ -353,16 +353,18 @@ test('unknown error during user creation', async (t) => {
         })
         
         test('open url error', async (t) => {
        -  profile.login = async (opener, prompt, opts) => { await opener() }
        +  profile.login = async (opener, prompt, opts) => {
        +    await opener()
        +  }
         
           await t.rejects(
             legacy({
               creds: {
                 username: 'u',
        -        password: 'p'
        +        password: 'p',
               },
               registry: 'https://registry.npmjs.org/',
        -      scope: ''
        +      scope: '',
             }),
             { message: 'failed open url', code: 'ERROR' },
             'should throw unknown error'
        @@ -380,10 +382,10 @@ test('login no credentials provided', async (t) => {
               username: undefined,
               password: undefined,
               email: undefined,
        -      alwaysAuth: undefined
        +      alwaysAuth: undefined,
             },
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           t.equal(
        @@ -404,10 +406,10 @@ test('scoped login', async (t) => {
               username: 'u',
               password: 'p',
               email: 'u@npmjs.org',
        -      alwaysAuth: false
        +      alwaysAuth: false,
             },
             registry: 'https://diff-registry.npmjs.org/',
        -    scope: 'myscope'
        +    scope: 'myscope',
           })
         
           t.equal(
        diff --git a/deps/npm/test/lib/auth/oauth.js b/deps/npm/test/lib/auth/oauth.js
        index a8461d235e5e59..82d478b52c7cc9 100644
        --- a/deps/npm/test/lib/auth/oauth.js
        +++ b/deps/npm/test/lib/auth/oauth.js
        @@ -6,7 +6,7 @@ test('oauth login', (t) => {
           const oauthOpts = {
             creds: {},
             registry: 'https://diff-registry.npmjs.org/',
        -    scope: 'myscope'
        +    scope: 'myscope',
           }
         
           const oauth = requireInject('../../../lib/auth/oauth.js', {
        @@ -18,9 +18,9 @@ test('oauth login', (t) => {
                 set: (key, value) => {
                   t.equal(key, 'sso-type', 'should define sso-type')
                   t.equal(value, 'oauth', 'should set sso-type to oauth')
        -        }
        -      }
        -    }
        +        },
        +      },
        +    },
           })
         
           oauth(oauthOpts)
        diff --git a/deps/npm/test/lib/auth/saml.js b/deps/npm/test/lib/auth/saml.js
        index 3e0015bf39be38..87fa6688b57ea7 100644
        --- a/deps/npm/test/lib/auth/saml.js
        +++ b/deps/npm/test/lib/auth/saml.js
        @@ -6,7 +6,7 @@ test('saml login', (t) => {
           const samlOpts = {
             creds: {},
             registry: 'https://diff-registry.npmjs.org/',
        -    scope: 'myscope'
        +    scope: 'myscope',
           }
         
           const saml = requireInject('../../../lib/auth/saml.js', {
        @@ -18,9 +18,9 @@ test('saml login', (t) => {
                 set: (key, value) => {
                   t.equal(key, 'sso-type', 'should define sso-type')
                   t.equal(value, 'saml', 'should set sso-type to saml')
        -        }
        -      }
        -    }
        +        },
        +      },
        +    },
           })
         
           saml(samlOpts)
        diff --git a/deps/npm/test/lib/auth/sso.js b/deps/npm/test/lib/auth/sso.js
        index 0e04309c82bf79..1fc04c64cd3cca 100644
        --- a/deps/npm/test/lib/auth/sso.js
        +++ b/deps/npm/test/lib/auth/sso.js
        @@ -5,7 +5,7 @@ let log = ''
         let warn = ''
         
         const _flatOptions = {
        -  ssoType: 'oauth'
        +  ssoType: 'oauth',
         }
         const token = '24528a24f240'
         const SSO_URL = 'https://registry.npmjs.org/{SSO_URL}'
        @@ -18,17 +18,17 @@ const sso = requireInject('../../../lib/auth/sso.js', {
             },
             warn: (...msgs) => {
               warn += msgs.join(' ')
        -    }
        +    },
           },
           'npm-profile': profile,
           'npm-registry-fetch': npmFetch,
           '../../../lib/npm.js': {
        -    flatOptions: _flatOptions
        +    flatOptions: _flatOptions,
           },
           '../../../lib/utils/open-url.js': (url, msg, cb) => {
        -    if (url) {
        +    if (url)
               cb()
        -    } else {
        +    else {
               cb(Object.assign(
                 new Error('failed open url'),
                 { code: 'ERROR' }
        @@ -36,15 +36,15 @@ const sso = requireInject('../../../lib/auth/sso.js', {
             }
           },
           '../../../lib/utils/otplease.js': (opts, fn) => {
        -    if (opts) {
        +    if (opts)
               return fn({ ...opts, otp: '1234' })
        -    } else {
        +    else {
               throw Object.assign(
                 new Error('failed retrieving otp'),
                 { code: 'ERROR' }
               )
             }
        -  }
        +  },
         })
         
         test('empty login', async (t) => {
        @@ -80,7 +80,7 @@ test('simple login', async (t) => {
                 otp: '1234',
                 registry: 'https://registry.npmjs.org/',
                 scope: '',
        -        ssoType: 'oauth'
        +        ssoType: 'oauth',
               },
               'should use dummy password'
             )
        @@ -91,11 +91,11 @@ test('simple login', async (t) => {
         
           const {
             message,
        -    newCreds
        +    newCreds,
           } = await sso({
             creds: {},
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           t.equal(
        @@ -160,7 +160,7 @@ test('polling retry', async (t) => {
           await sso({
             creds: {},
             registry: 'https://registry.npmjs.org/',
        -    scope: ''
        +    scope: '',
           })
         
           log = ''
        @@ -180,7 +180,7 @@ test('polling error', async (t) => {
             sso({
               creds: {},
               registry: 'https://registry.npmjs.org/',
        -      scope: ''
        +      scope: '',
             }),
             { message: 'unknown error', code: 'ERROR' },
             'should throw unknown error'
        @@ -199,7 +199,7 @@ test('no token retrieved from loginCouch', async (t) => {
             sso({
               creds: {},
               registry: 'https://registry.npmjs.org/',
        -      scope: ''
        +      scope: '',
             }),
             { message: 'no SSO token returned' },
             'should throw no SSO token returned error'
        @@ -217,7 +217,7 @@ test('no sso url retrieved from loginCouch', async (t) => {
             sso({
               creds: {},
               registry: 'https://registry.npmjs.org/',
        -      scope: ''
        +      scope: '',
             }),
             { message: 'no SSO URL returned by services' },
             'should throw no SSO url returned error'
        @@ -234,11 +234,11 @@ test('scoped login', async (t) => {
         
           const {
             message,
        -    newCreds
        +    newCreds,
           } = await sso({
             creds: {},
             registry: 'https://diff-registry.npmjs.org/',
        -    scope: 'myscope'
        +    scope: 'myscope',
           })
         
           t.equal(
        diff --git a/deps/npm/test/lib/bin.js b/deps/npm/test/lib/bin.js
        index 05fc1e21e05d4c..c5ed2a91b98310 100644
        --- a/deps/npm/test/lib/bin.js
        +++ b/deps/npm/test/lib/bin.js
        @@ -9,7 +9,7 @@ test('bin', (t) => {
             '../../lib/npm.js': { bin: dir, flatOptions: { global: false } },
             '../../lib/utils/output.js': (output) => {
               t.equal(output, dir, 'prints the correct directory')
        -    }
        +    },
           })
         
           bin([], (err) => {
        @@ -35,7 +35,7 @@ test('bin -g', (t) => {
             '../../lib/utils/path.js': [dir],
             '../../lib/utils/output.js': (output) => {
               t.equal(output, dir, 'prints the correct directory')
        -    }
        +    },
           })
         
           bin([], (err) => {
        @@ -61,7 +61,7 @@ test('bin -g (not in path)', (t) => {
             '../../lib/utils/path.js': ['/not/my/dir'],
             '../../lib/utils/output.js': (output) => {
               t.equal(output, dir, 'prints the correct directory')
        -    }
        +    },
           })
         
           bin([], (err) => {
        diff --git a/deps/npm/test/lib/birthday.js b/deps/npm/test/lib/birthday.js
        index 35255f97aa34bb..21b60b4c79620f 100644
        --- a/deps/npm/test/lib/birthday.js
        +++ b/deps/npm/test/lib/birthday.js
        @@ -38,6 +38,7 @@ test('birthday (nope again)', (t) => {
               const d = new D()
               return d[B[f]('Z2V0RnVsbFllYXI=', _6)[l]()]() + 1
             }
        +
             [B[f]('Z2V0VVRDTW9udGg=', _6)[l]()] () {
               return 9
             }
        @@ -66,6 +67,7 @@ test('birthday (yup)', (t) => {
             [B[f]('Z2V0VVRDTW9udGg=', _6)[l]()] () {
               return 8
             }
        +
             [B[f]('Z2V0VVRDRGF0ZQ==', _6)[l]()] () {
               return 29
             }
        diff --git a/deps/npm/test/lib/bugs.js b/deps/npm/test/lib/bugs.js
        index 79d5089724a50b..df64349878e619 100644
        --- a/deps/npm/test/lib/bugs.js
        +++ b/deps/npm/test/lib/bugs.js
        @@ -5,40 +5,40 @@ const pacote = {
           manifest: async (spec, options) => {
             return spec === 'nobugs' ? {
               name: 'nobugs',
        -      version: '1.2.3'
        -    }
        -    : spec === 'bugsurl' ? {
        -      name: 'bugsurl',
        -      version: '1.2.3',
        -      bugs: 'https://bugzilla.localhost/bugsurl'
        -    }
        -    : spec === 'bugsobj' ? {
        -      name: 'bugsobj',
        -      version: '1.2.3',
        -      bugs: { url: 'https://bugzilla.localhost/bugsobj' }
        -    }
        -    : spec === 'bugsobj-nourl' ? {
        -      name: 'bugsobj-nourl',
        -      version: '1.2.3',
        -      bugs: { no: 'url here' }
        -    }
        -    : spec === 'repourl' ? {
        -      name: 'repourl',
        -      version: '1.2.3',
        -      repository: 'https://github.com/foo/repourl'
        -    }
        -    : spec === 'repoobj' ? {
        -      name: 'repoobj',
               version: '1.2.3',
        -      repository: { url: 'https://github.com/foo/repoobj' }
             }
        -    : spec === '.' ? {
        -      name: 'thispkg',
        -      version: '1.2.3',
        -      bugs: 'https://example.com'
        -    }
        -    : null
        -  }
        +      : spec === 'bugsurl' ? {
        +        name: 'bugsurl',
        +        version: '1.2.3',
        +        bugs: 'https://bugzilla.localhost/bugsurl',
        +      }
        +      : spec === 'bugsobj' ? {
        +        name: 'bugsobj',
        +        version: '1.2.3',
        +        bugs: { url: 'https://bugzilla.localhost/bugsobj' },
        +      }
        +      : spec === 'bugsobj-nourl' ? {
        +        name: 'bugsobj-nourl',
        +        version: '1.2.3',
        +        bugs: { no: 'url here' },
        +      }
        +      : spec === 'repourl' ? {
        +        name: 'repourl',
        +        version: '1.2.3',
        +        repository: 'https://github.com/foo/repourl',
        +      }
        +      : spec === 'repoobj' ? {
        +        name: 'repoobj',
        +        version: '1.2.3',
        +        repository: { url: 'https://github.com/foo/repoobj' },
        +      }
        +      : spec === '.' ? {
        +        name: 'thispkg',
        +        version: '1.2.3',
        +        bugs: 'https://example.com',
        +      }
        +      : null
        +  },
         }
         
         // keep a tally of which urls got opened
        @@ -51,7 +51,7 @@ const openUrl = (url, errMsg, cb) => {
         
         const bugs = requireInject('../../lib/bugs.js', {
           pacote,
        -  '../../lib/utils/open-url.js': openUrl
        +  '../../lib/utils/open-url.js': openUrl,
         })
         
         t.test('completion', t => {
        @@ -70,7 +70,7 @@ t.test('open bugs urls', t => {
             bugsobj: 'https://bugzilla.localhost/bugsobj',
             repourl: 'https://github.com/foo/repourl/issues',
             repoobj: 'https://github.com/foo/repoobj/issues',
        -    '.': 'https://example.com'
        +    '.': 'https://example.com',
           }
           const keys = Object.keys(expect)
           t.plan(keys.length)
        diff --git a/deps/npm/test/lib/cache.js b/deps/npm/test/lib/cache.js
        new file mode 100644
        index 00000000000000..2e9ad346bb59bc
        --- /dev/null
        +++ b/deps/npm/test/lib/cache.js
        @@ -0,0 +1,228 @@
        +const t = require('tap')
        +const requireInject = require('require-inject')
        +const path = require('path')
        +
        +const usageUtil = () => 'usage instructions'
        +
        +const flatOptions = {
        +  force: false,
        +}
        +
        +const npm = {
        +  flatOptions,
        +  cache: '/fake/path',
        +}
        +
        +let rimrafPath = ''
        +const rimraf = (path, cb) => {
        +  rimrafPath = path
        +  return cb()
        +}
        +
        +let logOutput = []
        +const npmlog = {
        +  silly: (...args) => {
        +    logOutput.push(['silly', ...args])
        +  },
        +}
        +
        +let tarballStreamSpec = ''
        +let tarballStreamOpts = {}
        +const pacote = {
        +  tarball: {
        +    stream: (spec, handler, opts) => {
        +      tarballStreamSpec = spec
        +      tarballStreamOpts = opts
        +      return handler({
        +        resume: () => {},
        +        promise: () => Promise.resolve(),
        +      })
        +    },
        +  },
        +}
        +
        +let outputOutput = []
        +const output = (msg) => {
        +  outputOutput.push(msg)
        +}
        +
        +const cacacheVerifyStats = {
        +  keptSize: 100,
        +  verifiedContent: 1,
        +  totalEntries: 1,
        +  runTime: { total: 2000 },
        +}
        +const cacache = {
        +  verify: (path) => {
        +    return cacacheVerifyStats
        +  },
        +}
        +
        +const mocks = {
        +  cacache,
        +  npmlog,
        +  pacote,
        +  rimraf,
        +  '../../lib/npm.js': npm,
        +  '../../lib/utils/output.js': output,
        +  '../../lib/utils/usage.js': usageUtil,
        +}
        +
        +const cache = requireInject('../../lib/cache.js', mocks)
        +
        +t.test('cache no args', t => {
        +  cache([], err => {
        +    t.equal(err.message, 'usage instructions', 'should throw usage instructions')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache clean', t => {
        +  cache(['clean'], err => {
        +    t.match(err.message, 'the npm cache self-heals', 'should throw warning')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache clean (force)', t => {
        +  flatOptions.force = true
        +  t.teardown(() => {
        +    rimrafPath = ''
        +    flatOptions.force = false
        +  })
        +
        +  cache(['clear'], err => {
        +    t.ifError(err)
        +    t.equal(rimrafPath, path.join(npm.cache, '_cacache'))
        +    t.end()
        +  })
        +})
        +
        +t.test('cache clean with arg', t => {
        +  cache(['rm', 'pkg'], err => {
        +    t.match(err.message, 'does not accept arguments', 'should throw error')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache add no arg', t => {
        +  t.teardown(() => {
        +    logOutput = []
        +  })
        +
        +  cache(['add'], err => {
        +    t.strictSame(logOutput, [
        +      ['silly', 'cache add', 'args', []],
        +    ], 'logs correctly')
        +    t.equal(err.code, 'EUSAGE', 'throws usage error')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache add pkg only', t => {
        +  t.teardown(() => {
        +    logOutput = []
        +    tarballStreamSpec = ''
        +    tarballStreamOpts = {}
        +  })
        +
        +  cache(['add', 'mypkg'], err => {
        +    t.ifError(err)
        +    t.strictSame(logOutput, [
        +      ['silly', 'cache add', 'args', ['mypkg']],
        +      ['silly', 'cache add', 'spec', 'mypkg'],
        +    ], 'logs correctly')
        +    t.equal(tarballStreamSpec, 'mypkg', 'passes the correct spec to pacote')
        +    t.same(tarballStreamOpts, flatOptions, 'passes the correct options to pacote')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache add pkg w/ spec modifier', t => {
        +  t.teardown(() => {
        +    logOutput = []
        +    tarballStreamSpec = ''
        +    tarballStreamOpts = {}
        +  })
        +
        +  cache(['add', 'mypkg', 'latest'], err => {
        +    t.ifError(err)
        +    t.strictSame(logOutput, [
        +      ['silly', 'cache add', 'args', ['mypkg', 'latest']],
        +      ['silly', 'cache add', 'spec', 'mypkg@latest'],
        +    ], 'logs correctly')
        +    t.equal(tarballStreamSpec, 'mypkg@latest', 'passes the correct spec to pacote')
        +    t.same(tarballStreamOpts, flatOptions, 'passes the correct options to pacote')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache verify', t => {
        +  t.teardown(() => {
        +    outputOutput = []
        +  })
        +
        +  cache(['verify'], err => {
        +    t.ifError(err)
        +    t.match(outputOutput, [
        +      `Cache verified and compressed (${path.join(npm.cache, '_cacache')})`,
        +      'Content verified: 1 (100 bytes)',
        +      'Index entries: 1',
        +      'Finished in 2s',
        +    ], 'prints correct output')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache verify w/ extra output', t => {
        +  npm.cache = `${process.env.HOME}/fake/path`
        +  cacacheVerifyStats.badContentCount = 1
        +  cacacheVerifyStats.reclaimedCount = 2
        +  cacacheVerifyStats.reclaimedSize = 200
        +  cacacheVerifyStats.missingContent = 3
        +  t.teardown(() => {
        +    npm.cache = '/fake/path'
        +    outputOutput = []
        +    delete cacacheVerifyStats.badContentCount
        +    delete cacacheVerifyStats.reclaimedCount
        +    delete cacacheVerifyStats.reclaimedSize
        +    delete cacacheVerifyStats.missingContent
        +  })
        +
        +  cache(['check'], err => {
        +    t.ifError(err)
        +    t.match(outputOutput, [
        +      `Cache verified and compressed (~${path.join('/fake/path', '_cacache')})`,
        +      'Content verified: 1 (100 bytes)',
        +      'Corrupted content removed: 1',
        +      'Content garbage-collected: 2 (200 bytes)',
        +      'Missing content: 3',
        +      'Index entries: 1',
        +      'Finished in 2s',
        +    ], 'prints correct output')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache completion', t => {
        +  const { completion } = cache
        +
        +  const testComp = (argv, expect) => {
        +    completion({ conf: { argv: { remain: argv } } }, (err, res) => {
        +      t.ifError(err)
        +      t.strictSame(res, expect, argv.join(' '))
        +    })
        +  }
        +
        +  testComp(['npm', 'cache'], [
        +    'add',
        +    'clean',
        +    'verify',
        +  ])
        +
        +  testComp(['npm', 'cache', 'add'], [])
        +  testComp(['npm', 'cache', 'clean'], [])
        +  testComp(['npm', 'cache', 'verify'], [])
        +
        +  t.end()
        +})
        diff --git a/deps/npm/test/lib/ci.js b/deps/npm/test/lib/ci.js
        index 645fc6aed97e4f..8ddb8f8aad23ca 100644
        --- a/deps/npm/test/lib/ci.js
        +++ b/deps/npm/test/lib/ci.js
        @@ -3,7 +3,6 @@ const util = require('util')
         const readdir = util.promisify(fs.readdir)
         
         const { test } = require('tap')
        -const { resolve } = require('path')
         
         const requireInject = require('require-inject')
         
        @@ -12,9 +11,10 @@ test('should use Arborist', (t) => {
             '../../lib/npm.js': {
               prefix: 'foo',
               flatOptions: {
        -        global: false
        -      }
        +        global: false,
        +      },
             },
        +    '../../lib/utils/reify-finish.js': async () => {},
             '@npmcli/arborist': function (args) {
               t.ok(args, 'gets options object')
               this.loadVirtual = () => {
        @@ -25,40 +25,66 @@ test('should use Arborist', (t) => {
                 t.ok(true, 'reify is called')
               }
             },
        -    'util': {
        -      'inherits': () => {},
        -      'promisify': (fn) => fn
        +    util: {
        +      inherits: () => {},
        +      promisify: (fn) => fn,
             },
        -    'rimraf': (path) => {
        +    rimraf: (path) => {
               t.ok(path, 'rimraf called with path')
               return Promise.resolve(true)
             },
             '../../lib/utils/reify-output.js': function (arb) {
               t.ok(arb, 'gets arborist tree')
        -    }
        +    },
           })
        -  ci(null, () => {
        +  ci(null, er => {
        +    if (er)
        +      throw er
             t.end()
           })
         })
         
        +test('should pass flatOptions to Arborist.reify', (t) => {
        +  const ci = requireInject('../../lib/ci.js', {
        +    '../../lib/npm.js': {
        +      prefix: 'foo',
        +      flatOptions: {
        +        production: true,
        +      },
        +    },
        +    '../../lib/utils/reify-finish.js': async () => {},
        +    '@npmcli/arborist': function () {
        +      this.loadVirtual = () => Promise.resolve(true)
        +      this.reify = async (options) => {
        +        t.equal(options.production, true, 'should pass flatOptions to Arborist.reify')
        +        t.end()
        +      }
        +    },
        +  })
        +  ci(null, er => {
        +    if (er)
        +      throw er
        +  })
        +})
        +
         test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => {
           const testDir = t.testdir({
             'index.js': 'some contents',
        -    'package.json': 'some info'
        +    'package.json': 'some info',
           })
         
           const ci = requireInject('../../lib/ci.js', {
             '../../lib/npm.js': {
               prefix: testDir,
               flatOptions: {
        -        global: false
        -      }
        +        global: false,
        +      },
             },
        -    'npmlog': {
        +    '../../lib/utils/reify-finish.js': async () => {},
        +    npmlog: {
               verbose: () => {
                 t.ok(true, 'log fn called')
        -      }
        +      },
             },
           })
           ci(null, (err, res) => {
        @@ -73,9 +99,10 @@ test('should throw ECIGLOBAL', (t) => {
             '../../lib/npm.js': {
               prefix: 'foo',
               flatOptions: {
        -        global: true
        -      }
        -    }
        +        global: true,
        +      },
        +    },
        +    '../../lib/utils/reify-finish.js': async () => {},
           })
           ci(null, (err, res) => {
             t.equals(err.code, 'ECIGLOBAL', 'throws error with global packages')
        @@ -86,18 +113,19 @@ test('should throw ECIGLOBAL', (t) => {
         
         test('should remove existing node_modules before installing', (t) => {
           const testDir = t.testdir({
        -    'node_modules': {
        -      'some-file': 'some contents'
        -    }
        +    node_modules: {
        +      'some-file': 'some contents',
        +    },
           })
         
           const ci = requireInject('../../lib/ci.js', {
             '../../lib/npm.js': {
               prefix: testDir,
               flatOptions: {
        -        global: false
        -      }
        +        global: false,
        +      },
             },
        +    '../../lib/utils/reify-finish.js': async () => {},
             '@npmcli/arborist': function () {
               this.loadVirtual = () => Promise.resolve(true)
               this.reify = async (options) => {
        @@ -108,8 +136,11 @@ test('should remove existing node_modules before installing', (t) => {
                 t.same(nodeModules, ['node_modules'], 'should only have the node_modules directory')
                 t.end()
               }
        -    }
        +    },
           })
         
        -  ci(null, () => {})
        +  ci(null, er => {
        +    if (er)
        +      throw er
        +  })
         })
        diff --git a/deps/npm/test/lib/cli.js b/deps/npm/test/lib/cli.js
        index 0d9b6ad6a5a8a6..b5441be1e44d87 100644
        --- a/deps/npm/test/lib/cli.js
        +++ b/deps/npm/test/lib/cli.js
        @@ -8,14 +8,16 @@ const npmock = {
           config: {
             settings: {},
             get: (k) => npmock.config.settings[k],
        -    set: (k, v) => { npmock.config.settings[k] = v },
        +    set: (k, v) => {
        +      npmock.config.settings[k] = v
        +    },
           },
        -  commands: {}
        +  commands: {},
         }
         
         const unsupportedMock = {
           checkForBrokenNode: () => {},
        -  checkForUnsupportedNode: () => {}
        +  checkForUnsupportedNode: () => {},
         }
         
         let errorHandlerCalled = null
        @@ -31,7 +33,7 @@ const logs = []
         const npmlogMock = {
           pause: () => logs.push('pause'),
           verbose: (...msg) => logs.push(['verbose', ...msg]),
        -  info: (...msg) => logs.push(['info', ...msg])
        +  info: (...msg) => logs.push(['info', ...msg]),
         }
         
         const requireInject = require('require-inject')
        @@ -39,7 +41,7 @@ const cli = requireInject.installGlobally('../../lib/cli.js', {
           '../../lib/npm.js': npmock,
           '../../lib/utils/unsupported.js': unsupportedMock,
           '../../lib/utils/error-handler.js': errorHandlerMock,
        -  npmlog: npmlogMock
        +  npmlog: npmlogMock,
         })
         
         t.test('print the version, and treat npm_g to npm -g', t => {
        @@ -50,7 +52,7 @@ t.test('print the version, and treat npm_g to npm -g', t => {
           const proc = {
             argv: ['node', 'npm_g', '-v'],
             version: '420.69.lol',
        -    on: () => {}
        +    on: () => {},
           }
           process.argv = proc.argv
           npmock.config.settings.version = true
        @@ -58,14 +60,14 @@ t.test('print the version, and treat npm_g to npm -g', t => {
           cli(proc)
         
           t.strictSame(npmock.argv, [])
        -  t.strictSame(proc.argv, [ 'node', 'npm', '-g', '-v' ])
        +  t.strictSame(proc.argv, ['node', 'npm', '-g', '-v'])
           t.strictSame(logs, [
             'pause',
        -    [ 'verbose', 'cli', [ 'node', 'npm', '-g', '-v' ] ],
        -    [ 'info', 'using', 'npm@%s', '99.99.99' ],
        -    [ 'info', 'using', 'node@%s', '420.69.lol' ]
        +    ['verbose', 'cli', ['node', 'npm', '-g', '-v']],
        +    ['info', 'using', 'npm@%s', '99.99.99'],
        +    ['info', 'using', 'node@%s', '420.69.lol'],
           ])
        -  t.strictSame(consoleLogs, [ [ '99.99.99' ] ])
        +  t.strictSame(consoleLogs, [['99.99.99']])
           t.strictSame(errorHandlerExitCalled, 0)
         
           delete npmock.config.settings.version
        @@ -87,7 +89,7 @@ t.test('calling with --versions calls npm version with no args', t => {
           const processArgv = process.argv
           const proc = {
             argv: ['node', 'npm', 'install', 'or', 'whatever', '--versions'],
        -    on: () => {}
        +    on: () => {},
           }
           process.argv = proc.argv
           npmock.config.set('versions', true)
        @@ -107,12 +109,12 @@ t.test('calling with --versions calls npm version with no args', t => {
           npmock.commands.version = (args, cb) => {
             t.equal(proc.title, 'npm')
             t.strictSame(npmock.argv, [])
        -    t.strictSame(proc.argv, [ 'node', 'npm', 'install', 'or', 'whatever', '--versions' ])
        +    t.strictSame(proc.argv, ['node', 'npm', 'install', 'or', 'whatever', '--versions'])
             t.strictSame(logs, [
               'pause',
        -      [ 'verbose', 'cli', [ 'node', 'npm', 'install', 'or', 'whatever', '--versions' ] ],
        -      [ 'info', 'using', 'npm@%s', '99.99.99' ],
        -      [ 'info', 'using', 'node@%s', undefined ]
        +      ['verbose', 'cli', ['node', 'npm', 'install', 'or', 'whatever', '--versions']],
        +      ['info', 'using', 'npm@%s', '99.99.99'],
        +      ['info', 'using', 'node@%s', undefined],
             ])
         
             t.strictSame(consoleLogs, [])
        @@ -131,7 +133,7 @@ t.test('print usage if -h provided', t => {
           console.log = (...msg) => consoleLogs.push(msg)
           const proc = {
             argv: ['node', 'npm', 'asdf'],
        -    on: () => {}
        +    on: () => {},
           }
           npmock.argv = ['asdf']
         
        @@ -150,12 +152,12 @@ t.test('print usage if -h provided', t => {
             t.equal(proc.title, 'npm')
             t.strictSame(args, ['asdf'])
             t.strictSame(npmock.argv, ['asdf'])
        -    t.strictSame(proc.argv, [ 'node', 'npm', 'asdf' ])
        +    t.strictSame(proc.argv, ['node', 'npm', 'asdf'])
             t.strictSame(logs, [
               'pause',
        -      [ 'verbose', 'cli', [ 'node', 'npm', 'asdf' ] ],
        -      [ 'info', 'using', 'npm@%s', '99.99.99' ],
        -      [ 'info', 'using', 'node@%s', undefined ]
        +      ['verbose', 'cli', ['node', 'npm', 'asdf']],
        +      ['info', 'using', 'npm@%s', '99.99.99'],
        +      ['info', 'using', 'node@%s', undefined],
             ])
             t.strictSame(consoleLogs, [])
             t.strictSame(errorHandlerExitCalled, null)
        @@ -170,11 +172,10 @@ t.test('load error calls error handler', t => {
           LOAD_ERROR = er
           const proc = {
             argv: ['node', 'npm', 'asdf'],
        -    on: () => {}
        +    on: () => {},
           }
           cli(proc)
           t.strictSame(errorHandlerCalled, [er])
           LOAD_ERROR = null
           t.end()
         })
        -
        diff --git a/deps/npm/test/lib/config.js b/deps/npm/test/lib/config.js
        index 890d65731a88c7..8a11a40c813370 100644
        --- a/deps/npm/test/lib/config.js
        +++ b/deps/npm/test/lib/config.js
        @@ -25,20 +25,20 @@ const types = {
           'init-author-name': String,
           'init-version': String,
           'init.author.name': String,
        -  'init.version': String
        +  'init.version': String,
         }
         const defaults = {
           'init-author-name': '',
           'init-version': '1.0.0',
           'init.author.name': '',
        -  'init.version': '1.0.0'
        +  'init.version': '1.0.0',
         }
         
         const flatOptions = {
           editor: 'vi',
           json: false,
           long: false,
        -  global: false
        +  global: false,
         }
         
         const npm = {
        @@ -46,17 +46,21 @@ const npm = {
           log: {
             info: () => null,
             enableProgress: () => null,
        -    disableProgress: () => null
        +    disableProgress: () => null,
           },
           config: {
             data: new Map(Object.entries({
               default: { data: defaults, source: 'default values' },
               global: { data: {}, source: '/etc/npmrc' },
        -      cli: { data: flatOptions, source: 'command line options' }
        +      cli: { data: flatOptions, source: 'command line options' },
             })),
        -    get (key) { return flatOptions[key] },
        -    validate () { return true }
        -  }
        +    get (key) {
        +      return flatOptions[key]
        +    },
        +    validate () {
        +      return true
        +    },
        +  },
         }
         
         const usageUtil = () => 'usage instructions'
        @@ -64,8 +68,10 @@ const usageUtil = () => 'usage instructions'
         const mocks = {
           '../../lib/utils/config.js': { defaults, types },
           '../../lib/npm.js': npm,
        -  '../../lib/utils/output.js': msg => { result = msg },
        -  '../../lib/utils/usage.js': usageUtil
        +  '../../lib/utils/output.js': msg => {
        +    result = msg
        +  },
        +  '../../lib/utils/usage.js': usageUtil,
         }
         
         const config = requireInject('../../lib/config.js', mocks)
        @@ -99,9 +105,9 @@ t.test('config list overrides', t => {
           npm.config.data.set('user', {
             data: {
               'init.author.name': 'Foo',
        -      '//private-reg.npmjs.org/:_authThoken': 'f00ba1'
        +      '//private-reg.npmjs.org/:_authThoken': 'f00ba1',
             },
        -    source: '~/.npmrc'
        +    source: '~/.npmrc',
           })
           flatOptions['init.author.name'] = 'Bar'
           npm.config.find = () => 'cli'
        @@ -144,7 +150,7 @@ t.test('config list --json', t => {
           result = ''
           npm.config.list = [{
             '//private-reg.npmjs.org/:_authThoken': 'f00ba1',
        -    ...npm.config.data.get('cli').data
        +    ...npm.config.data.get('cli').data,
           }]
           const npmConfigGet = npm.config.get
           npm.config.get = key => npm.config.list[0][key]
        @@ -164,7 +170,7 @@ t.test('config list --json', t => {
                 editor: 'vi',
                 json: true,
                 long: false,
        -        global: false
        +        global: false,
               },
               'should list configs usin json'
             )
        @@ -413,7 +419,7 @@ t.test('config edit', t => {
         init.author.name=Foo
         sign-git-commit=true`
           npm.config.data.set('user', {
        -    source: '~/.npmrc'
        +    source: '~/.npmrc',
           })
           npm.config.save = async where => {
             t.equal(where, 'user', 'should save to user config by default')
        @@ -422,25 +428,29 @@ sign-git-commit=true`
             ...mocks,
             'mkdirp-infer-owner': async () => null,
             fs: {
        -      readFile (path, encoding, cb) { cb(null, npmrc) },
        +      readFile (path, encoding, cb) {
        +        cb(null, npmrc)
        +      },
               writeFile (file, data, encoding, cb) {
                 t.equal(file, '~/.npmrc', 'should save to expected file location')
                 t.matchSnapshot(data, 'should write config file')
                 cb()
        -      }
        +      },
             },
             editor: (file, { editor }, cb) => {
               t.equal(file, '~/.npmrc', 'should match user source data')
               t.equal(editor, 'vi', 'should use default editor')
               cb()
        -    }
        +    },
           }
           const config = requireInject('../../lib/config.js', editMocks)
           config(['edit'], (err) => {
             t.ifError(err, 'npm config edit')
         
             // test no config file result
        -    editMocks.fs.readFile = (p, e, cb) => { cb(new Error('ERR')) }
        +    editMocks.fs.readFile = (p, e, cb) => {
        +      cb(new Error('ERR'))
        +    }
             const config = requireInject('../../lib/config.js', editMocks)
             config(['edit'], (err) => {
               t.ifError(err, 'npm config edit')
        @@ -459,7 +469,7 @@ t.test('config edit --global', t => {
           flatOptions.global = true
           const npmrc = 'init.author.name=Foo'
           npm.config.data.set('global', {
        -    source: '/etc/npmrc'
        +    source: '/etc/npmrc',
           })
           npm.config.save = async where => {
             t.equal(where, 'global', 'should save to global config')
        @@ -468,18 +478,20 @@ t.test('config edit --global', t => {
             ...mocks,
             'mkdirp-infer-owner': async () => null,
             fs: {
        -      readFile (path, encoding, cb) { cb(null, npmrc) },
        +      readFile (path, encoding, cb) {
        +        cb(null, npmrc)
        +      },
               writeFile (file, data, encoding, cb) {
                 t.equal(file, '/etc/npmrc', 'should save to global file location')
                 t.matchSnapshot(data, 'should write global config file')
                 cb()
        -      }
        +      },
             },
             editor: (file, { editor }, cb) => {
               t.equal(file, '/etc/npmrc', 'should match global source data')
               t.equal(editor, 'vi', 'should use default editor')
               cb()
        -    }
        +    },
           }
           const config = requireInject('../../lib/config.js', editMocks)
           config(['edit'], (err) => {
        @@ -524,7 +536,7 @@ t.test('completion', t => {
             'ls',
             'rm',
             'edit',
        -    'list'
        +    'list',
           ])
           testComp(['npm', 'config', 'set', 'foo'], [])
           const possibleConfigKeys = [...Object.keys(types)]
        @@ -539,10 +551,10 @@ t.test('completion', t => {
           completion({
             conf: {
               argv: {
        -        remain: ['npm', 'config']
        -      }
        +        remain: ['npm', 'config'],
        +      },
             },
        -    partialWord: 'l'
        +    partialWord: 'l',
           }, (er, res) => {
             t.ifError(er)
             t.strictSame(res, [
        @@ -551,7 +563,7 @@ t.test('completion', t => {
               'delete',
               'ls',
               'rm',
        -      'edit'
        +      'edit',
             ], 'npm config')
           })
         
        diff --git a/deps/npm/test/lib/dedupe.js b/deps/npm/test/lib/dedupe.js
        index a88c41f6e9c674..ff2d2be5340524 100644
        --- a/deps/npm/test/lib/dedupe.js
        +++ b/deps/npm/test/lib/dedupe.js
        @@ -1,5 +1,4 @@
         const { test } = require('tap')
        -const dedupe = require('../../lib/dedupe.js')
         const requireInject = require('require-inject')
         
         test('should remove dupes using Arborist', (t) => {
        @@ -7,8 +6,8 @@ test('should remove dupes using Arborist', (t) => {
             '../../lib/npm.js': {
               prefix: 'foo',
               flatOptions: {
        -        'dryRun': 'false'
        -      }
        +        dryRun: 'false',
        +      },
             },
             '@npmcli/arborist': function (args) {
               t.ok(args, 'gets options object')
        @@ -18,11 +17,13 @@ test('should remove dupes using Arborist', (t) => {
                 t.ok(true, 'dedupe is called')
               }
             },
        -    '../../lib/utils/reify-output.js': (arb) => {
        +    '../../lib/utils/reify-finish.js': (arb) => {
               t.ok(arb, 'gets arborist tree')
        -    }
        +    },
           })
        -  dedupe({ dryRun: true }, () => {
        +  dedupe({ dryRun: true }, er => {
        +    if (er)
        +      throw er
             t.ok(true, 'callback is called')
             t.end()
           })
        @@ -33,17 +34,16 @@ test('should remove dupes using Arborist - no arguments', (t) => {
             '../../lib/npm.js': {
               prefix: 'foo',
               flatOptions: {
        -        'dryRun': 'true'
        -      }
        +        dryRun: 'true',
        +      },
             },
             '@npmcli/arborist': function (args) {
               t.ok(args.dryRun, 'gets dryRun from flatOptions')
               this.dedupe = () => {}
             },
        -    '../../lib/utils/reify-output.js': () => {}
        +    '../../lib/utils/reify-output.js': () => {},
           })
           dedupe(null, () => {
             t.end()
           })
         })
        -
        diff --git a/deps/npm/test/lib/dist-tag.js b/deps/npm/test/lib/dist-tag.js
        index ad08c2be13f635..e9dde48062dc27 100644
        --- a/deps/npm/test/lib/dist-tag.js
        +++ b/deps/npm/test/lib/dist-tag.js
        @@ -8,32 +8,33 @@ let log = ''
         // these declared opts are used in ./utils/read-local-package.js
         const _flatOptions = {
           global: false,
        -  get prefix () { return prefix }
        +  get prefix () {
        +    return prefix
        +  },
         }
         
         const routeMap = {
           '/-/package/@scoped%2fpkg/dist-tags': {
             latest: '1.0.0',
             a: '0.0.1',
        -    b: '0.5.0'
        +    b: '0.5.0',
           },
           '/-/package/@scoped%2fanother/dist-tags': {
             latest: '2.0.0',
             a: '0.0.2',
        -    b: '0.6.0'
        +    b: '0.6.0',
           },
           '/-/package/@scoped%2fanother/dist-tags/c': {
             latest: '7.7.7',
             a: '0.0.2',
             b: '0.6.0',
        -    c: '7.7.7'
        -  }
        +    c: '7.7.7',
        +  },
         }
         
         let npmRegistryFetchMock = (url, opts) => {
        -  if (url === '/-/package/foo/dist-tags') {
        +  if (url === '/-/package/foo/dist-tags')
             throw new Error('no package found')
        -  }
         
           return routeMap[url]
         }
        @@ -41,9 +42,9 @@ let npmRegistryFetchMock = (url, opts) => {
         npmRegistryFetchMock.json = async (url, opts) => routeMap[url]
         
         const logger = (...msgs) => {
        -  for (const msg of [...msgs]) {
        +  for (const msg of [...msgs])
             log += msg + ' '
        -  }
        +
           log += '\n'
         }
         
        @@ -52,25 +53,29 @@ const distTag = requireInject('../../lib/dist-tag.js', {
             error: logger,
             info: logger,
             verbose: logger,
        -    warn: logger
        +    warn: logger,
        +  },
        +  get 'npm-registry-fetch' () {
        +    return npmRegistryFetchMock
           },
        -  get 'npm-registry-fetch' () { return npmRegistryFetchMock },
           '../../lib/npm.js': {
             flatOptions: _flatOptions,
             config: {
               get (key) {
                 return _flatOptions[key]
        -      }
        -    }
        +      },
        +    },
        +  },
        +  '../../lib/utils/output.js': msg => {
        +    result = msg
           },
        -  '../../lib/utils/output.js': msg => { result = msg }
         })
         
         test('ls in current package', (t) => {
           prefix = t.testdir({
             'package.json': JSON.stringify({
        -      name: '@scoped/pkg'
        -    })
        +      name: '@scoped/pkg',
        +    }),
           })
           distTag(['ls'], (err) => {
             t.ifError(err, 'npm dist-tags ls')
        @@ -87,8 +92,8 @@ test('ls in current package', (t) => {
         test('no args in current package', (t) => {
           prefix = t.testdir({
             'package.json': JSON.stringify({
        -      name: '@scoped/pkg'
        -    })
        +      name: '@scoped/pkg',
        +    }),
           })
           distTag([], (err) => {
             t.ifError(err, 'npm dist-tags ls')
        @@ -146,8 +151,8 @@ test('ls on missing package', (t) => {
         test('ls on missing name in current package', (t) => {
           prefix = t.testdir({
             'package.json': JSON.stringify({
        -      version: '1.0.0'
        -    })
        +      version: '1.0.0',
        +    }),
           })
           distTag(['ls'], (err) => {
             t.matchSnapshot(
        @@ -294,9 +299,9 @@ test('completion', t => {
           completion({
             conf: {
               argv: {
        -        remain: ['npm', 'dist-tag']
        -      }
        -    }
        +        remain: ['npm', 'dist-tag'],
        +      },
        +    },
           }, (err, res) => {
             t.ifError(err, 'npm dist-tags completion')
         
        @@ -305,7 +310,7 @@ test('completion', t => {
               [
                 'add',
                 'rm',
        -        'ls'
        +        'ls',
               ],
               'should list npm dist-tag commands for completion'
             )
        @@ -314,9 +319,9 @@ test('completion', t => {
           completion({
             conf: {
               argv: {
        -        remain: ['npm', 'dist-tag', 'foobar']
        -      }
        -    }
        +        remain: ['npm', 'dist-tag', 'foobar'],
        +      },
        +    },
           }, (err) => {
             t.notOk(err, 'should ignore any unkown name')
           })
        diff --git a/deps/npm/test/lib/docs.js b/deps/npm/test/lib/docs.js
        index 48ba9a3b57f442..b4ede873167d4f 100644
        --- a/deps/npm/test/lib/docs.js
        +++ b/deps/npm/test/lib/docs.js
        @@ -5,30 +5,30 @@ const pacote = {
           manifest: async (spec, options) => {
             return spec === 'nodocs' ? {
               name: 'nodocs',
        -      version: '1.2.3'
        -    }
        -    : spec === 'docsurl' ? {
        -      name: 'docsurl',
        -      version: '1.2.3',
        -      homepage: 'https://bugzilla.localhost/docsurl'
        -    }
        -    : spec === 'repourl' ? {
        -      name: 'repourl',
        -      version: '1.2.3',
        -      repository: 'https://github.com/foo/repourl'
        -    }
        -    : spec === 'repoobj' ? {
        -      name: 'repoobj',
        -      version: '1.2.3',
        -      repository: { url: 'https://github.com/foo/repoobj' }
        -    }
        -    : spec === '.' ? {
        -      name: 'thispkg',
               version: '1.2.3',
        -      homepage: 'https://example.com'
             }
        -    : null
        -  }
        +      : spec === 'docsurl' ? {
        +        name: 'docsurl',
        +        version: '1.2.3',
        +        homepage: 'https://bugzilla.localhost/docsurl',
        +      }
        +      : spec === 'repourl' ? {
        +        name: 'repourl',
        +        version: '1.2.3',
        +        repository: 'https://github.com/foo/repourl',
        +      }
        +      : spec === 'repoobj' ? {
        +        name: 'repoobj',
        +        version: '1.2.3',
        +        repository: { url: 'https://github.com/foo/repoobj' },
        +      }
        +      : spec === '.' ? {
        +        name: 'thispkg',
        +        version: '1.2.3',
        +        homepage: 'https://example.com',
        +      }
        +      : null
        +  },
         }
         
         // keep a tally of which urls got opened
        @@ -41,7 +41,7 @@ const openUrl = (url, errMsg, cb) => {
         
         const docs = requireInject('../../lib/docs.js', {
           pacote,
        -  '../../lib/utils/open-url.js': openUrl
        +  '../../lib/utils/open-url.js': openUrl,
         })
         
         t.test('completion', t => {
        @@ -58,7 +58,7 @@ t.test('open docs urls', t => {
             docsurl: 'https://bugzilla.localhost/docsurl',
             repourl: 'https://github.com/foo/repourl#readme',
             repoobj: 'https://github.com/foo/repoobj#readme',
        -    '.': 'https://example.com'
        +    '.': 'https://example.com',
           }
           const keys = Object.keys(expect)
           t.plan(keys.length)
        diff --git a/deps/npm/test/lib/exec.js b/deps/npm/test/lib/exec.js
        index fb89776b55eaf9..c65f916428d968 100644
        --- a/deps/npm/test/lib/exec.js
        +++ b/deps/npm/test/lib/exec.js
        @@ -10,9 +10,11 @@ class Arborist {
             ARB_CTOR.push(options)
             this.path = options.path
           }
        +
           async loadActual () {
             return ARB_ACTUAL_TREE[this.path]
           }
        +
           async reify (options) {
             ARB_REIFY.push(options)
           }
        @@ -26,18 +28,18 @@ const npm = {
             yes: true,
             call: '',
             package: [],
        -    legacyPeerDeps: false
        +    legacyPeerDeps: false,
           },
           localPrefix: 'local-prefix',
           localBin: 'local-bin',
           globalBin: 'global-bin',
           config: {
             get: k => {
        -      if (k !== 'cache') {
        +      if (k !== 'cache')
                 throw new Error('unexpected config get')
        -      }
        +
               return 'cache-dir'
        -    }
        +    },
           },
           log: {
             disableProgress: () => {
        @@ -48,23 +50,22 @@ const npm = {
             },
             warn: (...args) => {
               LOG_WARN.push(args)
        -    }
        -  }
        +    },
        +  },
         }
         
         const RUN_SCRIPTS = []
         const runScript = async opt => {
           RUN_SCRIPTS.push(opt)
        -  if (!PROGRESS_IGNORED && PROGRESS_ENABLED) {
        +  if (!PROGRESS_IGNORED && PROGRESS_ENABLED)
             throw new Error('progress not disabled during run script!')
        -  }
         }
         
         const MANIFESTS = {}
         const pacote = {
           manifest: async (spec, options) => {
             return MANIFESTS[spec]
        -  }
        +  },
         }
         
         const MKDIRPS = []
        @@ -89,7 +90,7 @@ const mocks = {
           '../../lib/npm.js': npm,
           pacote,
           read,
        -  'mkdirp-infer-owner': mkdirp
        +  'mkdirp-infer-owner': mkdirp,
         }
         const exec = requireInject('../../lib/exec.js', mocks)
         
        @@ -113,7 +114,7 @@ t.afterEach(cb => {
         
         t.test('npx foo, bin already exists locally', async t => {
           const path = t.testdir({
        -    foo: 'just some file'
        +    foo: 'just some file',
           })
         
           PROGRESS_IGNORED = true
        @@ -129,15 +130,15 @@ t.test('npx foo, bin already exists locally', async t => {
             stdioString: true,
             event: 'npx',
             env: {
        -      PATH: [path, ...PATH].join(delimiter)
        +      PATH: [path, ...PATH].join(delimiter),
             },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
         t.test('npx foo, bin already exists globally', async t => {
           const path = t.testdir({
        -    foo: 'just some file'
        +    foo: 'just some file',
           })
         
           PROGRESS_IGNORED = true
        @@ -153,9 +154,9 @@ t.test('npx foo, bin already exists globally', async t => {
             stdioString: true,
             event: 'npx',
             env: {
        -      PATH: [path, ...PATH].join(delimiter)
        +      PATH: [path, ...PATH].join(delimiter),
             },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
        @@ -163,23 +164,22 @@ t.test('npm exec foo, already present locally', async t => {
           const path = t.testdir()
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]])
        +    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]]),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           await exec(['foo'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [], 'no need to make any dirs')
        -  t.match(ARB_CTOR, [ { package: ['foo'], path } ])
        +  t.match(ARB_CTOR, [{ package: ['foo'], path }])
           t.strictSame(ARB_REIFY, [], 'no need to reify anything')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           t.match(RUN_SCRIPTS, [{
        @@ -189,7 +189,7 @@ t.test('npm exec foo, already present locally', async t => {
             stdioString: true,
             event: 'npx',
             env: { PATH: process.env.PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
        @@ -198,26 +198,25 @@ t.test('npm exec foo, not present locally or in central loc', async t => {
           const installDir = resolve('cache-dir/_npx/f7fbba6e0636f890')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           await exec(['foo'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: ['foo'], path } ])
        +  t.match(ARB_CTOR, [{ package: ['foo'], path }])
           t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: false}], 'need to install foo@')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}`
        @@ -228,7 +227,7 @@ t.test('npm exec foo, not present locally or in central loc', async t => {
             stdioString: true,
             event: 'npx',
             env: { PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
        @@ -237,26 +236,25 @@ t.test('npm exec foo, not present locally but in central loc', async t => {
           const installDir = resolve('cache-dir/_npx/f7fbba6e0636f890')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]])
        +    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]]),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           await exec(['foo'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: ['foo'], path } ])
        +  t.match(ARB_CTOR, [{ package: ['foo'], path }])
           t.match(ARB_REIFY, [], 'no need to install again, already there')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}`
        @@ -267,7 +265,7 @@ t.test('npm exec foo, not present locally but in central loc', async t => {
             stdioString: true,
             event: 'npx',
             env: { PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
        @@ -276,26 +274,25 @@ t.test('npm exec foo, present locally but wrong version', async t => {
           const installDir = resolve('cache-dir/_npx/2badf4630f1cfaad')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]])
        +    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]]),
           }
           MANIFESTS['foo@2.x'] = {
             name: 'foo',
             version: '2.3.4',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@2.x'
        +    _from: 'foo@2.x',
           }
           await exec(['foo@2.x'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: ['foo'], path } ])
        +  t.match(ARB_CTOR, [{ package: ['foo'], path }])
           t.match(ARB_REIFY, [{ add: ['foo@2.x'], legacyPeerDeps: false }], 'need to add foo@2.x')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}`
        @@ -306,7 +303,7 @@ t.test('npm exec foo, present locally but wrong version', async t => {
             stdioString: true,
             event: 'npx',
             env: { PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
        @@ -314,24 +311,23 @@ t.test('npm exec --package=foo bar', async t => {
           const path = t.testdir()
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]])
        +    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]]),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           npm.flatOptions.package = ['foo']
           await exec(['bar'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [], 'no need to make any dirs')
        -  t.match(ARB_CTOR, [ { package: ['foo'], path } ])
        +  t.match(ARB_CTOR, [{ package: ['foo'], path }])
           t.strictSame(ARB_REIFY, [], 'no need to reify anything')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           t.match(RUN_SCRIPTS, [{
        @@ -341,7 +337,7 @@ t.test('npm exec --package=foo bar', async t => {
             stdioString: true,
             event: 'npx',
             env: { PATH: process.env.PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
        @@ -351,28 +347,27 @@ t.test('npm exec @foo/bar -- --some=arg, locally installed', async t => {
             version: '1.2.3',
             bin: {
               foo: 'foo',
        -      bar: 'bar'
        -    }
        +      bar: 'bar',
        +    },
           }
           const path = t.testdir({
             node_modules: {
               '@foo/bar': {
        -        'package.json': JSON.stringify(foobarManifest)
        -      }
        -    }
        +        'package.json': JSON.stringify(foobarManifest),
        +      },
        +    },
           })
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]])
        +    children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]]),
           }
           MANIFESTS['@foo/bar'] = foobarManifest
           await exec(['@foo/bar', '--some=arg'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [], 'no need to make any dirs')
        -  t.match(ARB_CTOR, [ { package: ['@foo/bar'], path } ])
        +  t.match(ARB_CTOR, [{ package: ['@foo/bar'], path }])
           t.strictSame(ARB_REIFY, [], 'no need to reify anything')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           t.match(RUN_SCRIPTS, [{
        @@ -382,10 +377,77 @@ t.test('npm exec @foo/bar -- --some=arg, locally installed', async t => {
             stdioString: true,
             event: 'npx',
             env: { PATH: process.env.PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
        +  }])
        +})
        +
        +t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locally installed', async t => {
        +  const foobarManifest = {
        +    name: '@foo/bar',
        +    version: '1.2.3',
        +    bin: {
        +      baz: 'corge', // pick the first one
        +      qux: 'corge',
        +      quux: 'corge',
        +    },
        +  }
        +  const path = t.testdir({
        +    node_modules: {
        +      '@foo/bar': {
        +        'package.json': JSON.stringify(foobarManifest),
        +      },
        +    },
        +  })
        +  npm.localPrefix = path
        +  ARB_ACTUAL_TREE[path] = {
        +    children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]]),
        +  }
        +  MANIFESTS['@foo/bar'] = foobarManifest
        +  await exec(['@foo/bar'], er => {
        +    if (er)
        +      throw er
        +  })
        +  t.strictSame(MKDIRPS, [], 'no need to make any dirs')
        +  t.match(ARB_CTOR, [{ package: ['@foo/bar'], path }])
        +  t.strictSame(ARB_REIFY, [], 'no need to reify anything')
        +  t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
        +  t.match(RUN_SCRIPTS, [{
        +    pkg: { scripts: { npx: 'baz' } },
        +    banner: false,
        +    path: process.cwd(),
        +    stdioString: true,
        +    event: 'npx',
        +    env: { PATH: process.env.PATH },
        +    stdio: 'inherit',
           }])
         })
         
        +t.test('npm exec @foo/bar, with different bin alias and no unscoped named bin, locally installed', t => {
        +  const path = t.testdir()
        +  npm.localPrefix = path
        +  ARB_ACTUAL_TREE[path] = {
        +    children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]]),
        +  }
        +  MANIFESTS['@foo/bar'] = {
        +    name: '@foo/bar',
        +    version: '1.2.3',
        +    bin: {
        +      foo: 'qux',
        +      corge: 'qux',
        +      baz: 'quux',
        +    },
        +    _from: 'foo@',
        +    _id: '@foo/bar@1.2.3',
        +  }
        +  return t.rejects(exec(['@foo/bar'], er => {
        +    if (er)
        +      throw er
        +  }), {
        +    message: 'could not determine executable to run',
        +    pkgid: '@foo/bar@1.2.3',
        +  })
        +})
        +
         t.test('run command with 2 packages, need install, verify sort', t => {
           // test both directions, should use same install dir both times
           // also test the read() call here, verify that the prompts match
        @@ -399,34 +461,33 @@ t.test('run command with 2 packages, need install, verify sort', t => {
               const installDir = resolve('cache-dir/_npx/07de77790e5f40f2')
               npm.localPrefix = path
               ARB_ACTUAL_TREE[path] = {
        -        children: new Map()
        +        children: new Map(),
               }
               ARB_ACTUAL_TREE[installDir] = {
        -        children: new Map()
        +        children: new Map(),
               }
               MANIFESTS.foo = {
                 name: 'foo',
                 version: '1.2.3',
                 bin: {
        -          foo: 'foo'
        +          foo: 'foo',
                 },
        -        _from: 'foo@'
        +        _from: 'foo@',
               }
               MANIFESTS.bar = {
                 name: 'bar',
                 version: '1.2.3',
                 bin: {
        -          bar: 'bar'
        +          bar: 'bar',
                 },
        -        _from: 'bar@'
        +        _from: 'bar@',
               }
               await exec(['foobar'], er => {
        -        if (er) {
        +        if (er)
                   throw er
        -        }
               })
               t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -      t.match(ARB_CTOR, [ { package: packages, path } ])
        +      t.match(ARB_CTOR, [{ package: packages, path }])
               t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages')
               t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
               const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}`
        @@ -437,7 +498,7 @@ t.test('run command with 2 packages, need install, verify sort', t => {
                 stdioString: true,
                 event: 'npx',
                 env: { PATH },
        -        stdio: 'inherit'
        +        stdio: 'inherit',
               }])
             })
           }
        @@ -447,21 +508,20 @@ t.test('npm exec foo, no bin in package', t => {
           const path = t.testdir()
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]])
        +    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]]),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             _from: 'foo@',
        -    _id: 'foo@1.2.3'
        +    _id: 'foo@1.2.3',
           }
           return t.rejects(exec(['foo'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           }), {
             message: 'could not determine executable to run',
        -    pkgid: 'foo@1.2.3'
        +    pkgid: 'foo@1.2.3',
           })
         })
         
        @@ -469,25 +529,24 @@ t.test('npm exec foo, many bins in package, none named foo', t => {
           const path = t.testdir()
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]])
        +    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]]),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
               bar: 'bar',
        -      baz: 'baz'
        +      baz: 'baz',
             },
             _from: 'foo@',
        -    _id: 'foo@1.2.3'
        +    _id: 'foo@1.2.3',
           }
           return t.rejects(exec(['foo'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           }), {
             message: 'could not determine executable to run',
        -    pkgid: 'foo@1.2.3'
        +    pkgid: 'foo@1.2.3',
           })
         })
         
        @@ -497,20 +556,19 @@ t.test('npm exec -p foo -c "ls -laF"', async t => {
           npm.flatOptions.package = ['foo']
           npm.flatOptions.call = 'ls -laF'
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]])
        +    children: new Map([['foo', { name: 'foo', version: '1.2.3' }]]),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           await exec([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [], 'no need to make any dirs')
        -  t.match(ARB_CTOR, [ { package: ['foo'], path } ])
        +  t.match(ARB_CTOR, [{ package: ['foo'], path }])
           t.strictSame(ARB_REIFY, [], 'no need to reify anything')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           t.match(RUN_SCRIPTS, [{
        @@ -520,7 +578,7 @@ t.test('npm exec -p foo -c "ls -laF"', async t => {
             stdioString: true,
             event: 'npx',
             env: { PATH: process.env.PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
         })
         
        @@ -552,34 +610,33 @@ t.test('prompt when installs are needed if not already present and shell is a TT
           const installDir = resolve('cache-dir/_npx/07de77790e5f40f2')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           MANIFESTS.bar = {
             name: 'bar',
             version: '1.2.3',
             bin: {
        -      bar: 'bar'
        +      bar: 'bar',
             },
        -    _from: 'bar@'
        +    _from: 'bar@',
           }
           await exec(['foobar'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: packages, path } ])
        +  t.match(ARB_CTOR, [{ package: packages, path }])
           t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}`
        @@ -590,11 +647,11 @@ t.test('prompt when installs are needed if not already present and shell is a TT
             stdioString: true,
             event: 'npx',
             env: { PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
           t.strictSame(READ, [{
             prompt: 'Need to install the following packages:\n  bar\n  foo\nOk to proceed? ',
        -    default: 'y'
        +    default: 'y',
           }])
         })
         
        @@ -621,34 +678,33 @@ t.test('skip prompt when installs are needed if not already present and shell is
           const installDir = resolve('cache-dir/_npx/07de77790e5f40f2')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           MANIFESTS.bar = {
             name: 'bar',
             version: '1.2.3',
             bin: {
        -      bar: 'bar'
        +      bar: 'bar',
             },
        -    _from: 'bar@'
        +    _from: 'bar@',
           }
           await exec(['foobar'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: packages, path } ])
        +  t.match(ARB_CTOR, [{ package: packages, path }])
           t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}`
        @@ -659,7 +715,7 @@ t.test('skip prompt when installs are needed if not already present and shell is
             stdioString: true,
             event: 'npx',
             env: { PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
           t.strictSame(READ, [], 'should not have prompted')
           t.strictSame(LOG_WARN, [['exec', 'The following packages were not found and will be installed: bar, foo']], 'should have printed a warning')
        @@ -688,26 +744,25 @@ t.test('skip prompt when installs are needed if not already present and shell is
           const installDir = resolve('cache-dir/_npx/f7fbba6e0636f890')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           await exec(['foobar'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: packages, path } ])
        +  t.match(ARB_CTOR, [{ package: packages, path }])
           t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install the package')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}`
        @@ -718,7 +773,7 @@ t.test('skip prompt when installs are needed if not already present and shell is
             stdioString: true,
             event: 'npx',
             env: { PATH },
        -    stdio: 'inherit'
        +    stdio: 'inherit',
           }])
           t.strictSame(READ, [], 'should not have prompted')
           t.strictSame(LOG_WARN, [['exec', 'The following package was not found and will be installed: foo']], 'should have printed a warning')
        @@ -742,43 +797,42 @@ t.test('abort if prompt rejected', async t => {
           npm.flatOptions.package = packages
           npm.flatOptions.yes = undefined
         
        -  const add = packages.map(p => `${p}@`).sort((a, b) => a.localeCompare(b))
           const path = t.testdir()
           const installDir = resolve('cache-dir/_npx/07de77790e5f40f2')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           MANIFESTS.bar = {
             name: 'bar',
             version: '1.2.3',
             bin: {
        -      bar: 'bar'
        +      bar: 'bar',
             },
        -    _from: 'bar@'
        +    _from: 'bar@',
           }
           await exec(['foobar'], er => {
             t.equal(er, 'canceled', 'should be canceled')
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: packages, path } ])
        +  t.match(ARB_CTOR, [{ package: packages, path }])
           t.strictSame(ARB_REIFY, [], 'no install performed')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           t.strictSame(RUN_SCRIPTS, [])
           t.strictSame(READ, [{
             prompt: 'Need to install the following packages:\n  bar\n  foo\nOk to proceed? ',
        -    default: 'y'
        +    default: 'y',
           }])
         })
         
        @@ -800,43 +854,42 @@ t.test('abort if prompt false', async t => {
           npm.flatOptions.package = packages
           npm.flatOptions.yes = undefined
         
        -  const add = packages.map(p => `${p}@`).sort((a, b) => a.localeCompare(b))
           const path = t.testdir()
           const installDir = resolve('cache-dir/_npx/07de77790e5f40f2')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           MANIFESTS.bar = {
             name: 'bar',
             version: '1.2.3',
             bin: {
        -      bar: 'bar'
        +      bar: 'bar',
             },
        -    _from: 'bar@'
        +    _from: 'bar@',
           }
           await exec(['foobar'], er => {
             t.equal(er, 'canceled', 'should be canceled')
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: packages, path } ])
        +  t.match(ARB_CTOR, [{ package: packages, path }])
           t.strictSame(ARB_REIFY, [], 'no install performed')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           t.strictSame(RUN_SCRIPTS, [])
           t.strictSame(READ, [{
             prompt: 'Need to install the following packages:\n  bar\n  foo\nOk to proceed? ',
        -    default: 'y'
        +    default: 'y',
           }])
         })
         
        @@ -857,37 +910,36 @@ t.test('abort if -n provided', async t => {
           npm.flatOptions.package = packages
           npm.flatOptions.yes = false
         
        -  const add = packages.map(p => `${p}@`).sort((a, b) => a.localeCompare(b))
           const path = t.testdir()
           const installDir = resolve('cache-dir/_npx/07de77790e5f40f2')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           MANIFESTS.bar = {
             name: 'bar',
             version: '1.2.3',
             bin: {
        -      bar: 'bar'
        +      bar: 'bar',
             },
        -    _from: 'bar@'
        +    _from: 'bar@',
           }
           await exec(['foobar'], er => {
             t.equal(er, 'canceled', 'should be canceled')
           })
           t.strictSame(MKDIRPS, [installDir], 'need to make install dir')
        -  t.match(ARB_CTOR, [ { package: packages, path } ])
        +  t.match(ARB_CTOR, [{ package: packages, path }])
           t.strictSame(ARB_REIFY, [], 'no install performed')
           t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
           t.strictSame(RUN_SCRIPTS, [])
        @@ -899,25 +951,24 @@ t.test('forward legacyPeerDeps opt', async t => {
           const installDir = resolve('cache-dir/_npx/f7fbba6e0636f890')
           npm.localPrefix = path
           ARB_ACTUAL_TREE[path] = {
        -    children: new Map()
        +    children: new Map(),
           }
           ARB_ACTUAL_TREE[installDir] = {
        -    children: new Map()
        +    children: new Map(),
           }
           MANIFESTS.foo = {
             name: 'foo',
             version: '1.2.3',
             bin: {
        -      foo: 'foo'
        +      foo: 'foo',
             },
        -    _from: 'foo@'
        +    _from: 'foo@',
           }
           npm.flatOptions.yes = true
           npm.flatOptions.legacyPeerDeps = true
           await exec(['foo'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: true}], 'need to install foo@ using legacyPeerDeps opt')
         })
        diff --git a/deps/npm/test/lib/explain.js b/deps/npm/test/lib/explain.js
        index a9db344f8b20ca..1eeca8c4c4f5d0 100644
        --- a/deps/npm/test/lib/explain.js
        +++ b/deps/npm/test/lib/explain.js
        @@ -3,7 +3,7 @@ const requireInject = require('require-inject')
         const npm = {
           prefix: null,
           color: true,
        -  flatOptions: {}
        +  flatOptions: {},
         }
         const { resolve } = require('path')
         
        @@ -20,8 +20,8 @@ const explain = requireInject('../../lib/explain.js', {
           '../../lib/utils/explain-dep.js': {
             explainNode: (expl, depth, color) => {
               return `${expl.name}@${expl.version} depth=${depth} color=${color}`
        -    }
        -  }
        +    },
        +  },
         })
         
         t.test('no args throws usage', async t => {
        @@ -68,15 +68,15 @@ t.test('explain some nodes', async t => {
                   name: 'foo',
                   version: '1.2.3',
                   dependencies: {
        -            bar: '*'
        -          }
        -        })
        +            bar: '*',
        +          },
        +        }),
               },
               bar: {
                 'package.json': JSON.stringify({
                   name: 'bar',
        -          version: '1.2.3'
        -        })
        +          version: '1.2.3',
        +        }),
               },
               baz: {
                 'package.json': JSON.stringify({
        @@ -84,40 +84,39 @@ t.test('explain some nodes', async t => {
                   version: '1.2.3',
                   dependencies: {
                     foo: '*',
        -            bar: '2'
        -          }
        +            bar: '2',
        +          },
                 }),
                 node_modules: {
                   bar: {
                     'package.json': JSON.stringify({
                       name: 'bar',
        -              version: '2.3.4'
        -            })
        +              version: '2.3.4',
        +            }),
                   },
                   extra: {
                     'package.json': JSON.stringify({
                       name: 'extra',
                       version: '99.9999.999999',
        -              description: 'extraneous package'
        -            })
        -          }
        -        }
        -      }
        +              description: 'extraneous package',
        +            }),
        +          },
        +        },
        +      },
             },
             'package.json': JSON.stringify({
               dependencies: {
        -        baz: '1'
        -      }
        -    })
        +        baz: '1',
        +      },
        +    }),
           })
         
           // works with either a full actual path or the location
           const p = 'node_modules/foo'
           for (const path of [p, resolve(npm.prefix, p)]) {
             await explain([path], er => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
             })
             t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']])
             OUTPUT.length = 0
        @@ -125,44 +124,40 @@ t.test('explain some nodes', async t => {
         
           // finds all nodes by name
           await explain(['bar'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(OUTPUT, [[
             'bar@1.2.3 depth=Infinity color=true\n\n' +
        -    'bar@2.3.4 depth=Infinity color=true'
        +    'bar@2.3.4 depth=Infinity color=true',
           ]])
           OUTPUT.length = 0
         
           // finds only nodes that match the spec
           await explain(['bar@1'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(OUTPUT, [['bar@1.2.3 depth=Infinity color=true']])
           OUTPUT.length = 0
         
           // finds extraneous nodes
           await explain(['extra'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(OUTPUT, [['extra@99.9999.999999 depth=Infinity color=true']])
           OUTPUT.length = 0
         
           npm.flatOptions.json = true
           await explain(['node_modules/foo'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.match(JSON.parse(OUTPUT[0][0]), [{
             name: 'foo',
             version: '1.2.3',
        -    dependents: Array
        +    dependents: Array,
           }])
           OUTPUT.length = 0
           npm.flatOptions.json = false
        @@ -174,4 +169,3 @@ t.test('explain some nodes', async t => {
             })
           })
         })
        -
        diff --git a/deps/npm/test/lib/explore.js b/deps/npm/test/lib/explore.js
        index 03ad230489d17d..64c70bcce7ef62 100644
        --- a/deps/npm/test/lib/explore.js
        +++ b/deps/npm/test/lib/explore.js
        @@ -13,12 +13,12 @@ let SPAWN_EXIT_CODE = 0
         let SPAWN_SHELL_EXEC = null
         let SPAWN_SHELL_ARGS = null
         const mockSpawn = (sh, shellArgs, opts) => {
        -  if (sh !== 'shell-command') {
        +  if (sh !== 'shell-command')
             throw new Error('got wrong shell command')
        -  }
        -  if (SPAWN_ERROR) {
        +
        +  if (SPAWN_ERROR)
             return Promise.reject(SPAWN_ERROR)
        -  }
        +
           SPAWN_SHELL_EXEC = sh
           SPAWN_SHELL_ARGS = shellArgs
           return Promise.resolve({ code: SPAWN_EXIT_CODE })
        @@ -29,28 +29,28 @@ let ERROR_HANDLER_CALLED = null
         const getExplore = windows => requireInject('../../lib/explore.js', {
           '../../lib/utils/is-windows.js': windows,
           '../../lib/utils/escape-arg.js': requireInject('../../lib/utils/escape-arg.js', {
        -    '../../lib/utils/is-windows.js': windows
        +    '../../lib/utils/is-windows.js': windows,
           }),
           path: require('path')[windows ? 'win32' : 'posix'],
           '../../lib/utils/escape-exec-path.js': requireInject('../../lib/utils/escape-arg.js', {
        -    '../../lib/utils/is-windows.js': windows
        +    '../../lib/utils/is-windows.js': windows,
           }),
           '../../lib/utils/error-handler.js': er => {
             ERROR_HANDLER_CALLED = er
           },
           fs: {
        -    stat: mockStat
        +    stat: mockStat,
           },
           '../../lib/npm.js': {
             dir: windows ? 'c:\\npm\\dir' : '/npm/dir',
             flatOptions: {
        -      shell: 'shell-command'
        -    }
        +      shell: 'shell-command',
        +    },
           },
           '@npmcli/promise-spawn': mockSpawn,
           '../../lib/utils/output.js': out => {
             output.push(out)
        -  }
        +  },
         })
         
         const windowsExplore = getExplore(true)
        @@ -63,42 +63,42 @@ t.test('basic interactive', t => {
           })
         
           t.test('windows', t => windowsExplore(['pkg'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: 'c:\\npm\\dir\\pkg',
               SPAWN_SHELL_EXEC: 'shell-command',
        -      SPAWN_SHELL_ARGS: []
        +      SPAWN_SHELL_ARGS: [],
             })
             t.strictSame(output, [
        -      "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n"
        +      "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n",
             ])
           }))
         
           t.test('posix', t => posixExplore(['pkg'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: '/npm/dir/pkg',
               SPAWN_SHELL_EXEC: 'shell-command',
        -      SPAWN_SHELL_ARGS: []
        +      SPAWN_SHELL_ARGS: [],
             })
             t.strictSame(output, [
        -      "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n"
        +      "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n",
             ])
           }))
         
        @@ -120,43 +120,43 @@ t.test('interactive tracks exit code', t => {
           })
         
           t.test('windows', t => windowsExplore(['pkg'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: 'c:\\npm\\dir\\pkg',
               SPAWN_SHELL_EXEC: 'shell-command',
        -      SPAWN_SHELL_ARGS: []
        +      SPAWN_SHELL_ARGS: [],
             })
             t.strictSame(output, [
        -      "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n"
        +      "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n",
             ])
             t.equal(process.exitCode, 99)
           }))
         
           t.test('posix', t => posixExplore(['pkg'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: '/npm/dir/pkg',
               SPAWN_SHELL_EXEC: 'shell-command',
        -      SPAWN_SHELL_ARGS: []
        +      SPAWN_SHELL_ARGS: [],
             })
             t.strictSame(output, [
        -      "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n"
        +      "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n",
             ])
             t.equal(process.exitCode, 99)
           }))
        @@ -166,14 +166,14 @@ t.test('interactive tracks exit code', t => {
               SPAWN_ERROR = null
             })
             SPAWN_ERROR = Object.assign(new Error('glorb'), {
        -      code: 33
        +      code: 33,
             })
             return posixExplore(['pkg'], er => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
        +
               t.strictSame(output, [
        -        "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n"
        +        "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n",
               ])
               t.equal(process.exitCode, 33)
             })
        @@ -189,14 +189,14 @@ t.test('basic non-interactive', t => {
           })
         
           t.test('windows', t => windowsExplore(['pkg', 'ls'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: 'c:\\npm\\dir\\pkg',
        @@ -206,25 +206,25 @@ t.test('basic non-interactive', t => {
                 '/s',
                 '/c',
                 '"ls"',
        -      ]
        +      ],
             })
             t.strictSame(output, [])
           }))
         
           t.test('posix', t => posixExplore(['pkg', 'ls'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: '/npm/dir/pkg',
               SPAWN_SHELL_EXEC: 'shell-command',
        -      SPAWN_SHELL_ARGS: ['-c', 'ls']
        +      SPAWN_SHELL_ARGS: ['-c', 'ls'],
             })
             t.strictSame(output, [])
           }))
        @@ -239,19 +239,19 @@ t.test('usage if no pkg provided', t => {
           })
           t.plan(1)
           posixExplore([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: '/npm/dir/pkg',
               SPAWN_SHELL_EXEC: 'shell-command',
        -      SPAWN_SHELL_ARGS: ['-c', 'ls']
        +      SPAWN_SHELL_ARGS: ['-c', 'ls'],
             })
           }).catch(er => t.equal(er, 'npm explore  [ -- ]'))
         })
        @@ -261,19 +261,19 @@ t.test('pkg not installed', t => {
           t.plan(1)
         
           posixExplore(['pkg', 'ls'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame({
               ERROR_HANDLER_CALLED,
               STAT_CALLED,
               SPAWN_SHELL_EXEC,
        -      SPAWN_SHELL_ARGS
        +      SPAWN_SHELL_ARGS,
             }, {
               ERROR_HANDLER_CALLED: null,
               STAT_CALLED: '/npm/dir/pkg',
               SPAWN_SHELL_EXEC: 'shell-command',
        -      SPAWN_SHELL_ARGS: ['-c', 'ls']
        +      SPAWN_SHELL_ARGS: ['-c', 'ls'],
             })
             t.strictSame(output, [])
           }).catch(er => {
        diff --git a/deps/npm/test/lib/find-dupes.js b/deps/npm/test/lib/find-dupes.js
        index 2f6272b90c1296..73c8fa2dc2793f 100644
        --- a/deps/npm/test/lib/find-dupes.js
        +++ b/deps/npm/test/lib/find-dupes.js
        @@ -1,5 +1,4 @@
         const { test } = require('tap')
        -const findDupes = require('../../lib/find-dupes.js')
         const requireInject = require('require-inject')
         
         test('should run dedupe in dryRun mode', (t) => {
        @@ -7,11 +6,10 @@ test('should run dedupe in dryRun mode', (t) => {
             '../../lib/dedupe.js': function (args, cb) {
               t.ok(args.dryRun, 'dryRun is true')
               cb()
        -    }
        +    },
           })
           findDupes(null, () => {
             t.ok(true, 'callback is called')
             t.end()
           })
         })
        -
        diff --git a/deps/npm/test/lib/fund.js b/deps/npm/test/lib/fund.js
        index fc6a63aa17752a..a23fc88ced89e3 100644
        --- a/deps/npm/test/lib/fund.js
        +++ b/deps/npm/test/lib/fund.js
        @@ -6,7 +6,7 @@ const requireInject = require('require-inject')
         const version = '1.0.0'
         const funding = {
           type: 'individual',
        -  url: 'http://example.com/donate'
        +  url: 'http://example.com/donate',
         }
         
         const maintainerOwnsAllDeps = {
        @@ -16,8 +16,8 @@ const maintainerOwnsAllDeps = {
             funding,
             dependencies: {
               'dep-foo': '*',
        -      'dep-bar': '*'
        -    }
        +      'dep-bar': '*',
        +    },
           }),
           node_modules: {
             'dep-foo': {
        @@ -26,27 +26,27 @@ const maintainerOwnsAllDeps = {
                 version,
                 funding,
                 dependencies: {
        -          'dep-sub-foo': '*'
        -        }
        +          'dep-sub-foo': '*',
        +        },
               }),
               node_modules: {
                 'dep-sub-foo': {
                   'package.json': JSON.stringify({
                     name: 'dep-sub-foo',
                     version,
        -            funding
        -          })
        -        }
        -      }
        +            funding,
        +          }),
        +        },
        +      },
             },
             'dep-bar': {
               'package.json': JSON.stringify({
                 name: 'dep-bar',
                 version,
        -        funding
        -      })
        -    }
        -  }
        +        funding,
        +      }),
        +    },
        +  },
         }
         
         const nestedNoFundingPackages = {
        @@ -54,11 +54,11 @@ const nestedNoFundingPackages = {
             name: 'nested-no-funding-packages',
             version,
             dependencies: {
        -      foo: '*'
        +      foo: '*',
             },
             devDependencies: {
        -      lorem: '*'
        -    }
        +      lorem: '*',
        +    },
           }),
           node_modules: {
             foo: {
        @@ -66,38 +66,38 @@ const nestedNoFundingPackages = {
                 name: 'foo',
                 version,
                 dependencies: {
        -          bar: '*'
        -        }
        +          bar: '*',
        +        },
               }),
               node_modules: {
                 bar: {
                   'package.json': JSON.stringify({
                     name: 'bar',
                     version,
        -            funding
        +            funding,
                   }),
                   node_modules: {
                     'sub-bar': {
                       'package.json': JSON.stringify({
                         name: 'sub-bar',
                         version,
        -                funding: 'https://example.com/sponsor'
        -              })
        -            }
        -          }
        -        }
        -      }
        +                funding: 'https://example.com/sponsor',
        +              }),
        +            },
        +          },
        +        },
        +      },
             },
             lorem: {
               'package.json': JSON.stringify({
                 name: 'lorem',
                 version,
                 funding: {
        -          url: 'https://example.com/lorem'
        -        }
        -      })
        -    }
        -  }
        +          url: 'https://example.com/lorem',
        +        },
        +      }),
        +    },
        +  },
         }
         
         const nestedMultipleFundingPackages = {
        @@ -106,14 +106,14 @@ const nestedMultipleFundingPackages = {
             version,
             funding: [
               'https://one.example.com',
        -      'https://two.example.com'
        +      'https://two.example.com',
             ],
             dependencies: {
        -      foo: '*'
        +      foo: '*',
             },
             devDependencies: {
        -      bar: '*'
        -    }
        +      bar: '*',
        +    },
           }),
           node_modules: {
             foo: {
        @@ -123,9 +123,9 @@ const nestedMultipleFundingPackages = {
                 funding: [
                   'http://example.com',
                   { url: 'http://sponsors.example.com/me' },
        -          'http://collective.example.com'
        -        ]
        -      })
        +          'http://collective.example.com',
        +        ],
        +      }),
             },
             bar: {
               'package.json': JSON.stringify({
        @@ -133,11 +133,11 @@ const nestedMultipleFundingPackages = {
                 version,
                 funding: [
                   'http://collective.example.com',
        -          { url: 'http://sponsors.example.com/you' }
        -        ]
        -      })
        -    }
        -  }
        +          { url: 'http://sponsors.example.com/you' },
        +        ],
        +      }),
        +    },
        +  },
         }
         
         const conflictingFundingPackages = {
        @@ -145,19 +145,19 @@ const conflictingFundingPackages = {
             name: 'conflicting-funding-packages',
             version,
             dependencies: {
        -      foo: '1.0.0'
        +      foo: '1.0.0',
             },
             devDependencies: {
        -      bar: '1.0.0'
        -    }
        +      bar: '1.0.0',
        +    },
           }),
           node_modules: {
             foo: {
               'package.json': JSON.stringify({
                 name: 'foo',
                 version: '1.0.0',
        -        funding: 'http://example.com/1'
        -      })
        +        funding: 'http://example.com/1',
        +      }),
             },
             bar: {
               node_modules: {
        @@ -165,19 +165,19 @@ const conflictingFundingPackages = {
                   'package.json': JSON.stringify({
                     name: 'foo',
                     version: '2.0.0',
        -            funding: 'http://example.com/2'
        -          })
        -        }
        +            funding: 'http://example.com/2',
        +          }),
        +        },
               },
               'package.json': JSON.stringify({
                 name: 'bar',
                 version: '1.0.0',
                 dependencies: {
        -          foo: '2.0.0'
        -        }
        -      })
        -    }
        -  }
        +          foo: '2.0.0',
        +        },
        +      }),
        +    },
        +  },
         }
         
         let result = ''
        @@ -188,7 +188,7 @@ const _flatOptions = {
           global: false,
           prefix: undefined,
           unicode: false,
        -  which: undefined
        +  which: undefined,
         }
         const openUrl = (url, msg, cb) => {
           if (url === 'http://npmjs.org') {
        @@ -198,35 +198,39 @@ const openUrl = (url, msg, cb) => {
           if (_flatOptions.json) {
             printUrl = JSON.stringify({
               title: msg,
        -      url: url
        +      url: url,
             })
        -  } else {
        +  } else
             printUrl = `${msg}:\n  ${url}`
        -  }
        +
           cb()
         }
         const fund = requireInject('../../lib/fund.js', {
           '../../lib/npm.js': {
             flatOptions: _flatOptions,
        -    get prefix () { return _flatOptions.prefix }
        +    get prefix () {
        +      return _flatOptions.prefix
        +    },
           },
           '../../lib/utils/open-url.js': openUrl,
        -  '../../lib/utils/output.js': msg => { result += msg + '\n' },
        +  '../../lib/utils/output.js': msg => {
        +    result += msg + '\n'
        +  },
           pacote: {
             manifest: (arg) => arg.name === 'ntl'
               ? Promise.resolve({
        -        funding: 'http://example.com/pacote'
        +        funding: 'http://example.com/pacote',
               })
        -      : Promise.reject(new Error('ERROR'))
        -  }
        +      : Promise.reject(new Error('ERROR')),
        +  },
         })
         
         test('fund with no package containing funding', t => {
           _flatOptions.prefix = t.testdir({
             'package.json': JSON.stringify({
               name: 'no-funding-package',
        -      version: '0.0.0'
        -    })
        +      version: '0.0.0',
        +    }),
           })
         
           fund([], (err) => {
        @@ -264,7 +268,7 @@ test('fund in which same maintainer owns all its deps, using --json option', t =
                 dependencies: {
                   'dep-bar': {
                     version: '1.0.0',
        -            funding: { type: 'individual', url: 'http://example.com/donate' }
        +            funding: { type: 'individual', url: 'http://example.com/donate' },
                   },
                   'dep-foo': {
                     version: '1.0.0',
        @@ -272,11 +276,11 @@ test('fund in which same maintainer owns all its deps, using --json option', t =
                     dependencies: {
                       'dep-sub-foo': {
                         version: '1.0.0',
        -                funding: { type: 'individual', url: 'http://example.com/donate' }
        -              }
        -            }
        -          }
        -        }
        +                funding: { type: 'individual', url: 'http://example.com/donate' },
        +              },
        +            },
        +          },
        +        },
               },
               'should print stack packages together'
             )
        @@ -317,13 +321,13 @@ test('fund containing multi-level nested deps with no funding, using --json opti
                 dependencies: {
                   lorem: {
                     version: '1.0.0',
        -            funding: { url: 'https://example.com/lorem' }
        +            funding: { url: 'https://example.com/lorem' },
                   },
                   bar: {
                     version: '1.0.0',
        -            funding: { type: 'individual', url: 'http://example.com/donate' }
        -          }
        -        }
        +            funding: { type: 'individual', url: 'http://example.com/donate' },
        +          },
        +        },
               },
               'should omit dependencies with no funding declared in json output'
             )
        @@ -348,39 +352,39 @@ test('fund containing multi-level nested deps with no funding, using --json opti
                 version: '1.0.0',
                 funding: [
                   {
        -            url: 'https://one.example.com'
        +            url: 'https://one.example.com',
                   },
                   {
        -            url: 'https://two.example.com'
        -          }
        +            url: 'https://two.example.com',
        +          },
                 ],
                 dependencies: {
                   bar: {
                     version: '1.0.0',
                     funding: [
                       {
        -                url: 'http://collective.example.com'
        +                url: 'http://collective.example.com',
                       },
                       {
        -                url: 'http://sponsors.example.com/you'
        -              }
        -            ]
        +                url: 'http://sponsors.example.com/you',
        +              },
        +            ],
                   },
                   foo: {
                     version: '1.0.0',
                     funding: [
                       {
        -                url: 'http://example.com'
        +                url: 'http://example.com',
                       },
                       {
        -                url: 'http://sponsors.example.com/me'
        +                url: 'http://sponsors.example.com/me',
                       },
                       {
        -                url: 'http://collective.example.com'
        -              }
        -            ]
        -          }
        -        }
        +                url: 'http://collective.example.com',
        +              },
        +            ],
        +          },
        +        },
               },
               'should list multiple funding entries in json output'
             )
        @@ -440,8 +444,8 @@ test('fund using string shorthand', t => {
             'package.json': JSON.stringify({
               name: 'funding-string-shorthand',
               version: '0.0.0',
        -      funding: 'https://example.com/sponsor'
        -    })
        +      funding: 'https://example.com/sponsor',
        +    }),
           })
         
           fund(['.'], (err) => {
        @@ -469,18 +473,18 @@ test('fund using symlink ref', t => {
           _flatOptions.prefix = t.testdir({
             'package.json': JSON.stringify({
               name: 'using-symlink-ref',
        -      version: '1.0.0'
        +      version: '1.0.0',
             }),
             a: {
               'package.json': JSON.stringify({
                 name: 'a',
                 version: '1.0.0',
        -        funding: 'http://example.com/a'
        -      })
        +        funding: 'http://example.com/a',
        +      }),
             },
             node_modules: {
        -      a: t.fixture('symlink', '../a')
        -    }
        +      a: t.fixture('symlink', '../a'),
        +    },
           })
         
           // using symlinked ref
        @@ -515,33 +519,33 @@ test('fund using data from actual tree', t => {
           _flatOptions.prefix = t.testdir({
             'package.json': JSON.stringify({
               name: 'using-actual-tree',
        -      version: '1.0.0'
        +      version: '1.0.0',
             }),
             node_modules: {
               a: {
                 'package.json': JSON.stringify({
                   name: 'a',
                   version: '1.0.0',
        -          funding: 'http://example.com/a'
        -        })
        +          funding: 'http://example.com/a',
        +        }),
               },
               b: {
                 'package.json': JSON.stringify({
                   name: 'a',
                   version: '1.0.0',
        -          funding: 'http://example.com/b'
        +          funding: 'http://example.com/b',
                 }),
                 node_modules: {
                   a: {
                     'package.json': JSON.stringify({
                       name: 'a',
                       version: '1.0.1',
        -              funding: 'http://example.com/_AAA'
        -            })
        -          }
        -        }
        -      }
        -    }
        +              funding: 'http://example.com/_AAA',
        +            }),
        +          },
        +        },
        +      },
        +    },
           })
         
           // using symlinked ref
        @@ -595,7 +599,7 @@ test('fund using package argument with no browser, using --json option', t => {
               JSON.parse(printUrl),
               {
                 title: 'individual funding available at the following URL',
        -        url: 'http://example.com/donate'
        +        url: 'http://example.com/donate',
               },
               'should open funding url using json output'
             )
        @@ -676,8 +680,8 @@ test('fund pkg missing version number', t => {
           _flatOptions.prefix = t.testdir({
             'package.json': JSON.stringify({
               name: 'foo',
        -      funding: 'http://example.com/foo'
        -    })
        +      funding: 'http://example.com/foo',
        +    }),
           })
         
           fund([], (err) => {
        @@ -693,8 +697,8 @@ test('fund a package throws on openUrl', t => {
             'package.json': JSON.stringify({
               name: 'foo',
               version: '1.0.0',
        -      funding: 'http://npmjs.org'
        -    })
        +      funding: 'http://npmjs.org',
        +    }),
           })
         
           fund(['.'], (err) => {
        @@ -711,14 +715,14 @@ test('fund a package with type and multiple sources', t => {
               funding: [
                 {
                   type: 'Foo',
        -          url: 'http://example.com/foo'
        +          url: 'http://example.com/foo',
                 },
                 {
                   type: 'Lorem',
        -          url: 'http://example.com/foo-lorem'
        -        }
        -      ]
        -    })
        +          url: 'http://example.com/foo-lorem',
        +        },
        +      ],
        +    }),
           })
         
           fund(['.'], (err) => {
        @@ -738,16 +742,16 @@ test('fund colors', t => {
               dependencies: {
                 a: '^1.0.0',
                 b: '^1.0.0',
        -        c: '^1.0.0'
        -      }
        +        c: '^1.0.0',
        +      },
             }),
             node_modules: {
               a: {
                 'package.json': JSON.stringify({
                   name: 'a',
                   version: '1.0.0',
        -          funding: 'http://example.com/a'
        -        })
        +          funding: 'http://example.com/a',
        +        }),
               },
               b: {
                 'package.json': JSON.stringify({
        @@ -756,32 +760,32 @@ test('fund colors', t => {
                   funding: 'http://example.com/b',
                   dependencies: {
                     d: '^1.0.0',
        -            e: '^1.0.0'
        -          }
        -        })
        +            e: '^1.0.0',
        +          },
        +        }),
               },
               c: {
                 'package.json': JSON.stringify({
                   name: 'c',
                   version: '1.0.0',
        -          funding: 'http://example.com/b'
        -        })
        +          funding: 'http://example.com/b',
        +        }),
               },
               d: {
                 'package.json': JSON.stringify({
                   name: 'd',
                   version: '1.0.0',
        -          funding: 'http://example.com/d'
        -        })
        +          funding: 'http://example.com/d',
        +        }),
               },
               e: {
                 'package.json': JSON.stringify({
                   name: 'e',
                   version: '1.0.0',
        -          funding: 'http://example.com/e'
        -        })
        -      }
        -    }
        +          funding: 'http://example.com/e',
        +        }),
        +      },
        +    },
           })
           _flatOptions.color = true
         
        @@ -802,8 +806,8 @@ test('sub dep with fund info and a parent with no funding info', t => {
               version: '1.0.0',
               dependencies: {
                 a: '^1.0.0',
        -        b: '^1.0.0'
        -      }
        +        b: '^1.0.0',
        +      },
             }),
             node_modules: {
               a: {
        @@ -811,16 +815,16 @@ test('sub dep with fund info and a parent with no funding info', t => {
                   name: 'a',
                   version: '1.0.0',
                   dependencies: {
        -            c: '^1.0.0'
        -          }
        -        })
        +            c: '^1.0.0',
        +          },
        +        }),
               },
               b: {
                 'package.json': JSON.stringify({
                   name: 'b',
                   version: '1.0.0',
        -          funding: 'http://example.com/b'
        -        })
        +          funding: 'http://example.com/b',
        +        }),
               },
               c: {
                 'package.json': JSON.stringify({
        @@ -828,11 +832,11 @@ test('sub dep with fund info and a parent with no funding info', t => {
                   version: '1.0.0',
                   funding: [
                     'http://example.com/c',
        -            'http://example.com/c-other'
        -          ]
        -        })
        -      }
        -    }
        +            'http://example.com/c-other',
        +          ],
        +        }),
        +      },
        +    },
           })
         
           fund([], (err) => {
        diff --git a/deps/npm/test/lib/get.js b/deps/npm/test/lib/get.js
        index 5f2f29bd922ae1..5260c00bae795c 100644
        --- a/deps/npm/test/lib/get.js
        +++ b/deps/npm/test/lib/get.js
        @@ -9,9 +9,9 @@ test('should retrieve values from npm.commands.config', (t) => {
                   t.equal(action, 'get', 'should use config get action')
                   t.equal(arg, 'foo', 'should use expected key')
                   t.end()
        -        }
        -      }
        -    }
        +        },
        +      },
        +    },
           })
         
           get(['foo'])
        diff --git a/deps/npm/test/lib/init.js b/deps/npm/test/lib/init.js
        new file mode 100644
        index 00000000000000..e73cc4b30988cc
        --- /dev/null
        +++ b/deps/npm/test/lib/init.js
        @@ -0,0 +1,236 @@
        +const t = require('tap')
        +const requireInject = require('require-inject')
        +
        +let result = ''
        +const npmLog = {
        +  disableProgress: () => null,
        +  enableProgress: () => null,
        +  info: () => null,
        +  pause: () => null,
        +  resume: () => null,
        +  silly: () => null,
        +}
        +const npm = {
        +  config: { set () {} },
        +  flatOptions: {},
        +  log: npmLog,
        +}
        +const mocks = {
        +  'init-package-json': (dir, initFile, config, cb) => cb(null, 'data'),
        +  '../../lib/npm.js': npm,
        +  '../../lib/utils/usage.js': () => 'usage instructions',
        +  '../../lib/utils/output.js': (...msg) => {
        +    result += msg.join('\n')
        +  },
        +}
        +const init = requireInject('../../lib/init.js', mocks)
        +
        +t.afterEach(cb => {
        +  result = ''
        +  npm.config = { get: () => '', set () {} }
        +  npm.commands = {}
        +  Object.defineProperty(npm, 'flatOptions', { value: {} })
        +  npm.log = npmLog
        +  cb()
        +})
        +
        +t.test('classic npm init no args', t => {
        +  npm.config = {
        +    get () {
        +      return '~/.npm-init.js'
        +    },
        +  }
        +  init([], err => {
        +    t.ifError(err, 'npm init no args')
        +    t.matchSnapshot(result, 'should print helper info')
        +    t.end()
        +  })
        +})
        +
        +t.test('classic npm init -y', t => {
        +  t.plan(7)
        +  npm.config = {
        +    get: () => '~/.npm-init.js',
        +  }
        +  Object.defineProperty(npm, 'flatOptions', { value: { yes: true} })
        +  npm.log = { ...npm.log }
        +  npm.log.silly = (title, msg) => {
        +    t.equal(title, 'package data', 'should print title')
        +    t.equal(msg, 'data', 'should print pkg data info')
        +  }
        +  npm.log.resume = () => {
        +    t.ok('should resume logs')
        +  }
        +  npm.log.info = (title, msg) => {
        +    t.equal(title, 'init', 'should print title')
        +    t.equal(msg, 'written successfully', 'should print done info')
        +  }
        +  init([], err => {
        +    t.ifError(err, 'npm init -y')
        +    t.equal(result, '')
        +  })
        +})
        +
        +t.test('npm init ', t => {
        +  t.plan(4)
        +  npm.config = {
        +    set (key, val) {
        +      t.equal(key, 'package', 'should set package key')
        +      t.deepEqual(val, [], 'should set empty array value')
        +    },
        +  }
        +  npm.commands.exec = (arr, cb) => {
        +    t.deepEqual(
        +      arr,
        +      ['create-react-app'],
        +      'should npx with listed packages'
        +    )
        +    cb()
        +  }
        +  init(['react-app'], err => {
        +    t.ifError(err, 'npm init react-app')
        +  })
        +})
        +
        +t.test('npm init @scope/name', t => {
        +  t.plan(2)
        +  npm.commands.exec = (arr, cb) => {
        +    t.deepEqual(
        +      arr,
        +      ['@npmcli/create-something'],
        +      'should npx with scoped packages'
        +    )
        +    cb()
        +  }
        +  init(['@npmcli/something'], err => {
        +    t.ifError(err, 'npm init init @scope/name')
        +  })
        +})
        +
        +t.test('npm init git spec', t => {
        +  t.plan(2)
        +  npm.commands.exec = (arr, cb) => {
        +    t.deepEqual(
        +      arr,
        +      ['npm/create-something'],
        +      'should npx with git-spec packages'
        +    )
        +    cb()
        +  }
        +  init(['npm/something'], err => {
        +    t.ifError(err, 'npm init init @scope/name')
        +  })
        +})
        +
        +t.test('npm init @scope', t => {
        +  t.plan(2)
        +  npm.commands.exec = (arr, cb) => {
        +    t.deepEqual(
        +      arr,
        +      ['@npmcli/create'],
        +      'should npx with @scope/create pkgs'
        +    )
        +    cb()
        +  }
        +  init(['@npmcli'], err => {
        +    t.ifError(err, 'npm init init @scope/create')
        +  })
        +})
        +
        +t.test('npm init tgz', t => {
        +  init(['something.tgz'], err => {
        +    t.match(
        +      err,
        +      /Error: Unrecognized initializer: something.tgz/,
        +      'should throw error when using an unsupported spec'
        +    )
        +    t.end()
        +  })
        +})
        +
        +t.test('npm init @next', t => {
        +  t.plan(2)
        +  npm.commands.exec = (arr, cb) => {
        +    t.deepEqual(
        +      arr,
        +      ['create-something@next'],
        +      'should npx with something@next'
        +    )
        +    cb()
        +  }
        +  init(['something@next'], err => {
        +    t.ifError(err, 'npm init init something@next')
        +  })
        +})
        +
        +t.test('npm init exec error', t => {
        +  npm.commands.exec = (arr, cb) => {
        +    cb(new Error('ERROR'))
        +  }
        +  init(['something@next'], err => {
        +    t.match(
        +      err,
        +      /ERROR/,
        +      'should exit with exec error'
        +    )
        +    t.end()
        +  })
        +})
        +
        +t.test('should not rewrite flatOptions', t => {
        +  t.plan(4)
        +  Object.defineProperty(npm, 'flatOptions', {
        +    get: () => ({}),
        +    set () {
        +      throw new Error('Should not set flatOptions')
        +    },
        +  })
        +  npm.config = {
        +    set (key, val) {
        +      t.equal(key, 'package', 'should set package key')
        +      t.deepEqual(val, [], 'should set empty array value')
        +    },
        +  }
        +  npm.commands.exec = (arr, cb) => {
        +    t.deepEqual(
        +      arr,
        +      ['create-react-app', 'my-app'],
        +      'should npx with extra args'
        +    )
        +    cb()
        +  }
        +  init(['react-app', 'my-app'], err => {
        +    t.ifError(err, 'npm init react-app')
        +  })
        +})
        +
        +t.test('npm init cancel', t => {
        +  t.plan(3)
        +  const init = requireInject('../../lib/init.js', {
        +    ...mocks,
        +    'init-package-json': (dir, initFile, config, cb) => cb(
        +      new Error('canceled')
        +    ),
        +  })
        +  npm.log = { ...npm.log }
        +  npm.log.warn = (title, msg) => {
        +    t.equal(title, 'init', 'should have init title')
        +    t.equal(msg, 'canceled', 'should log canceled')
        +  }
        +  init([], err => {
        +    t.ifError(err, 'npm init cancel')
        +  })
        +})
        +
        +t.test('npm init error', t => {
        +  const init = requireInject('../../lib/init.js', {
        +    ...mocks,
        +    'init-package-json': (dir, initFile, config, cb) => cb(
        +      new Error('Unknown Error')
        +    ),
        +  })
        +  init([], err => {
        +    t.match(err, /Unknown Error/, 'should throw error')
        +    t.end()
        +  })
        +})
        diff --git a/deps/npm/test/lib/install.js b/deps/npm/test/lib/install.js
        index 1650dcb8c0a32e..7e243e7ff35f28 100644
        --- a/deps/npm/test/lib/install.js
        +++ b/deps/npm/test/lib/install.js
        @@ -14,17 +14,17 @@ test('should install using Arborist', (t) => {
               globalDir: 'path/to/node_modules/',
               prefix: 'foo',
               flatOptions: {
        -        global: false
        +        global: false,
               },
               config: {
        -        get: () => true
        -      }
        +        get: () => true,
        +      },
             },
             '@npmcli/run-script': ({ event }) => {
               SCRIPTS.push(event)
             },
        -    'npmlog': {
        -      warn: () => {}
        +    npmlog: {
        +      warn: () => {},
             },
             '@npmcli/arborist': function (args) {
               ARB_ARGS = args
        @@ -33,15 +33,16 @@ test('should install using Arborist', (t) => {
                 REIFY_CALLED = true
               }
             },
        -    '../../lib/utils/reify-output.js': arb => {
        -      if (arb !== ARB_OBJ) {
        -        throw new Error('got wrong object passed to reify-output')
        -      }
        -    }
        +    '../../lib/utils/reify-finish.js': arb => {
        +      if (arb !== ARB_OBJ)
        +        throw new Error('got wrong object passed to reify-finish')
        +    },
           })
         
           t.test('with args', t => {
        -    install(['fizzbuzz'], () => {
        +    install(['fizzbuzz'], er => {
        +      if (er)
        +        throw er
               t.match(ARB_ARGS, { global: false, path: 'foo' })
               t.equal(REIFY_CALLED, true, 'called reify')
               t.strictSame(SCRIPTS, [], 'no scripts when adding dep')
        @@ -50,7 +51,9 @@ test('should install using Arborist', (t) => {
           })
         
           t.test('just a local npm install', t => {
        -    install([], () => {
        +    install([], er => {
        +      if (er)
        +        throw er
               t.match(ARB_ARGS, { global: false, path: 'foo' })
               t.equal(REIFY_CALLED, true, 'called reify')
               t.strictSame(SCRIPTS, [
        @@ -60,7 +63,7 @@ test('should install using Arborist', (t) => {
                 'prepublish',
                 'preprepare',
                 'prepare',
        -        'postprepare'
        +        'postprepare',
               ], 'exec scripts when doing local build')
               t.end()
             })
        @@ -71,42 +74,45 @@ test('should install using Arborist', (t) => {
         
         test('should install globally using Arborist', (t) => {
           const install = requireInject('../../lib/install.js', {
        +    '../../lib/utils/reify-finish.js': async () => {},
             '../../lib/npm.js': {
               globalDir: 'path/to/node_modules/',
               prefix: 'foo',
               flatOptions: {
        -        'global': 'true',
        +        global: 'true',
               },
               config: {
        -        get: () => false
        -      }
        +        get: () => false,
        +      },
             },
             '@npmcli/arborist': function () {
               this.reify = () => {}
             },
           })
        -  install([], () => {
        +  install([], er => {
        +    if (er)
        +      throw er
             t.end()
           })
         })
         
         test('completion to folder', (t) => {
           const install = requireInject('../../lib/install.js', {
        -    'util': {
        -      'promisify': (fn) => fn
        +    '../../lib/utils/reify-finish.js': async () => {},
        +    util: {
        +      promisify: (fn) => fn,
             },
        -    'fs': {
        -      'readdir': (path) => {
        -        if (path === '/') {
        +    fs: {
        +      readdir: (path) => {
        +        if (path === '/')
                   return ['arborist']
        -        } else {
        +        else
                   return ['package.json']
        -        }
        -      }
        -    }
        +      },
        +    },
           })
           install.completion({
        -    partialWord: '/ar'
        +    partialWord: '/ar',
           }, (er, res) => {
             t.equal(er, null)
             const expect = process.platform === 'win32' ? '\\arborist' : '/arborist'
        @@ -117,17 +123,18 @@ test('completion to folder', (t) => {
         
         test('completion to folder - invalid dir', (t) => {
           const install = requireInject('../../lib/install.js', {
        -    'util': {
        -      'promisify': (fn) => fn
        +    '../../lib/utils/reify-finish.js': async () => {},
        +    util: {
        +      promisify: (fn) => fn,
             },
        -    'fs': {
        -      'readdir': () => {
        +    fs: {
        +      readdir: () => {
                 throw new Error('EONT')
        -      }
        -    }
        +      },
        +    },
           })
           install.completion({
        -    partialWord: 'path/to/folder'
        +    partialWord: 'path/to/folder',
           }, (er, res) => {
             t.equal(er, null)
             t.strictSame(res, [], 'invalid dir: no matching')
        @@ -137,17 +144,18 @@ test('completion to folder - invalid dir', (t) => {
         
         test('completion to folder - no matches', (t) => {
           const install = requireInject('../../lib/install.js', {
        -    'util': {
        -      'promisify': (fn) => fn
        +    '../../lib/utils/reify-finish.js': async () => {},
        +    util: {
        +      promisify: (fn) => fn,
             },
        -    'fs': {
        -      'readdir': (path) => {
        +    fs: {
        +      readdir: (path) => {
                 return ['foobar']
        -      }
        -    }
        +      },
        +    },
           })
           install.completion({
        -    partialWord: '/pa'
        +    partialWord: '/pa',
           }, (er, res) => {
             t.equal(er, null)
             t.strictSame(res, [], 'no name match')
        @@ -157,21 +165,21 @@ test('completion to folder - no matches', (t) => {
         
         test('completion to folder - match is not a package', (t) => {
           const install = requireInject('../../lib/install.js', {
        -    'util': {
        -      'promisify': (fn) => fn
        +    '../../lib/utils/reify-finish.js': async () => {},
        +    util: {
        +      promisify: (fn) => fn,
             },
        -    'fs': {
        -      'readdir': (path) => {
        -        if (path === '/') {
        +    fs: {
        +      readdir: (path) => {
        +        if (path === '/')
                   return ['arborist']
        -        } else {
        +        else
                   throw new Error('EONT')
        -        }
        -      }
        -    }
        +      },
        +    },
           })
           install.completion({
        -    partialWord: '/ar'
        +    partialWord: '/ar',
           }, (er, res) => {
             t.equal(er, null)
             t.strictSame(res, [], 'no name match')
        @@ -181,7 +189,7 @@ test('completion to folder - match is not a package', (t) => {
         
         test('completion to url', (t) => {
           install.completion({
        -    partialWord: 'http://path/to/url'
        +    partialWord: 'http://path/to/url',
           }, (er, res) => {
             t.equal(er, null)
             t.strictSame(res, [])
        @@ -191,7 +199,7 @@ test('completion to url', (t) => {
         
         test('completion', (t) => {
           install.completion({
        -    partialWord: 'toto'
        +    partialWord: 'toto',
           }, (er, res) => {
             t.notOk(er)
             t.notOk(res)
        diff --git a/deps/npm/test/lib/link.js b/deps/npm/test/lib/link.js
        index aafdb8188e85cf..9b7c5df642178f 100644
        --- a/deps/npm/test/lib/link.js
        +++ b/deps/npm/test/lib/link.js
        @@ -20,8 +20,10 @@ const npm = {
           prefix: null,
           flatOptions: {},
           config: {
        -    get () { return false }
        -  }
        +    get () {
        +      return false
        +    },
        +  },
         }
         const printLinks = async (opts) => {
           let res = ''
        @@ -30,16 +32,15 @@ const printLinks = async (opts) => {
           const linkedItems = [...tree.inventory.values()]
             .sort((a, b) => a.pkgid.localeCompare(b.pkgid))
           for (const item of linkedItems) {
        -    if (item.target) {
        +    if (item.target)
               res += `${item.path} -> ${item.target.path}\n`
        -    }
           }
           return res
         }
         
         const mocks = {
           '../../lib/npm.js': npm,
        -  '../../lib/utils/reify-output.js': () => reifyOutput()
        +  '../../lib/utils/reify-output.js': () => reifyOutput(),
         }
         
         const link = requireInject('../../lib/link.js', mocks)
        @@ -54,18 +55,18 @@ t.test('link to globalDir when in current working dir of pkg and no args', (t) =
                   a: {
                     'package.json': JSON.stringify({
                       name: 'a',
        -              version: '1.0.0'
        -            })
        -          }
        -        }
        -      }
        +              version: '1.0.0',
        +            }),
        +          },
        +        },
        +      },
             },
             'test-pkg-link': {
               'package.json': JSON.stringify({
                 name: 'test-pkg-link',
        -        version: '1.0.0'
        -      })
        -    }
        +        version: '1.0.0',
        +      }),
        +    },
           })
           npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules')
           npm.prefix = resolve(testdir, 'test-pkg-link')
        @@ -75,7 +76,7 @@ t.test('link to globalDir when in current working dir of pkg and no args', (t) =
         
             const links = await printLinks({
               path: resolve(npm.globalDir, '..'),
        -      global: true
        +      global: true,
             })
         
             t.matchSnapshot(links, 'should create a global link to current pkg')
        @@ -97,68 +98,68 @@ t.test('link global linked pkg to local nm when using args', (t) => {
                     foo: {
                       'package.json': JSON.stringify({
                         name: '@myscope/foo',
        -                version: '1.0.0'
        -              })
        +                version: '1.0.0',
        +              }),
                     },
                     bar: {
                       'package.json': JSON.stringify({
                         name: '@myscope/bar',
        -                version: '1.0.0'
        -              })
        +                version: '1.0.0',
        +              }),
                     },
        -            linked: t.fixture('symlink', '../../../../scoped-linked')
        +            linked: t.fixture('symlink', '../../../../scoped-linked'),
                   },
                   a: {
                     'package.json': JSON.stringify({
                       name: 'a',
        -              version: '1.0.0'
        -            })
        +              version: '1.0.0',
        +            }),
                   },
                   b: {
                     'package.json': JSON.stringify({
                       name: 'b',
        -              version: '1.0.0'
        -            })
        +              version: '1.0.0',
        +            }),
                   },
        -          'test-pkg-link': t.fixture('symlink', '../../../test-pkg-link')
        -        }
        -      }
        +          'test-pkg-link': t.fixture('symlink', '../../../test-pkg-link'),
        +        },
        +      },
             },
             'test-pkg-link': {
               'package.json': JSON.stringify({
                 name: 'test-pkg-link',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             'link-me-too': {
               'package.json': JSON.stringify({
                 name: 'link-me-too',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             'scoped-linked': {
               'package.json': JSON.stringify({
                 name: '@myscope/linked',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             'my-project': {
               'package.json': JSON.stringify({
                 name: 'my-project',
                 version: '1.0.0',
                 dependencies: {
        -          foo: '^1.0.0'
        -        }
        +          foo: '^1.0.0',
        +        },
               }),
               node_modules: {
                 foo: {
                   'package.json': JSON.stringify({
                     name: 'foo',
        -            version: '1.0.0'
        -          })
        -        }
        -      }
        -    }
        +            version: '1.0.0',
        +          }),
        +        },
        +      },
        +    },
           })
           npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules')
           npm.prefix = resolve(testdir, 'my-project')
        @@ -171,7 +172,7 @@ t.test('link global linked pkg to local nm when using args', (t) => {
             process.chdir(_cwd)
         
             const links = await printLinks({
        -      path: npm.prefix
        +      path: npm.prefix,
             })
         
             t.matchSnapshot(links, 'should create a local symlink to global pkg')
        @@ -188,7 +189,7 @@ t.test('link global linked pkg to local nm when using args', (t) => {
             '@myscope/linked',
             '@myscope/bar',
             'a',
        -    'file:../link-me-too'
        +    'file:../link-me-too',
           ], (err) => {
             t.ifError(err, 'should not error out')
           })
        @@ -202,23 +203,23 @@ t.test('link pkg already in global space', (t) => {
               lib: {
                 node_modules: {
                   '@myscope': {
        -            linked: t.fixture('symlink', '../../../../scoped-linked')
        -          }
        -        }
        -      }
        +            linked: t.fixture('symlink', '../../../../scoped-linked'),
        +          },
        +        },
        +      },
             },
             'scoped-linked': {
               'package.json': JSON.stringify({
                 name: '@myscope/linked',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             'my-project': {
               'package.json': JSON.stringify({
                 name: 'my-project',
        -        version: '1.0.0'
        -      })
        -    }
        +        version: '1.0.0',
        +      }),
        +    },
           })
           npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules')
           npm.prefix = resolve(testdir, 'my-project')
        @@ -231,7 +232,7 @@ t.test('link pkg already in global space', (t) => {
             process.chdir(_cwd)
         
             const links = await printLinks({
        -      path: npm.prefix
        +      path: npm.prefix,
             })
         
             t.matchSnapshot(links, 'should create a local symlink to global pkg')
        @@ -256,10 +257,10 @@ t.test('completion', (t) => {
                   foo: {},
                   bar: {},
                   lorem: {},
        -          ipsum: {}
        -        }
        -      }
        -    }
        +          ipsum: {},
        +        },
        +      },
        +    },
           })
           npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules')
         
        @@ -276,7 +277,9 @@ t.test('completion', (t) => {
         
         t.test('--global option', (t) => {
           const _config = npm.config
        -  npm.config = { get () { return true } }
        +  npm.config = { get () {
        +    return true
        +  } }
           link([], (err) => {
             npm.config = _config
         
        diff --git a/deps/npm/test/lib/ll.js b/deps/npm/test/lib/ll.js
        index 989800944f6cb3..7d4e2b94f2b7e2 100644
        --- a/deps/npm/test/lib/ll.js
        +++ b/deps/npm/test/lib/ll.js
        @@ -7,15 +7,15 @@ const ll = requireInject('../../lib/ll.js', {
             config: {
               set: (k, v) => {
                 configs[k] = v
        -      }
        +      },
             },
             commands: {
               ls: (args, cb) => {
                 lsCalled = true
                 cb()
        -      }
        -    }
        -  }
        +      },
        +    },
        +  },
         })
         
         const ls = require('../../lib/ls.js')
        diff --git a/deps/npm/test/lib/load-all-commands.js b/deps/npm/test/lib/load-all-commands.js
        index 1669f435e9b097..fa73b8a78d8fa2 100644
        --- a/deps/npm/test/lib/load-all-commands.js
        +++ b/deps/npm/test/lib/load-all-commands.js
        @@ -4,9 +4,8 @@ const t = require('tap')
         const { cmdList } = require('../../lib/utils/cmd-list.js')
         
         t.test('load npm', t => npm.load(er => {
        -  if (er) {
        +  if (er)
             throw er
        -  }
         }))
         
         t.test('load each command', t => {
        diff --git a/deps/npm/test/lib/load-all.js b/deps/npm/test/lib/load-all.js
        index 72879c2c4448aa..02736c18ccc387 100644
        --- a/deps/npm/test/lib/load-all.js
        +++ b/deps/npm/test/lib/load-all.js
        @@ -4,9 +4,9 @@ const { resolve } = require('path')
         
         const full = process.env.npm_lifecycle_event === 'check-coverage'
         
        -if (!full) {
        +if (!full)
           t.pass('nothing to do here, not checking for full coverage')
        -} else {
        +else {
           // some files do config.get() on load, so have to load npm first
           const npm = require('../../lib/npm.js')
           t.test('load npm first', t => npm.load(t.end))
        diff --git a/deps/npm/test/lib/logout.js b/deps/npm/test/lib/logout.js
        index 0d00422dc83366..96b1bcc7fe8c41 100644
        --- a/deps/npm/test/lib/logout.js
        +++ b/deps/npm/test/lib/logout.js
        @@ -3,7 +3,7 @@ const { test } = require('tap')
         
         const _flatOptions = {
           registry: 'https://registry.npmjs.org/',
        -  scope: ''
        +  scope: '',
         }
         
         const config = {}
        @@ -19,8 +19,8 @@ const mocks = {
           'npm-registry-fetch': npmFetch,
           '../../lib/npm.js': {
             flatOptions: _flatOptions,
        -    config
        -  }
        +    config,
        +  },
         }
         
         const logout = requireInject('../../lib/logout.js', mocks)
        @@ -64,8 +64,8 @@ test('token logout', async (t) => {
                     scope: '',
                     token: '@foo/',
                     method: 'DELETE',
        -            ignoreBody: true
        -          }
        +            ignoreBody: true,
        +          },
                 },
                 'should call npm-registry-fetch with expected values'
               )
        @@ -134,8 +134,8 @@ test('token scoped logout', async (t) => {
                     scope: '@myscope',
                     token: '@foo/',
                     method: 'DELETE',
        -            ignoreBody: true
        -          }
        +            ignoreBody: true,
        +          },
                 },
                 'should call npm-registry-fetch with expected values'
               )
        @@ -241,8 +241,8 @@ test('ignore invalid scoped registry config', async (t) => {
                     '@myscope:registry': '',
                     token: '@foo/',
                     method: 'DELETE',
        -            ignoreBody: true
        -          }
        +            ignoreBody: true,
        +          },
                 },
                 'should call npm-registry-fetch with expected values'
               )
        diff --git a/deps/npm/test/lib/ls.js b/deps/npm/test/lib/ls.js
        index 6a91e8c3520cd0..256ebf3534302e 100644
        --- a/deps/npm/test/lib/ls.js
        +++ b/deps/npm/test/lib/ls.js
        @@ -7,28 +7,28 @@ t.cleanSnapshot = str => str.split(/\r\n/).join('\n')
         
         const simpleNmFixture = {
           node_modules: {
        -    'foo': {
        +    foo: {
               'package.json': JSON.stringify({
                 name: 'foo',
                 version: '1.0.0',
                 dependencies: {
        -          'bar': '^1.0.0'
        -        }
        -      })
        +          bar: '^1.0.0',
        +        },
        +      }),
             },
        -    'bar': {
        +    bar: {
               'package.json': JSON.stringify({
                 name: 'bar',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
        -    'lorem': {
        +    lorem: {
               'package.json': JSON.stringify({
                 name: 'lorem',
        -        version: '1.0.0'
        -      })
        -    }
        -  }
        +        version: '1.0.0',
        +      }),
        +    },
        +  },
         }
         
         const diffDepTypesNmFixture = {
        @@ -39,9 +39,9 @@ const diffDepTypesNmFixture = {
                 description: 'A DEV dep kind of dep',
                 version: '1.0.0',
                 dependencies: {
        -          'foo': '^1.0.0'
        -        }
        -      })
        +          foo: '^1.0.0',
        +        },
        +      }),
             },
             'prod-dep': {
               'package.json': JSON.stringify({
        @@ -49,35 +49,35 @@ const diffDepTypesNmFixture = {
                 description: 'A PROD dep kind of dep',
                 version: '1.0.0',
                 dependencies: {
        -          'bar': '^2.0.0'
        -        }
        +          bar: '^2.0.0',
        +        },
               }),
               node_modules: {
                 bar: {
                   'package.json': JSON.stringify({
                     name: 'bar',
                     description: 'A dep that bars',
        -            version: '2.0.0'
        -          })
        -        }
        -      }
        +            version: '2.0.0',
        +          }),
        +        },
        +      },
             },
             'optional-dep': {
               'package.json': JSON.stringify({
                 name: 'optional-dep',
                 description: 'Maybe a dep?',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             'peer-dep': {
               'package.json': JSON.stringify({
                 name: 'peer-dep',
                 description: 'Peer-dep description here',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
        -    ...simpleNmFixture.node_modules
        -  }
        +    ...simpleNmFixture.node_modules,
        +  },
         }
         
         let prefix
        @@ -95,24 +95,32 @@ const _flatOptions = {
           link: false,
           only: null,
           parseable: false,
        -  get prefix () { return prefix },
        -  production: false
        +  get prefix () {
        +    return prefix
        +  },
        +  production: false,
         }
         const ls = requireInject('../../lib/ls.js', {
           '../../lib/npm.js': {
             flatOptions: _flatOptions,
             limit: {
        -      fetch: 3
        +      fetch: 3,
        +    },
        +    get prefix () {
        +      return _flatOptions.prefix
        +    },
        +    get globalDir () {
        +      return globalDir
             },
        -    get prefix () { return _flatOptions.prefix },
        -    get globalDir () { return globalDir },
             config: {
               get (key) {
                 return _flatOptions[key]
        -      }
        -    }
        +      },
        +    },
        +  },
        +  '../../lib/utils/output.js': msg => {
        +    result = msg
           },
        -  '../../lib/utils/output.js': msg => { result = msg }
         })
         
         const redactCwd = res =>
        @@ -136,10 +144,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -150,7 +158,7 @@ t.test('ls', (t) => {
         
           t.test('missing package.json', (t) => {
             prefix = t.testdir({
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
        @@ -169,10 +177,10 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          foo: '^1.0.0'
        -        }
        +          foo: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.equal(err.code, 'ELSPROBLEMS', 'should have error code')
        @@ -194,10 +202,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['lorem'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -216,10 +224,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['.'], (err) => {
               t.ifError(err, 'should not throw on missing dep above current level')
        @@ -237,10 +245,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['bar'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -257,18 +265,18 @@ t.test('ls', (t) => {
                 dependencies: {
                   foo: '^1.0.0',
                   lorem: '^1.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
               node_modules: {
                 ...simpleNmFixture.node_modules,
                 ipsum: {
                   'package.json': JSON.stringify({
                     name: 'ipsum',
        -            version: '1.0.0'
        -          })
        -        }
        -      }
        +            version: '1.0.0',
        +          }),
        +        },
        +      },
             })
             ls(['bar@*', 'lorem@1.0.0'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -284,10 +292,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['notadep'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -311,10 +319,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -334,10 +342,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -357,8 +365,8 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   a: '^1.0.0',
        -          e: '^1.0.0'
        -        }
        +          e: '^1.0.0',
        +        },
               }),
               node_modules: {
                 a: {
        @@ -366,9 +374,9 @@ t.test('ls', (t) => {
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^1.0.0'
        -            }
        -          })
        +              b: '^1.0.0',
        +            },
        +          }),
                 },
                 b: {
                   'package.json': JSON.stringify({
        @@ -376,29 +384,29 @@ t.test('ls', (t) => {
                     version: '1.0.0',
                     dependencies: {
                       c: '^1.0.0',
        -              d: '*'
        -            }
        -          })
        +              d: '*',
        +            },
        +          }),
                 },
                 c: {
                   'package.json': JSON.stringify({
                     name: 'c',
        -            version: '1.0.0'
        -          })
        +            version: '1.0.0',
        +          }),
                 },
                 d: {
                   'package.json': JSON.stringify({
                     name: 'd',
        -            version: '1.0.0'
        -          })
        +            version: '1.0.0',
        +          }),
                 },
                 e: {
                   'package.json': JSON.stringify({
                     name: 'e',
        -            version: '1.0.0'
        -          })
        -        }
        -      }
        +            version: '1.0.0',
        +          }),
        +        },
        +      },
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -416,10 +424,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^2.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.equal(err.code, 'ELSPROBLEMS', 'should have error code')
        @@ -443,10 +451,10 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^2.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.equal(err.code, 'ELSPROBLEMS', 'should have error code')
        @@ -464,19 +472,19 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps')
        @@ -493,19 +501,19 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps')
        @@ -522,29 +530,29 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0',
        -          'linked-dep': '^1.0.0'
        +          lorem: '^1.0.0',
        +          'linked-dep': '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
               'linked-dep': {
                 'package.json': JSON.stringify({
                   name: 'linked-dep',
        -          version: '1.0.0'
        -        })
        +          version: '1.0.0',
        +        }),
               },
               node_modules: {
                 'linked-dep': t.fixture('symlink', '../linked-dep'),
        -        ...diffDepTypesNmFixture.node_modules
        -      }
        +        ...diffDepTypesNmFixture.node_modules,
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps')
        @@ -559,15 +567,15 @@ t.test('ls', (t) => {
                 name: 'print-deduped-symlinks',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0',
        -          'b': '^1.0.0'
        -        }
        +          a: '^1.0.0',
        +          b: '^1.0.0',
        +        },
               }),
        -      'b': {
        +      b: {
                 'package.json': JSON.stringify({
                   name: 'b',
        -          version: '1.0.0'
        -        })
        +          version: '1.0.0',
        +        }),
               },
               node_modules: {
                 a: {
        @@ -575,12 +583,12 @@ t.test('ls', (t) => {
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^1.0.0'
        -            }
        -          })
        +              b: '^1.0.0',
        +            },
        +          }),
                 },
        -        'b': t.fixture('symlink', '../b')
        -      }
        +        b: t.fixture('symlink', '../b'),
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps')
        @@ -597,19 +605,19 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing production deps')
        @@ -626,19 +634,19 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps')
        @@ -655,19 +663,19 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions')
        @@ -686,19 +694,19 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions')
        @@ -711,7 +719,7 @@ t.test('ls', (t) => {
         
           t.test('json read problems', (t) => {
             prefix = t.testdir({
        -      'package.json': '{broken json'
        +      'package.json': '{broken json',
             })
             ls([], (err) => {
               t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error')
        @@ -736,19 +744,19 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^2.0.0' // mismatching version #
        -        }
        +          'peer-dep': '^2.0.0', // mismatching version #
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems')
        @@ -763,9 +771,9 @@ t.test('ls', (t) => {
                 name: 'invalid-deduped-dep',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0',
        -          'b': '^2.0.0'
        -        }
        +          a: '^1.0.0',
        +          b: '^2.0.0',
        +        },
               }),
               node_modules: {
                 a: {
        @@ -773,17 +781,17 @@ t.test('ls', (t) => {
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^2.0.0'
        -            }
        -          })
        +              b: '^2.0.0',
        +            },
        +          }),
                 },
                 b: {
                   'package.json': JSON.stringify({
                     name: 'b',
        -            version: '1.0.0'
        -          })
        -        }
        -      }
        +            version: '1.0.0',
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems')
        @@ -798,9 +806,9 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0',
        -          'b': '^1.0.0'
        -        }
        +          a: '^1.0.0',
        +          b: '^1.0.0',
        +        },
               }),
               node_modules: {
                 a: {
        @@ -808,11 +816,11 @@ t.test('ls', (t) => {
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^1.0.0'
        -            }
        -          })
        -        }
        -      }
        +              b: '^1.0.0',
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
        @@ -828,9 +836,9 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 peerDependencies: {
        -          'peer-dep': '*'
        -        }
        -      })
        +          'peer-dep': '*',
        +        },
        +      }),
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
        @@ -848,20 +856,20 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
                   'missing-optional-dep': '^1.0.0',
        -          'optional-dep': '^2.0.0' // mismatching version #
        +          'optional-dep': '^2.0.0', // mismatching version #
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
        @@ -878,29 +886,29 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0'
        -        }
        +          a: '^1.0.0',
        +        },
               }),
               node_modules: {
        -        'a': {
        +        a: {
                   'package.json': JSON.stringify({
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^1.0.0'
        -            }
        -          })
        +              b: '^1.0.0',
        +            },
        +          }),
                 },
        -        'b': {
        +        b: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     dependencies: {
        -              a: '^1.0.0'
        -            }
        -          })
        -        }
        -      }
        +              a: '^1.0.0',
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -916,29 +924,29 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0'
        -        }
        +          a: '^1.0.0',
        +        },
               }),
               node_modules: {
        -        'a': {
        +        a: {
                   'package.json': JSON.stringify({
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^1.0.0'
        -            }
        -          })
        +              b: '^1.0.0',
        +            },
        +          }),
                 },
        -        'b': {
        +        b: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     dependencies: {
        -              a: '^1.0.0'
        -            }
        -          })
        -        }
        -      }
        +              a: '^1.0.0',
        +            },
        +          }),
        +        },
        +      },
             })
             ls(['a'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -956,37 +964,37 @@ t.test('ls', (t) => {
                 dependencies: {
                   '@npmcli/a': '^1.0.0',
                   '@npmcli/b': '^1.0.0',
        -          '@npmcli/c': '^1.0.0'
        -        }
        +          '@npmcli/c': '^1.0.0',
        +        },
               }),
               node_modules: {
                 '@npmcli': {
        -          'a': {
        +          a: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/a',
                       version: '1.0.0',
                       dependencies: {
        -                '@npmcli/b': '^1.0.0'
        -              }
        -            })
        +                '@npmcli/b': '^1.0.0',
        +              },
        +            }),
                   },
        -          'b': {
        +          b: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/b',
        -              version: '1.1.2'
        -            })
        +              version: '1.1.2',
        +            }),
                   },
        -          'c': {
        +          c: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/c',
                       version: '1.0.0',
                       dependencies: {
        -                '@npmcli/b': '^1.0.0'
        -              }
        -            })
        -          }
        -        }
        -      }
        +                '@npmcli/b': '^1.0.0',
        +              },
        +            }),
        +          },
        +        },
        +      },
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1005,37 +1013,37 @@ t.test('ls', (t) => {
                 dependencies: {
                   '@npmcli/a': '^1.0.0',
                   '@npmcli/b': '^1.0.0',
        -          '@npmcli/c': '^1.0.0'
        -        }
        +          '@npmcli/c': '^1.0.0',
        +        },
               }),
               node_modules: {
                 '@npmcli': {
        -          'a': {
        +          a: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/a',
                       version: '1.0.0',
                       dependencies: {
        -                '@npmcli/b': '^1.0.0'
        -              }
        -            })
        +                '@npmcli/b': '^1.0.0',
        +              },
        +            }),
                   },
        -          'b': {
        +          b: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/b',
        -              version: '1.1.2'
        -            })
        +              version: '1.1.2',
        +            }),
                   },
        -          'c': {
        +          c: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/c',
                       version: '1.0.0',
                       dependencies: {
        -                '@npmcli/b': '^1.0.0'
        -              }
        -            })
        -          }
        -        }
        -      }
        +                '@npmcli/b': '^1.0.0',
        +              },
        +            }),
        +          },
        +        },
        +      },
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1055,37 +1063,37 @@ t.test('ls', (t) => {
                 dependencies: {
                   '@npmcli/a': '^1.0.0',
                   '@npmcli/b': '^1.0.0',
        -          '@npmcli/c': '^1.0.0'
        -        }
        +          '@npmcli/c': '^1.0.0',
        +        },
               }),
               node_modules: {
                 '@npmcli': {
        -          'a': {
        +          a: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/a',
                       version: '1.0.0',
                       dependencies: {
        -                '@npmcli/b': '^1.0.0'
        -              }
        -            })
        +                '@npmcli/b': '^1.0.0',
        +              },
        +            }),
                   },
        -          'b': {
        +          b: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/b',
        -              version: '1.1.2'
        -            })
        +              version: '1.1.2',
        +            }),
                   },
        -          'c': {
        +          c: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/c',
                       version: '1.0.0',
                       dependencies: {
        -                '@npmcli/b': '^1.0.0'
        -              }
        -            })
        -          }
        -        }
        -      }
        +                '@npmcli/b': '^1.0.0',
        +              },
        +            }),
        +          },
        +        },
        +      },
             })
             ls(['@npmcli/b'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1103,37 +1111,37 @@ t.test('ls', (t) => {
                 dependencies: {
                   '@npmcli/a': '^1.0.0',
                   '@npmcli/b': '^1.0.0',
        -          '@npmcli/c': '^1.0.0'
        -        }
        +          '@npmcli/c': '^1.0.0',
        +        },
               }),
               node_modules: {
                 '@npmcli': {
        -          'a': {
        +          a: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/a',
                       version: '1.0.0',
                       dependencies: {
        -                '@npmcli/c': '^1.0.0'
        -              }
        -            })
        +                '@npmcli/c': '^1.0.0',
        +              },
        +            }),
                   },
        -          'b': {
        +          b: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/b',
                       version: '1.1.2',
                       dependencies: {
        -                '@npmcli/c': '^1.0.0'
        -              }
        -            })
        +                '@npmcli/c': '^1.0.0',
        +              },
        +            }),
                   },
        -          'c': {
        +          c: {
                     'package.json': JSON.stringify({
                       name: '@npmcli/c',
        -              version: '1.0.0'
        -            })
        -          }
        -        }
        -      }
        +              version: '1.0.0',
        +            }),
        +          },
        +        },
        +      },
             })
             ls(['@npmcli/c'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1148,22 +1156,22 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          a: 'npm:b@1.0.0'
        -        }
        +          a: 'npm:b@1.0.0',
        +        },
               }),
               node_modules: {
        -        'a': {
        +        a: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     _from: 'a@npm:b',
                     _resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
                     _requested: {
        -              type: 'alias'
        -            }
        -          })
        -        }
        -      }
        +              type: 'alias',
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing aliases')
        @@ -1177,11 +1185,11 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'abbrev': 'git+https://github.com/isaacs/abbrev-js.git'
        -        }
        +          abbrev: 'git+https://github.com/isaacs/abbrev-js.git',
        +        },
               }),
               node_modules: {
        -        'abbrev': {
        +        abbrev: {
                   'package.json': JSON.stringify({
                     name: 'abbrev',
                     version: '1.1.1',
        @@ -1194,11 +1202,11 @@ t.test('ls', (t) => {
                       rawSpec: 'git+https:github.com/isaacs/abbrev-js.git',
                       saveSpec: 'git+https://github.com/isaacs/abbrev-js.git',
                       fetchSpec: 'https://github.com/isaacs/abbrev-js.git',
        -              gitCommittish: null
        -            }
        -          })
        -        }
        -      }
        +              gitCommittish: null,
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1213,36 +1221,36 @@ t.test('ls', (t) => {
                 a: {
                   'package.json': JSON.stringify({
                     name: 'a',
        -            version: '1.0.1'
        -          })
        -        }
        +            version: '1.0.1',
        +          }),
        +        },
               },
               'package-lock.json': JSON.stringify({
        -        'name': 'npm-broken-resolved-field-test',
        -        'version': '1.0.0',
        -        'lockfileVersion': 2,
        -        'requires': true,
        -        'packages': {
        +        name: 'npm-broken-resolved-field-test',
        +        version: '1.0.0',
        +        lockfileVersion: 2,
        +        requires: true,
        +        packages: {
                   '': {
        -            'name': 'a',
        -            'version': '1.0.1'
        -          }
        +            name: 'a',
        +            version: '1.0.1',
        +          },
                 },
        -        'dependencies': {
        +        dependencies: {
                   a: {
        -            'version': '1.0.1',
        -            'resolved': 'foo@bar://b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
        -            'integrity': 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ=='
        -          }
        -        }
        -      }),
        -      'package.json': JSON.stringify({
        -        'name': 'npm-broken-resolved-field-test',
        -        'version': '1.0.0',
        -        'dependencies': {
        -          'a': '^1.0.1'
        -        }
        -      })
        +            version: '1.0.1',
        +            resolved: 'foo@bar://b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
        +            integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
        +          },
        +        },
        +      }),
        +      'package.json': JSON.stringify({
        +        name: 'npm-broken-resolved-field-test',
        +        version: '1.0.0',
        +        dependencies: {
        +          a: '^1.0.1',
        +        },
        +      }),
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1257,8 +1265,8 @@ t.test('ls', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'simple-output': '^2.0.0'
        -        }
        +          'simple-output': '^2.0.0',
        +        },
               }),
               node_modules: {
                 'simple-output': {
        @@ -1276,17 +1284,17 @@ t.test('ls', (t) => {
                       escapedName: 'simple-output',
                       rawSpec: '',
                       saveSpec: null,
        -              fetchSpec: 'latest'
        +              fetchSpec: 'latest',
                     },
                     _requiredBy: [
                       '#USER',
        -              '/'
        +              '/',
                     ],
                     _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
        -            _spec: 'simple-output'
        -          })
        -        }
        -      }
        +            _spec: 'simple-output',
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should not be printed in tree output')
        @@ -1301,24 +1309,24 @@ t.test('ls', (t) => {
                 a: {
                   'package.json': JSON.stringify({
                     name: 'a',
        -            version: '1.0.0'
        -          })
        +            version: '1.0.0',
        +          }),
                 },
                 b: {
                   'package.json': JSON.stringify({
                     name: 'b',
        -            version: '1.0.0'
        +            version: '1.0.0',
                   }),
                   node_modules: {
                     c: {
                       'package.json': JSON.stringify({
                         name: 'c',
        -                version: '1.0.0'
        -              })
        -            }
        -          }
        -        }
        -      }
        +                version: '1.0.0',
        +              }),
        +            },
        +          },
        +        },
        +      },
             })
         
             // mimics lib/npm.js globalDir getter but pointing to fixtures
        @@ -1338,8 +1346,8 @@ t.test('ls', (t) => {
                 name: 'filter-by-child-of-missing-dep',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0'
        -        }
        +          a: '^1.0.0',
        +        },
               }),
               node_modules: {
                 b: {
        @@ -1347,34 +1355,34 @@ t.test('ls', (t) => {
                     name: 'b',
                     version: '1.0.0',
                     dependencies: {
        -              c: '^1.0.0'
        -            }
        -          })
        +              c: '^1.0.0',
        +            },
        +          }),
                 },
                 c: {
                   'package.json': JSON.stringify({
                     name: 'c',
        -            version: '1.0.0'
        -          })
        +            version: '1.0.0',
        +          }),
                 },
                 d: {
                   'package.json': JSON.stringify({
                     name: 'd',
                     version: '1.0.0',
                     dependencies: {
        -              c: '^2.0.0'
        -            }
        +              c: '^2.0.0',
        +            },
                   }),
                   node_modules: {
                     c: {
                       'package.json': JSON.stringify({
                         name: 'c',
        -                version: '2.0.0'
        -              })
        -            }
        -          }
        -        }
        -      }
        +                version: '2.0.0',
        +              }),
        +            },
        +          },
        +        },
        +      },
             })
         
             ls(['c'], (err) => {
        @@ -1391,8 +1399,8 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 workspaces: [
                   './a',
        -          './b'
        -        ]
        +          './b',
        +        ],
               }),
               node_modules: {
                 a: t.fixture('symlink', '../a'),
        @@ -1400,25 +1408,25 @@ t.test('ls', (t) => {
                 c: {
                   'package.json': JSON.stringify({
                     name: 'c',
        -            version: '1.0.0'
        -          })
        -        }
        +            version: '1.0.0',
        +          }),
        +        },
               },
               a: {
                 'package.json': JSON.stringify({
                   name: 'a',
                   version: '1.0.0',
                   dependencies: {
        -            c: '^1.0.0'
        -          }
        -        })
        +            c: '^1.0.0',
        +          },
        +        }),
               },
               b: {
                 'package.json': JSON.stringify({
                   name: 'b',
        -          version: '1.0.0'
        -        })
        -      }
        +          version: '1.0.0',
        +        }),
        +      },
             })
         
             ls([], (err) => {
        @@ -1443,44 +1451,44 @@ t.test('ls', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   a: '^1.0.0',
        -          b: '^1.0.0'
        -        }
        +          b: '^1.0.0',
        +        },
               }),
               node_modules: {
                 a: {
                   'package.json': JSON.stringify({
                     name: 'a',
        -            version: '1.0.0'
        -          })
        +            version: '1.0.0',
        +          }),
                 },
                 b: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     dependencies: {
        -              c: '^1.0.0'
        -            }
        -          })
        +              c: '^1.0.0',
        +            },
        +          }),
                 },
                 c: {
                   'package.json': JSON.stringify({
                     name: 'c',
                     version: '1.0.0',
                     dependencies: {
        -              d: '^1.0.0'
        -            }
        -          })
        +              d: '^1.0.0',
        +            },
        +          }),
                 },
                 d: {
                   'package.json': JSON.stringify({
                     name: 'd',
                     version: '1.0.0',
                     dependencies: {
        -              a: '^1.0.0'
        -            }
        -          })
        -        }
        -      }
        +              a: '^1.0.0',
        +            },
        +          }),
        +        },
        +      },
             })
         
             t.plan(6)
        @@ -1521,10 +1529,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1535,7 +1543,7 @@ t.test('ls --parseable', (t) => {
         
           t.test('missing package.json', (t) => {
             prefix = t.testdir({
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
        @@ -1554,10 +1562,10 @@ t.test('ls --parseable', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          foo: '^1.0.0'
        -        }
        +          foo: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.equal(err.code, 'ELSPROBLEMS', 'should have error code')
        @@ -1573,10 +1581,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['lorem'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1592,10 +1600,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['bar'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1612,18 +1620,18 @@ t.test('ls --parseable', (t) => {
                 dependencies: {
                   foo: '^1.0.0',
                   lorem: '^1.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
               node_modules: {
                 ...simpleNmFixture.node_modules,
                 ipsum: {
                   'package.json': JSON.stringify({
                     name: 'ipsum',
        -            version: '1.0.0'
        -          })
        -        }
        -      }
        +            version: '1.0.0',
        +          }),
        +        },
        +      },
             })
             ls(['bar@*', 'lorem@1.0.0'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1639,10 +1647,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['notadep'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1666,10 +1674,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1689,10 +1697,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1712,10 +1720,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -1733,10 +1741,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^2.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems')
        @@ -1753,19 +1761,19 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps')
        @@ -1782,19 +1790,19 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps')
        @@ -1811,29 +1819,29 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0',
        -          'linked-dep': '^1.0.0'
        +          lorem: '^1.0.0',
        +          'linked-dep': '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
               'linked-dep': {
                 'package.json': JSON.stringify({
                   name: 'linked-dep',
        -          version: '1.0.0'
        -        })
        +          version: '1.0.0',
        +        }),
               },
               node_modules: {
                 'linked-dep': t.fixture('symlink', '../linked-dep'),
        -        ...diffDepTypesNmFixture.node_modules
        -      }
        +        ...diffDepTypesNmFixture.node_modules,
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps')
        @@ -1850,19 +1858,19 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing production deps')
        @@ -1879,19 +1887,19 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps')
        @@ -1908,19 +1916,19 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions')
        @@ -1935,10 +1943,10 @@ t.test('ls --parseable', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          foo: '^1.0.0'
        -        }
        +          foo: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.equal(err.code, 'ELSPROBLEMS', 'should have error code')
        @@ -1956,10 +1964,10 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^2.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems')
        @@ -1977,29 +1985,29 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0',
        -          'linked-dep': '^1.0.0'
        +          lorem: '^1.0.0',
        +          'linked-dep': '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
               'linked-dep': {
                 'package.json': JSON.stringify({
                   name: 'linked-dep',
        -          version: '1.0.0'
        -        })
        +          version: '1.0.0',
        +        }),
               },
               node_modules: {
                 'linked-dep': t.fixture('symlink', '../linked-dep'),
        -        ...diffDepTypesNmFixture.node_modules
        -      }
        +        ...diffDepTypesNmFixture.node_modules,
        +      },
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2019,19 +2027,19 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions')
        @@ -2044,7 +2052,7 @@ t.test('ls --parseable', (t) => {
         
           t.test('json read problems', (t) => {
             prefix = t.testdir({
        -      'package.json': '{broken json'
        +      'package.json': '{broken json',
             })
             ls([], (err) => {
               t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error')
        @@ -2069,19 +2077,19 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^2.0.0' // mismatching version #
        -        }
        +          'peer-dep': '^2.0.0', // mismatching version #
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems')
        @@ -2096,20 +2104,20 @@ t.test('ls --parseable', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
                   'missing-optional-dep': '^1.0.0',
        -          'optional-dep': '^2.0.0' // mismatching version #
        +          'optional-dep': '^2.0.0', // mismatching version #
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
        @@ -2125,29 +2133,29 @@ t.test('ls --parseable', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0'
        -        }
        +          a: '^1.0.0',
        +        },
               }),
               node_modules: {
        -        'a': {
        +        a: {
                   'package.json': JSON.stringify({
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^1.0.0'
        -            }
        -          })
        +              b: '^1.0.0',
        +            },
        +          }),
                 },
        -        'b': {
        +        b: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     dependencies: {
        -              a: '^1.0.0'
        -            }
        -          })
        -        }
        -      }
        +              a: '^1.0.0',
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should print tree output ommiting deduped ref')
        @@ -2161,22 +2169,22 @@ t.test('ls --parseable', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          a: 'npm:b@1.0.0'
        -        }
        +          a: 'npm:b@1.0.0',
        +        },
               }),
               node_modules: {
        -        'a': {
        +        a: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     _from: 'a@npm:b',
                     _resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
                     _requested: {
        -              type: 'alias'
        -            }
        -          })
        -        }
        -      }
        +              type: 'alias',
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing aliases')
        @@ -2190,11 +2198,11 @@ t.test('ls --parseable', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'abbrev': 'git+https://github.com/isaacs/abbrev-js.git'
        -        }
        +          abbrev: 'git+https://github.com/isaacs/abbrev-js.git',
        +        },
               }),
               node_modules: {
        -        'abbrev': {
        +        abbrev: {
                   'package.json': JSON.stringify({
                     name: 'abbrev',
                     version: '1.1.1',
        @@ -2207,11 +2215,11 @@ t.test('ls --parseable', (t) => {
                       rawSpec: 'git+https:github.com/isaacs/abbrev-js.git',
                       saveSpec: 'git+https://github.com/isaacs/abbrev-js.git',
                       fetchSpec: 'https://github.com/isaacs/abbrev-js.git',
        -              gitCommittish: null
        -            }
        -          })
        -        }
        -      }
        +              gitCommittish: null,
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should output tree containing git refs')
        @@ -2225,8 +2233,8 @@ t.test('ls --parseable', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'simple-output': '^2.0.0'
        -        }
        +          'simple-output': '^2.0.0',
        +        },
               }),
               node_modules: {
                 'simple-output': {
        @@ -2244,17 +2252,17 @@ t.test('ls --parseable', (t) => {
                       escapedName: 'simple-output',
                       rawSpec: '',
                       saveSpec: null,
        -              fetchSpec: 'latest'
        +              fetchSpec: 'latest',
                     },
                     _requiredBy: [
                       '#USER',
        -              '/'
        +              '/',
                     ],
                     _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
        -            _spec: 'simple-output'
        -          })
        -        }
        -      }
        +            _spec: 'simple-output',
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.matchSnapshot(redactCwd(result), 'should not be printed in tree output')
        @@ -2269,24 +2277,24 @@ t.test('ls --parseable', (t) => {
                 a: {
                   'package.json': JSON.stringify({
                     name: 'a',
        -            version: '1.0.0'
        -          })
        +            version: '1.0.0',
        +          }),
                 },
                 b: {
                   'package.json': JSON.stringify({
                     name: 'b',
        -            version: '1.0.0'
        +            version: '1.0.0',
                   }),
                   node_modules: {
                     c: {
                       'package.json': JSON.stringify({
                         name: 'c',
        -                version: '1.0.0'
        -              })
        -            }
        -          }
        -        }
        -      }
        +                version: '1.0.0',
        +              }),
        +            },
        +          },
        +        },
        +      },
             })
         
             // mimics lib/npm.js globalDir getter but pointing to fixtures
        @@ -2314,10 +2322,10 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2326,19 +2334,19 @@ t.test('ls --json', (t) => {
                 {
                   name: 'test-npm-ls',
                   version: '1.0.0',
        -          'dependencies': {
        -            'foo': {
        -              'version': '1.0.0',
        -              'dependencies': {
        -                'bar': {
        -                  'version': '1.0.0'
        -                }
        -              }
        -            },
        -            'lorem': {
        -              'version': '1.0.0'
        -            }
        -          }
        +          dependencies: {
        +            foo: {
        +              version: '1.0.0',
        +              dependencies: {
        +                bar: {
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +            lorem: {
        +              version: '1.0.0',
        +            },
        +          },
                 },
                 'should output json representation of dependencies structure'
               )
        @@ -2348,46 +2356,46 @@ t.test('ls --json', (t) => {
         
           t.test('missing package.json', (t) => {
             prefix = t.testdir({
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems')
               t.deepEqual(
                 jsonParse(result),
                 {
        -          'problems': [
        +          problems: [
                     'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/bar',
                     'extraneous: foo@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/foo',
        -            'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/lorem'
        +            'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/lorem',
                   ],
        -          'dependencies': {
        -            'bar': {
        -              'version': '1.0.0',
        -              'extraneous': true,
        -              'problems': [
        -                'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/bar'
        -              ]
        -            },
        -            'foo': {
        -              'version': '1.0.0',
        -              'extraneous': true,
        -              'problems': [
        -                'extraneous: foo@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/foo'
        +          dependencies: {
        +            bar: {
        +              version: '1.0.0',
        +              extraneous: true,
        +              problems: [
        +                'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/bar',
        +              ],
        +            },
        +            foo: {
        +              version: '1.0.0',
        +              extraneous: true,
        +              problems: [
        +                'extraneous: foo@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/foo',
        +              ],
        +              dependencies: {
        +                bar: {
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +            lorem: {
        +              version: '1.0.0',
        +              extraneous: true,
        +              problems: [
        +                'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/lorem',
                       ],
        -              'dependencies': {
        -                'bar': {
        -                  'version': '1.0.0'
        -                }
        -              }
        -            },
        -            'lorem': {
        -              'version': '1.0.0',
        -              'extraneous': true,
        -              'problems': [
        -                'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/lorem'
        -              ]
        -            }
        -          }
        +            },
        +          },
                 },
                 'should output json missing name/version of top-level package'
               )
        @@ -2401,10 +2409,10 @@ t.test('ls --json', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          foo: '^1.0.0'
        -        }
        +          foo: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.equal(
        @@ -2422,26 +2430,26 @@ t.test('ls --json', (t) => {
                 {
                   name: 'test-npm-ls',
                   version: '1.0.0',
        -          'problems': [
        -            'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-extraneous-deps/node_modules/lorem'
        +          problems: [
        +            'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-extraneous-deps/node_modules/lorem',
                   ],
        -          'dependencies': {
        -            'foo': {
        -              'version': '1.0.0',
        -              'dependencies': {
        -                'bar': {
        -                  'version': '1.0.0'
        -                }
        -              }
        -            },
        -            'lorem': {
        -              'version': '1.0.0',
        -              'extraneous': true,
        -              'problems': [
        -                'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-extraneous-deps/node_modules/lorem'
        -              ]
        -            }
        -          }
        +          dependencies: {
        +            foo: {
        +              version: '1.0.0',
        +              dependencies: {
        +                bar: {
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +            lorem: {
        +              version: '1.0.0',
        +              extraneous: true,
        +              problems: [
        +                'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-extraneous-deps/node_modules/lorem',
        +              ],
        +            },
        +          },
                 },
                 'should output json containing problems info'
               )
        @@ -2456,10 +2464,10 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['lorem'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2468,11 +2476,11 @@ t.test('ls --json', (t) => {
                 {
                   name: 'test-npm-ls',
                   version: '1.0.0',
        -          'dependencies': {
        -            'lorem': {
        -              'version': '1.0.0'
        -            }
        -          }
        +          dependencies: {
        +            lorem: {
        +              version: '1.0.0',
        +            },
        +          },
                 },
                 'should output json contaning only occurences of filtered by package'
               )
        @@ -2492,10 +2500,10 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['bar'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2509,11 +2517,11 @@ t.test('ls --json', (t) => {
                       version: '1.0.0',
                       dependencies: {
                         bar: {
        -                  version: '1.0.0'
        -                }
        -              }
        -            }
        -          }
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +          },
                 },
                 'should output json contaning only occurences of filtered by package'
               )
        @@ -2529,39 +2537,39 @@ t.test('ls --json', (t) => {
                 dependencies: {
                   foo: '^1.0.0',
                   lorem: '^1.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
               node_modules: {
                 ...simpleNmFixture.node_modules,
                 ipsum: {
                   'package.json': JSON.stringify({
                     name: 'ipsum',
        -            version: '1.0.0'
        -          })
        -        }
        -      }
        +            version: '1.0.0',
        +          }),
        +        },
        +      },
             })
             ls(['bar@*', 'lorem@1.0.0'], (err) => {
               t.ifError(err, 'npm ls')
               t.deepEqual(
                 jsonParse(result),
                 {
        -          'version': '1.0.0',
        -          'name': 'test-npm-ls',
        -          'dependencies': {
        -            'foo': {
        -              'version': '1.0.0',
        -              'dependencies': {
        -                'bar': {
        -                  'version': '1.0.0'
        -                }
        -              }
        -            },
        -            'lorem': {
        -              'version': '1.0.0'
        -            }
        -          }
        +          version: '1.0.0',
        +          name: 'test-npm-ls',
        +          dependencies: {
        +            foo: {
        +              version: '1.0.0',
        +              dependencies: {
        +                bar: {
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +            lorem: {
        +              version: '1.0.0',
        +            },
        +          },
                 },
                 'should output json contaning only occurences of multiple filtered packages and their ancestors'
               )
        @@ -2576,10 +2584,10 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls(['notadep'], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2587,7 +2595,7 @@ t.test('ls --json', (t) => {
                 jsonParse(result),
                 {
                   name: 'test-npm-ls',
        -          version: '1.0.0'
        +          version: '1.0.0',
                 },
                 'should output json containing no dependencies info'
               )
        @@ -2610,10 +2618,10 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2622,14 +2630,14 @@ t.test('ls --json', (t) => {
                 {
                   name: 'test-npm-ls',
                   version: '1.0.0',
        -          'dependencies': {
        -            'foo': {
        -              'version': '1.0.0'
        +          dependencies: {
        +            foo: {
        +              version: '1.0.0',
                     },
        -            'lorem': {
        -              'version': '1.0.0'
        -            }
        -          }
        +            lorem: {
        +              version: '1.0.0',
        +            },
        +          },
                 },
                 'should output json containing only top-level dependencies'
               )
        @@ -2648,10 +2656,10 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2660,14 +2668,14 @@ t.test('ls --json', (t) => {
                 {
                   name: 'test-npm-ls',
                   version: '1.0.0',
        -          'dependencies': {
        -            'foo': {
        -              'version': '1.0.0'
        +          dependencies: {
        +            foo: {
        +              version: '1.0.0',
                     },
        -            'lorem': {
        -              'version': '1.0.0'
        -            }
        -          }
        +            lorem: {
        +              version: '1.0.0',
        +            },
        +          },
                 },
                 'should output json containing only top-level dependencies'
               )
        @@ -2686,10 +2694,10 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^1.0.0',
        -          lorem: '^1.0.0'
        -        }
        +          lorem: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.ifError(err, 'npm ls')
        @@ -2698,19 +2706,19 @@ t.test('ls --json', (t) => {
                 {
                   name: 'test-npm-ls',
                   version: '1.0.0',
        -          'dependencies': {
        -            'foo': {
        -              'version': '1.0.0',
        -              'dependencies': {
        -                'bar': {
        -                  'version': '1.0.0'
        -                }
        -              }
        -            },
        -            'lorem': {
        -              'version': '1.0.0'
        -            }
        -          }
        +          dependencies: {
        +            foo: {
        +              version: '1.0.0',
        +              dependencies: {
        +                bar: {
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +            lorem: {
        +              version: '1.0.0',
        +            },
        +          },
                 },
                 'should output json containing top-level deps and their deps only'
               )
        @@ -2727,51 +2735,51 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   foo: '^2.0.0',
        -          ipsum: '^1.0.0'
        -        }
        +          ipsum: '^1.0.0',
        +        },
               }),
        -      ...simpleNmFixture
        +      ...simpleNmFixture,
             })
             ls([], (err) => {
               t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems')
               t.deepEqual(
                 jsonParse(result),
                 {
        -          'name': 'test-npm-ls',
        -          'version': '1.0.0',
        -          'problems': [
        +          name: 'test-npm-ls',
        +          version: '1.0.0',
        +          problems: [
                     'invalid: foo@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/foo',
                     'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
        -            'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/lorem'
        +            'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/lorem',
                   ],
        -          'dependencies': {
        -            'foo': {
        -              'version': '1.0.0',
        -              'invalid': true,
        -              'problems': [
        -                'invalid: foo@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/foo'
        +          dependencies: {
        +            foo: {
        +              version: '1.0.0',
        +              invalid: true,
        +              problems: [
        +                'invalid: foo@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/foo',
        +              ],
        +              dependencies: {
        +                bar: {
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +            lorem: {
        +              version: '1.0.0',
        +              extraneous: true,
        +              problems: [
        +                'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/lorem',
        +              ],
        +            },
        +            ipsum: {
        +              required: '^1.0.0',
        +              missing: true,
        +              problems: [
        +                'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
                       ],
        -              'dependencies': {
        -                'bar': {
        -                  'version': '1.0.0'
        -                }
        -              }
        -            },
        -            'lorem': {
        -              'version': '1.0.0',
        -              'extraneous': true,
        -              'problems': [
        -                'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/lorem'
        -              ]
        -            },
        -            'ipsum': {
        -              'required': '^1.0.0',
        -              'missing': true,
        -              'problems': [
        -                'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'
        -              ]
        -            }
        -          }
        +            },
        +          },
                 },
                 'should output json containing top-level deps and their deps only'
               )
        @@ -2787,19 +2795,19 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.deepEqual(
        @@ -2813,11 +2821,11 @@ t.test('ls --json', (t) => {
                       dependencies: {
                         foo: {
                           version: '1.0.0',
        -                  dependencies: { bar: { version: '1.0.0' } }
        -                }
        -              }
        -            }
        -          }
        +                  dependencies: { bar: { version: '1.0.0' } },
        +                },
        +              },
        +            },
        +          },
                 },
                 'should output json containing dev deps'
               )
        @@ -2834,19 +2842,19 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.deepEqual(
        @@ -2860,11 +2868,11 @@ t.test('ls --json', (t) => {
                       dependencies: {
                         foo: {
                           version: '1.0.0',
        -                  dependencies: { bar: { version: '1.0.0' } }
        -                }
        -              }
        -            }
        -          }
        +                  dependencies: { bar: { version: '1.0.0' } },
        +                },
        +              },
        +            },
        +          },
                 },
                 'should output json containing only development deps'
               )
        @@ -2881,29 +2889,29 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0',
        -          'linked-dep': '^1.0.0'
        +          lorem: '^1.0.0',
        +          'linked-dep': '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
               'linked-dep': {
                 'package.json': JSON.stringify({
                   name: 'linked-dep',
        -          version: '1.0.0'
        -        })
        +          version: '1.0.0',
        +        }),
               },
               node_modules: {
                 'linked-dep': t.fixture('symlink', '../linked-dep'),
        -        ...diffDepTypesNmFixture.node_modules
        -      }
        +        ...diffDepTypesNmFixture.node_modules,
        +      },
             })
             ls([], () => {
               t.deepEqual(
        @@ -2914,9 +2922,9 @@ t.test('ls --json', (t) => {
                   dependencies: {
                     'linked-dep': {
                       version: '1.0.0',
        -              resolved: 'file:../linked-dep'
        -            }
        -          }
        +              resolved: 'file:../linked-dep',
        +            },
        +          },
                 },
                 'should output json containing linked deps'
               )
        @@ -2933,19 +2941,19 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.deepEqual(
        @@ -2956,8 +2964,8 @@ t.test('ls --json', (t) => {
                   dependencies: {
                     lorem: { version: '1.0.0' },
                     'optional-dep': { version: '1.0.0' },
        -            'prod-dep': { version: '1.0.0', dependencies: { bar: { version: '2.0.0' } } }
        -          }
        +            'prod-dep': { version: '1.0.0', dependencies: { bar: { version: '2.0.0' } } },
        +          },
                 },
                 'should output json containing production deps'
               )
        @@ -2974,19 +2982,19 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.deepEqual(
        @@ -2997,8 +3005,8 @@ t.test('ls --json', (t) => {
                   dependencies: {
                     lorem: { version: '1.0.0' },
                     'optional-dep': { version: '1.0.0' },
        -            'prod-dep': { version: '1.0.0', dependencies: { bar: { version: '2.0.0' } } }
        -          }
        +            'prod-dep': { version: '1.0.0', dependencies: { bar: { version: '2.0.0' } } },
        +          },
                 },
                 'should output json containing only prod deps'
               )
        @@ -3014,121 +3022,121 @@ t.test('ls --json', (t) => {
                   'dedupe-tests-a': {
                     'package.json': JSON.stringify({
                       name: '@isaacs/dedupe-tests-a',
        -              version: '1.0.1'
        +              version: '1.0.1',
                     }),
                     node_modules: {
                       '@isaacs': {
                         'dedupe-tests-b': {
                           name: '@isaacs/dedupe-tests-b',
        -                  version: '1.0.0'
        -                }
        -              }
        -            }
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
                   },
                   'dedupe-tests-b': {
                     'package.json': JSON.stringify({
                       name: '@isaacs/dedupe-tests-b',
        -              version: '2.0.0'
        -            })
        -          }
        -        }
        +              version: '2.0.0',
        +            }),
        +          },
        +        },
               },
               'package-lock.json': JSON.stringify({
        -        'name': 'dedupe-lockfile',
        -        'version': '1.0.0',
        -        'lockfileVersion': 2,
        -        'requires': true,
        -        'packages': {
        +        name: 'dedupe-lockfile',
        +        version: '1.0.0',
        +        lockfileVersion: 2,
        +        requires: true,
        +        packages: {
                   '': {
        -            'name': 'dedupe-lockfile',
        -            'version': '1.0.0',
        -            'dependencies': {
        +            name: 'dedupe-lockfile',
        +            version: '1.0.0',
        +            dependencies: {
                       '@isaacs/dedupe-tests-a': '1.0.1',
        -              '@isaacs/dedupe-tests-b': '1||2'
        -            }
        +              '@isaacs/dedupe-tests-b': '1||2',
        +            },
                   },
                   'node_modules/@isaacs/dedupe-tests-a': {
        -            'name': '@isaacs/dedupe-tests-a',
        -            'version': '1.0.1',
        -            'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
        -            'integrity': 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
        -            'dependencies': {
        -              '@isaacs/dedupe-tests-b': '1'
        -            }
        +            name: '@isaacs/dedupe-tests-a',
        +            version: '1.0.1',
        +            resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
        +            integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
        +            dependencies: {
        +              '@isaacs/dedupe-tests-b': '1',
        +            },
                   },
                   'node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b': {
        -            'name': '@isaacs/dedupe-tests-b',
        -            'version': '1.0.0',
        -            'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
        -            'integrity': 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w=='
        +            name: '@isaacs/dedupe-tests-b',
        +            version: '1.0.0',
        +            resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
        +            integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==',
                   },
                   'node_modules/@isaacs/dedupe-tests-b': {
        -            'name': '@isaacs/dedupe-tests-b',
        -            'version': '2.0.0',
        -            'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
        -            'integrity': 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA=='
        -          }
        +            name: '@isaacs/dedupe-tests-b',
        +            version: '2.0.0',
        +            resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
        +            integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==',
        +          },
                 },
        -        'dependencies': {
        +        dependencies: {
                   '@isaacs/dedupe-tests-a': {
        -            'version': '1.0.1',
        -            'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
        -            'integrity': 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
        -            'requires': {
        -              '@isaacs/dedupe-tests-b': '1'
        +            version: '1.0.1',
        +            resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
        +            integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
        +            requires: {
        +              '@isaacs/dedupe-tests-b': '1',
                     },
        -            'dependencies': {
        +            dependencies: {
                       '@isaacs/dedupe-tests-b': {
        -                'version': '1.0.0',
        -                'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
        -                'integrity': 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w=='
        -              }
        -            }
        +                version: '1.0.0',
        +                resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
        +                integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==',
        +              },
        +            },
                   },
                   '@isaacs/dedupe-tests-b': {
        -            'version': '2.0.0',
        -            'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
        -            'integrity': 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA=='
        -          }
        -        }
        +            version: '2.0.0',
        +            resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
        +            integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==',
        +          },
        +        },
               }),
               'package.json': JSON.stringify({
        -        'name': 'dedupe-lockfile',
        -        'version': '1.0.0',
        -        'dependencies': {
        +        name: 'dedupe-lockfile',
        +        version: '1.0.0',
        +        dependencies: {
                   '@isaacs/dedupe-tests-a': '1.0.1',
        -          '@isaacs/dedupe-tests-b': '1||2'
        -        }
        -      })
        +          '@isaacs/dedupe-tests-b': '1||2',
        +        },
        +      }),
             })
             ls([], () => {
               t.deepEqual(
                 jsonParse(result),
                 {
        -          'version': '1.0.0',
        -          'name': 'dedupe-lockfile',
        -          'dependencies': {
        +          version: '1.0.0',
        +          name: 'dedupe-lockfile',
        +          dependencies: {
                     '@isaacs/dedupe-tests-a': {
        -              'version': '1.0.1',
        -              'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
        -              'dependencies': {
        +              version: '1.0.1',
        +              resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
        +              dependencies: {
                         '@isaacs/dedupe-tests-b': {
        -                  'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
        -                  'extraneous': true,
        -                  'problems': [
        -                    'extraneous: @isaacs/dedupe-tests-b@ {CWD}/ls-ls-json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b'
        -                  ]
        -                }
        -              }
        +                  resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
        +                  extraneous: true,
        +                  problems: [
        +                    'extraneous: @isaacs/dedupe-tests-b@ {CWD}/ls-ls-json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b',
        +                  ],
        +                },
        +              },
                     },
                     '@isaacs/dedupe-tests-b': {
        -              'version': '2.0.0',
        -              'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz'
        -            }
        +              version: '2.0.0',
        +              resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
        +            },
                   },
        -          'problems': [
        -            'extraneous: @isaacs/dedupe-tests-b@ {CWD}/ls-ls-json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b'
        -          ]
        +          problems: [
        +            'extraneous: @isaacs/dedupe-tests-b@ {CWD}/ls-ls-json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b',
        +          ],
                 },
                 'should output json containing only prod deps'
               )
        @@ -3144,19 +3152,19 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.deepEqual(
        @@ -3174,7 +3182,7 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: {},
                       path: '{CWD}/ls-ls-json--long/node_modules/peer-dep',
        -              extraneous: false
        +              extraneous: false,
                     },
                     'dev-dep': {
                       name: 'dev-dep',
        @@ -3193,23 +3201,23 @@ t.test('ls --json', (t) => {
                               peerDependencies: {},
                               _dependencies: {},
                               path: '{CWD}/ls-ls-json--long/node_modules/bar',
        -                      extraneous: false
        -                    }
        +                      extraneous: false,
        +                    },
                           },
                           _id: 'foo@1.0.0',
                           devDependencies: {},
                           peerDependencies: {},
                           _dependencies: { bar: '^1.0.0' },
                           path: '{CWD}/ls-ls-json--long/node_modules/foo',
        -                  extraneous: false
        -                }
        +                  extraneous: false,
        +                },
                       },
                       _id: 'dev-dep@1.0.0',
                       devDependencies: {},
                       peerDependencies: {},
                       _dependencies: { foo: '^1.0.0' },
                       path: '{CWD}/ls-ls-json--long/node_modules/dev-dep',
        -              extraneous: false
        +              extraneous: false,
                     },
                     lorem: {
                       name: 'lorem',
        @@ -3219,7 +3227,7 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: {},
                       path: '{CWD}/ls-ls-json--long/node_modules/lorem',
        -              extraneous: false
        +              extraneous: false,
                     },
                     'optional-dep': {
                       name: 'optional-dep',
        @@ -3230,7 +3238,7 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: {},
                       path: '{CWD}/ls-ls-json--long/node_modules/optional-dep',
        -              extraneous: false
        +              extraneous: false,
                     },
                     'prod-dep': {
                       name: 'prod-dep',
        @@ -3246,16 +3254,16 @@ t.test('ls --json', (t) => {
                           peerDependencies: {},
                           _dependencies: {},
                           path: '{CWD}/ls-ls-json--long/node_modules/prod-dep/node_modules/bar',
        -                  extraneous: false
        -                }
        +                  extraneous: false,
        +                },
                       },
                       _id: 'prod-dep@1.0.0',
                       devDependencies: {},
                       peerDependencies: {},
                       _dependencies: { bar: '^2.0.0' },
                       path: '{CWD}/ls-ls-json--long/node_modules/prod-dep',
        -              extraneous: false
        -            }
        +              extraneous: false,
        +            },
                   },
                   devDependencies: { 'dev-dep': '^1.0.0' },
                   optionalDependencies: { 'optional-dep': '^1.0.0' },
        @@ -3263,7 +3271,7 @@ t.test('ls --json', (t) => {
                   _id: 'test-npm-ls@1.0.0',
                   _dependencies: { 'prod-dep': '^1.0.0', lorem: '^1.0.0', 'optional-dep': '^1.0.0' },
                   path: '{CWD}/ls-ls-json--long',
        -          extraneous: false
        +          extraneous: false,
                 },
                 'should output long json info'
               )
        @@ -3282,19 +3290,19 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], () => {
               t.deepEqual(
        @@ -3312,7 +3320,7 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: {},
                       path: '{CWD}/ls-ls-json--long-depth-0/node_modules/peer-dep',
        -              extraneous: false
        +              extraneous: false,
                     },
                     'dev-dep': {
                       name: 'dev-dep',
        @@ -3323,7 +3331,7 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: { foo: '^1.0.0' },
                       path: '{CWD}/ls-ls-json--long-depth-0/node_modules/dev-dep',
        -              extraneous: false
        +              extraneous: false,
                     },
                     lorem: {
                       name: 'lorem',
        @@ -3333,7 +3341,7 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: {},
                       path: '{CWD}/ls-ls-json--long-depth-0/node_modules/lorem',
        -              extraneous: false
        +              extraneous: false,
                     },
                     'optional-dep': {
                       name: 'optional-dep',
        @@ -3344,7 +3352,7 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: {},
                       path: '{CWD}/ls-ls-json--long-depth-0/node_modules/optional-dep',
        -              extraneous: false
        +              extraneous: false,
                     },
                     'prod-dep': {
                       name: 'prod-dep',
        @@ -3355,8 +3363,8 @@ t.test('ls --json', (t) => {
                       peerDependencies: {},
                       _dependencies: { bar: '^2.0.0' },
                       path: '{CWD}/ls-ls-json--long-depth-0/node_modules/prod-dep',
        -              extraneous: false
        -            }
        +              extraneous: false,
        +            },
                   },
                   devDependencies: { 'dev-dep': '^1.0.0' },
                   optionalDependencies: { 'optional-dep': '^1.0.0' },
        @@ -3364,7 +3372,7 @@ t.test('ls --json', (t) => {
                   _id: 'test-npm-ls@1.0.0',
                   _dependencies: { 'prod-dep': '^1.0.0', lorem: '^1.0.0', 'optional-dep': '^1.0.0' },
                   path: '{CWD}/ls-ls-json--long-depth-0',
        -          extraneous: false
        +          extraneous: false,
                 },
                 'should output json containing top-level deps in long format'
               )
        @@ -3377,7 +3385,7 @@ t.test('ls --json', (t) => {
         
           t.test('json read problems', (t) => {
             prefix = t.testdir({
        -      'package.json': '{broken json'
        +      'package.json': '{broken json',
             })
             ls([], (err) => {
               t.match(err.message, 'Failed to parse root package.json', 'should have missin root package.json msg')
        @@ -3387,8 +3395,8 @@ t.test('ls --json', (t) => {
                 {
                   invalid: true,
                   problems: [
        -            'error in {CWD}/ls-ls-json-json-read-problems: Failed to parse root package.json'
        -          ]
        +            'error in {CWD}/ls-ls-json-json-read-problems: Failed to parse root package.json',
        +          ],
                 },
                 'should print empty json result'
               )
        @@ -3416,19 +3424,19 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
        -          'optional-dep': '^1.0.0'
        +          'optional-dep': '^1.0.0',
                 },
                 peerDependencies: {
        -          'peer-dep': '^2.0.0' // mismatching version #
        -        }
        +          'peer-dep': '^2.0.0', // mismatching version #
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'Should have ELSPROBLEMS error code')
        @@ -3438,29 +3446,29 @@ t.test('ls --json', (t) => {
                   name: 'test-npm-ls',
                   version: '1.0.0',
                   problems: [
        -            'invalid: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-peer-dep/node_modules/peer-dep'
        +            'invalid: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-peer-dep/node_modules/peer-dep',
                   ],
                   dependencies: {
                     'peer-dep': {
                       version: '1.0.0',
                       invalid: true,
                       problems: [
        -                'invalid: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-peer-dep/node_modules/peer-dep'
        -              ]
        +                'invalid: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-peer-dep/node_modules/peer-dep',
        +              ],
                     },
                     'dev-dep': {
                       version: '1.0.0',
                       dependencies: {
                         foo: {
                           version: '1.0.0',
        -                  dependencies: { bar: { version: '1.0.0' } }
        -                }
        -              }
        +                  dependencies: { bar: { version: '1.0.0' } },
        +                },
        +              },
                     },
                     lorem: { version: '1.0.0' },
                     'optional-dep': { version: '1.0.0' },
        -            'prod-dep': { version: '1.0.0', dependencies: { bar: { version: '2.0.0' } } }
        -          }
        +            'prod-dep': { version: '1.0.0', dependencies: { bar: { version: '2.0.0' } } },
        +          },
                 },
                 'should output json signaling missing peer dep in problems'
               )
        @@ -3475,20 +3483,20 @@ t.test('ls --json', (t) => {
                 version: '1.0.0',
                 dependencies: {
                   'prod-dep': '^1.0.0',
        -          'lorem': '^1.0.0'
        +          lorem: '^1.0.0',
                 },
                 devDependencies: {
        -          'dev-dep': '^1.0.0'
        +          'dev-dep': '^1.0.0',
                 },
                 optionalDependencies: {
                   'missing-optional-dep': '^1.0.0',
        -          'optional-dep': '^2.0.0' // mismatching version #
        +          'optional-dep': '^2.0.0', // mismatching version #
                 },
                 peerDependencies: {
        -          'peer-dep': '^1.0.0'
        -        }
        +          'peer-dep': '^1.0.0',
        +        },
               }),
        -      ...diffDepTypesNmFixture
        +      ...diffDepTypesNmFixture,
             })
             ls([], (err) => {
               t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
        @@ -3499,32 +3507,32 @@ t.test('ls --json', (t) => {
                   name: 'test-npm-ls',
                   version: '1.0.0',
                   problems: [
        -            'invalid: optional-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/optional-dep' // mismatching optional deps get flagged in problems
        +            'invalid: optional-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/optional-dep', // mismatching optional deps get flagged in problems
                   ],
                   dependencies: {
                     'optional-dep': {
                       version: '1.0.0',
                       invalid: true,
                       problems: [
        -                'invalid: optional-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/optional-dep'
        -              ]
        +                'invalid: optional-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/optional-dep',
        +              ],
                     },
                     'peer-dep': {
        -              version: '1.0.0'
        +              version: '1.0.0',
                     },
                     'dev-dep': {
                       version: '1.0.0',
                       dependencies: {
                         foo: {
                           version: '1.0.0',
        -                  dependencies: { bar: { version: '1.0.0' } }
        -                }
        -              }
        +                  dependencies: { bar: { version: '1.0.0' } },
        +                },
        +              },
                     },
                     lorem: { version: '1.0.0' },
                     'prod-dep': { version: '1.0.0', dependencies: { bar: { version: '2.0.0' } } },
        -            'missing-optional-dep': {} // missing optional dep has an empty entry in json output
        -          }
        +            'missing-optional-dep': {}, // missing optional dep has an empty entry in json output
        +          },
                 },
                 'should output json with empty entry for missing optional deps'
               )
        @@ -3538,29 +3546,29 @@ t.test('ls --json', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'a': '^1.0.0'
        -        }
        +          a: '^1.0.0',
        +        },
               }),
               node_modules: {
        -        'a': {
        +        a: {
                   'package.json': JSON.stringify({
                     name: 'a',
                     version: '1.0.0',
                     dependencies: {
        -              b: '^1.0.0'
        -            }
        -          })
        +              b: '^1.0.0',
        +            },
        +          }),
                 },
        -        'b': {
        +        b: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     dependencies: {
        -              a: '^1.0.0'
        -            }
        -          })
        -        }
        -      }
        +              a: '^1.0.0',
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.deepEqual(
        @@ -3575,12 +3583,12 @@ t.test('ls --json', (t) => {
                         b: {
                           version: '1.0.0',
                           dependencies: {
        -                    a: { version: '1.0.0' }
        -                  }
        -                }
        -              }
        -            }
        -          }
        +                    a: { version: '1.0.0' },
        +                  },
        +                },
        +              },
        +            },
        +          },
                 },
                 'should print json output containing deduped ref'
               )
        @@ -3594,22 +3602,22 @@ t.test('ls --json', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          a: 'npm:b@1.0.0'
        -        }
        +          a: 'npm:b@1.0.0',
        +        },
               }),
               node_modules: {
        -        'a': {
        +        a: {
                   'package.json': JSON.stringify({
                     name: 'b',
                     version: '1.0.0',
                     _from: 'a@npm:b',
                     _resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
                     _requested: {
        -              type: 'alias'
        -            }
        -          })
        -        }
        -      }
        +              type: 'alias',
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.deepEqual(
        @@ -3620,9 +3628,9 @@ t.test('ls --json', (t) => {
                   dependencies: {
                     a: {
                       version: '1.0.0',
        -              resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz'
        -            }
        -          }
        +              resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
        +            },
        +          },
                 },
                 'should output json containing aliases'
               )
        @@ -3636,11 +3644,11 @@ t.test('ls --json', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'abbrev': 'git+https://github.com/isaacs/abbrev-js.git'
        -        }
        +          abbrev: 'git+https://github.com/isaacs/abbrev-js.git',
        +        },
               }),
               node_modules: {
        -        'abbrev': {
        +        abbrev: {
                   'package.json': JSON.stringify({
                     name: 'abbrev',
                     version: '1.1.1',
        @@ -3653,11 +3661,11 @@ t.test('ls --json', (t) => {
                       rawSpec: 'git+https:github.com/isaacs/abbrev-js.git',
                       saveSpec: 'git+https://github.com/isaacs/abbrev-js.git',
                       fetchSpec: 'https://github.com/isaacs/abbrev-js.git',
        -              gitCommittish: null
        -            }
        -          })
        -        }
        -      }
        +              gitCommittish: null,
        +            },
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.deepEqual(
        @@ -3668,9 +3676,9 @@ t.test('ls --json', (t) => {
                   dependencies: {
                     abbrev: {
                       version: '1.1.1',
        -              resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c'
        -            }
        -          }
        +              resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
        +            },
        +          },
                 },
                 'should output json containing git refs'
               )
        @@ -3684,8 +3692,8 @@ t.test('ls --json', (t) => {
                 name: 'test-npm-ls',
                 version: '1.0.0',
                 dependencies: {
        -          'simple-output': '^2.0.0'
        -        }
        +          'simple-output': '^2.0.0',
        +        },
               }),
               node_modules: {
                 'simple-output': {
        @@ -3703,17 +3711,17 @@ t.test('ls --json', (t) => {
                       escapedName: 'simple-output',
                       rawSpec: '',
                       saveSpec: null,
        -              fetchSpec: 'latest'
        +              fetchSpec: 'latest',
                     },
                     _requiredBy: [
                       '#USER',
        -              '/'
        +              '/',
                     ],
                     _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
        -            _spec: 'simple-output'
        -          })
        -        }
        -      }
        +            _spec: 'simple-output',
        +          }),
        +        },
        +      },
             })
             ls([], () => {
               t.deepEqual(
        @@ -3724,9 +3732,9 @@ t.test('ls --json', (t) => {
                   dependencies: {
                     'simple-output': {
                       version: '2.1.1',
        -              resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz'
        -            }
        -          }
        +              resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
        +            },
        +          },
                 },
                 'should be printed in json output'
               )
        @@ -3737,15 +3745,15 @@ t.test('ls --json', (t) => {
           t.test('node.name fallback if missing root package name', (t) => {
             prefix = t.testdir({
               'package.json': JSON.stringify({
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             })
             ls([], () => {
               t.deepEqual(
                 jsonParse(result),
                 {
        -          'version': '1.0.0',
        -          'name': 'ls-ls-json-node-name-fallback-if-missing-root-package-name'
        +          version: '1.0.0',
        +          name: 'ls-ls-json-node-name-fallback-if-missing-root-package-name',
                 },
                 'should use node.name as key in json result obj'
               )
        @@ -3760,24 +3768,24 @@ t.test('ls --json', (t) => {
                 a: {
                   'package.json': JSON.stringify({
                     name: 'a',
        -            version: '1.0.0'
        -          })
        +            version: '1.0.0',
        +          }),
                 },
                 b: {
                   'package.json': JSON.stringify({
                     name: 'b',
        -            version: '1.0.0'
        +            version: '1.0.0',
                   }),
                   node_modules: {
                     c: {
                       'package.json': JSON.stringify({
                         name: 'c',
        -                version: '1.0.0'
        -              })
        -            }
        -          }
        -        }
        -      }
        +                version: '1.0.0',
        +              }),
        +            },
        +          },
        +        },
        +      },
             })
         
             // mimics lib/npm.js globalDir getter but pointing to fixtures
        @@ -3787,19 +3795,19 @@ t.test('ls --json', (t) => {
               t.deepEqual(
                 jsonParse(result),
                 {
        -          'dependencies': {
        -            'a': {
        -              'version': '1.0.0'
        -            },
        -            'b': {
        -              'version': '1.0.0',
        -              'dependencies': {
        -                'c': {
        -                  'version': '1.0.0'
        -                }
        -              }
        -            }
        -          }
        +          dependencies: {
        +            a: {
        +              version: '1.0.0',
        +            },
        +            b: {
        +              version: '1.0.0',
        +              dependencies: {
        +                c: {
        +                  version: '1.0.0',
        +                },
        +              },
        +            },
        +          },
                 },
                 'should print json output for global deps'
               )
        diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js
        index b2be5543fa1ea6..0e0adcf1db9376 100644
        --- a/deps/npm/test/lib/npm.js
        +++ b/deps/npm/test/lib/npm.js
        @@ -24,14 +24,14 @@ const actualPlatform = process.platform
         const beWindows = () => {
           Object.defineProperty(process, 'platform', {
             value: 'win32',
        -    configurable: true
        +    configurable: true,
           })
         }
         
         const bePosix = () => {
           Object.defineProperty(process, 'platform', {
             value: 'posix',
        -    configurable: true
        +    configurable: true,
           })
         }
         
        @@ -41,9 +41,9 @@ const npmPath = resolve(__dirname, '..', '..')
         const Config = require('@npmcli/config')
         const { types, defaults, shorthands } = require('../../lib/utils/config.js')
         const freshConfig = (opts = {}) => {
        -  for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) {
        +  for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e)))
             delete process.env[env]
        -  }
        +
           process.env.npm_config_cache = CACHE
         
           npm.config = new Config({
        @@ -52,14 +52,13 @@ const freshConfig = (opts = {}) => {
             shorthands,
             npmPath,
             log: npmlog,
        -    ...opts
        +    ...opts,
           })
         }
         
         const logs = []
        -for (const level of ['silly', 'verbose', 'timing', 'notice', 'warn', 'error']) {
        +for (const level of ['silly', 'verbose', 'timing', 'notice', 'warn', 'error'])
           npmlog[level] = (...msg) => logs.push([level, ...msg])
        -}
         
         const npm = require('../../lib/npm.js')
         
        @@ -73,7 +72,7 @@ t.test('not yet loaded', t => {
             config: {
               loaded: false,
               get: Function,
        -      set: Function
        +      set: Function,
             },
             version: String,
           })
        @@ -103,7 +102,9 @@ t.test('npm.load', t => {
           t.test('load error', t => {
             const { load } = npm.config
             const loadError = new Error('load error')
        -    npm.config.load = async () => { throw loadError }
        +    npm.config.load = async () => {
        +      throw loadError
        +    }
             npm.load(er => {
               t.equal(er, loadError)
               t.equal(npm.loadErr, loadError)
        @@ -120,13 +121,13 @@ t.test('npm.load', t => {
         
           t.test('basic loading', t => {
             const dir = t.testdir({
        -      node_modules: {}
        +      node_modules: {},
             })
             let firstCalled = false
             const first = (er) => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
        +
               firstCalled = true
               t.equal(npm.loaded, true)
               t.equal(npm.config.loaded, true)
        @@ -134,7 +135,9 @@ t.test('npm.load', t => {
             }
         
             let secondCalled = false
        -    const second = () => { secondCalled = true }
        +    const second = () => {
        +      secondCalled = true
        +    }
         
             t.equal(npm.loading, false, 'not loading yet')
             const p = npm.load(first).then(() => {
        @@ -142,16 +145,18 @@ t.test('npm.load', t => {
               t.match(npm, {
                 loaded: true,
                 loading: false,
        -        flatOptions: {}
        +        flatOptions: {},
               })
               t.equal(firstCalled, true, 'first callback got called')
               t.equal(secondCalled, true, 'second callback got called')
               let thirdCalled = false
        -      const third = () => { thirdCalled = true }
        +      const third = () => {
        +        thirdCalled = true
        +      }
               npm.load(third)
               t.equal(thirdCalled, true, 'third callbback got called')
               t.match(logs, [
        -        ['timing', 'npm:load', /Completed in [0-9]+ms/]
        +        ['timing', 'npm:load', /Completed in [0-9]+ms/],
               ])
               logs.length = 0
         
        @@ -216,22 +221,22 @@ t.test('npm.load', t => {
         
           t.test('forceful loading', t => {
             // also, don't get thrown off if argv[0] isn't found for some reason
        -    const [ argv0 ] = process.argv
        +    const [argv0] = process.argv
             t.teardown(() => {
               process.argv[0] = argv0
             })
             freshConfig({ argv: [...process.argv, '--force', '--color', 'always'] })
             process.argv[0] = 'this exe does not exist or else this test will fail'
             return npm.load(er => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
        +
               t.match(logs.filter(l => l[0] !== 'timing'), [
                 [
                   'warn',
                   'using --force',
        -          'Recommended protections disabled.'
        -        ]
        +          'Recommended protections disabled.',
        +        ],
               ])
               logs.length = 0
             })
        @@ -240,7 +245,7 @@ t.test('npm.load', t => {
           t.test('node is a symlink', async t => {
             const node = actualPlatform === 'win32' ? 'node.exe' : 'node'
             const dir = t.testdir({
        -      '.npmrc': 'foo = bar'
        +      '.npmrc': 'foo = bar',
             })
         
             // create manually to set the 'file' option in windows
        @@ -256,7 +261,10 @@ t.test('npm.load', t => {
               '--prefix', dir,
               '--userconfig', `${dir}/.npmrc`,
               '--usage',
        -      '--scope=foo'
        +      '--scope=foo',
        +      'token',
        +      'revoke',
        +      'blergggg',
             ]
         
             freshConfig()
        @@ -276,16 +284,16 @@ t.test('npm.load', t => {
             logs.length = 0
         
             await npm.load(er => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
        +
               t.equal(npm.config.get('scope'), '@foo', 'added the @ sign to scope')
               t.equal(npm.config.get('metrics-registry'), 'http://example.com')
               t.match(logs.filter(l => l[0] !== 'timing' || !/^config:/.test(l[1])), [
                 [
                   'verbose',
                   'node symlink',
        -          resolve(dir, node)
        +          resolve(dir, node),
                 ],
                 [
                   'timing',
        @@ -298,9 +306,9 @@ t.test('npm.load', t => {
             })
         
             await npm.commands.ll([], (er) => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
        +
               t.same(consoleLogs, [[require('../../lib/ls.js').usage]], 'print usage')
               consoleLogs.length = 0
               npm.config.set('usage', false)
        @@ -309,9 +317,9 @@ t.test('npm.load', t => {
             })
         
             await npm.commands.get(['scope', '\u2010not-a-dash'], (er) => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
        +
               t.match(logs, [
                 [
                   'error',
        @@ -353,3 +361,91 @@ t.test('loading as main will load the cli', t => {
             t.end()
           })
         })
        +
        +t.test('set process.title', t => {
        +  const { argv: processArgv } = process
        +  const { log } = console
        +  const titleDesc = Object.getOwnPropertyDescriptor(process, 'title')
        +  Object.defineProperty(process, 'title', {
        +    value: '',
        +    settable: true,
        +    enumerable: true,
        +    configurable: true,
        +  })
        +  const consoleLogs = []
        +  console.log = (...msg) => consoleLogs.push(msg)
        +
        +  t.teardown(() => {
        +    console.log = log
        +    process.argv = processArgv
        +    Object.defineProperty(process, 'title', titleDesc)
        +    freshConfig()
        +  })
        +
        +  t.afterEach(cb => {
        +    consoleLogs.length = 0
        +    cb()
        +  })
        +
        +  t.test('basic title setting', async t => {
        +    freshConfig({
        +      argv: [
        +        process.execPath,
        +        process.argv[1],
        +        '--metrics-registry', 'http://example.com',
        +        '--usage',
        +        '--scope=foo',
        +        'ls',
        +      ],
        +    })
        +    await npm.load(er => {
        +      if (er)
        +        throw er
        +      t.equal(npm.title, 'npm ls')
        +      t.equal(process.title, 'npm ls')
        +    })
        +  })
        +
        +  t.test('do not expose token being revoked', async t => {
        +    freshConfig({
        +      argv: [
        +        process.execPath,
        +        process.argv[1],
        +        '--metrics-registry', 'http://example.com',
        +        '--usage',
        +        '--scope=foo',
        +        'token',
        +        'revoke',
        +        'deadbeefcafebad',
        +      ],
        +    })
        +    await npm.load(er => {
        +      if (er)
        +        throw er
        +      t.equal(npm.title, 'npm token revoke ***')
        +      t.equal(process.title, 'npm token revoke ***')
        +    })
        +  })
        +
        +  t.test('do show *** unless a token is actually being revoked', async t => {
        +    freshConfig({
        +      argv: [
        +        process.execPath,
        +        process.argv[1],
        +        '--metrics-registry', 'http://example.com',
        +        '--usage',
        +        '--scope=foo',
        +        'token',
        +        'revoke',
        +      ],
        +    })
        +    await npm.load(er => {
        +      if (er)
        +        throw er
        +      t.equal(npm.title, 'npm token revoke')
        +      t.equal(process.title, 'npm token revoke')
        +    })
        +  })
        +
        +  t.end()
        +})
        diff --git a/deps/npm/test/lib/outdated.js b/deps/npm/test/lib/outdated.js
        index 0cba04d5471304..7a5bd8f0ef870c 100644
        --- a/deps/npm/test/lib/outdated.js
        +++ b/deps/npm/test/lib/outdated.js
        @@ -6,58 +6,57 @@ const packument = spec => {
             alpha: {
               name: 'alpha',
               'dist-tags': {
        -        latest: '1.0.1'
        +        latest: '1.0.1',
               },
               versions: {
                 '1.0.1': {
                   version: '1.0.1',
                   dependencies: {
        -            gamma: '2.0.0'
        -          }
        -        }
        -      }
        +            gamma: '2.0.0',
        +          },
        +        },
        +      },
             },
             beta: {
               name: 'beta',
               'dist-tags': {
        -        latest: '1.0.1'
        +        latest: '1.0.1',
               },
               versions: {
                 '1.0.1': {
        -          version: '1.0.1'
        -        }
        -      }
        +          version: '1.0.1',
        +        },
        +      },
             },
             gamma: {
               name: 'gamma',
               'dist-tags': {
        -        latest: '2.0.0'
        +        latest: '2.0.0',
               },
               versions: {
                 '1.0.1': {
        -          version: '1.0.1'
        +          version: '1.0.1',
                 },
                 '2.0.0': {
        -          version: '2.0.0'
        -        }
        -      }
        +          version: '2.0.0',
        +        },
        +      },
             },
             theta: {
               name: 'theta',
               'dist-tags': {
        -        latest: '1.0.1'
        +        latest: '1.0.1',
               },
               versions: {
                 '1.0.1': {
        -          version: '1.0.1'
        -        }
        -      }
        -    }
        +          version: '1.0.1',
        +        },
        +      },
        +    },
           }
         
        -  if (spec.name === 'eta') {
        +  if (spec.name === 'eta')
             throw new Error('There is an error with this package.')
        -  }
         
           if (!mocks[spec.name]) {
             const err = new Error()
        @@ -87,10 +86,10 @@ const globalDir = t.testdir({
             alpha: {
               'package.json': JSON.stringify({
                 name: 'alpha',
        -        version: '1.0.0'
        -      }, null, 2)
        -    }
        -  }
        +        version: '1.0.0',
        +      }, null, 2),
        +    },
        +  },
         })
         
         const outdated = (dir, opts) => requireInject(
        @@ -99,11 +98,11 @@ const outdated = (dir, opts) => requireInject(
             '../../lib/npm.js': {
               prefix: dir,
               globalDir: `${globalDir}/node_modules`,
        -      flatOptions: opts
        +      flatOptions: opts,
             },
             pacote: {
        -      packument
        -    }
        +      packument,
        +    },
           }
         )
         
        @@ -127,14 +126,14 @@ t.test('should display outdated deps', t => {
               dependencies: {
                 alpha: '^1.0.0',
                 gamma: '^1.0.0',
        -        theta: '^1.0.0'
        +        theta: '^1.0.0',
               },
               devDependencies: {
        -        zeta: '^1.0.0'
        +        zeta: '^1.0.0',
               },
               peerDependencies: {
        -        beta: '^1.0.0'
        -      }
        +        beta: '^1.0.0',
        +      },
             }, null, 2),
             node_modules: {
               alpha: {
        @@ -142,42 +141,42 @@ t.test('should display outdated deps', t => {
                   name: 'alpha',
                   version: '1.0.0',
                   dependencies: {
        -            gamma: '2.0.0'
        -          }
        +            gamma: '2.0.0',
        +          },
                 }, null, 2),
                 node_modules: {
                   gamma: {
                     'package.json': JSON.stringify({
                       name: 'gamma',
        -              version: '2.0.0'
        -            }, null, 2)
        -          }
        -        }
        +              version: '2.0.0',
        +            }, null, 2),
        +          },
        +        },
               },
               beta: {
                 'package.json': JSON.stringify({
                   name: 'beta',
        -          version: '1.0.0'
        -        }, null, 2)
        +          version: '1.0.0',
        +        }, null, 2),
               },
               gamma: {
                 'package.json': JSON.stringify({
                   name: 'gamma',
        -          version: '1.0.1'
        -        }, null, 2)
        +          version: '1.0.1',
        +        }, null, 2),
               },
               zeta: {
                 'package.json': JSON.stringify({
                   name: 'zeta',
        -          version: '1.0.0'
        -        }, null, 2)
        -      }
        -    }
        +          version: '1.0.0',
        +        }, null, 2),
        +      },
        +    },
           })
         
           t.test('outdated global', t => {
             outdated(null, {
        -      global: true
        +      global: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -187,7 +186,7 @@ t.test('should display outdated deps', t => {
           t.test('outdated', t => {
             outdated(testDir, {
               global: false,
        -      color: true
        +      color: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -198,7 +197,7 @@ t.test('should display outdated deps', t => {
             outdated(testDir, {
               global: false,
               color: true,
        -      omit: ['dev']
        +      omit: ['dev'],
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -209,7 +208,7 @@ t.test('should display outdated deps', t => {
             outdated(testDir, {
               global: false,
               color: true,
        -      omit: ['dev', 'peer']
        +      omit: ['dev', 'peer'],
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -220,7 +219,7 @@ t.test('should display outdated deps', t => {
             outdated(testDir, {
               global: false,
               color: true,
        -      omit: ['prod']
        +      omit: ['prod'],
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -230,7 +229,7 @@ t.test('should display outdated deps', t => {
           t.test('outdated --long', t => {
             outdated(testDir, {
               global: false,
        -      long: true
        +      long: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -240,7 +239,7 @@ t.test('should display outdated deps', t => {
           t.test('outdated --json', t => {
             outdated(testDir, {
               global: false,
        -      json: true
        +      json: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -251,7 +250,7 @@ t.test('should display outdated deps', t => {
             outdated(testDir, {
               global: false,
               json: true,
        -      long: true
        +      long: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -261,7 +260,7 @@ t.test('should display outdated deps', t => {
           t.test('outdated --parseable', t => {
             outdated(testDir, {
               global: false,
        -      parseable: true
        +      parseable: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -272,7 +271,7 @@ t.test('should display outdated deps', t => {
             outdated(testDir, {
               global: false,
               parseable: true,
        -      long: true
        +      long: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -281,7 +280,7 @@ t.test('should display outdated deps', t => {
         
           t.test('outdated --all', t => {
             outdated(testDir, {
        -      all: true
        +      all: true,
             })([], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -290,7 +289,7 @@ t.test('should display outdated deps', t => {
         
           t.test('outdated specific dep', t => {
             outdated(testDir, {
        -      global: false
        +      global: false,
             })(['alpha'], () => {
               t.matchSnapshot(logs)
               t.end()
        @@ -306,21 +305,21 @@ t.test('should return if no outdated deps', t => {
               name: 'delta',
               version: '1.0.0',
               dependencies: {
        -        alpha: '^1.0.0'
        -      }
        +        alpha: '^1.0.0',
        +      },
             }, null, 2),
             node_modules: {
               alpha: {
                 'package.json': JSON.stringify({
                   name: 'alpha',
        -          version: '1.0.1'
        -        }, null, 2)
        -      }
        -    }
        +          version: '1.0.1',
        +        }, null, 2),
        +      },
        +    },
           })
         
           outdated(testDir, {
        -    global: false
        +    global: false,
           })([], () => {
             t.equals(logs.length, 0, 'no logs')
             t.end()
        @@ -333,21 +332,21 @@ t.test('throws if error with a dep', t => {
               name: 'delta',
               version: '1.0.0',
               dependencies: {
        -        eta: '^1.0.0'
        -      }
        +        eta: '^1.0.0',
        +      },
             }, null, 2),
             node_modules: {
               eta: {
                 'package.json': JSON.stringify({
                   name: 'eta',
        -          version: '1.0.1'
        -        }, null, 2)
        -      }
        -    }
        +          version: '1.0.1',
        +        }, null, 2),
        +      },
        +    },
           })
         
           outdated(testDir, {
        -    global: false
        +    global: false,
           })([], (err) => {
             t.equals(err.message, 'There is an error with this package.')
             t.end()
        @@ -360,14 +359,14 @@ t.test('should skip missing non-prod deps', t => {
               name: 'delta',
               version: '1.0.0',
               devDependencies: {
        -        beta: '^1.0.0'
        -      }
        +        beta: '^1.0.0',
        +      },
             }, null, 2),
        -    node_modules: {}
        +    node_modules: {},
           })
         
           outdated(testDir, {
        -    global: false
        +    global: false,
           })([], () => {
             t.equals(logs.length, 0, 'no logs')
             t.end()
        @@ -380,17 +379,17 @@ t.test('should skip invalid pkg ranges', t => {
               name: 'delta',
               version: '1.0.0',
               dependencies: {
        -        alpha: '>=^2'
        -      }
        +        alpha: '>=^2',
        +      },
             }, null, 2),
             node_modules: {
               alpha: {
                 'package.json': JSON.stringify({
                   name: 'alpha',
        -          version: '1.0.0'
        -        }, null, 2)
        -      }
        -    }
        +          version: '1.0.0',
        +        }, null, 2),
        +      },
        +    },
           })
         
           outdated(testDir, {})([], () => {
        @@ -405,17 +404,17 @@ t.test('should skip git specs', t => {
               name: 'delta',
               version: '1.0.0',
               dependencies: {
        -        alpha: 'github:username/foo'
        -      }
        +        alpha: 'github:username/foo',
        +      },
             }, null, 2),
             node_modules: {
               alpha: {
                 'package.json': JSON.stringify({
                   name: 'alpha',
        -          version: '1.0.0'
        -        }, null, 2)
        -      }
        -    }
        +          version: '1.0.0',
        +        }, null, 2),
        +      },
        +    },
           })
         
           outdated(testDir, {})([], () => {
        diff --git a/deps/npm/test/lib/owner.js b/deps/npm/test/lib/owner.js
        index dc179e4662028c..e217533f0de241 100644
        --- a/deps/npm/test/lib/owner.js
        +++ b/deps/npm/test/lib/owner.js
        @@ -16,17 +16,19 @@ const mocks = {
           'npm-registry-fetch': npmFetch,
           pacote,
           '../../lib/npm.js': npm,
        -  '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') },
        +  '../../lib/utils/output.js': (...msg) => {
        +    result += msg.join('\n')
        +  },
           '../../lib/utils/otplease.js': async (opts, fn) => fn({ otp: '123456', opts }),
           '../../lib/utils/read-local-package.js': async () => readLocalPkgResponse,
        -  '../../lib/utils/usage.js': () => 'usage instructions'
        +  '../../lib/utils/usage.js': () => 'usage instructions',
         }
         
         const npmcliMaintainers = [
           { email: 'quitlahok@gmail.com', name: 'nlf' },
           { email: 'ruyadorno@hotmail.com', name: 'ruyadorno' },
           { email: 'darcy@darcyclarke.me', name: 'darcyclarke' },
        -  { email: 'i@izs.me', name: 'isaacs' }
        +  { email: 'i@izs.me', name: 'isaacs' },
         ]
         
         const owner = requireInject('../../lib/owner.js', mocks)
        @@ -59,7 +61,7 @@ t.test('owner ls no args', t => {
               opts,
               {
                 ...npm.flatOptions,
        -        fullMetadata: true
        +        fullMetadata: true,
               },
               'should forward expected options to pacote.packument'
             )
        @@ -132,7 +134,7 @@ t.test('owner ls ', t => {
               opts,
               {
                 ...npm.flatOptions,
        -        fullMetadata: true
        +        fullMetadata: true,
               },
               'should forward expected options to pacote.packument'
             )
        @@ -178,7 +180,7 @@ t.test('owner add  ', t => {
               return {
                 _id: 'org.couchdb.user:foo',
                 email: 'foo@github.com',
        -        name: 'foo'
        +        name: 'foo',
               }
             } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1') {
               t.ok('should put changed owner')
        @@ -187,12 +189,12 @@ t.test('owner add  ', t => {
                 method: 'PUT',
                 body: {
                   _rev: '1-foobaaa1',
        -          maintainers: npmcliMaintainers
        +          maintainers: npmcliMaintainers,
                 },
                 otp: '123456',
                 spec: {
        -          name: '@npmcli/map-workspaces'
        -        }
        +          name: '@npmcli/map-workspaces',
        +        },
               }, 'should use expected opts')
               t.deepEqual(
                 opts.body.maintainers,
        @@ -200,15 +202,14 @@ t.test('owner add  ', t => {
                   ...npmcliMaintainers,
                   {
                     name: 'foo',
        -            email: 'foo@github.com'
        -          }
        +            email: 'foo@github.com',
        +          },
                 ],
                 'should contain expected new owners, adding requested user'
               )
               return {}
        -    } else {
        +    } else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => {
             t.equal(spec.name, '@npmcli/map-workspaces', 'should use expect pkg name')
        @@ -216,13 +217,13 @@ t.test('owner add  ', t => {
               opts,
               {
                 ...npm.flatOptions,
        -        fullMetadata: true
        +        fullMetadata: true,
               },
               'should forward expected options to pacote.packument'
             )
             return {
               _rev: '1-foobaaa1',
        -      maintainers: npmcliMaintainers
        +      maintainers: npmcliMaintainers,
             }
           }
           t.teardown(() => {
        @@ -246,17 +247,16 @@ t.test('owner add  cwd package', t => {
               return {
                 _id: 'org.couchdb.user:foo',
                 email: 'foo@github.com',
        -        name: 'foo'
        +        name: 'foo',
               }
        -    } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1') {
        +    } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1')
               return {}
        -    } else {
        +    else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => ({
             _rev: '1-foobaaa1',
        -    maintainers: npmcliMaintainers
        +    maintainers: npmcliMaintainers,
           })
           t.teardown(() => {
             result = ''
        @@ -290,16 +290,15 @@ t.test('owner add   already an owner', t => {
               return {
                 _id: 'org.couchdb.user:ruyadorno',
                 email: 'ruyadorno@hotmail.com',
        -        name: 'ruyadorno'
        +        name: 'ruyadorno',
               }
        -    } else {
        +    } else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => {
             return {
               _rev: '1-foobaaa1',
        -      maintainers: npmcliMaintainers
        +      maintainers: npmcliMaintainers,
             }
           }
           t.teardown(() => {
        @@ -319,17 +318,16 @@ t.test('owner add   fails to retrieve user', t => {
           readLocalPkgResponse =
           npmFetch.json = async (uri, opts) => {
             // retrieve borked user info from couchdb request
        -    if (uri === '/-/user/org.couchdb.user:foo') {
        +    if (uri === '/-/user/org.couchdb.user:foo')
               return { ok: false }
        -    } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1') {
        +    else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1')
               return {}
        -    } else {
        +    else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => ({
             _rev: '1-foobaaa1',
        -    maintainers: npmcliMaintainers
        +    maintainers: npmcliMaintainers,
           })
           t.teardown(() => {
             result = ''
        @@ -357,22 +355,21 @@ t.test('owner add   fails to PUT updates', t => {
               return {
                 _id: 'org.couchdb.user:foo',
                 email: 'foo@github.com',
        -        name: 'foo'
        +        name: 'foo',
               }
             } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1') {
               return {
                 error: {
                   status: '418',
        -          message: "I'm a teapot"
        -        }
        +          message: "I'm a teapot",
        +        },
               }
        -    } else {
        +    } else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => ({
             _rev: '1-foobaaa1',
        -    maintainers: npmcliMaintainers
        +    maintainers: npmcliMaintainers,
           })
           t.teardown(() => {
             result = ''
        @@ -406,13 +403,12 @@ t.test('owner add   fails to retrieve user info', t => {
                 new Error("I'm a teapot"),
                 { status: 418 }
               )
        -    } else {
        +    } else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => ({
             _rev: '1-foobaaa1',
        -    maintainers: npmcliMaintainers
        +    maintainers: npmcliMaintainers,
           })
           t.teardown(() => {
             result = ''
        @@ -438,18 +434,17 @@ t.test('owner add   no previous maintainers property from server', t
               return {
                 _id: 'org.couchdb.user:foo',
                 email: 'foo@github.com',
        -        name: 'foo'
        +        name: 'foo',
               }
        -    } else if (uri === '/@npmcli%2fno-owners-pkg/-rev/1-foobaaa1') {
        +    } else if (uri === '/@npmcli%2fno-owners-pkg/-rev/1-foobaaa1')
               return {}
        -    } else {
        +    else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => {
             return {
               _rev: '1-foobaaa1',
        -      maintainers: null
        +      maintainers: null,
             }
           }
           t.teardown(() => {
        @@ -509,7 +504,7 @@ t.test('owner rm  ', t => {
               return {
                 _id: 'org.couchdb.user:ruyadorno',
                 email: 'ruyadorno@hotmail.com',
        -        name: 'ruyadorno'
        +        name: 'ruyadorno',
               }
             } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1') {
               t.ok('should put changed owner')
        @@ -517,12 +512,12 @@ t.test('owner rm  ', t => {
                 ...npm.flatOptions,
                 method: 'PUT',
                 body: {
        -          _rev: '1-foobaaa1'
        +          _rev: '1-foobaaa1',
                 },
                 otp: '123456',
                 spec: {
        -          name: '@npmcli/map-workspaces'
        -        }
        +          name: '@npmcli/map-workspaces',
        +        },
               }, 'should use expected opts')
               t.deepEqual(
                 opts.body.maintainers,
        @@ -530,9 +525,8 @@ t.test('owner rm  ', t => {
                 'should contain expected new owners, removing requested user'
               )
               return {}
        -    } else {
        +    } else
               t.fail(`unexpected fetch json call to: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => {
             t.equal(spec.name, '@npmcli/map-workspaces', 'should use expect pkg name')
        @@ -540,13 +534,13 @@ t.test('owner rm  ', t => {
               opts,
               {
                 ...npm.flatOptions,
        -        fullMetadata: true
        +        fullMetadata: true,
               },
               'should forward expected options to pacote.packument'
             )
             return {
               _rev: '1-foobaaa1',
        -      maintainers: npmcliMaintainers
        +      maintainers: npmcliMaintainers,
             }
           }
           t.teardown(() => {
        @@ -575,18 +569,17 @@ t.test('owner rm   not a current owner', t => {
               return {
                 _id: 'org.couchdb.user:foo',
                 email: 'foo@github.com',
        -        name: 'foo'
        +        name: 'foo',
               }
        -    } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1') {
        +    } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1')
               return {}
        -    } else {
        +    else
               t.fail(`unexpected fetch json call to: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => {
             return {
               _rev: '1-foobaaa1',
        -      maintainers: npmcliMaintainers
        +      maintainers: npmcliMaintainers,
             }
           }
           t.teardown(() => {
        @@ -610,17 +603,16 @@ t.test('owner rm  cwd package', t => {
               return {
                 _id: 'org.couchdb.user:ruyadorno',
                 email: 'ruyadorno@hotmail.com',
        -        name: 'ruyadorno'
        +        name: 'ruyadorno',
               }
        -    } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1') {
        +    } else if (uri === '/@npmcli%2fmap-workspaces/-rev/1-foobaaa1')
               return {}
        -    } else {
        +    else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => ({
             _rev: '1-foobaaa1',
        -    maintainers: npmcliMaintainers
        +    maintainers: npmcliMaintainers,
           })
           t.teardown(() => {
             result = ''
        @@ -645,18 +637,17 @@ t.test('owner rm  only user', t => {
               return {
                 _id: 'org.couchdb.user:ruyadorno',
                 email: 'ruyadorno@hotmail.com',
        -        name: 'ruyadorno'
        +        name: 'ruyadorno',
               }
        -    } else {
        +    } else
               t.fail(`unexpected fetch json call to uri: ${uri}`)
        -    }
           }
           pacote.packument = async (spec, opts) => ({
             _rev: '1-foobaaa1',
             maintainers: [{
               name: 'ruyadorno',
        -      email: 'ruyadorno@hotmail.com'
        -    }]
        +      email: 'ruyadorno@hotmail.com',
        +    }],
           })
           t.teardown(() => {
             result = ''
        @@ -722,7 +713,7 @@ t.test('completion', t => {
           testComp(['npm', 'owner'], [
             'add',
             'rm',
        -    'ls'
        +    'ls',
           ])
           testComp(['npm', 'owner', 'add'], [])
           testComp(['npm', 'owner', 'ls'], [])
        @@ -735,7 +726,7 @@ t.test('completion', t => {
             pacote.packument = async spec => {
               t.equal(spec.name, readLocalPkgResponse, 'should use package spec')
               return {
        -        maintainers: npmcliMaintainers
        +        maintainers: npmcliMaintainers,
               }
             }
             t.teardown(() => {
        @@ -751,7 +742,7 @@ t.test('completion', t => {
                   'nlf',
                   'ruyadorno',
                   'darcyclarke',
        -          'isaacs'
        +          'isaacs',
                 ],
                 'should return list of current owners'
               )
        @@ -772,7 +763,7 @@ t.test('completion', t => {
             pacote.packument = async spec => {
               t.equal(spec.name, readLocalPkgResponse, 'should use package spec')
               return {
        -        maintainers: []
        +        maintainers: [],
               }
             }
             t.teardown(() => {
        diff --git a/deps/npm/test/lib/pack.js b/deps/npm/test/lib/pack.js
        index 097204ea92bea3..851174d259cb35 100644
        --- a/deps/npm/test/lib/pack.js
        +++ b/deps/npm/test/lib/pack.js
        @@ -4,11 +4,10 @@ const requireInject = require('require-inject')
         const OUTPUT = []
         const output = (...msg) => OUTPUT.push(msg)
         
        -const libnpmpackActual = require('libnpmpack')
         const libnpmpack = async (spec, opts) => {
        - if (!opts) {
        +  if (!opts)
             throw new Error('expected options object')
        -  }
        +
           return ''
         }
         
        @@ -24,21 +23,21 @@ t.test('should pack current directory with no arguments', (t) => {
               flatOptions: {
                 unicode: false,
                 json: false,
        -        dryRun: false
        -      }
        +        dryRun: false,
        +      },
             },
             libnpmpack,
             npmlog: {
               notice: () => {},
               showProgress: () => {},
        -      clearProgress: () => {}
        -    }
        +      clearProgress: () => {},
        +    },
           })
         
           return pack([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             const filename = `npm-${require('../../package.json').version}.tgz`
             t.strictSame(OUTPUT, [[filename]])
           })
        @@ -48,8 +47,8 @@ t.test('should pack given directory', (t) => {
           const testDir = t.testdir({
             'package.json': JSON.stringify({
               name: 'my-cool-pkg',
        -      version: '1.0.0'
        -    }, null, 2)
        +      version: '1.0.0',
        +    }, null, 2),
           })
         
           const pack = requireInject('../../lib/pack.js', {
        @@ -58,21 +57,21 @@ t.test('should pack given directory', (t) => {
               flatOptions: {
                 unicode: true,
                 json: true,
        -        dryRun: true
        -      }
        +        dryRun: true,
        +      },
             },
             libnpmpack,
             npmlog: {
               notice: () => {},
        -      'showProgress': () => {},
        -      'clearProgress': () => {}
        -    }
        +      showProgress: () => {},
        +      clearProgress: () => {},
        +    },
           })
         
           return pack([testDir], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             const filename = 'my-cool-pkg-1.0.0.tgz'
             t.strictSame(OUTPUT, [[filename]])
           })
        @@ -82,8 +81,8 @@ t.test('should pack given directory for scoped package', (t) => {
           const testDir = t.testdir({
             'package.json': JSON.stringify({
               name: '@cool/my-pkg',
        -      version: '1.0.0'
        -    }, null, 2)
        +      version: '1.0.0',
        +    }, null, 2),
           })
         
           const pack = requireInject('../../lib/pack.js', {
        @@ -92,21 +91,21 @@ t.test('should pack given directory for scoped package', (t) => {
               flatOptions: {
                 unicode: true,
                 json: true,
        -        dryRun: true
        -      }
        +        dryRun: true,
        +      },
             },
             libnpmpack,
             npmlog: {
               notice: () => {},
        -      'showProgress': () => {},
        -      'clearProgress': () => {}
        -    }
        +      showProgress: () => {},
        +      clearProgress: () => {},
        +    },
           })
         
           return pack([testDir], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             const filename = 'cool-my-pkg-1.0.0.tgz'
             t.strictSame(OUTPUT, [[filename]])
           })
        @@ -119,27 +118,27 @@ t.test('should log pack contents', (t) => {
               ...require('../../lib/utils/tar.js'),
               logTar: () => {
                 t.ok(true, 'logTar is called')
        -      } 
        +      },
             },
             '../../lib/npm.js': {
               flatOptions: {
                 unicode: false,
                 json: false,
        -        dryRun: false
        -      }
        +        dryRun: false,
        +      },
             },
             libnpmpack,
             npmlog: {
               notice: () => {},
        -      'showProgress': () => {},
        -      'clearProgress': () => {}
        -    }
        +      showProgress: () => {},
        +      clearProgress: () => {},
        +    },
           })
         
           return pack([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             const filename = `npm-${require('../../package.json').version}.tgz`
             t.strictSame(OUTPUT, [[filename]])
           })
        diff --git a/deps/npm/test/lib/ping.js b/deps/npm/test/lib/ping.js
        index d27bf4d603cf11..a185919dddc332 100644
        --- a/deps/npm/test/lib/ping.js
        +++ b/deps/npm/test/lib/ping.js
        @@ -22,8 +22,8 @@ test('pings', (t) => {
                   t.equal(type, 'PONG', 'should log a PONG')
                   t.match(spec, /\d+ms/, 'should log the elapsed milliseconds')
                 }
        -      }
        -    }
        +      },
        +    },
           })
         
           ping([], (err) => {
        @@ -51,7 +51,7 @@ test('pings and logs details', (t) => {
                 if (noticeCalls === 1) {
                   t.equal(type, 'PING', 'should log a PING')
                   t.equal(spec, flatOptions.registry, 'should log the registry url')
        -        } else if (noticeCalls == 2) {
        +        } else if (noticeCalls === 2) {
                   t.equal(type, 'PONG', 'should log a PONG')
                   t.match(spec, /\d+ms/, 'should log the elapsed milliseconds')
                 } else {
        @@ -59,8 +59,8 @@ test('pings and logs details', (t) => {
                   const parsed = JSON.parse(spec)
                   t.match(parsed, details, 'should log JSON stringified details')
                 }
        -      }
        -    }
        +      },
        +    },
           })
         
           ping([], (err) => {
        @@ -98,8 +98,8 @@ test('pings and returns json', (t) => {
                   t.equal(type, 'PONG', 'should log a PONG')
                   t.match(spec, /\d+ms/, 'should log the elapsed milliseconds')
                 }
        -      }
        -    }
        +      },
        +    },
           })
         
           ping([], (err) => {
        diff --git a/deps/npm/test/lib/prefix.js b/deps/npm/test/lib/prefix.js
        index a6e4d731ab1871..83e2d636808596 100644
        --- a/deps/npm/test/lib/prefix.js
        +++ b/deps/npm/test/lib/prefix.js
        @@ -9,7 +9,7 @@ test('prefix', (t) => {
             '../../lib/npm.js': { prefix: dir },
             '../../lib/utils/output.js': (output) => {
               t.equal(output, dir, 'prints the correct directory')
        -    }
        +    },
           })
         
           prefix([], (err) => {
        diff --git a/deps/npm/test/lib/prune.js b/deps/npm/test/lib/prune.js
        index 27c16355fa6412..074f4eac6eeee2 100644
        --- a/deps/npm/test/lib/prune.js
        +++ b/deps/npm/test/lib/prune.js
        @@ -1,5 +1,4 @@
         const { test } = require('tap')
        -const prune = require('../../lib/prune.js')
         const requireInject = require('require-inject')
         
         test('should prune using Arborist', (t) => {
        @@ -7,8 +6,8 @@ test('should prune using Arborist', (t) => {
             '../../lib/npm.js': {
               prefix: 'foo',
               flatOptions: {
        -        'foo': 'bar'
        -      }
        +        foo: 'bar',
        +      },
             },
             '@npmcli/arborist': function (args) {
               t.ok(args, 'gets options object')
        @@ -17,13 +16,14 @@ test('should prune using Arborist', (t) => {
                 t.ok(true, 'prune is called')
               }
             },
        -    '../../lib/utils/reify-output.js': (arb) => {
        +    '../../lib/utils/reify-finish.js': (arb) => {
               t.ok(arb, 'gets arborist tree')
        -    }
        +    },
           })
        -  prune(null, () => {
        +  prune(null, er => {
        +    if (er)
        +      throw er
             t.ok(true, 'callback is called')
             t.end()
           })
         })
        -
        diff --git a/deps/npm/test/lib/repo.js b/deps/npm/test/lib/repo.js
        index fcc95f343890eb..c4b1b46e7342b7 100644
        --- a/deps/npm/test/lib/repo.js
        +++ b/deps/npm/test/lib/repo.js
        @@ -5,105 +5,105 @@ const pacote = {
           manifest: async (spec, options) => {
             return spec === 'norepo' ? {
               name: 'norepo',
        -      version: '1.2.3'
        +      version: '1.2.3',
             }
         
        -    : spec === 'repoobbj-nourl' ? {
        -      name: 'repoobj-nourl',
        -      repository: { no: 'url' }
        -    }
        +      : spec === 'repoobbj-nourl' ? {
        +        name: 'repoobj-nourl',
        +        repository: { no: 'url' },
        +      }
         
        -    : spec === 'hostedgit' ? {
        -      repository: 'git://github.com/foo/hostedgit'
        -    }
        -    : spec === 'hostedgitat' ? {
        -      repository: 'git@github.com:foo/hostedgitat'
        -    }
        -    : spec === 'hostedssh' ? {
        -      repository: 'ssh://git@github.com/foo/hostedssh'
        -    }
        -    : spec === 'hostedgitssh' ? {
        -      repository: 'git+ssh://git@github.com/foo/hostedgitssh'
        -    }
        -    : spec === 'hostedgithttp' ? {
        -      repository: 'git+http://github.com/foo/hostedgithttp'
        -    }
        -    : spec === 'hostedgithttps' ? {
        -      repository: 'git+https://github.com/foo/hostedgithttps'
        -    }
        +      : spec === 'hostedgit' ? {
        +        repository: 'git://github.com/foo/hostedgit',
        +      }
        +      : spec === 'hostedgitat' ? {
        +        repository: 'git@github.com:foo/hostedgitat',
        +      }
        +      : spec === 'hostedssh' ? {
        +        repository: 'ssh://git@github.com/foo/hostedssh',
        +      }
        +      : spec === 'hostedgitssh' ? {
        +        repository: 'git+ssh://git@github.com/foo/hostedgitssh',
        +      }
        +      : spec === 'hostedgithttp' ? {
        +        repository: 'git+http://github.com/foo/hostedgithttp',
        +      }
        +      : spec === 'hostedgithttps' ? {
        +        repository: 'git+https://github.com/foo/hostedgithttps',
        +      }
         
        -    : spec === 'hostedgitobj' ? {
        -      repository: { url: 'git://github.com/foo/hostedgitobj' }
        -    }
        -    : spec === 'hostedgitatobj' ? {
        -      repository: { url: 'git@github.com:foo/hostedgitatobj' }
        -    }
        -    : spec === 'hostedsshobj' ? {
        -      repository: { url: 'ssh://git@github.com/foo/hostedsshobj' }
        -    }
        -    : spec === 'hostedgitsshobj' ? {
        -      repository: { url: 'git+ssh://git@github.com/foo/hostedgitsshobj' }
        -    }
        -    : spec === 'hostedgithttpobj' ? {
        -      repository: { url: 'git+http://github.com/foo/hostedgithttpobj' }
        -    }
        -    : spec === 'hostedgithttpsobj' ? {
        -      repository: { url: 'git+https://github.com/foo/hostedgithttpsobj' }
        -    }
        +      : spec === 'hostedgitobj' ? {
        +        repository: { url: 'git://github.com/foo/hostedgitobj' },
        +      }
        +      : spec === 'hostedgitatobj' ? {
        +        repository: { url: 'git@github.com:foo/hostedgitatobj' },
        +      }
        +      : spec === 'hostedsshobj' ? {
        +        repository: { url: 'ssh://git@github.com/foo/hostedsshobj' },
        +      }
        +      : spec === 'hostedgitsshobj' ? {
        +        repository: { url: 'git+ssh://git@github.com/foo/hostedgitsshobj' },
        +      }
        +      : spec === 'hostedgithttpobj' ? {
        +        repository: { url: 'git+http://github.com/foo/hostedgithttpobj' },
        +      }
        +      : spec === 'hostedgithttpsobj' ? {
        +        repository: { url: 'git+https://github.com/foo/hostedgithttpsobj' },
        +      }
         
        -    : spec === 'unhostedgit' ? {
        -      repository: 'git://gothib.com/foo/unhostedgit'
        -    }
        -    : spec === 'unhostedgitat' ? {
        -      repository: 'git@gothib.com:foo/unhostedgitat'
        -    }
        -    : spec === 'unhostedssh' ? {
        -      repository: 'ssh://git@gothib.com/foo/unhostedssh'
        -    }
        -    : spec === 'unhostedgitssh' ? {
        -      repository: 'git+ssh://git@gothib.com/foo/unhostedgitssh'
        -    }
        -    : spec === 'unhostedgithttp' ? {
        -      repository: 'git+http://gothib.com/foo/unhostedgithttp'
        -    }
        -    : spec === 'unhostedgithttps' ? {
        -      repository: 'git+https://gothib.com/foo/unhostedgithttps'
        -    }
        +      : spec === 'unhostedgit' ? {
        +        repository: 'git://gothib.com/foo/unhostedgit',
        +      }
        +      : spec === 'unhostedgitat' ? {
        +        repository: 'git@gothib.com:foo/unhostedgitat',
        +      }
        +      : spec === 'unhostedssh' ? {
        +        repository: 'ssh://git@gothib.com/foo/unhostedssh',
        +      }
        +      : spec === 'unhostedgitssh' ? {
        +        repository: 'git+ssh://git@gothib.com/foo/unhostedgitssh',
        +      }
        +      : spec === 'unhostedgithttp' ? {
        +        repository: 'git+http://gothib.com/foo/unhostedgithttp',
        +      }
        +      : spec === 'unhostedgithttps' ? {
        +        repository: 'git+https://gothib.com/foo/unhostedgithttps',
        +      }
         
        -    : spec === 'unhostedgitobj' ? {
        -      repository: { url: 'git://gothib.com/foo/unhostedgitobj' }
        -    }
        -    : spec === 'unhostedgitatobj' ? {
        -      repository: { url: 'git@gothib.com:foo/unhostedgitatobj' }
        -    }
        -    : spec === 'unhostedsshobj' ? {
        -      repository: { url: 'ssh://git@gothib.com/foo/unhostedsshobj' }
        -    }
        -    : spec === 'unhostedgitsshobj' ? {
        -      repository: { url: 'git+ssh://git@gothib.com/foo/unhostedgitsshobj' }
        -    }
        -    : spec === 'unhostedgithttpobj' ? {
        -      repository: { url: 'git+http://gothib.com/foo/unhostedgithttpobj' }
        -    }
        -    : spec === 'unhostedgithttpsobj' ? {
        -      repository: { url: 'git+https://gothib.com/foo/unhostedgithttpsobj' }
        -    }
        +      : spec === 'unhostedgitobj' ? {
        +        repository: { url: 'git://gothib.com/foo/unhostedgitobj' },
        +      }
        +      : spec === 'unhostedgitatobj' ? {
        +        repository: { url: 'git@gothib.com:foo/unhostedgitatobj' },
        +      }
        +      : spec === 'unhostedsshobj' ? {
        +        repository: { url: 'ssh://git@gothib.com/foo/unhostedsshobj' },
        +      }
        +      : spec === 'unhostedgitsshobj' ? {
        +        repository: { url: 'git+ssh://git@gothib.com/foo/unhostedgitsshobj' },
        +      }
        +      : spec === 'unhostedgithttpobj' ? {
        +        repository: { url: 'git+http://gothib.com/foo/unhostedgithttpobj' },
        +      }
        +      : spec === 'unhostedgithttpsobj' ? {
        +        repository: { url: 'git+https://gothib.com/foo/unhostedgithttpsobj' },
        +      }
         
        -    : spec === 'directory' ? {
        -      repository: {
        -        type: 'git',
        -        url: 'git+https://github.com/foo/test-repo-with-directory.git',
        -        directory: 'some/directory'
        +      : spec === 'directory' ? {
        +        repository: {
        +          type: 'git',
        +          url: 'git+https://github.com/foo/test-repo-with-directory.git',
        +          directory: 'some/directory',
        +        },
               }
        -    }
         
        -    : spec === '.' ? {
        -      name: 'thispkg',
        -      version: '1.2.3',
        -      repository: 'https://example.com/thispkg.git'
        -    }
        -    : null
        -  }
        +      : spec === '.' ? {
        +        name: 'thispkg',
        +        version: '1.2.3',
        +        repository: 'https://example.com/thispkg.git',
        +      }
        +      : null
        +  },
         }
         
         // keep a tally of which urls got opened
        @@ -116,7 +116,7 @@ const openUrl = (url, errMsg, cb) => {
         
         const repo = requireInject('../../lib/repo.js', {
           pacote,
        -  '../../lib/utils/open-url.js': openUrl
        +  '../../lib/utils/open-url.js': openUrl,
         })
         
         t.test('completion', t => {
        @@ -152,7 +152,7 @@ t.test('open repo urls', t => {
             unhostedgithttpobj: 'http://gothib.com/foo/unhostedgithttpobj',
             unhostedgithttpsobj: 'https://gothib.com/foo/unhostedgithttpsobj',
             directory: 'https://github.com/foo/test-repo-with-directory/tree/master/some/directory',
        -    '.': 'https://example.com/thispkg'
        +    '.': 'https://example.com/thispkg',
           }
           const keys = Object.keys(expect)
           t.plan(keys.length)
        @@ -174,7 +174,7 @@ t.test('fail if cannot figure out repo url', t => {
             'norepo',
             'repoobbj-nourl',
             'unhostedgitat',
        -    'unhostedgitatobj'
        +    'unhostedgitatobj',
           ]
         
           t.plan(cases.length)
        diff --git a/deps/npm/test/lib/root.js b/deps/npm/test/lib/root.js
        index 210e9b029121c8..8c23152b3efca9 100644
        --- a/deps/npm/test/lib/root.js
        +++ b/deps/npm/test/lib/root.js
        @@ -9,7 +9,7 @@ test('root', (t) => {
             '../../lib/npm.js': { dir },
             '../../lib/utils/output.js': (output) => {
               t.equal(output, dir, 'prints the correct directory')
        -    }
        +    },
           })
         
           root([], (err) => {
        diff --git a/deps/npm/test/lib/run-script.js b/deps/npm/test/lib/run-script.js
        index 7a034aff01561b..bad8a63c0d7783 100644
        --- a/deps/npm/test/lib/run-script.js
        +++ b/deps/npm/test/lib/run-script.js
        @@ -1,37 +1,38 @@
         const t = require('tap')
         const requireInject = require('require-inject')
         
        -let RUN_FAIL = null
         const RUN_SCRIPTS = []
         const npm = {
           localPrefix: __dirname,
           flatOptions: {
             scriptShell: undefined,
             json: false,
        -    parseable: false
        +    parseable: false,
           },
           config: {
             settings: {
        -      'if-present': false
        +      'if-present': false,
             },
             get: k => npm.config.settings[k],
             set: (k, v) => {
               npm.config.settings[k] = v
        -    }
        -  }
        +    },
        +  },
         }
         
         const output = []
         
         const npmlog = { level: 'warn' }
         const getRS = windows => requireInject('../../lib/run-script.js', {
        -  '@npmcli/run-script': async opts => {
        +  '@npmcli/run-script': Object.assign(async opts => {
             RUN_SCRIPTS.push(opts)
        -  },
        +  }, {
        +    isServerPackage: require('@npmcli/run-script').isServerPackage,
        +  }),
           npmlog,
           '../../lib/npm.js': npm,
           '../../lib/utils/is-windows-shell.js': windows,
        -  '../../lib/utils/output.js': (...msg) => output.push(msg)
        +  '../../lib/utils/output.js': (...msg) => output.push(msg),
         })
         
         const runScript = getRS(false)
        @@ -42,41 +43,41 @@ t.test('completion', t => {
           const dir = t.testdir()
           npm.localPrefix = dir
           t.test('already have a script name', t => {
        -    runScript.completion({conf:{argv:{remain: ['npm','run','x']}}}, (er, results) => {
        -      if (er) {
        +    runScript.completion({conf: {argv: {remain: ['npm', 'run', 'x']}}}, (er, results) => {
        +      if (er)
                 throw er
        -      }
        +
               t.equal(results, undefined)
               t.end()
             })
           })
           t.test('no package.json', t => {
        -    runScript.completion({conf:{argv:{remain: ['npm','run']}}}, (er, results) => {
        -      if (er) {
        +    runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}, (er, results) => {
        +      if (er)
                 throw er
        -      }
        +
               t.strictSame(results, [])
               t.end()
             })
           })
           t.test('has package.json, no scripts', t => {
             writeFileSync(`${dir}/package.json`, JSON.stringify({}))
        -    runScript.completion({conf:{argv:{remain: ['npm', 'run']}}}, (er, results) => {
        -      if (er) {
        +    runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}, (er, results) => {
        +      if (er)
                 throw er
        -      }
        +
               t.strictSame(results, [])
               t.end()
             })
           })
           t.test('has package.json, with scripts', t => {
             writeFileSync(`${dir}/package.json`, JSON.stringify({
        -      scripts: { hello: 'echo hello', world: 'echo world' }
        +      scripts: { hello: 'echo hello', world: 'echo world' },
             }))
        -    runScript.completion({conf:{argv:{remain: ['npm', 'run']}}}, (er, results) => {
        -      if (er) {
        +    runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}, (er, results) => {
        +      if (er)
                 throw er
        -      }
        +
               t.strictSame(results, ['hello', 'world'])
               t.end()
             })
        @@ -90,15 +91,34 @@ t.test('fail if no package.json', async t => {
           await runScript(['test'], er => t.match(er, { code: 'ENOENT' }))
         })
         
        -t.test('default env and restart scripts', async t => {
        +t.test('default env, start, and restart scripts', async t => {
           npm.localPrefix = t.testdir({
        -    'package.json': JSON.stringify({ name: 'x', version: '1.2.3' })
        +    'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }),
        +    'server.js': 'console.log("hello, world")',
           })
         
        +  await runScript(['start'], er => {
        +    if (er)
        +      throw er
        +
        +    t.match(RUN_SCRIPTS, [
        +      {
        +        path: npm.localPrefix,
        +        args: [],
        +        scriptShell: undefined,
        +        stdio: 'inherit',
        +        stdioString: true,
        +        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {}},
        +        event: 'start',
        +      },
        +    ])
        +  })
        +  RUN_SCRIPTS.length = 0
        +
           await runScript(['env'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.match(RUN_SCRIPTS, [
               {
                 path: npm.localPrefix,
        @@ -106,19 +126,22 @@ t.test('default env and restart scripts', async t => {
                 scriptShell: undefined,
                 stdio: 'inherit',
                 stdioString: true,
        -        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {
        -          env: 'env'
        -        } },
        -        event: 'env'
        -      }
        +        pkg: { name: 'x',
        +          version: '1.2.3',
        +          _id: 'x@1.2.3',
        +          scripts: {
        +            env: 'env',
        +          } },
        +        event: 'env',
        +      },
             ])
           })
           RUN_SCRIPTS.length = 0
         
           await runScriptWin(['env'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.match(RUN_SCRIPTS, [
               {
                 path: npm.localPrefix,
        @@ -126,19 +149,22 @@ t.test('default env and restart scripts', async t => {
                 scriptShell: undefined,
                 stdio: 'inherit',
                 stdioString: true,
        -        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {
        -          env: 'SET'
        -        } },
        -        event: 'env'
        -      }
        +        pkg: { name: 'x',
        +          version: '1.2.3',
        +          _id: 'x@1.2.3',
        +          scripts: {
        +            env: 'SET',
        +          } },
        +        event: 'env',
        +      },
             ])
           })
           RUN_SCRIPTS.length = 0
         
           await runScript(['restart'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.match(RUN_SCRIPTS, [
               {
                 path: npm.localPrefix,
        @@ -146,11 +172,14 @@ t.test('default env and restart scripts', async t => {
                 scriptShell: undefined,
                 stdio: 'inherit',
                 stdioString: true,
        -        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {
        -          restart: 'npm stop --if-present && npm start'
        -        } },
        -        event: 'restart'
        -      }
        +        pkg: { name: 'x',
        +          version: '1.2.3',
        +          _id: 'x@1.2.3',
        +          scripts: {
        +            restart: 'npm stop --if-present && npm start',
        +          } },
        +        event: 'restart',
        +      },
             ])
           })
           RUN_SCRIPTS.length = 0
        @@ -159,29 +188,29 @@ t.test('default env and restart scripts', async t => {
         t.test('try to run missing script', t => {
           npm.localPrefix = t.testdir({
             'package.json': JSON.stringify({
        -      scripts: { hello: 'world' }
        -    })
        +      scripts: { hello: 'world' },
        +    }),
           })
           t.test('no suggestions', async t => {
             await runScript(['notevenclose'], er => {
               t.match(er, {
        -        message: 'missing script: notevenclose'
        +        message: 'missing script: notevenclose',
               })
             })
           })
           t.test('suggestions', async t => {
             await runScript(['helo'], er => {
               t.match(er, {
        -        message: 'missing script: helo\n\nDid you mean this?\n    hello'
        +        message: 'missing script: helo\n\nDid you mean this?\n    hello',
               })
             })
           })
           t.test('with --if-present', async t => {
             npm.config.set('if-present', true)
             await runScript(['goodbye'], er => {
        -      if (er) {
        +      if (er)
                 throw er
        -      }
        +
               t.strictSame(RUN_SCRIPTS, [], 'did not try to run anything')
             })
           })
        @@ -195,15 +224,15 @@ t.test('run pre/post hooks', async t => {
               version: '1.2.3',
               scripts: {
                 preenv: 'echo before the env',
        -        postenv: 'echo after the env'
        -      }
        -    })
        +        postenv: 'echo after the env',
        +      },
        +    }),
           })
         
           await runScript(['env'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.match(RUN_SCRIPTS, [
               { event: 'preenv' },
               {
        @@ -212,12 +241,15 @@ t.test('run pre/post hooks', async t => {
                 scriptShell: undefined,
                 stdio: 'inherit',
                 stdioString: true,
        -        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {
        -          env: 'env'
        -        } },
        -        event: 'env'
        +        pkg: { name: 'x',
        +          version: '1.2.3',
        +          _id: 'x@1.2.3',
        +          scripts: {
        +            env: 'env',
        +          } },
        +        event: 'env',
               },
        -      { event: 'postenv' }
        +      { event: 'postenv' },
             ])
           })
           RUN_SCRIPTS.length = 0
        @@ -232,15 +264,15 @@ t.test('skip pre/post hooks when using ignoreScripts', async t => {
               version: '1.2.3',
               scripts: {
                 preenv: 'echo before the env',
        -        postenv: 'echo after the env'
        -      }
        -    })
        +        postenv: 'echo after the env',
        +      },
        +    }),
           })
         
           await runScript(['env'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.deepEqual(RUN_SCRIPTS, [
               {
                 path: npm.localPrefix,
        @@ -248,14 +280,17 @@ t.test('skip pre/post hooks when using ignoreScripts', async t => {
                 scriptShell: undefined,
                 stdio: 'inherit',
                 stdioString: true,
        -        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {
        -          preenv: 'echo before the env',
        -          postenv: 'echo after the env',
        -          env: 'env'
        -        } },
        +        pkg: { name: 'x',
        +          version: '1.2.3',
        +          _id: 'x@1.2.3',
        +          scripts: {
        +            preenv: 'echo before the env',
        +            postenv: 'echo after the env',
        +            env: 'env',
        +          } },
                 banner: true,
        -        event: 'env'
        -      }
        +        event: 'env',
        +      },
             ])
         
             delete npm.flatOptions.ignoreScripts
        @@ -265,7 +300,9 @@ t.test('skip pre/post hooks when using ignoreScripts', async t => {
         
         t.test('run silent', async t => {
           npmlog.level = 'silent'
        -  t.teardown(() => { npmlog.level = 'warn' })
        +  t.teardown(() => {
        +    npmlog.level = 'warn'
        +  })
         
           npm.localPrefix = t.testdir({
             'package.json': JSON.stringify({
        @@ -273,19 +310,19 @@ t.test('run silent', async t => {
               version: '1.2.3',
               scripts: {
                 preenv: 'echo before the env',
        -        postenv: 'echo after the env'
        -      }
        -    })
        +        postenv: 'echo after the env',
        +      },
        +    }),
           })
         
           await runScript(['env'], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.match(RUN_SCRIPTS, [
               {
                 event: 'preenv',
        -        stdio: 'inherit'
        +        stdio: 'inherit',
               },
               {
                 path: npm.localPrefix,
        @@ -293,16 +330,19 @@ t.test('run silent', async t => {
                 scriptShell: undefined,
                 stdio: 'inherit',
                 stdioString: true,
        -        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {
        -          env: 'env'
        -        } },
        +        pkg: { name: 'x',
        +          version: '1.2.3',
        +          _id: 'x@1.2.3',
        +          scripts: {
        +            env: 'env',
        +          } },
                 event: 'env',
        -        banner: false
        +        banner: false,
               },
               {
                 event: 'postenv',
        -        stdio: 'inherit'
        -      }
        +        stdio: 'inherit',
        +      },
             ])
           })
           RUN_SCRIPTS.length = 0
        @@ -314,46 +354,43 @@ t.test('list scripts', async t => {
             start: 'node server.js',
             stop: 'node kill-server.js',
             preenv: 'echo before the env',
        -    postenv: 'echo after the env'
        +    postenv: 'echo after the env',
           }
           npm.localPrefix = t.testdir({
             'package.json': JSON.stringify({
               name: 'x',
               version: '1.2.3',
        -      scripts
        -    })
        +      scripts,
        +    }),
           })
         
           await runScript([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(output, [
        -    [ 'Lifecycle scripts included in x:' ],
        -    [ '  test\n    exit 2' ],
        -    [ '  start\n    node server.js' ],
        -    [ '  stop\n    node kill-server.js' ],
        -    [ '\navailable via `npm run-script`:' ],
        -    [ '  preenv\n    echo before the env' ],
        -    [ '  postenv\n    echo after the env' ]
        +    ['Lifecycle scripts included in x:'],
        +    ['  test\n    exit 2'],
        +    ['  start\n    node server.js'],
        +    ['  stop\n    node kill-server.js'],
        +    ['\navailable via `npm run-script`:'],
        +    ['  preenv\n    echo before the env'],
        +    ['  postenv\n    echo after the env'],
           ], 'basic report')
           output.length = 0
         
           npmlog.level = 'silent'
           await runScript([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(output, [])
           npmlog.level = 'warn'
         
           npm.flatOptions.json = true
           await runScript([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(output, [[JSON.stringify(scripts, 0, 2)]], 'json report')
           output.length = 0
        @@ -361,16 +398,15 @@ t.test('list scripts', async t => {
         
           npm.flatOptions.parseable = true
           await runScript([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(output, [
        -    [ 'test:exit 2' ],
        -    [ 'start:node server.js' ],
        -    [ 'stop:node kill-server.js' ],
        -    [ 'preenv:echo before the env' ],
        -    [ 'postenv:echo after the env' ]
        +    ['test:exit 2'],
        +    ['start:node server.js'],
        +    ['stop:node kill-server.js'],
        +    ['preenv:echo before the env'],
        +    ['postenv:echo after the env'],
           ])
           output.length = 0
           npm.flatOptions.parseable = false
        @@ -380,14 +416,13 @@ t.test('list scripts when no scripts', async t => {
           npm.localPrefix = t.testdir({
             'package.json': JSON.stringify({
               name: 'x',
        -      version: '1.2.3'
        -    })
        +      version: '1.2.3',
        +    }),
           })
         
           await runScript([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(output, [], 'nothing to report')
           output.length = 0
        @@ -398,18 +433,17 @@ t.test('list scripts, only commands', async t => {
             'package.json': JSON.stringify({
               name: 'x',
               version: '1.2.3',
        -      scripts: { preversion: 'echo doing the version dance' }
        -    })
        +      scripts: { preversion: 'echo doing the version dance' },
        +    }),
           })
         
           await runScript([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(output, [
        -    ["Lifecycle scripts included in x:"],
        -    ["  preversion\n    echo doing the version dance"],
        +    ['Lifecycle scripts included in x:'],
        +    ['  preversion\n    echo doing the version dance'],
           ])
           output.length = 0
         })
        @@ -419,18 +453,17 @@ t.test('list scripts, only non-commands', async t => {
             'package.json': JSON.stringify({
               name: 'x',
               version: '1.2.3',
        -      scripts: { glorp: 'echo doing the glerp glop' }
        -    })
        +      scripts: { glorp: 'echo doing the glerp glop' },
        +    }),
           })
         
           await runScript([], er => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
           })
           t.strictSame(output, [
        -    ["Scripts available in x via `npm run-script`:"],
        -    ["  glorp\n    echo doing the glerp glop"]
        +    ['Scripts available in x via `npm run-script`:'],
        +    ['  glorp\n    echo doing the glerp glop'],
           ])
           output.length = 0
         })
        diff --git a/deps/npm/test/lib/star.js b/deps/npm/test/lib/star.js
        new file mode 100644
        index 00000000000000..ea5e07b94f9a8c
        --- /dev/null
        +++ b/deps/npm/test/lib/star.js
        @@ -0,0 +1,144 @@
        +const requireInject = require('require-inject')
        +const t = require('tap')
        +
        +let result = ''
        +
        +const noop = () => null
        +const npm = { config: { get () {} }, flatOptions: { unicode: false } }
        +const npmFetch = { json: noop }
        +const npmlog = { error: noop, info: noop, verbose: noop }
        +const mocks = {
        +  npmlog,
        +  'npm-registry-fetch': npmFetch,
        +  '../../lib/npm.js': npm,
        +  '../../lib/utils/output.js': (...msg) => {
        +    result += msg.join('\n')
        +  },
        +  '../../lib/utils/get-identity.js': async () => 'foo',
        +  '../../lib/utils/usage.js': () => 'usage instructions',
        +}
        +
        +const star = requireInject('../../lib/star.js', mocks)
        +
        +t.afterEach(cb => {
        +  npm.config = { get () {} }
        +  npm.flatOptions.unicode = false
        +  npmlog.info = noop
        +  result = ''
        +  cb()
        +})
        +
        +t.test('no args', t => {
        +  star([], err => {
        +    t.match(
        +      err,
        +      /usage instructions/,
        +      'should throw usage instructions'
        +    )
        +    t.end()
        +  })
        +})
        +
        +t.test('star a package', t => {
        +  t.plan(4)
        +  const pkgName = '@npmcli/arborist'
        +  npmFetch.json = async (uri, opts) => ({
        +    _id: pkgName,
        +    _rev: 'hash',
        +    users: (
        +      opts.method === 'PUT'
        +        ? { foo: true }
        +        : {}
        +    ),
        +  })
        +  npmlog.info = (title, msg, id) => {
        +    t.equal(title, 'star', 'should use expected title')
        +    t.equal(msg, 'starring', 'should use expected msg')
        +    t.equal(id, pkgName, 'should use expected id')
        +  }
        +  star([pkgName], err => {
        +    if (err)
        +      throw err
        +    t.equal(
        +      result,
        +      '(*) @npmcli/arborist',
        +      'should output starred package msg'
        +    )
        +  })
        +})
        +
        +t.test('unstar a package', t => {
        +  t.plan(4)
        +  const pkgName = '@npmcli/arborist'
        +  npm.config.get = key => key === 'star.unstar'
        +  npmFetch.json = async (uri, opts) => ({
        +    _id: pkgName,
        +    _rev: 'hash',
        +    ...(opts.method === 'PUT'
        +      ? {}
        +      : { foo: true }
        +    ),
        +  })
        +  npmlog.info = (title, msg, id) => {
        +    t.equal(title, 'unstar', 'should use expected title')
        +    t.equal(msg, 'unstarring', 'should use expected msg')
        +    t.equal(id, pkgName, 'should use expected id')
        +  }
        +  star([pkgName], err => {
        +    if (err)
        +      throw err
        +    t.equal(
        +      result,
        +      '( ) @npmcli/arborist',
        +      'should output unstarred package msg'
        +    )
        +  })
        +})
        +
        +t.test('unicode', async t => {
        +  t.test('star a package', t => {
        +    npm.flatOptions.unicode = true
        +    npmFetch.json = async (uri, opts) => ({})
        +    star(['pkg'], err => {
        +      if (err)
        +        throw err
        +      t.equal(
        +        result,
        +        '\u2605  pkg',
        +        'should output unicode starred package msg'
        +      )
        +      t.end()
        +    })
        +  })
        +
        +  t.test('unstar a package', t => {
        +    npm.flatOptions.unicode = true
        +    npm.config.get = key => key === 'star.unstar'
        +    npmFetch.json = async (uri, opts) => ({})
        +    star(['pkg'], err => {
        +      if (err)
        +        throw err
        +      t.equal(
        +        result,
        +        '\u2606  pkg',
        +        'should output unstarred package msg'
        +      )
        +      t.end()
        +    })
        +  })
        +})
        +
        +t.test('logged out user', t => {
        +  const star = requireInject('../../lib/star.js', {
        +    ...mocks,
        +    '../../lib/utils/get-identity.js': async () => undefined,
        +  })
        +  star(['@npmcli/arborist'], err => {
        +    t.match(
        +      err,
        +      /You need to be logged in/,
        +      'should throw login required error'
        +    )
        +    t.end()
        +  })
        +})
        diff --git a/deps/npm/test/lib/test.js b/deps/npm/test/lib/test.js
        index 8b6d0662659cfe..9a44e4760a2a51 100644
        --- a/deps/npm/test/lib/test.js
        +++ b/deps/npm/test/lib/test.js
        @@ -6,11 +6,11 @@ const npmock = {
             run: (args, cb) => {
               RUN_ARGS = args
               cb()
        -    }
        -  }
        +    },
        +  },
         }
         const test = requireInject('../../lib/test.js', {
        -  '../../lib/npm.js': npmock
        +  '../../lib/npm.js': npmock,
         })
         
         t.test('run a test', t => {
        @@ -22,7 +22,7 @@ t.test('run a test', t => {
           })
         
           const lcErr = Object.assign(new Error('should not see this'), {
        -    code: 'ELIFECYCLE'
        +    code: 'ELIFECYCLE',
           })
           const otherErr = new Error('should see this')
         
        diff --git a/deps/npm/test/lib/token.js b/deps/npm/test/lib/token.js
        index dc5a8ad05e4448..f9888107223d9b 100644
        --- a/deps/npm/test/lib/token.js
        +++ b/deps/npm/test/lib/token.js
        @@ -6,7 +6,7 @@ const mocks = {
           profile: {},
           output: () => {},
           log: {},
        -  readUserInfo: {}
        +  readUserInfo: {},
         }
         
         const tokenMock = requireInject('../../lib/token.js', {
        @@ -17,28 +17,26 @@ const tokenMock = requireInject('../../lib/token.js', {
           },
           '../../lib/utils/read-user-info.js': mocks.readUserInfo,
           'npm-profile': mocks.profile,
        -  'npmlog': mocks.log
        +  npmlog: mocks.log,
         })
         
         const tokenWithMocks = (mockRequests) => {
           for (const mod in mockRequests) {
        -    if (typeof mockRequests[mod] === 'function') {
        +    if (typeof mockRequests[mod] === 'function')
               mocks[mod] = mockRequests[mod]
        -    } else {
        -      for (const key in mockRequests[mod]) {
        +    else {
        +      for (const key in mockRequests[mod])
                 mocks[mod][key] = mockRequests[mod][key]
        -      }
             }
           }
         
           const reset = () => {
             for (const mod in mockRequests) {
        -      if (typeof mockRequests[mod] === 'function') {
        +      if (typeof mockRequests[mod] === 'function')
                 mocks[mod] = () => {}
        -      } else {
        -        for (const key in mockRequests[mod]) {
        +      else {
        +        for (const key in mockRequests[mod])
                   delete mocks[mod][key]
        -        }
               }
             }
           }
        @@ -51,9 +49,8 @@ test('completion', (t) => {
         
           const testComp = (argv, expect) => {
             tokenMock.completion({ conf: { argv: { remain: argv } } }, (err, res) => {
        -      if (err) {
        +      if (err)
                 throw err
        -      }
         
               t.strictSame(res, expect, argv.join(' '))
             })
        @@ -62,14 +59,14 @@ test('completion', (t) => {
           testComp(['npm', 'token'], [
             'list',
             'revoke',
        -    'create'
        +    'create',
           ])
         
           testComp(['npm', 'token', 'list'], [])
           testComp(['npm', 'token', 'revoke'], [])
           testComp(['npm', 'token', 'create'], [])
         
        -  tokenMock.completion({ conf: { argv: { remain: ['npm', 'token', 'foobar' ] } } }, (err) => {
        +  tokenMock.completion({ conf: { argv: { remain: ['npm', 'token', 'foobar'] } } }, (err) => {
             t.match(err, { message: 'foobar not recognized' })
           })
         })
        @@ -77,14 +74,14 @@ test('completion', (t) => {
         test('token foobar', (t) => {
           t.plan(2)
         
        -  const [token, reset] = tokenWithMocks({
        +  const [, reset] = tokenWithMocks({
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'shows a gauge')
        -        }
        -      }
        -    }
        +        },
        +      },
        +    },
           })
         
           t.tearDown(reset)
        @@ -104,14 +101,14 @@ test('token list', (t) => {
             cidr_whitelist: null,
             readonly: false,
             created: now,
        -    updated: now
        +    updated: now,
           }, {
             key: 'abcd1256',
             token: 'hgfe8765',
             cidr_whitelist: ['192.168.1.1/32'],
             readonly: true,
             created: now,
        -    updated: now
        +    updated: now,
           }]
         
           const [token, reset] = tokenWithMocks({
        @@ -121,25 +118,25 @@ test('token list', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             profile: {
               listTokens: (conf) => {
                 t.same(conf.auth, { token: 'thisisnotarealtoken', otp: '123456' })
                 return tokens
        -      }
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token')
        -        }
        +        },
               },
               info: (type, msg) => {
                 t.equal(type, 'token')
                 t.equal(msg, 'getting list')
        -      }
        +      },
             },
             output: (spec) => {
               const lines = spec.split(/\r?\n/)
        @@ -152,7 +149,7 @@ test('token list', (t) => {
               t.match(lines[5], ` ${now.slice(0, 10)} `, 'includes the trimmed creation timestamp')
               t.match(lines[5], ' yes ', 'includes the "no" string for readonly state')
               t.match(lines[5], ` ${tokens[1].cidr_whitelist.join(',')} `, 'includes the cidr whitelist')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -172,7 +169,7 @@ test('token list json output', (t) => {
             cidr_whitelist: null,
             readonly: false,
             created: now,
        -    updated: now
        +    updated: now,
           }]
         
           const [token, reset] = tokenWithMocks({
        @@ -182,31 +179,31 @@ test('token list json output', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { username: 'foo', password: 'bar' }
        -        }
        -      }
        +        },
        +      },
             },
             profile: {
               listTokens: (conf) => {
                 t.same(conf.auth, { basic: { username: 'foo', password: 'bar' } }, 'passes the correct auth')
                 return tokens
        -      }
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token')
        -        }
        +        },
               },
               info: (type, msg) => {
                 t.equal(type, 'token')
                 t.equal(msg, 'getting list')
        -      }
        +      },
             },
             output: (spec) => {
               t.type(spec, 'string', 'is called with a string')
               const parsed = JSON.parse(spec)
               t.match(parsed, tokens, 'prints the json parsed tokens')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -226,14 +223,14 @@ test('token list parseable output', (t) => {
             cidr_whitelist: null,
             readonly: false,
             created: now,
        -    updated: now
        +    updated: now,
           }, {
             key: 'efgh5678ijkl9101',
             token: 'hgfe8765',
             cidr_whitelist: ['192.168.1.1/32'],
             readonly: true,
             created: now,
        -    updated: now
        +    updated: now,
           }]
         
           let callCount = 0
        @@ -245,37 +242,36 @@ test('token list parseable output', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { auth: Buffer.from('foo:bar').toString('base64') }
        -        }
        -      }
        +        },
        +      },
             },
             profile: {
               listTokens: (conf) => {
                 t.same(conf.auth, { basic: { username: 'foo', password: 'bar' } }, 'passes the correct auth')
                 return tokens
        -      }
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token')
        -        }
        +        },
               },
               info: (type, msg) => {
                 t.equal(type, 'token')
                 t.equal(msg, 'getting list')
        -      }
        +      },
             },
             output: (spec) => {
               ++callCount
               t.type(spec, 'string', 'is called with a string')
        -      if (callCount === 1) {
        +      if (callCount === 1)
                 t.equal(spec, ['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t'), 'prints header')
        -      } else if (callCount === 2) {
        +      else if (callCount === 2)
                 t.equal(spec, [tokens[0].key, tokens[0].token, tokens[0].created, tokens[0].readonly, ''].join('\t'), 'prints token info')
        -      } else {
        +      else
                 t.equal(spec, [tokens[1].key, tokens[1].token, tokens[1].created, tokens[1].readonly, tokens[1].cidr_whitelist.join(',')].join('\t'), 'prints token info')
        -      }
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -295,14 +291,14 @@ test('token revoke', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return {}
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               newItem: (action, len) => {
                 t.equal(action, 'removing tokens')
        @@ -311,24 +307,24 @@ test('token revoke', (t) => {
                   info: (name, progress) => {
                     t.equal(name, 'token')
                     t.equal(progress, 'getting existing list')
        -          }
        +          },
                 }
        -      }
        +      },
             },
             profile: {
               listTokens: (conf) => {
                 t.same(conf.auth, {}, 'passes the correct empty auth')
                 return Promise.resolve([
        -          { key: 'abcd1234' }
        +          { key: 'abcd1234' },
                 ])
               },
               removeToken: (key) => {
                 t.equal(key, 'abcd1234', 'deletes the correct token')
        -      }
        +      },
             },
             output: (spec) => {
               t.equal(spec, 'Removed 1 token')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -348,14 +344,14 @@ test('token revoke multiple tokens', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               newItem: (action, len) => {
                 t.equal(action, 'removing tokens')
        @@ -364,23 +360,23 @@ test('token revoke multiple tokens', (t) => {
                   info: (name, progress) => {
                     t.equal(name, 'token')
                     t.equal(progress, 'getting existing list')
        -          }
        +          },
                 }
        -      }
        +      },
             },
             profile: {
               listTokens: () => Promise.resolve([
                 { key: 'abcd1234' },
        -        { key: 'efgh5678' }
        +        { key: 'efgh5678' },
               ]),
               removeToken: (key) => {
                 // this will run twice
                 t.ok(['abcd1234', 'efgh5678'].includes(key), 'deletes the correct token')
        -      }
        +      },
             },
             output: (spec) => {
               t.equal(spec, 'Removed 2 tokens')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -400,14 +396,14 @@ test('token revoke json output', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               newItem: (action, len) => {
                 t.equal(action, 'removing tokens')
        @@ -416,23 +412,23 @@ test('token revoke json output', (t) => {
                   info: (name, progress) => {
                     t.equal(name, 'token')
                     t.equal(progress, 'getting existing list')
        -          }
        +          },
                 }
        -      }
        +      },
             },
             profile: {
               listTokens: () => Promise.resolve([
        -        { key: 'abcd1234' }
        +        { key: 'abcd1234' },
               ]),
               removeToken: (key) => {
                 t.equal(key, 'abcd1234', 'deletes the correct token')
        -      }
        +      },
             },
             output: (spec) => {
               t.type(spec, 'string', 'is given a string')
               const parsed = JSON.parse(spec)
               t.same(parsed, ['abcd1234'], 'logs the token as json')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -452,14 +448,14 @@ test('token revoke parseable output', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               newItem: (action, len) => {
                 t.equal(action, 'removing tokens')
        @@ -468,21 +464,21 @@ test('token revoke parseable output', (t) => {
                   info: (name, progress) => {
                     t.equal(name, 'token')
                     t.equal(progress, 'getting existing list')
        -          }
        +          },
                 }
        -      }
        +      },
             },
             profile: {
               listTokens: () => Promise.resolve([
        -        { key: 'abcd1234' }
        +        { key: 'abcd1234' },
               ]),
               removeToken: (key) => {
                 t.equal(key, 'abcd1234', 'deletes the correct token')
        -      }
        +      },
             },
             output: (spec) => {
               t.equal(spec, 'abcd1234', 'logs the token as a string')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -502,14 +498,14 @@ test('token revoke by token', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               newItem: (action, len) => {
                 t.equal(action, 'removing tokens')
        @@ -518,21 +514,21 @@ test('token revoke by token', (t) => {
                   info: (name, progress) => {
                     t.equal(name, 'token')
                     t.equal(progress, 'getting existing list')
        -          }
        +          },
                 }
        -      }
        +      },
             },
             profile: {
               listTokens: () => Promise.resolve([
        -        { key: 'abcd1234', token: 'efgh5678' }
        +        { key: 'abcd1234', token: 'efgh5678' },
               ]),
               removeToken: (key) => {
                 t.equal(key, 'efgh5678', 'passes through user input')
        -      }
        +      },
             },
             output: (spec) => {
               t.equal(spec, 'Removed 1 token')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -550,9 +546,9 @@ test('token revoke requires an id', (t) => {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token')
        -        }
        -      }
        -    }
        +        },
        +      },
        +    },
           })
         
           t.tearDown(reset)
        @@ -572,14 +568,14 @@ test('token revoke ambiguous id errors', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               newItem: (action, len) => {
                 t.equal(action, 'removing tokens')
        @@ -588,16 +584,16 @@ test('token revoke ambiguous id errors', (t) => {
                   info: (name, progress) => {
                     t.equal(name, 'token')
                     t.equal(progress, 'getting existing list')
        -          }
        +          },
                 }
        -      }
        +      },
             },
             profile: {
               listTokens: () => Promise.resolve([
                 { key: 'abcd1234' },
        -        { key: 'abcd5678' }
        -      ])
        -    }
        +        { key: 'abcd5678' },
        +      ]),
        +    },
           })
         
           t.tearDown(reset)
        @@ -617,14 +613,14 @@ test('token revoke unknown id errors', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               newItem: (action, len) => {
                 t.equal(action, 'removing tokens')
        @@ -633,15 +629,15 @@ test('token revoke unknown id errors', (t) => {
                   info: (name, progress) => {
                     t.equal(name, 'token')
                     t.equal(progress, 'getting existing list')
        -          }
        +          },
                 }
        -      }
        +      },
             },
             profile: {
               listTokens: () => Promise.resolve([
        -        { key: 'abcd1234' }
        -      ])
        -    }
        +        { key: 'abcd1234' },
        +      ]),
        +    },
           })
         
           t.tearDown(reset)
        @@ -664,22 +660,22 @@ test('token create', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               info: (name, message) => {
                 t.equal(name, 'token')
                 t.equal(message, 'creating')
        -      }
        +      },
             },
             readUserInfo: {
        -      password: () => Promise.resolve(password)
        +      password: () => Promise.resolve(password),
             },
             profile: {
               createToken: (pw, readonly, cidr) => {
        @@ -692,9 +688,9 @@ test('token create', (t) => {
                   created: now,
                   updated: now,
                   readonly: false,
        -          cidr_whitelist: []
        +          cidr_whitelist: [],
                 }
        -      }
        +      },
             },
             output: (spec) => {
               const lines = spec.split(/\r?\n/)
        @@ -705,7 +701,7 @@ test('token create', (t) => {
               t.match(lines[5], 'readonly')
               t.match(lines[5], 'false', 'prints the readonly flag')
               t.match(lines[7], 'cidr_whitelist')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -728,22 +724,22 @@ test('token create json output', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               info: (name, message) => {
                 t.equal(name, 'token')
                 t.equal(message, 'creating')
        -      }
        +      },
             },
             readUserInfo: {
        -      password: () => Promise.resolve(password)
        +      password: () => Promise.resolve(password),
             },
             profile: {
               createToken: (pw, readonly, cidr) => {
        @@ -756,15 +752,15 @@ test('token create json output', (t) => {
                   created: now,
                   updated: now,
                   readonly: false,
        -          cidr_whitelist: []
        +          cidr_whitelist: [],
                 }
        -      }
        +      },
             },
             output: (spec) => {
               t.type(spec, 'string', 'outputs a string')
               const parsed = JSON.parse(spec)
               t.same(parsed, { token: 'efgh5678', created: now, readonly: false, cidr_whitelist: [] }, 'outputs the correct object')
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -788,22 +784,22 @@ test('token create parseable output', (t) => {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        +        },
               },
               info: (name, message) => {
                 t.equal(name, 'token')
                 t.equal(message, 'creating')
        -      }
        +      },
             },
             readUserInfo: {
        -      password: () => Promise.resolve(password)
        +      password: () => Promise.resolve(password),
             },
             profile: {
               createToken: (pw, readonly, cidr) => {
        @@ -816,22 +812,21 @@ test('token create parseable output', (t) => {
                   created: now,
                   updated: now,
                   readonly: false,
        -          cidr_whitelist: []
        +          cidr_whitelist: [],
                 }
        -      }
        +      },
             },
             output: (spec) => {
               ++callCount
        -      if (callCount === 1) {
        +      if (callCount === 1)
                 t.match(spec, 'token\tefgh5678', 'prints the token')
        -      } else if (callCount === 2) {
        +      else if (callCount === 2)
                 t.match(spec, `created\t${now}`, 'prints the created timestamp')
        -      } else if (callCount === 3) {
        +      else if (callCount === 3)
                 t.match(spec, 'readonly\tfalse', 'prints the readonly flag')
        -      } else {
        +      else
                 t.match(spec, 'cidr_whitelist\t', 'prints the cidr whitelist')
        -      }
        -    }
        +    },
           })
         
           t.tearDown(reset)
        @@ -844,28 +839,28 @@ test('token create parseable output', (t) => {
         test('token create ipv6 cidr', (t) => {
           t.plan(4)
         
        -  const now = new Date().toISOString()
           const password = 'thisisnotreallyapassword'
         
           const [token, reset] = tokenWithMocks({
             npm: {
        -      flatOptions: { registry: 'https://registry.npmjs.org', cidr: '::1/128' }, config: {
        +      flatOptions: { registry: 'https://registry.npmjs.org', cidr: '::1/128' },
        +      config: {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        -      }
        +        },
        +      },
             },
             readUserInfo: {
        -      password: () => Promise.resolve(password)
        -    }
        +      password: () => Promise.resolve(password),
        +    },
           })
         
           t.tearDown(reset)
        @@ -879,28 +874,28 @@ test('token create ipv6 cidr', (t) => {
         test('token create invalid cidr', (t) => {
           t.plan(4)
         
        -  const now = new Date().toISOString()
           const password = 'thisisnotreallyapassword'
         
           const [token, reset] = tokenWithMocks({
             npm: {
        -      flatOptions: { registry: 'https://registry.npmjs.org', cidr: 'apple/cider' }, config: {
        +      flatOptions: { registry: 'https://registry.npmjs.org', cidr: 'apple/cider' },
        +      config: {
                 getCredentialsByURI: (uri) => {
                   t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry')
                   return { token: 'thisisnotarealtoken' }
        -        }
        -      }
        +        },
        +      },
             },
             log: {
               gauge: {
                 show: (name) => {
                   t.equal(name, 'token', 'starts a gauge')
        -        }
        -      }
        +        },
        +      },
             },
             readUserInfo: {
        -      password: () => Promise.resolve(password)
        -    }
        +      password: () => Promise.resolve(password),
        +    },
           })
         
           t.tearDown(reset)
        diff --git a/deps/npm/test/lib/unstar.js b/deps/npm/test/lib/unstar.js
        new file mode 100644
        index 00000000000000..63b2028a18eeec
        --- /dev/null
        +++ b/deps/npm/test/lib/unstar.js
        @@ -0,0 +1,28 @@
        +const requireInject = require('require-inject')
        +const t = require('tap')
        +
        +t.test('unstar', t => {
        +  t.plan(3)
        +
        +  const unstar = requireInject('../../lib/unstar.js', {
        +    '../../lib/npm.js': {
        +      config: {
        +        set: (key, value) => {
        +          t.equal(key, 'star.unstar', 'should set unstar config value')
        +          t.equal(value, true, 'should set a truthy value')
        +        },
        +      },
        +      commands: {
        +        star: (args, cb) => {
        +          t.deepEqual(args, ['pkg'], 'should forward packages')
        +          cb()
        +        },
        +      },
        +    },
        +  })
        +
        +  unstar(['pkg'], err => {
        +    if (err)
        +      throw err
        +  })
        +})
        diff --git a/deps/npm/test/lib/utils/audit-error.js b/deps/npm/test/lib/utils/audit-error.js
        index f183a16e8d005f..cc5f4c006e14fc 100644
        --- a/deps/npm/test/lib/utils/audit-error.js
        +++ b/deps/npm/test/lib/utils/audit-error.js
        @@ -6,14 +6,14 @@ const npm = {
           command: null,
           flatOptions: {},
           log: {
        -    warn: (...msg) => LOGS.push(msg)
        -  }
        +    warn: (...msg) => LOGS.push(msg),
        +  },
         }
         const OUTPUT = []
         const output = (...msg) => OUTPUT.push(msg)
         const auditError = requireInject('../../../lib/utils/audit-error.js', {
           '../../../lib/npm.js': npm,
        -  '../../../lib/utils/output.js': output
        +  '../../../lib/utils/output.js': output,
         })
         
         t.afterEach(cb => {
        @@ -40,10 +40,10 @@ t.test('error, not audit command', t => {
               method: 'POST',
               uri: 'https://example.com/not/a/registry',
               headers: {
        -        head: ['ers']
        +        head: ['ers'],
               },
        -      statusCode: '420'
        -    }
        +      statusCode: '420',
        +    },
           }), true, 'had error')
           t.strictSame(OUTPUT, [], 'no output')
           t.strictSame(LOGS, [], 'no warnings')
        @@ -60,14 +60,14 @@ t.test('error, audit command, not json', t => {
               method: 'POST',
               uri: 'https://example.com/not/a/registry',
               headers: {
        -        head: ['ers']
        +        head: ['ers'],
               },
        -      statusCode: '420'
        -    }
        +      statusCode: '420',
        +    },
           }))
         
        -  t.strictSame(OUTPUT, [ [ 'body' ] ], 'some output')
        -  t.strictSame(LOGS, [ [ 'audit', 'message' ] ], 'some warnings')
        +  t.strictSame(OUTPUT, [['body']], 'some output')
        +  t.strictSame(LOGS, [['audit', 'message']], 'some warnings')
           t.end()
         })
         
        @@ -81,10 +81,10 @@ t.test('error, audit command, json', t => {
               method: 'POST',
               uri: 'https://example.com/not/a/registry',
               headers: {
        -        head: ['ers']
        +        head: ['ers'],
               },
        -      statusCode: '420'
        -    }
        +      statusCode: '420',
        +    },
           }))
         
           t.strictSame(OUTPUT, [
        @@ -102,9 +102,9 @@ t.test('error, audit command, json', t => {
                 '  "body": {\n' +
                 '    "response": "body"\n' +
                 '  }\n' +
        -        '}'
        -    ]
        +        '}',
        +    ],
           ], 'some output')
        -  t.strictSame(LOGS, [ [ 'audit', 'message' ] ], 'some warnings')
        +  t.strictSame(LOGS, [['audit', 'message']], 'some warnings')
           t.end()
         })
        diff --git a/deps/npm/test/lib/utils/cleanup-log-files.js b/deps/npm/test/lib/utils/cleanup-log-files.js
        index ee2c11e62ab7ae..7af0633fe715dd 100644
        --- a/deps/npm/test/lib/utils/cleanup-log-files.js
        +++ b/deps/npm/test/lib/utils/cleanup-log-files.js
        @@ -6,7 +6,7 @@ const rimraf = require('rimraf')
         const mocks = { glob, rimraf }
         const cleanup = requireInject('../../../lib/utils/cleanup-log-files.js', {
           glob: (...args) => mocks.glob(...args),
        -  rimraf: (...args) => mocks.rimraf(...args)
        +  rimraf: (...args) => mocks.rimraf(...args),
         })
         const { basename } = require('path')
         
        @@ -19,15 +19,15 @@ t.test('clean up those files', t => {
               '2-debug.log': 'hello',
               '3-debug.log': 'hello',
               '4-debug.log': 'hello',
        -      '5-debug.log': 'hello'
        -    }
        +      '5-debug.log': 'hello',
        +    },
           })
           const warn = (...warning) => t.fail('failed cleanup', { warning })
           return cleanup(cache, 3, warn).then(() => {
             t.strictSame(fs.readdirSync(cache + '/_logs').sort(), [
               '3-debug.log',
               '4-debug.log',
        -      '5-debug.log'
        +      '5-debug.log',
             ])
           })
         })
        @@ -36,14 +36,14 @@ t.test('nothing to clean up', t => {
           const cache = t.testdir({
             _logs: {
               '4-debug.log': 'hello',
        -      '5-debug.log': 'hello'
        -    }
        +      '5-debug.log': 'hello',
        +    },
           })
           const warn = (...warning) => t.fail('failed cleanup', { warning })
           return cleanup(cache, 3, warn).then(() => {
             t.strictSame(fs.readdirSync(cache + '/_logs').sort(), [
               '4-debug.log',
        -      '5-debug.log'
        +      '5-debug.log',
             ])
           })
         })
        @@ -66,15 +66,15 @@ t.test('rimraf fail', t => {
               '2-debug.log': 'hello',
               '3-debug.log': 'hello',
               '4-debug.log': 'hello',
        -      '5-debug.log': 'hello'
        -    }
        +      '5-debug.log': 'hello',
        +    },
           })
           const warnings = []
           const warn = (...warning) => warnings.push(basename(warning[2]))
           return cleanup(cache, 3, warn).then(() => {
             t.strictSame(warnings.sort((a, b) => a.localeCompare(b)), [
               '1-debug.log',
        -      '2-debug.log'
        +      '2-debug.log',
             ])
           })
         })
        diff --git a/deps/npm/test/lib/utils/completion/installed-deep.js b/deps/npm/test/lib/utils/completion/installed-deep.js
        index 74c15e8f77c9f8..a2a3756104f4b7 100644
        --- a/deps/npm/test/lib/utils/completion/installed-deep.js
        +++ b/deps/npm/test/lib/utils/completion/installed-deep.js
        @@ -7,19 +7,25 @@ let globalDir = 'MISSING_GLOBAL_DIR'
         const _flatOptions = {
           depth: Infinity,
           global: false,
        -  get prefix () { return prefix }
        +  get prefix () {
        +    return prefix
        +  },
         }
         const installedDeep = requireInject('../../../../lib/utils/completion/installed-deep.js', {
           '../../../../lib/npm.js': {
             flatOptions: _flatOptions,
        -    get prefix () { return _flatOptions.prefix },
        -    get globalDir () { return globalDir },
        +    get prefix () {
        +      return _flatOptions.prefix
        +    },
        +    get globalDir () {
        +      return globalDir
        +    },
             config: {
               get (key) {
                 return _flatOptions[key]
        -      }
        -    }
        -  }
        +      },
        +    },
        +  },
         })
         
         const fixture = {
        @@ -29,14 +35,14 @@ const fixture = {
             dependencies: {
               a: '^1.0.0',
               b: '^1.0.0',
        -      c: '^1.0.0'
        +      c: '^1.0.0',
             },
             devDependencies: {
        -      d: '^1.0.0'
        +      d: '^1.0.0',
             },
             peerDependencies: {
        -      e: '^1.0.0'
        -    }
        +      e: '^1.0.0',
        +    },
           }),
           node_modules: {
             a: {
        @@ -44,33 +50,33 @@ const fixture = {
                 name: 'a',
                 version: '1.0.0',
                 dependencies: {
        -          f: '^1.0.0'
        -        }
        -      })
        +          f: '^1.0.0',
        +        },
        +      }),
             },
             b: {
               'package.json': JSON.stringify({
                 name: 'b',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             c: {
               'package.json': JSON.stringify({
                 name: 'c',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             d: {
               'package.json': JSON.stringify({
                 name: 'd',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             e: {
               'package.json': JSON.stringify({
                 name: 'e',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             f: {
               'package.json': JSON.stringify({
        @@ -78,8 +84,8 @@ const fixture = {
                 version: '1.0.0',
                 dependencies: {
                   g: '^1.0.0',
        -          e: '^2.0.0'
        -        }
        +          e: '^2.0.0',
        +        },
               }),
               node_modules: {
                 e: {
        @@ -87,27 +93,27 @@ const fixture = {
                     name: 'e',
                     version: '2.0.0',
                     dependencies: {
        -              bb: '^1.0.0'
        -            }
        +              bb: '^1.0.0',
        +            },
                   }),
                   node_modules: {
                     bb: {
                       'package.json': JSON.stringify({
                         name: 'bb',
        -                version: '1.0.0'
        -              })
        -            }
        -          }
        -        }
        -      }
        +                version: '1.0.0',
        +              }),
        +            },
        +          },
        +        },
        +      },
             },
             g: {
               'package.json': JSON.stringify({
                 name: 'g',
        -        version: '1.0.0'
        -      })
        -    }
        -  }
        +        version: '1.0.0',
        +      }),
        +    },
        +  },
         }
         
         const globalFixture = {
        @@ -115,33 +121,33 @@ const globalFixture = {
             foo: {
               'package.json': JSON.stringify({
                 name: 'foo',
        -        version: '1.0.0'
        -      })
        +        version: '1.0.0',
        +      }),
             },
             bar: {
               'package.json': JSON.stringify({
                 name: 'bar',
                 version: '1.0.0',
                 dependencies: {
        -          'a-bar': '^1.0.0'
        -        }
        +          'a-bar': '^1.0.0',
        +        },
               }),
               node_modules: {
                 'a-bar': {
                   'package.json': JSON.stringify({
                     name: 'a-bar',
        -            version: '1.0.0'
        -          })
        -        }
        -      }
        -    }
        -  }
        +            version: '1.0.0',
        +          }),
        +        },
        +      },
        +    },
        +  },
         }
         
         test('get list of package names', (t) => {
           const fix = t.testdir({
             local: fixture,
        -    global: globalFixture
        +    global: globalFixture,
           })
         
           prefix = resolve(fix, 'local')
        @@ -152,12 +158,12 @@ test('get list of package names', (t) => {
             t.deepEqual(
               res,
               [
        -        [ 'bar', '-g' ],
        -        [ 'foo', '-g' ],
        -        [ 'a-bar', '-g' ],
        +        ['bar', '-g'],
        +        ['foo', '-g'],
        +        ['a-bar', '-g'],
                 'a', 'b', 'c',
                 'd', 'e', 'f',
        -        'g', 'bb'
        +        'g', 'bb',
               ],
               'should return list of package names and global flag'
             )
        @@ -168,7 +174,7 @@ test('get list of package names', (t) => {
         test('get list of package names as global', (t) => {
           const fix = t.testdir({
             local: fixture,
        -    global: globalFixture
        +    global: globalFixture,
           })
         
           prefix = resolve(fix, 'local')
        @@ -183,7 +189,7 @@ test('get list of package names as global', (t) => {
               [
                 'bar',
                 'foo',
        -        'a-bar'
        +        'a-bar',
               ],
               'should return list of global packages with no extra flags'
             )
        @@ -195,7 +201,7 @@ test('get list of package names as global', (t) => {
         test('limit depth', (t) => {
           const fix = t.testdir({
             local: fixture,
        -    global: globalFixture
        +    global: globalFixture,
           })
         
           prefix = resolve(fix, 'local')
        @@ -208,12 +214,12 @@ test('limit depth', (t) => {
             t.deepEqual(
               res,
               [
        -        [ 'bar', '-g' ],
        -        [ 'foo', '-g' ],
        +        ['bar', '-g'],
        +        ['foo', '-g'],
                 'a', 'b',
                 'c', 'd',
                 'e', 'f',
        -        'g'
        +        'g',
               ],
               'should print only packages up to the specified depth'
             )
        @@ -225,7 +231,7 @@ test('limit depth', (t) => {
         test('limit depth as global', (t) => {
           const fix = t.testdir({
             local: fixture,
        -    global: globalFixture
        +    global: globalFixture,
           })
         
           prefix = resolve(fix, 'local')
        @@ -240,7 +246,7 @@ test('limit depth as global', (t) => {
               res,
               [
                 'bar',
        -        'foo'
        +        'foo',
               ],
               'should reorder so that packages above that level depth goes last'
             )
        diff --git a/deps/npm/test/lib/utils/completion/installed-shallow.js b/deps/npm/test/lib/utils/completion/installed-shallow.js
        index eb628a8ce81e31..1d6369bc782545 100644
        --- a/deps/npm/test/lib/utils/completion/installed-shallow.js
        +++ b/deps/npm/test/lib/utils/completion/installed-shallow.js
        @@ -6,7 +6,7 @@ const { resolve } = require('path')
         
         const p = '../../../../lib/utils/completion/installed-shallow.js'
         const installed = requireInject(p, {
        -  '../../../../lib/npm.js': npm
        +  '../../../../lib/npm.js': npm,
         })
         
         t.test('global not set, include globals with -g', t => {
        @@ -15,32 +15,32 @@ t.test('global not set, include globals with -g', t => {
               node_modules: {
                 x: {},
                 '@scope': {
        -          y: {}
        -        }
        -      }
        +          y: {},
        +        },
        +      },
             },
             local: {
               node_modules: {
                 a: {},
                 '@scope': {
        -          b: {}
        -        }
        -      }
        -    }
        +          b: {},
        +        },
        +      },
        +    },
           })
           npm.globalDir = resolve(dir, 'global/node_modules')
           npm.localDir = resolve(dir, 'local/node_modules')
           flatOptions.global = false
           const opt = { conf: { argv: { remain: [] } } }
           installed(opt, (er, res) => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame(res.sort(), [
               '@scope/y -g',
               'x -g',
               'a',
        -      '@scope/b'
        +      '@scope/b',
             ].sort())
             t.end()
           })
        @@ -52,18 +52,18 @@ t.test('global set, include globals and not locals', t => {
               node_modules: {
                 x: {},
                 '@scope': {
        -          y: {}
        -        }
        -      }
        +          y: {},
        +        },
        +      },
             },
             local: {
               node_modules: {
                 a: {},
                 '@scope': {
        -          b: {}
        -        }
        -      }
        -    }
        +          b: {},
        +        },
        +      },
        +    },
           })
           npm.globalDir = resolve(dir, 'global/node_modules')
           npm.localDir = resolve(dir, 'local/node_modules')
        @@ -72,7 +72,7 @@ t.test('global set, include globals and not locals', t => {
           installed(opt, (er, res) => {
             t.strictSame(res.sort(), [
               '@scope/y',
        -      'x'
        +      'x',
             ].sort())
             t.end()
           })
        @@ -84,27 +84,27 @@ t.test('more than 3 items in argv, skip it', t => {
               node_modules: {
                 x: {},
                 '@scope': {
        -          y: {}
        -        }
        -      }
        +          y: {},
        +        },
        +      },
             },
             local: {
               node_modules: {
                 a: {},
                 '@scope': {
        -          b: {}
        -        }
        -      }
        -    }
        +          b: {},
        +        },
        +      },
        +    },
           })
           npm.globalDir = resolve(dir, 'global/node_modules')
           npm.localDir = resolve(dir, 'local/node_modules')
           flatOptions.global = false
           const opt = { conf: { argv: { remain: [1, 2, 3, 4, 5, 6] } } }
           installed(opt, (er, res) => {
        -    if (er) {
        +    if (er)
               throw er
        -    }
        +
             t.strictSame(res, null)
             t.end()
           })
        diff --git a/deps/npm/test/lib/utils/completion/none.js b/deps/npm/test/lib/utils/completion/none.js
        index 27f713b81e16b8..70488be07ec159 100644
        --- a/deps/npm/test/lib/utils/completion/none.js
        +++ b/deps/npm/test/lib/utils/completion/none.js
        @@ -1,6 +1,6 @@
         const t = require('tap')
         const none = require('../../../../lib/utils/completion/none.js')
        -none({any:'thing'}, (er, res) => {
        +none({any: 'thing'}, (er, res) => {
           t.equal(er, null)
           t.strictSame(res, [])
         })
        diff --git a/deps/npm/test/lib/utils/config.js b/deps/npm/test/lib/utils/config.js
        index e8133eecb24f1b..38fbe6753e75b0 100644
        --- a/deps/npm/test/lib/utils/config.js
        +++ b/deps/npm/test/lib/utils/config.js
        @@ -4,25 +4,25 @@ Object.defineProperty(process, 'umask', {
           value: () => 0o26,
           writable: true,
           configurable: true,
        -  enumerable: true
        +  enumerable: true,
         })
         
         // have to fake the node version, or else it'll only pass on this one
         Object.defineProperty(process, 'version', {
        -  value: 'v14.8.0'
        +  value: 'v14.8.0',
         })
         
         t.formatSnapshot = obj => {
        -  if (typeof obj !== 'object' || !obj || !obj.types) {
        +  if (typeof obj !== 'object' || !obj || !obj.types)
             return obj
        -  }
        +
           return {
             ...obj,
             defaults: {
               ...obj.defaults,
        -      cache: '{CACHE DIR} ' + path.basename(obj.defaults.cache)
        +      cache: '{CACHE DIR} ' + path.basename(obj.defaults.cache),
             },
        -    types: formatTypes(obj.types)
        +    types: formatTypes(obj.types),
           }
         }
         
        @@ -38,19 +38,18 @@ const formatTypes = (types) => Object.entries(types).map(([key, value]) => {
         }, {})
         
         const formatTypeValue = (value) => {
        -  if (Array.isArray(value)) {
        +  if (Array.isArray(value))
             return value.map(formatTypeValue)
        -  } else if (value === url) {
        +  else if (value === url)
             return '{URL MODULE}'
        -  } else if (value === path) {
        +  else if (value === path)
             return '{PATH MODULE}'
        -  } else if (value === semver) {
        +  else if (value === semver)
             return '{SEMVER MODULE}'
        -  } else if (typeof value === 'function') {
        +  else if (typeof value === 'function')
             return `{${value.name} TYPE}`
        -  } else {
        +  else
             return value
        -  }
         }
         
         process.env.ComSpec = 'cmd.exe'
        @@ -65,8 +64,8 @@ const networkInterfacesThrow = () => {
           throw new Error('no network interfaces for some reason')
         }
         const networkInterfaces = () => ({
        -  'eth420': [{ address: '127.0.0.1' }],
        -  'eth69': [{ address: 'no place like home' }]
        +  eth420: [{ address: '127.0.0.1' }],
        +  eth69: [{ address: 'no place like home' }],
         })
         const tmpdir = () => '/tmp'
         const os = { networkInterfaces, tmpdir }
        @@ -77,7 +76,7 @@ t.test('working network interfaces, not windows', t => {
             os,
             '@npmcli/ci-detect': () => false,
             '../../../lib/utils/is-windows.js': false,
        -    '../../../package.json': pkg
        +    '../../../package.json': pkg,
           })
           t.matchSnapshot(config)
           t.end()
        @@ -88,7 +87,7 @@ t.test('no working network interfaces, on windows', t => {
             os: { tmpdir, networkInterfaces: networkInterfacesThrow },
             '@npmcli/ci-detect': () => false,
             '../../../lib/utils/is-windows.js': true,
        -    '../../../package.json': pkg
        +    '../../../package.json': pkg,
           })
           t.matchSnapshot(config)
           t.end()
        @@ -99,21 +98,21 @@ t.test('no process.umask() method', t => {
             value: null,
             writable: true,
             configurable: true,
        -    enumerable: true
        +    enumerable: true,
           })
           t.teardown(() => {
             Object.defineProperty(process, 'umask', {
               value: () => 0o26,
               writable: true,
               configurable: true,
        -      enumerable: true
        +      enumerable: true,
             })
           })
           const config = requireInject('../../../lib/utils/config.js', {
             os: { tmpdir, networkInterfaces: networkInterfacesThrow },
             '@npmcli/ci-detect': () => false,
             '../../../lib/utils/is-windows.js': true,
        -    '../../../package.json': pkg
        +    '../../../package.json': pkg,
           })
           t.equal(config.defaults.umask, 0o22)
           t.matchSnapshot(config)
        @@ -125,7 +124,7 @@ t.test('no comspec on windows', t => {
           const config = requireInject('../../../lib/utils/config.js', {
             os: { tmpdir, networkInterfaces: networkInterfacesThrow },
             '@npmcli/ci-detect': () => false,
        -    '../../../lib/utils/is-windows.js': true
        +    '../../../lib/utils/is-windows.js': true,
           })
           t.equal(config.defaults.shell, 'cmd')
           t.end()
        @@ -136,7 +135,7 @@ t.test('no shell on posix', t => {
           const config = requireInject('../../../lib/utils/config.js', {
             os,
             '@npmcli/ci-detect': () => false,
        -    '../../../lib/utils/is-windows.js': false
        +    '../../../lib/utils/is-windows.js': false,
           })
           t.equal(config.defaults.shell, 'sh')
           t.end()
        @@ -147,7 +146,7 @@ t.test('no EDITOR env, use VISUAL', t => {
           const config = requireInject('../../../lib/utils/config.js', {
             os,
             '@npmcli/ci-detect': () => false,
        -    '../../../lib/utils/is-windows.js': false
        +    '../../../lib/utils/is-windows.js': false,
           })
           t.equal(config.defaults.editor, 'mate')
           t.end()
        @@ -158,7 +157,7 @@ t.test('no VISUAL, use system default, not windows', t => {
           const config = requireInject('../../../lib/utils/config.js', {
             os,
             '@npmcli/ci-detect': () => false,
        -    '../../../lib/utils/is-windows.js': false
        +    '../../../lib/utils/is-windows.js': false,
           })
           t.equal(config.defaults.editor, 'vi')
           t.end()
        @@ -169,7 +168,7 @@ t.test('no VISUAL, use system default, not windows', t => {
           const config = requireInject('../../../lib/utils/config.js', {
             os,
             '@npmcli/ci-detect': () => false,
        -    '../../../lib/utils/is-windows.js': true
        +    '../../../lib/utils/is-windows.js': true,
           })
           t.equal(config.defaults.editor, 'notepad.exe')
           t.end()
        diff --git a/deps/npm/test/lib/utils/error-handler.js b/deps/npm/test/lib/utils/error-handler.js
        index 840b3a35650313..2dc116a4d31711 100644
        --- a/deps/npm/test/lib/utils/error-handler.js
        +++ b/deps/npm/test/lib/utils/error-handler.js
        @@ -26,23 +26,23 @@ t.cleanSnapshot = (str) => redactCwd(str)
         // internal modules mocks
         const cacheFile = {
           append: () => null,
        -  write: () => null
        +  write: () => null,
         }
         const config = {
           values: {
             cache: 'cachefolder',
        -    timing: true
        +    timing: true,
           },
           loaded: true,
           updateNotification: null,
           get (key) {
             return this.values[key]
        -  }
        +  },
         }
         
         const npm = {
           version: '1.0.0',
        -  config
        +  config,
         }
         
         const npmlog = {
        @@ -52,26 +52,34 @@ const npmlog = {
               id: this.record.length,
               level,
               message: args.reduce((res, i) => `${res} ${i.message ? i.message : i}`, ''),
        -      prefix: level !== 'verbose' ? 'foo' : ''
        +      prefix: level !== 'verbose' ? 'foo' : '',
             })
           },
        -  error (...args) { this.log('error', ...args) },
        -  info (...args) { this.log('info', ...args) },
        +  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
        +    silent: 4,
        +  },
        +  notice (...args) {
        +    this.log('notice', ...args)
           },
        -  notice (...args) { this.log('notice', ...args) },
           record: [],
        -  verbose (...args) { this.log('verbose', ...args) }
        +  verbose (...args) {
        +    this.log('verbose', ...args)
        +  },
         }
         
         const metrics = {
        -  stop: () => null
        +  stop: () => null,
         }
         
         // overrides OS type/release for cross platform snapshots
        @@ -96,8 +104,10 @@ process = Object.assign(
             exit () {},
             exitCode: 0,
             version: 'v1.0.0',
        -    stdout: { write (_, cb) { cb() } },
        -    stderr: { write () {} }
        +    stdout: { write (_, cb) {
        +      cb()
        +    } },
        +    stderr: { write () {} },
           }
         )
         // needs to put process back in its place
        @@ -112,10 +122,10 @@ const mocks = {
           '../../../lib/utils/error-message.js': (err) => ({
             ...err,
             summary: [['ERR', err.message]],
        -    detail: [['ERR', err.message]]
        +    detail: [['ERR', err.message]],
           }),
           '../../../lib/utils/metrics.js': metrics,
        -  '../../../lib/utils/cache-file.js': cacheFile
        +  '../../../lib/utils/cache-file.js': cacheFile,
         }
         
         requireInject.installGlobally('../../../lib/utils/error-handler.js', mocks)
        @@ -218,16 +228,16 @@ t.test('console.log output using --json', (t) => {
         
           config.values.json = true
         
        -  const _log = console.log
        -  console.log = (jsonOutput) => {
        +  const _error = console.error
        +  console.error = (jsonOutput) => {
             t.deepEqual(
               JSON.parse(jsonOutput),
               {
                 error: {
                   code: 'EBADTHING', // should default error code to E[A-Z]+
                   summary: 'Error: EBADTHING Something happened',
        -          detail: 'Error: EBADTHING Something happened'
        -        }
        +          detail: 'Error: EBADTHING Something happened',
        +        },
               },
               'should output expected json output'
             )
        @@ -236,7 +246,7 @@ t.test('console.log output using --json', (t) => {
           errorHandler(new Error('Error: EBADTHING Something happened'))
         
           t.teardown(() => {
        -    console.log = _log
        +    console.error = _error
             delete config.values.json
           })
         })
        @@ -246,7 +256,7 @@ t.test('throw a non-error obj', (t) => {
         
           const weirdError = {
             code: 'ESOMETHING',
        -    message: 'foo bar'
        +    message: 'foo bar',
           }
         
           const _logError = npmlog.error
        @@ -379,7 +389,7 @@ t.test('uses code from errno', (t) => {
           errorHandler(Object.assign(
             new Error('Error with errno'),
             {
        -      errno: 127
        +      errno: 127,
             }
           ))
         
        @@ -408,7 +418,7 @@ t.test('uses exitCode as code if using a number', (t) => {
           errorHandler(Object.assign(
             new Error('Error with code type number'),
             {
        -      code: 404
        +      code: 404,
             }
           ))
         
        @@ -464,7 +474,7 @@ t.test('defaults to log error msg if stack is missing', (t) => {
             new Error('Error with no stack'),
             {
               code: 'ENOSTACK',
        -      errno: 127
        +      errno: 127,
             }
           )
           delete noStackErr.stack
        diff --git a/deps/npm/test/lib/utils/error-message.js b/deps/npm/test/lib/utils/error-message.js
        index 2647a8e1994ea1..86db7c94bad496 100644
        --- a/deps/npm/test/lib/utils/error-message.js
        +++ b/deps/npm/test/lib/utils/error-message.js
        @@ -7,13 +7,13 @@ process.getgid = () => 420
         
         Object.defineProperty(process, 'arch', {
           value: 'x64',
        -  configurable: true
        +  configurable: true,
         })
         
         const beWindows = () => {
           Object.defineProperty(process, 'platform', {
             value: 'win32',
        -    configurable: true
        +    configurable: true,
           })
           delete require.cache[require.resolve('../../../lib/utils/is-windows.js')]
         }
        @@ -21,7 +21,7 @@ const beWindows = () => {
         const bePosix = () => {
           Object.defineProperty(process, 'platform', {
             value: 'posix',
        -    configurable: true
        +    configurable: true,
           })
           delete require.cache[require.resolve('../../../lib/utils/is-windows.js')]
         }
        @@ -33,22 +33,21 @@ npm.config = {
           loaded: false,
           localPrefix: '/some/prefix/dir',
           get: key => {
        -    if (key === 'cache') {
        +    if (key === 'cache')
               return CACHE
        -    } else if (key === 'node-version') {
        +    else if (key === 'node-version')
               return '99.99.99'
        -    } else if (key === 'global') {
        +    else if (key === 'global')
               return false
        -    } else {
        +    else
               throw new Error('unexpected config lookup: ' + key)
        -    }
        -  }
        +  },
         }
         
         npm.version = '123.69.420-npm'
         Object.defineProperty(process, 'version', {
           value: '123.69.420-node',
        -  configurable: true
        +  configurable: true,
         })
         
         const npmlog = require('npmlog')
        @@ -64,8 +63,8 @@ const errorMessage = requireInject('../../../lib/utils/error-message.js', {
             report: (...args) => {
               EXPLAIN_CALLED.push(args)
               return 'explanation'
        -    }
        -  }
        +    },
        +  },
         })
         
         t.test('just simple messages', t => {
        @@ -92,7 +91,7 @@ t.test('just simple messages', t => {
             'EINVALIDTYPE',
             'ETOOMANYARGS',
             'ETARGET',
        -    'E403'
        +    'E403',
           ]
           t.plan(codes.length)
           codes.forEach(code => {
        @@ -100,13 +99,12 @@ t.test('just simple messages', t => {
             const pkgid = 'some@package'
             const file = '/some/file'
             const stack = 'dummy stack trace'
        -    const required = { node: '1.2.3', npm: '4.2.0' }
             const er = Object.assign(new Error('foo'), {
               code,
               path,
               pkgid,
               file,
        -      stack
        +      stack,
             })
             t.matchSnapshot(errorMessage(er))
           })
        @@ -132,18 +130,19 @@ t.test('replace message/stack sensistive info', t => {
         
         t.test('bad engine with config loaded', t => {
           npm.config.loaded = true
        -  t.teardown(() => { npm.config.loaded = false })
        +  t.teardown(() => {
        +    npm.config.loaded = false
        +  })
           const path = '/some/path'
           const pkgid = 'some@package'
           const file = '/some/file'
           const stack = 'dummy stack trace'
        -  const required = { node: '1.2.3', npm: '4.2.0' }
           const er = Object.assign(new Error('foo'), {
             code: 'EBADENGINE',
             path,
             pkgid,
             file,
        -    stack
        +    stack,
           })
           t.matchSnapshot(errorMessage(er))
           t.end()
        @@ -152,14 +151,12 @@ t.test('bad engine with config loaded', t => {
         t.test('enoent without a file', t => {
           const path = '/some/path'
           const pkgid = 'some@package'
        -  const file = '/some/file'
           const stack = 'dummy stack trace'
        -  const required = { node: '1.2.3', npm: '4.2.0' }
           const er = Object.assign(new Error('foo'), {
             code: 'ENOENT',
             path,
             pkgid,
        -    stack
        +    stack,
           })
           t.matchSnapshot(errorMessage(er))
           t.end()
        @@ -171,13 +168,12 @@ t.test('enolock without a command', t => {
           const pkgid = 'some@package'
           const file = '/some/file'
           const stack = 'dummy stack trace'
        -  const required = { node: '1.2.3', npm: '4.2.0' }
           const er = Object.assign(new Error('foo'), {
             code: 'ENOLOCK',
             path,
             pkgid,
             file,
        -    stack
        +    stack,
           })
           t.matchSnapshot(errorMessage(er))
           t.end()
        @@ -191,18 +187,18 @@ t.test('default message', t => {
             signal: 'SIGYOLO',
             args: ['a', 'r', 'g', 's'],
             stdout: 'stdout',
        -    stderr: 'stderr'
        +    stderr: 'stderr',
           })))
           t.end()
         })
         
         t.test('eacces/eperm', t => {
           const runTest = (windows, loaded, cachePath, cacheDest) => t => {
        -    if (windows) {
        +    if (windows)
               beWindows()
        -    } else {
        +    else
               bePosix()
        -    }
        +
             npm.config.loaded = loaded
             const path = `${cachePath ? CACHE : '/not/cache/dir'}/path`
             const dest = `${cacheDest ? CACHE : '/not/cache/dir'}/dest`
        @@ -210,7 +206,7 @@ t.test('eacces/eperm', t => {
               code: 'EACCES',
               path,
               dest,
        -      stack: 'dummy stack trace'
        +      stack: 'dummy stack trace',
             })
             verboseLogs.length = 0
             t.matchSnapshot(errorMessage(er))
        @@ -272,36 +268,36 @@ t.test('json parse', t => {
             }
           }
         }
        -`
        +`,
             })
             const { prefix } = npm
             const { argv } = process
             t.teardown(() => {
               Object.defineProperty(npm, 'prefix', {
                 value: prefix,
        -        configurable: true
        +        configurable: true,
               })
               process.argv = argv
             })
             Object.defineProperty(npm, 'prefix', { value: dir, configurable: true })
             process.argv = ['arg', 'v']
        -    const ok = t.matchSnapshot(errorMessage(Object.assign(new Error('conflicted'), {
        +    t.matchSnapshot(errorMessage(Object.assign(new Error('conflicted'), {
               code: 'EJSONPARSE',
        -      file: resolve(dir, 'package.json')
        +      file: resolve(dir, 'package.json'),
             })))
             t.end()
           })
         
           t.test('just regular bad json in package.json', t => {
             const dir = t.testdir({
        -      'package.json': 'not even slightly json'
        +      'package.json': 'not even slightly json',
             })
             const { prefix } = npm
             const { argv } = process
             t.teardown(() => {
               Object.defineProperty(npm, 'prefix', {
                 value: prefix,
        -        configurable: true
        +        configurable: true,
               })
               process.argv = argv
             })
        @@ -309,14 +305,14 @@ t.test('json parse', t => {
             process.argv = ['arg', 'v']
             t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), {
               code: 'EJSONPARSE',
        -      file: resolve(dir, 'package.json')
        +      file: resolve(dir, 'package.json'),
             })))
             t.end()
           })
         
           t.test('json somewhere else', t => {
             const dir = t.testdir({
        -      'blerg.json': 'not even slightly json'
        +      'blerg.json': 'not even slightly json',
             })
             const { argv } = process
             t.teardown(() => {
        @@ -325,7 +321,7 @@ t.test('json parse', t => {
             process.argv = ['arg', 'v']
             t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), {
               code: 'EJSONPARSE',
        -      file: `${dir}/blerg.json`
        +      file: `${dir}/blerg.json`,
             })))
             t.end()
           })
        @@ -336,7 +332,7 @@ t.test('json parse', t => {
         t.test('eotp/e401', t => {
           t.test('401, no auth headers', t => {
             t.matchSnapshot(errorMessage(Object.assign(new Error('nope'), {
        -      code: 'E401'
        +      code: 'E401',
             })))
             t.end()
           })
        @@ -350,7 +346,7 @@ t.test('eotp/e401', t => {
         
           t.test('one-time pass challenge code', t => {
             t.matchSnapshot(errorMessage(Object.assign(new Error('nope'), {
        -      code: 'EOTP'
        +      code: 'EOTP',
             })))
             t.end()
           })
        @@ -358,7 +354,7 @@ t.test('eotp/e401', t => {
           t.test('one-time pass challenge message', t => {
             const message = 'one-time pass'
             t.matchSnapshot(errorMessage(Object.assign(new Error(message), {
        -      code: 'E401'
        +      code: 'E401',
             })))
             t.end()
           })
        @@ -368,16 +364,16 @@ t.test('eotp/e401', t => {
               'Bearer realm=do, charset="UTF-8", challenge="yourself"',
               'Basic realm=by, charset="UTF-8", challenge="your friends"',
               'PickACardAnyCard realm=friday, charset="UTF-8"',
        -      'WashYourHands, charset="UTF-8"'
        +      'WashYourHands, charset="UTF-8"',
             ]
             t.plan(auths.length)
             for (const auth of auths) {
               t.test(auth, t => {
                 const er = Object.assign(new Error('challenge!'), {
                   headers: {
        -            'www-authenticate': [ auth ]
        +            'www-authenticate': [auth],
                   },
        -          code: 'E401'
        +          code: 'E401',
                 })
                 t.matchSnapshot(errorMessage(er))
                 t.end()
        @@ -397,7 +393,7 @@ t.test('404', t => {
           t.test('you should publish it', t => {
             const er = Object.assign(new Error('404 not found'), {
               pkgid: 'yolo',
        -      code: 'E404'
        +      code: 'E404',
             })
             t.matchSnapshot(errorMessage(er))
             t.end()
        @@ -405,7 +401,7 @@ t.test('404', t => {
           t.test('name with warning', t => {
             const er = Object.assign(new Error('404 not found'), {
               pkgid: new Array(215).fill('x').join(''),
        -      code: 'E404'
        +      code: 'E404',
             })
             t.matchSnapshot(errorMessage(er))
             t.end()
        @@ -413,7 +409,7 @@ t.test('404', t => {
           t.test('name with error', t => {
             const er = Object.assign(new Error('404 not found'), {
               pkgid: 'node_modules',
        -      code: 'E404'
        +      code: 'E404',
             })
             t.matchSnapshot(errorMessage(er))
             t.end()
        @@ -427,13 +423,13 @@ t.test('bad platform', t => {
               pkgid: 'lodash@1.0.0',
               current: {
                 os: 'posix',
        -        cpu: 'x64'
        +        cpu: 'x64',
               },
               required: {
                 os: '!yours',
        -        cpu: 'x420'
        +        cpu: 'x420',
               },
        -      code: 'EBADPLATFORM'
        +      code: 'EBADPLATFORM',
             })
             t.matchSnapshot(errorMessage(er))
             t.end()
        @@ -443,13 +439,13 @@ t.test('bad platform', t => {
               pkgid: 'lodash@1.0.0',
               current: {
                 os: 'posix',
        -        cpu: 'x64'
        +        cpu: 'x64',
               },
               required: {
                 os: ['!yours', 'mine'],
        -        cpu: ['x420', 'x69']
        +        cpu: ['x420', 'x69'],
               },
        -      code: 'EBADPLATFORM'
        +      code: 'EBADPLATFORM',
             })
             t.matchSnapshot(errorMessage(er))
             t.end()
        @@ -460,7 +456,7 @@ t.test('bad platform', t => {
         
         t.test('explain ERESOLVE errors', t => {
           const er = Object.assign(new Error('could not resolve'), {
        -    code: 'ERESOLVE'
        +    code: 'ERESOLVE',
           })
           t.matchSnapshot(errorMessage(er))
           t.strictSame(EXPLAIN_CALLED, [[er]])
        diff --git a/deps/npm/test/lib/utils/escape-arg.js b/deps/npm/test/lib/utils/escape-arg.js
        index 413fa47838bac6..b80a63f0b877bc 100644
        --- a/deps/npm/test/lib/utils/escape-arg.js
        +++ b/deps/npm/test/lib/utils/escape-arg.js
        @@ -2,7 +2,7 @@ const requireInject = require('require-inject')
         const t = require('tap')
         const getEscape = win => requireInject('../../../lib/utils/escape-arg.js', {
           '../../../lib/utils/is-windows.js': win,
        -  path: require('path')[win ? 'win32' : 'posix']
        +  path: require('path')[win ? 'win32' : 'posix'],
         })
         
         const winEscape = getEscape(true)
        diff --git a/deps/npm/test/lib/utils/escape-exec-path.js b/deps/npm/test/lib/utils/escape-exec-path.js
        index 28fe75c2a98f4f..f16c576ec5550e 100644
        --- a/deps/npm/test/lib/utils/escape-exec-path.js
        +++ b/deps/npm/test/lib/utils/escape-exec-path.js
        @@ -2,7 +2,7 @@ const requireInject = require('require-inject')
         const t = require('tap')
         const getEscape = win => requireInject('../../../lib/utils/escape-exec-path.js', {
           '../../../lib/utils/is-windows.js': win,
        -  path: require('path')[win ? 'win32' : 'posix']
        +  path: require('path')[win ? 'win32' : 'posix'],
         })
         
         const winEscape = getEscape(true)
        diff --git a/deps/npm/test/lib/utils/explain-dep.js b/deps/npm/test/lib/utils/explain-dep.js
        index e0305348653af0..28f14477ab709b 100644
        --- a/deps/npm/test/lib/utils/explain-dep.js
        +++ b/deps/npm/test/lib/utils/explain-dep.js
        @@ -2,7 +2,7 @@ const t = require('tap')
         const requireInject = require('require-inject')
         const npm = {}
         const { explainNode, printNode } = requireInject('../../../lib/utils/explain-dep.js', {
        -  '../../../lib/npm.js': npm
        +  '../../../lib/npm.js': npm,
         })
         
         const cases = {
        @@ -16,10 +16,10 @@ const cases = {
                 name: 'prod-dep',
                 spec: '1.x',
                 from: {
        -          location: '/path/to/project'
        -        }
        -      }
        -    ]
        +          location: '/path/to/project',
        +        },
        +      },
        +    ],
           },
         
           deepDev: {
        @@ -51,16 +51,16 @@ const cases = {
                             name: 'topdev',
                             spec: '4.x',
                             from: {
        -                      location: '/path/to/project'
        -                    }
        -                  }
        -                ]
        -              }
        -            }
        -          ]
        -        }
        -      }
        -    ]
        +                      location: '/path/to/project',
        +                    },
        +                  },
        +                ],
        +              },
        +            },
        +          ],
        +        },
        +      },
        +    ],
           },
         
           optional: {
        @@ -74,10 +74,10 @@ const cases = {
                 name: 'optdep',
                 spec: '1.0.0',
                 from: {
        -          location: '/path/to/project'
        -        }
        -      }
        -    ]
        +          location: '/path/to/project',
        +        },
        +      },
        +    ],
           },
         
           peer: {
        @@ -91,10 +91,10 @@ const cases = {
                 name: 'peer',
                 spec: '1.0.0',
                 from: {
        -          location: '/path/to/project'
        -        }
        -      }
        -    ]
        +          location: '/path/to/project',
        +        },
        +      },
        +    ],
           },
         
           extraneous: {
        @@ -102,8 +102,8 @@ const cases = {
             version: '1337.420.69-lol',
             location: 'node_modules/extra-neos',
             dependents: [],
        -    extraneous: true
        -  }
        +    extraneous: true,
        +  },
         }
         
         cases.manyDeps = {
        @@ -114,31 +114,39 @@ cases.manyDeps = {
               type: 'prod',
               name: 'manydep',
               spec: '1.0.0',
        -      from: cases.prodDep
        +      from: cases.prodDep,
             },
             {
               type: 'optional',
               name: 'manydep',
               spec: '1.x',
        -      from: cases.optional
        +      from: cases.optional,
             },
             {
               type: 'prod',
               name: 'manydep',
               spec: '1.0.x',
        -      from: cases.extraneous
        +      from: cases.extraneous,
             },
             {
               type: 'dev',
               name: 'manydep',
               spec: '*',
        -      from: cases.deepDev
        +      from: cases.deepDev,
             },
             {
               type: 'peer',
               name: 'manydep',
               spec: '>1.0.0-beta <1.0.1',
        -      from: cases.peer
        +      from: cases.peer,
        +    },
        +    {
        +      type: 'prod',
        +      name: 'manydep',
        +      spec: '>1.0.0-beta <1.0.1',
        +      from: {
        +        location: '/path/to/project',
        +      },
             },
             {
               type: 'prod',
        @@ -148,9 +156,9 @@ cases.manyDeps = {
                 name: 'a package with a pretty long name',
                 version: '1.2.3',
                 dependents: {
        -          location: '/path/to/project'
        -        }
        -      }
        +          location: '/path/to/project',
        +        },
        +      },
             },
             {
               type: 'prod',
        @@ -160,9 +168,9 @@ cases.manyDeps = {
                 name: 'another package with a pretty long name',
                 version: '1.2.3',
                 dependents: {
        -          location: '/path/to/project'
        -        }
        -      }
        +          location: '/path/to/project',
        +        },
        +      },
             },
             {
               type: 'prod',
        @@ -172,14 +180,13 @@ cases.manyDeps = {
                 name: 'yet another a package with a pretty long name',
                 version: '1.2.3',
                 dependents: {
        -          location: '/path/to/project'
        -        }
        -      }
        +          location: '/path/to/project',
        +        },
        +      },
             },
        -  ]
        +  ],
         }
         
        -
         for (const [name, expl] of Object.entries(cases)) {
           t.test(name, t => {
             npm.color = true
        diff --git a/deps/npm/test/lib/utils/explain-eresolve.js b/deps/npm/test/lib/utils/explain-eresolve.js
        index def13153d242dd..8dae1b92cd514f 100644
        --- a/deps/npm/test/lib/utils/explain-eresolve.js
        +++ b/deps/npm/test/lib/utils/explain-eresolve.js
        @@ -2,7 +2,7 @@ const t = require('tap')
         const requireInject = require('require-inject')
         const npm = {}
         const { explain, report } = requireInject('../../../lib/utils/explain-eresolve.js', {
        -  '../../../lib/npm.js': npm
        +  '../../../lib/npm.js': npm,
         })
         const { statSync, readFileSync, unlinkSync } = require('fs')
         // strip out timestamps from reports
        diff --git a/deps/npm/test/lib/utils/file-exists.js b/deps/npm/test/lib/utils/file-exists.js
        index f247f564e0766a..473a4b050edef2 100644
        --- a/deps/npm/test/lib/utils/file-exists.js
        +++ b/deps/npm/test/lib/utils/file-exists.js
        @@ -3,7 +3,7 @@ const fileExists = require('../../../lib/utils/file-exists.js')
         
         test('returns true when arg is a file', async (t) => {
           const path = t.testdir({
        -    foo: 'just some file'
        +    foo: 'just some file',
           })
         
           const result = await fileExists(`${path}/foo`)
        @@ -13,7 +13,7 @@ test('returns true when arg is a file', async (t) => {
         
         test('returns false when arg is not a file', async (t) => {
           const path = t.testdir({
        -    foo: {}
        +    foo: {},
           })
         
           const result = await fileExists(`${path}/foo`)
        diff --git a/deps/npm/test/lib/utils/flat-options.js b/deps/npm/test/lib/utils/flat-options.js
        index d3b8b89bc865ab..82c00fc7e5de25 100644
        --- a/deps/npm/test/lib/utils/flat-options.js
        +++ b/deps/npm/test/lib/utils/flat-options.js
        @@ -12,7 +12,7 @@ class Mocknpm {
             this.modes = {
               exec: 0o777,
               file: 0o666,
        -      umask: 0o22
        +      umask: 0o22,
             }
             this.color = true
             this.projectScope = '@npmcli'
        @@ -110,14 +110,16 @@ class MockConfig {
               'user-agent': 'user-agent',
               '@scope:registry': '@scope:registry',
               '//nerf.dart:_authToken': '//nerf.dart:_authToken',
        -      'proxy': 'proxy',
        -      'noproxy': 'noproxy',
        -      ...opts
        +      proxy: 'proxy',
        +      noproxy: 'noproxy',
        +      ...opts,
             }]
           }
        +
           get (key) {
             return this.list[0][key]
           }
        +
           set (key, val) {
             this.list[0][key] = val
           }
        @@ -127,7 +129,7 @@ const flatOptions = require('../../../lib/utils/flat-options.js')
         t.match(logs, [[
           'verbose',
           'npm-session',
        -  /^[0-9a-f]{16}$/
        +  /^[0-9a-f]{16}$/,
         ]], 'logged npm session verbosely')
         logs.length = 0
         
        @@ -139,7 +141,7 @@ t.test('basic', t => {
             npmBin: '/path/to/npm/bin.js',
             log: {},
             npmSession: '12345',
        -    cache: generatedFlat.cache.replace(/\\/g, '/')
        +    cache: generatedFlat.cache.replace(/\\/g, '/'),
           }
           t.matchSnapshot(clean, 'flat options')
           t.equal(generatedFlat.npmCommand, null, 'command not set yet')
        @@ -158,7 +160,7 @@ t.test('basic', t => {
         t.test('get preferOffline from cache-min', t => {
           const npm = new Mocknpm({
             'cache-min': 9999999,
        -    'prefer-offline': undefined
        +    'prefer-offline': undefined,
           })
           const opts = flatOptions(npm)
           t.equal(opts.preferOffline, true, 'got preferOffline from cache min')
        @@ -172,7 +174,7 @@ t.test('get preferOffline from cache-min', t => {
         t.test('get preferOnline from cache-max', t => {
           const npm = new Mocknpm({
             'cache-max': -1,
        -    'prefer-online': undefined
        +    'prefer-online': undefined,
           })
           const opts = flatOptions(npm)
           t.equal(opts.preferOnline, true, 'got preferOnline from cache min')
        @@ -194,7 +196,7 @@ t.test('tag emits warning', t => {
         t.test('omit/include options', t => {
           t.test('omit explicitly', t => {
             const npm = new Mocknpm({
        -      omit: ['dev', 'optional', 'peer']
        +      omit: ['dev', 'optional', 'peer'],
             })
             t.strictSame(flatOptions(npm).omit, ['dev', 'optional', 'peer'])
             t.end()
        @@ -203,7 +205,7 @@ t.test('omit/include options', t => {
           t.test('omit and include some', t => {
             const npm = new Mocknpm({
               omit: ['dev', 'optional', 'peer'],
        -      include: ['peer']
        +      include: ['peer'],
             })
             t.strictSame(flatOptions(npm).omit, ['dev', 'optional'])
             t.end()
        @@ -213,7 +215,7 @@ t.test('omit/include options', t => {
             const npm = new Mocknpm({
               omit: ['dev', 'optional', 'peer'],
               include: [],
        -      dev: true
        +      dev: true,
             })
             t.strictSame(flatOptions(npm).omit, ['optional', 'peer'])
             t.end()
        @@ -223,7 +225,7 @@ t.test('omit/include options', t => {
             const npm = new Mocknpm({
               omit: [],
               include: [],
        -      production: true
        +      production: true,
             })
             t.strictSame(flatOptions(npm).omit, ['dev'])
             t.end()
        @@ -236,7 +238,7 @@ t.test('omit/include options', t => {
               const npm = new Mocknpm({
                 omit: [],
                 include: [],
        -        only: c
        +        only: c,
               })
               t.strictSame(flatOptions(npm).omit, ['dev'])
               t.end()
        @@ -246,7 +248,7 @@ t.test('omit/include options', t => {
           t.test('also dev', t => {
             const npm = new Mocknpm({
               omit: ['dev', 'optional', 'peer'],
        -      also: 'dev'
        +      also: 'dev',
             })
             t.strictSame(flatOptions(npm).omit, ['optional', 'peer'])
             t.end()
        @@ -256,7 +258,7 @@ t.test('omit/include options', t => {
             const npm = new Mocknpm({
               optional: false,
               omit: null,
        -      include: null
        +      include: null,
             })
             t.strictSame(flatOptions(npm).omit, ['optional'])
             t.end()
        @@ -276,9 +278,9 @@ t.test('various default values and falsey fallbacks', t => {
             'script-shell': false,
             registry: 'http://example.com',
             'metrics-registry': null,
        -    'searchlimit': 0,
        +    searchlimit: 0,
             'save-exact': false,
        -    'save-prefix': '>='
        +    'save-prefix': '>=',
           })
           const opts = flatOptions(npm)
           t.equal(opts.scriptShell, undefined, 'scriptShell is undefined if falsey')
        @@ -291,12 +293,24 @@ t.test('various default values and falsey fallbacks', t => {
           t.end()
         })
         
        +t.test('legacy _auth token', t => {
        +  const npm = new Mocknpm({
        +    _auth: 'asdfasdf',
        +  })
        +  t.strictSame(
        +    flatOptions(npm)._auth,
        +    'asdfasdf',
        +    'should set legacy _auth token'
        +  )
        +  t.end()
        +})
        +
         t.test('save-type', t => {
           const base = {
             'save-optional': false,
             'save-peer': false,
             'save-dev': false,
        -    'save-prod': false
        +    'save-prod': false,
           }
           const cases = [
             ['peerOptional', {
        @@ -304,23 +318,23 @@ t.test('save-type', t => {
               'save-peer': true,
             }],
             ['optional', {
        -      'save-optional': true
        +      'save-optional': true,
             }],
             ['dev', {
        -      'save-dev': true
        +      'save-dev': true,
             }],
             ['peer', {
        -      'save-peer': true
        +      'save-peer': true,
             }],
             ['prod', {
        -      'save-prod': true
        +      'save-prod': true,
             }],
        -    [null, {}]
        +    [null, {}],
           ]
           for (const [expect, options] of cases) {
             const opts = flatOptions(new Mocknpm({
               ...base,
        -      ...options
        +      ...options,
             }))
             t.equal(opts.saveType, expect, JSON.stringify(options))
           }
        diff --git a/deps/npm/test/lib/utils/get-identity.js b/deps/npm/test/lib/utils/get-identity.js
        index c72f48b2e8f62a..8a4de8835257a6 100644
        --- a/deps/npm/test/lib/utils/get-identity.js
        +++ b/deps/npm/test/lib/utils/get-identity.js
        @@ -4,7 +4,7 @@ const requireInject = require('require-inject')
         test('throws ENOREGISTRY when no registry option is provided', async (t) => {
           t.plan(2)
           const getIdentity = requireInject('../../../lib/utils/get-identity.js', {
        -    '../../../lib/npm.js': {}
        +    '../../../lib/npm.js': {},
           })
         
           try {
        @@ -23,9 +23,9 @@ test('returns username from uri when provided', async (t) => {
               config: {
                 getCredentialsByURI: () => {
                   return { username: 'foo' }
        -        }
        -      }
        -    }
        +        },
        +      },
        +    },
           })
         
           const identity = await getIdentity({ registry: 'https://registry.npmjs.org' })
        @@ -37,22 +37,22 @@ test('calls registry whoami when token is provided', async (t) => {
         
           const options = {
             registry: 'https://registry.npmjs.org',
        -    token: 'thisisnotreallyatoken'
        +    token: 'thisisnotreallyatoken',
           }
         
           const getIdentity = requireInject('../../../lib/utils/get-identity.js', {
             '../../../lib/npm.js': {
               config: {
        -        getCredentialsByURI: () => options
        -      }
        +        getCredentialsByURI: () => options,
        +      },
             },
             'npm-registry-fetch': {
               json: (path, opts) => {
                 t.equal(path, '/-/whoami', 'calls whoami')
                 t.same(opts, options, 'passes through provided options')
                 return { username: 'foo' }
        -      }
        -    }
        +      },
        +    },
           })
         
           const identity = await getIdentity(options)
        @@ -64,22 +64,22 @@ test('throws ENEEDAUTH when response does not include a username', async (t) =>
         
           const options = {
             registry: 'https://registry.npmjs.org',
        -    token: 'thisisnotreallyatoken'
        +    token: 'thisisnotreallyatoken',
           }
         
           const getIdentity = requireInject('../../../lib/utils/get-identity.js', {
             '../../../lib/npm.js': {
               config: {
        -        getCredentialsByURI: () => options
        -      }
        +        getCredentialsByURI: () => options,
        +      },
             },
             'npm-registry-fetch': {
               json: (path, opts) => {
                 t.equal(path, '/-/whoami', 'calls whoami')
                 t.same(opts, options, 'passes through provided options')
                 return {}
        -      }
        -    }
        +      },
        +    },
           })
         
           try {
        @@ -94,9 +94,9 @@ test('throws ENEEDAUTH when neither username nor token is configured', async (t)
           const getIdentity = requireInject('../../../lib/utils/get-identity.js', {
             '../../../lib/npm.js': {
               config: {
        -        getCredentialsByURI: () => ({})
        -      }
        -    }
        +        getCredentialsByURI: () => ({}),
        +      },
        +    },
           })
         
           try {
        diff --git a/deps/npm/test/lib/utils/get-project-scope.js b/deps/npm/test/lib/utils/get-project-scope.js
        index 15ab2bdeff1054..9737b06433c227 100644
        --- a/deps/npm/test/lib/utils/get-project-scope.js
        +++ b/deps/npm/test/lib/utils/get-project-scope.js
        @@ -3,7 +3,7 @@ const t = require('tap')
         
         t.test('package.json with scope', t => {
           const dir = t.testdir({
        -    'package.json': JSON.stringify({ name: '@foo/bar' })
        +    'package.json': JSON.stringify({ name: '@foo/bar' }),
           })
           t.equal(getProjectScope(dir), '@foo')
           t.end()
        @@ -11,7 +11,7 @@ t.test('package.json with scope', t => {
         
         t.test('package.json with slash, but no @', t => {
           const dir = t.testdir({
        -    'package.json': JSON.stringify({ name: 'foo/bar' })
        +    'package.json': JSON.stringify({ name: 'foo/bar' }),
           })
           t.equal(getProjectScope(dir), '')
           t.end()
        @@ -19,7 +19,7 @@ t.test('package.json with slash, but no @', t => {
         
         t.test('package.json without scope', t => {
           const dir = t.testdir({
        -    'package.json': JSON.stringify({ name: 'foo' })
        +    'package.json': JSON.stringify({ name: 'foo' }),
           })
           t.equal(getProjectScope(dir), '')
           t.end()
        @@ -27,7 +27,7 @@ t.test('package.json without scope', t => {
         
         t.test('package.json without name', t => {
           const dir = t.testdir({
        -    'package.json': JSON.stringify({})
        +    'package.json': JSON.stringify({}),
           })
           t.equal(getProjectScope(dir), '')
           t.end()
        @@ -35,7 +35,7 @@ t.test('package.json without name', t => {
         
         t.test('package.json not JSON', t => {
           const dir = t.testdir({
        -    'package.json': 'hello'
        +    'package.json': 'hello',
           })
           t.equal(getProjectScope(dir), '')
           t.end()
        diff --git a/deps/npm/test/lib/utils/hosted-git-info-from-manifest.js b/deps/npm/test/lib/utils/hosted-git-info-from-manifest.js
        index f87cb84eed8232..516d3d5867acbd 100644
        --- a/deps/npm/test/lib/utils/hosted-git-info-from-manifest.js
        +++ b/deps/npm/test/lib/utils/hosted-git-info-from-manifest.js
        @@ -9,13 +9,13 @@ t.equal(hostedFromMani({ repository: 'not hosted anywhere' }), null)
         t.equal(hostedFromMani({ repository: { url: 'not hosted anywhere' } }), null)
         
         t.match(hostedFromMani({
        -  repository: 'git+https://github.com/isaacs/abbrev-js'
        +  repository: 'git+https://github.com/isaacs/abbrev-js',
         }), hostedGitInfo.fromUrl('git+https://github.com/isaacs/abbrev-js'))
         
         t.match(hostedFromMani({
        -  repository: { url: 'git+https://github.com/isaacs/abbrev-js' }
        +  repository: { url: 'git+https://github.com/isaacs/abbrev-js' },
         }), hostedGitInfo.fromUrl('https://github.com/isaacs/abbrev-js'))
         
         t.match(hostedFromMani({
        -  repository: { url: 'git+ssh://git@github.com/isaacs/abbrev-js' }
        +  repository: { url: 'git+ssh://git@github.com/isaacs/abbrev-js' },
         }), hostedGitInfo.fromUrl('ssh://git@github.com/isaacs/abbrev-js'))
        diff --git a/deps/npm/test/lib/utils/is-windows-bash.js b/deps/npm/test/lib/utils/is-windows-bash.js
        index 730dfe301bc764..94fde0ace17ce4 100644
        --- a/deps/npm/test/lib/utils/is-windows-bash.js
        +++ b/deps/npm/test/lib/utils/is-windows-bash.js
        @@ -8,13 +8,13 @@ const isWindowsBash = () => {
         
         Object.defineProperty(process, 'platform', {
           value: 'posix',
        -  configurable: true
        +  configurable: true,
         })
         t.equal(isWindowsBash(), false, 'false when not windows')
         
         Object.defineProperty(process, 'platform', {
           value: 'win32',
        -  configurable: true
        +  configurable: true,
         })
         process.env.MSYSTEM = 'not ming'
         process.env.TERM = 'dumb'
        diff --git a/deps/npm/test/lib/utils/is-windows-shell.js b/deps/npm/test/lib/utils/is-windows-shell.js
        index e2164c222be67d..95519925c97ce6 100644
        --- a/deps/npm/test/lib/utils/is-windows-shell.js
        +++ b/deps/npm/test/lib/utils/is-windows-shell.js
        @@ -1,6 +1,6 @@
         const t = require('tap')
         Object.defineProperty(process, 'platform', {
        -  value: 'win32'
        +  value: 'win32',
         })
         const isWindows = require('../../../lib/utils/is-windows.js')
         const isWindowsBash = require('../../../lib/utils/is-windows-bash.js')
        diff --git a/deps/npm/test/lib/utils/is-windows.js b/deps/npm/test/lib/utils/is-windows.js
        index 9100071699e771..f8f2999c99433d 100644
        --- a/deps/npm/test/lib/utils/is-windows.js
        +++ b/deps/npm/test/lib/utils/is-windows.js
        @@ -2,7 +2,7 @@ const t = require('tap')
         const actuallyWindows = process.platform === 'win32'
         t.equal(actuallyWindows, require('../../../lib/utils/is-windows.js'))
         Object.defineProperty(process, 'platform', {
        -  value: actuallyWindows ? 'posix' : 'win32'
        +  value: actuallyWindows ? 'posix' : 'win32',
         })
         delete require.cache[require.resolve('../../../lib/utils/is-windows.js')]
         t.equal(!actuallyWindows, require('../../../lib/utils/is-windows.js'))
        diff --git a/deps/npm/test/lib/utils/lifecycle-cmd.js b/deps/npm/test/lib/utils/lifecycle-cmd.js
        index 7338229546cf52..0eb342cee50124 100644
        --- a/deps/npm/test/lib/utils/lifecycle-cmd.js
        +++ b/deps/npm/test/lib/utils/lifecycle-cmd.js
        @@ -3,9 +3,9 @@ const requireInject = require('require-inject')
         const lifecycleCmd = requireInject('../../../lib/utils/lifecycle-cmd.js', {
           '../../../lib/npm.js': {
             commands: {
        -      run: (args, cb) => cb(null, 'called npm.commands.run')
        -    }
        -  }
        +      run: (args, cb) => cb(null, 'called npm.commands.run'),
        +    },
        +  },
         })
         
         t.test('create a lifecycle command', t => {
        diff --git a/deps/npm/test/lib/utils/path.js b/deps/npm/test/lib/utils/path.js
        index facee06459d4c0..74fb93462f7553 100644
        --- a/deps/npm/test/lib/utils/path.js
        +++ b/deps/npm/test/lib/utils/path.js
        @@ -3,7 +3,7 @@ const requireInject = require('require-inject')
         const mod = '../../../lib/utils/path.js'
         const delim = require('../../../lib/utils/is-windows.js') ? ';' : ':'
         Object.defineProperty(process, 'env', {
        -  value: {}
        +  value: {},
         })
         process.env.path = ['foo', 'bar', 'baz'].join(delim)
         t.strictSame(requireInject(mod), ['foo', 'bar', 'baz'])
        diff --git a/deps/npm/test/lib/utils/perf.js b/deps/npm/test/lib/utils/perf.js
        index 9b38a3da8198c7..840dcb6e32399b 100644
        --- a/deps/npm/test/lib/utils/perf.js
        +++ b/deps/npm/test/lib/utils/perf.js
        @@ -20,15 +20,15 @@ t.test('time some stuff', t => {
               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/ ],
        +        ['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'
        -        ]
        +          'baz',
        +        ],
               ])
               t.match(timings, { foo: Number, bar: Number })
               t.equal(timings.foo > timings.bar, true, 'foo should be > bar')
        diff --git a/deps/npm/test/lib/utils/ping.js b/deps/npm/test/lib/utils/ping.js
        index d2b269556e6058..6e0451538f9fac 100644
        --- a/deps/npm/test/lib/utils/ping.js
        +++ b/deps/npm/test/lib/utils/ping.js
        @@ -11,7 +11,7 @@ test('pings', async (t) => {
               t.equal(url, '/-/ping?write=true', 'calls the correct url')
               t.equal(opts, options, 'passes through options')
               return { json: () => Promise.resolve(response) }
        -    }
        +    },
           })
         
           const res = await ping(options)
        @@ -28,7 +28,7 @@ test('catches errors and returns empty json', async (t) => {
               t.equal(url, '/-/ping?write=true', 'calls the correct url')
               t.equal(opts, options, 'passes through options')
               return { json: () => Promise.reject(response) }
        -    }
        +    },
           })
         
           const res = await ping(options)
        diff --git a/deps/npm/test/lib/utils/proc-log-listener.js b/deps/npm/test/lib/utils/proc-log-listener.js
        index 0a6119d1a1c0ed..2c1009503762d5 100644
        --- a/deps/npm/test/lib/utils/proc-log-listener.js
        +++ b/deps/npm/test/lib/utils/proc-log-listener.js
        @@ -5,11 +5,11 @@ const { inspect } = require('util')
         const logs = []
         const npmlog = {
           warn: (...args) => logs.push(['warn', ...args]),
        -  verbose: (...args) => logs.push(['verbose', ...args])
        +  verbose: (...args) => logs.push(['verbose', ...args]),
         }
         
         requireInject('../../../lib/utils/proc-log-listener.js', {
        -  npmlog
        +  npmlog,
         })()
         
         process.emit('log', 'warn', 'hello', 'i am a warning')
        @@ -17,22 +17,26 @@ t.strictSame(logs, [['warn', 'hello', 'i am a warning']])
         logs.length = 0
         
         const nopeError = new Error('nope')
        -npmlog.warn = () => { throw nopeError }
        +npmlog.warn = () => {
        +  throw nopeError
        +}
         
         process.emit('log', 'warn', 'fail')
         t.strictSame(logs, [[
           'verbose',
           `attempt to log ${inspect(['warn', 'fail'])} crashed`,
        -  nopeError
        +  nopeError,
         ]])
         logs.length = 0
         
        -npmlog.verbose = () => { throw nopeError }
        +npmlog.verbose = () => {
        +  throw nopeError
        +}
         const consoleErrors = []
         console.error = (...args) => consoleErrors.push(args)
         process.emit('log', 'warn', 'fail2')
         t.strictSame(logs, [])
         t.strictSame(consoleErrors, [[
           `attempt to log ${inspect(['warn', 'fail2'])} crashed`,
        -  nopeError
        +  nopeError,
         ]])
        diff --git a/deps/npm/test/lib/utils/read-local-package.js b/deps/npm/test/lib/utils/read-local-package.js
        index 8854cf4e5f2179..33a408eb532379 100644
        --- a/deps/npm/test/lib/utils/read-local-package.js
        +++ b/deps/npm/test/lib/utils/read-local-package.js
        @@ -5,21 +5,23 @@ let prefix
         const _flatOptions = {
           json: false,
           global: false,
        -  get prefix () { return prefix }
        +  get prefix () {
        +    return prefix
        +  },
         }
         
         const readLocalPackageName = requireInject('../../../lib/utils/read-local-package.js', {
           '../../../lib/npm.js': {
        -    flatOptions: _flatOptions
        -  }
        +    flatOptions: _flatOptions,
        +  },
         })
         
         test('read local package.json', async (t) => {
           prefix = t.testdir({
             'package.json': JSON.stringify({
               name: 'my-local-package',
        -      version: '1.0.0'
        -    })
        +      version: '1.0.0',
        +    }),
           })
           const packageName = await readLocalPackageName()
           t.equal(
        @@ -33,8 +35,8 @@ test('read local scoped-package.json', async (t) => {
           prefix = t.testdir({
             'package.json': JSON.stringify({
               name: '@my-scope/my-local-package',
        -      version: '1.0.0'
        -    })
        +      version: '1.0.0',
        +    }),
           })
           const packageName = await readLocalPackageName()
           t.equal(
        diff --git a/deps/npm/test/lib/utils/reify-finish.js b/deps/npm/test/lib/utils/reify-finish.js
        new file mode 100644
        index 00000000000000..d6c7d2e7b2d6d8
        --- /dev/null
        +++ b/deps/npm/test/lib/utils/reify-finish.js
        @@ -0,0 +1,80 @@
        +const t = require('tap')
        +const requireInject = require('require-inject')
        +
        +const npm = {
        +  config: {
        +    data: {
        +      get: () => builtinConfMock,
        +    },
        +  },
        +}
        +
        +const builtinConfMock = {
        +  loadError: new Error('no builtin config'),
        +  raw: { hasBuiltinConfig: true, x: 'y', nested: { foo: 'bar' }},
        +}
        +
        +const reifyOutput = () => {}
        +
        +let expectWrite = false
        +const realFs = require('fs')
        +const fs = {
        +  ...realFs,
        +  promises: {
        +    ...realFs.promises,
        +    writeFile: async (path, data) => {
        +      if (!expectWrite)
        +        throw new Error('did not expect to write builtin config file')
        +      return realFs.promises.writeFile(path, data)
        +    },
        +  },
        +}
        +
        +const reifyFinish = requireInject('../../../lib/utils/reify-finish.js', {
        +  fs,
        +  '../../../lib/npm.js': npm,
        +  '../../../lib/utils/reify-output.js': reifyOutput,
        +})
        +
        +t.test('should not write if not global', async t => {
        +  expectWrite = false
        +  await reifyFinish({
        +    options: { global: false },
        +    actualTree: {},
        +  })
        +})
        +
        +t.test('should not write if no global npm module', async t => {
        +  expectWrite = false
        +  await reifyFinish({
        +    options: { global: true },
        +    actualTree: {
        +      inventory: new Map(),
        +    },
        +  })
        +})
        +
        +t.test('should not write if builtin conf had load error', async t => {
        +  expectWrite = false
        +  await reifyFinish({
        +    options: { global: true },
        +    actualTree: {
        +      inventory: new Map([['node_modules/npm', {}]]),
        +    },
        +  })
        +})
        +
        +t.test('should write if everything above passes', async t => {
        +  expectWrite = true
        +  delete builtinConfMock.loadError
        +  const path = t.testdir()
        +  await reifyFinish({
        +    options: { global: true },
        +    actualTree: {
        +      inventory: new Map([['node_modules/npm', {path}]]),
        +    },
        +  })
        +  // windowwwwwwssss!!!!!
        +  const data = fs.readFileSync(`${path}/npmrc`, 'utf8').replace(/\r\n/g, '\n')
        +  t.matchSnapshot(data, 'written config')
        +})
        diff --git a/deps/npm/test/lib/utils/reify-output.js b/deps/npm/test/lib/utils/reify-output.js
        index 55f77f1d9d3a74..b905c9ab0f30f1 100644
        --- a/deps/npm/test/lib/utils/reify-output.js
        +++ b/deps/npm/test/lib/utils/reify-output.js
        @@ -9,18 +9,18 @@ log.level = 'warn'
         t.cleanSnapshot = str => str.replace(/in [0-9]+m?s/g, 'in {TIME}')
         
         const settings = {
        -  fund: true
        +  fund: true,
         }
         const npmock = {
           started: Date.now(),
        -  flatOptions: settings
        +  flatOptions: settings,
         }
         const getReifyOutput = tester =>
           requireInject(
             '../../../lib/utils/reify-output.js',
             {
               '../../../lib/npm.js': npmock,
        -      '../../../lib/utils/output.js': tester
        +      '../../../lib/utils/output.js': tester,
             }
           )
         
        @@ -36,11 +36,11 @@ t.test('missing info', (t) => {
         
           reifyOutput({
             actualTree: {
        -      children: []
        +      children: [],
             },
             diff: {
        -      children: []
        -    }
        +      children: [],
        +    },
           })
         })
         
        @@ -56,12 +56,11 @@ t.test('even more missing info', t => {
         
           reifyOutput({
             actualTree: {
        -      children: []
        -    }
        +      children: [],
        +    },
           })
         })
         
        -
         t.test('single package', (t) => {
           t.plan(1)
           const reifyOutput = getReifyOutput(
        @@ -81,14 +80,14 @@ t.test('single package', (t) => {
             // the command is not 'audit'
             auditReport: {
               error: {
        -        message: 'no audit for youuuuu'
        -      }
        +        message: 'no audit for youuuuu',
        +      },
             },
             actualTree: {
               name: 'foo',
               package: {
                 name: 'foo',
        -        version: '1.0.0'
        +        version: '1.0.0',
               },
               edgesOut: new Map([
                 ['bar', {
        @@ -97,26 +96,27 @@ t.test('single package', (t) => {
                     package: {
                       name: 'bar',
                       version: '1.0.0',
        -              funding: { type: 'foo', url: 'http://example.com' }
        -            }
        -          }
        -        }]
        -      ])
        +              funding: { type: 'foo', url: 'http://example.com' },
        +            },
        +          },
        +        }],
        +      ]),
             },
             diff: {
        -      children: []
        -    }
        +      children: [],
        +    },
           })
         })
         
         t.test('no message when funding config is false', (t) => {
        -  t.teardown(() => { settings.fund = true })
        +  t.teardown(() => {
        +    settings.fund = true
        +  })
           settings.fund = false
           const reifyOutput = getReifyOutput(
             out => {
        -      if (out.endsWith('looking for funding')) {
        +      if (out.endsWith('looking for funding'))
                 t.fail('should not print funding info', { actual: out })
        -      }
             }
           )
         
        @@ -125,7 +125,7 @@ t.test('no message when funding config is false', (t) => {
               name: 'foo',
               package: {
                 name: 'foo',
        -        version: '1.0.0'
        +        version: '1.0.0',
               },
               edgesOut: new Map([
                 ['bar', {
        @@ -134,15 +134,15 @@ t.test('no message when funding config is false', (t) => {
                     package: {
                       name: 'bar',
                       version: '1.0.0',
        -              funding: { type: 'foo', url: 'http://example.com' }
        -            }
        -          }
        -        }]
        -      ])
        +              funding: { type: 'foo', url: 'http://example.com' },
        +            },
        +          },
        +        }],
        +      ]),
             },
             diff: {
        -      children: []
        -    }
        +      children: [],
        +    },
           })
         
           t.end()
        @@ -167,7 +167,7 @@ t.test('print appropriate message for many packages', (t) => {
               name: 'foo',
               package: {
                 name: 'foo',
        -        version: '1.0.0'
        +        version: '1.0.0',
               },
               edgesOut: new Map([
                 ['bar', {
        @@ -176,9 +176,9 @@ t.test('print appropriate message for many packages', (t) => {
                     package: {
                       name: 'bar',
                       version: '1.0.0',
        -              funding: { type: 'foo', url: 'http://example.com' }
        -            }
        -          }
        +              funding: { type: 'foo', url: 'http://example.com' },
        +            },
        +          },
                 }],
                 ['lorem', {
                   to: {
        @@ -186,9 +186,9 @@ t.test('print appropriate message for many packages', (t) => {
                     package: {
                       name: 'lorem',
                       version: '1.0.0',
        -              funding: { type: 'foo', url: 'http://example.com' }
        -            }
        -          }
        +              funding: { type: 'foo', url: 'http://example.com' },
        +            },
        +          },
                 }],
                 ['ipsum', {
                   to: {
        @@ -196,15 +196,15 @@ t.test('print appropriate message for many packages', (t) => {
                     package: {
                       name: 'ipsum',
                       version: '1.0.0',
        -              funding: { type: 'foo', url: 'http://example.com' }
        -            }
        -          }
        -        }]
        -      ])
        +              funding: { type: 'foo', url: 'http://example.com' },
        +            },
        +          },
        +        }],
        +      ]),
             },
             diff: {
        -      children: []
        -    }
        +      children: [],
        +    },
           })
         })
         
        @@ -217,19 +217,21 @@ t.test('no output when silent', t => {
           reifyOutput({
             actualTree: { inventory: { size: 999 }, children: [] },
             auditReport: {
        -      toJSON: () => mock.auditReport,
        +      toJSON: () => {
        +        throw new Error('this should not get called')
        +      },
               vulnerabilities: {},
               metadata: {
                 vulnerabilities: {
        -          total: 99
        -        }
        -      }
        +          total: 99,
        +        },
        +      },
             },
             diff: {
               children: [
        -        { action: 'ADD', ideal: { location: 'loc' } }
        -      ]
        -    }
        +        { action: 'ADD', ideal: { location: 'loc' } },
        +      ],
        +    },
           })
           t.end()
         })
        @@ -251,22 +253,22 @@ t.test('packages changed message', t => {
                 vulnerabilities: {},
                 metadata: {
                   vulnerabilities: {
        -            total: 0
        -          }
        -        }
        +            total: 0,
        +          },
        +        },
               } : null,
               diff: {
                 children: [
        -          { action: 'some random unexpected junk' }
        -        ]
        -      }
        +          { action: 'some random unexpected junk' },
        +        ],
        +      },
             }
        -    for (let i = 0; i < added; i++) {
        +    for (let i = 0; i < added; i++)
               mock.diff.children.push({ action: 'ADD', ideal: { location: 'loc' } })
        -    }
        -    for (let i = 0; i < removed; i++) {
        +
        +    for (let i = 0; i < removed; i++)
               mock.diff.children.push({ action: 'REMOVE', actual: { location: 'loc' } })
        -    }
        +
             for (let i = 0; i < changed; i++) {
               const actual = { location: 'loc' }
               const ideal = { location: 'loc' }
        @@ -279,7 +281,7 @@ t.test('packages changed message', t => {
               removed,
               changed,
               audited,
        -      json
        +      json,
             }))
           }
         
        @@ -288,9 +290,8 @@ t.test('packages changed message', t => {
             for (const removed of [0, 1, 2]) {
               for (const changed of [0, 1, 2]) {
                 for (const audited of [0, 1, 2]) {
        -          for (const json of [true, false]) {
        +          for (const json of [true, false])
                     cases.push([added, removed, changed, audited, json, 'install'])
        -          }
                 }
               }
             }
        @@ -301,9 +302,8 @@ t.test('packages changed message', t => {
           cases.push([0, 0, 0, 2, false, 'audit'])
         
           t.plan(cases.length)
        -  for (const [added, removed, changed, audited, json, command] of cases) {
        +  for (const [added, removed, changed, audited, json, command] of cases)
             testCase(t, added, removed, changed, audited, json, command)
        -  }
         
           t.end()
         })
        @@ -319,14 +319,14 @@ t.test('added packages should be looked up within returned tree', t => {
               actualTree: {
                 name: 'foo',
                 inventory: {
        -          has: () => true
        -        }
        +          has: () => true,
        +        },
               },
               diff: {
                 children: [
        -          { action: 'ADD', ideal: { name: 'baz' } }
        -        ]
        -      }
        +          { action: 'ADD', ideal: { name: 'baz' } },
        +        ],
        +      },
             })
           })
         
        @@ -340,14 +340,14 @@ t.test('added packages should be looked up within returned tree', t => {
               actualTree: {
                 name: 'foo',
                 inventory: {
        -          has: () => false
        -        }
        +          has: () => false,
        +        },
               },
               diff: {
                 children: [
        -          { action: 'ADD', ideal: { name: 'baz' } }
        -        ]
        -      }
        +          { action: 'ADD', ideal: { name: 'baz' } },
        +        ],
        +      },
             })
           })
           t.end()
        diff --git a/deps/npm/test/lib/utils/setup-log.js b/deps/npm/test/lib/utils/setup-log.js
        index 2d5d794f1377a5..4398200abe22c0 100644
        --- a/deps/npm/test/lib/utils/setup-log.js
        +++ b/deps/npm/test/lib/utils/setup-log.js
        @@ -1,15 +1,18 @@
         const t = require('tap')
         const requireInject = require('require-inject')
         
        -const settings = {}
        +const settings = {
        +  level: 'warn',
        +}
         t.afterEach(cb => {
        -  Object.keys(settings).forEach(k => { delete settings[k] })
        +  Object.keys(settings).forEach(k => {
        +    delete settings[k]
        +  })
           cb()
         })
         
         const WARN_CALLED = []
         const npmlog = {
        -  level: 'warn',
           warn: (...args) => {
             WARN_CALLED.push(args)
           },
        @@ -22,17 +25,39 @@ const npmlog = {
             notice: 3500,
             warn: 4000,
             error: 5000,
        -    silent: Infinity
        +    silent: Infinity,
           },
           settings,
        -  enableColor: () => { settings.color = true },
        -  disableColor: () => { settings.color = false },
        -  enableUnicode: () => { settings.unicode = true },
        -  disableUnicode: () => { settings.unicode = false },
        -  enableProgress: () => { settings.progress = true },
        -  disableProgress: () => { settings.progress = false },
        -  set heading (h) { settings.heading = h },
        -  set level (l) { settings.level = l }
        +  enableColor: () => {
        +    settings.color = true
        +  },
        +  disableColor: () => {
        +    settings.color = false
        +  },
        +  enableUnicode: () => {
        +    settings.unicode = true
        +  },
        +  disableUnicode: () => {
        +    settings.unicode = false
        +  },
        +  enableProgress: () => {
        +    settings.progress = true
        +  },
        +  disableProgress: () => {
        +    settings.progress = false
        +  },
        +  get heading () {
        +    return settings.heading
        +  },
        +  set heading (h) {
        +    settings.heading = h
        +  },
        +  get level () {
        +    return settings.level
        +  },
        +  set level (l) {
        +    settings.level = l
        +  },
         }
         
         const EXPLAIN_CALLED = []
        @@ -41,9 +66,9 @@ const setupLog = requireInject('../../../lib/utils/setup-log.js', {
             explain: (...args) => {
               EXPLAIN_CALLED.push(args)
               return 'explanation'
        -    }
        +    },
           },
        -  npmlog
        +  npmlog,
         })
         
         const config = obj => ({
        @@ -52,7 +77,7 @@ const config = obj => ({
           },
           set (k, v) {
             obj[k] = v
        -  }
        +  },
         })
         
         t.test('setup with color=always and unicode', t => {
        @@ -65,7 +90,7 @@ t.test('setup with color=always and unicode', t => {
             loglevel: 'warn',
             color: 'always',
             unicode: true,
        -    progress: false
        +    progress: false,
           })), true)
         
           npmlog.warn('ERESOLVE', 'hello', { some: { other: 'object' } })
        @@ -73,7 +98,7 @@ t.test('setup with color=always and unicode', t => {
             'log.warn(ERESOLVE) patched to call explainEresolve()')
           t.strictSame(WARN_CALLED, [
             ['ERESOLVE', 'hello'],
        -    ['', 'explanation']
        +    ['', 'explanation'],
           ], 'warn the explanation')
           EXPLAIN_CALLED.length = 0
           WARN_CALLED.length = 0
        @@ -86,7 +111,7 @@ t.test('setup with color=always and unicode', t => {
             color: true,
             unicode: true,
             progress: false,
        -    heading: 'npm'
        +    heading: 'npm',
           })
         
           t.end()
        @@ -106,7 +131,7 @@ t.test('setup with color=true, no unicode, and non-TTY terminal', t => {
             loglevel: 'warn',
             color: false,
             progress: false,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })), false)
         
           t.strictSame(settings, {
        @@ -114,7 +139,7 @@ t.test('setup with color=true, no unicode, and non-TTY terminal', t => {
             color: false,
             unicode: false,
             progress: false,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })
         
           t.end()
        @@ -137,7 +162,7 @@ t.test('setup with color=true, no unicode, and dumb TTY terminal', t => {
             loglevel: 'warn',
             color: true,
             progress: false,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })), true)
         
           t.strictSame(settings, {
        @@ -145,7 +170,7 @@ t.test('setup with color=true, no unicode, and dumb TTY terminal', t => {
             color: true,
             unicode: false,
             progress: false,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })
         
           t.end()
        @@ -168,7 +193,7 @@ t.test('setup with color=true, no unicode, and non-dumb TTY terminal', t => {
             loglevel: 'warn',
             color: true,
             progress: true,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })), true)
         
           t.strictSame(settings, {
        @@ -176,7 +201,7 @@ t.test('setup with color=true, no unicode, and non-dumb TTY terminal', t => {
             color: true,
             unicode: false,
             progress: true,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })
         
           t.end()
        @@ -199,7 +224,7 @@ t.test('setup with non-TTY stdout, TTY stderr', t => {
             loglevel: 'warn',
             color: true,
             progress: true,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })), false)
         
           t.strictSame(settings, {
        @@ -207,7 +232,7 @@ t.test('setup with non-TTY stdout, TTY stderr', t => {
             color: true,
             unicode: false,
             progress: true,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })
         
           t.end()
        @@ -229,7 +254,7 @@ t.test('setup with TTY stdout, non-TTY stderr', t => {
             loglevel: 'warn',
             color: true,
             progress: true,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })), true)
         
           t.strictSame(settings, {
        @@ -237,7 +262,7 @@ t.test('setup with TTY stdout, non-TTY stderr', t => {
             color: false,
             unicode: false,
             progress: false,
        -    heading: 'asdf'
        +    heading: 'asdf',
           })
         
           t.end()
        @@ -246,7 +271,7 @@ t.test('setup with TTY stdout, non-TTY stderr', t => {
         t.test('set loglevel to timing', t => {
           setupLog(config({
             timing: true,
        -    loglevel: 'notice'
        +    loglevel: 'notice',
           }))
           t.equal(settings.level, 'timing')
           t.end()
        @@ -266,7 +291,7 @@ t.test('silent has no logging', t => {
           process.env.TERM = 'totes not dum'
         
           setupLog(config({
        -    loglevel: 'silent'
        +    loglevel: 'silent',
           }))
           t.equal(settings.progress, false, 'progress disabled when silent')
           t.end()
        diff --git a/deps/npm/test/lib/utils/tar.js b/deps/npm/test/lib/utils/tar.js
        index 827bc9262db825..b780a73e5ec1c7 100644
        --- a/deps/npm/test/lib/utils/tar.js
        +++ b/deps/npm/test/lib/utils/tar.js
        @@ -11,9 +11,9 @@ const printLogs = (tarball, unicode) => {
             log: {
               notice: (...args) => {
                 args.map(el => logs.push(el))
        -      }
        +      },
             },
        -    unicode
        +    unicode,
           })
           return logs.join('\n')
         }
        @@ -24,19 +24,19 @@ test('should log tarball contents', async (t) => {
               name: 'my-cool-pkg',
               version: '1.0.0',
               bundleDependencies: [
        -        'bundle-dep'
        -      ]
        +        'bundle-dep',
        +      ],
             }, null, 2),
        -    'node_modules': {
        -      'bundle-dep': 'toto'
        -    }
        +    node_modules: {
        +      'bundle-dep': 'toto',
        +    },
           })
         
           const tarball = await pack(testDir)
           const tarballContents = await getContents({
             _id: '1',
             name: 'my-cool-pkg',
        -    version: '1.0.0'
        +    version: '1.0.0',
           }, tarball)
         
           t.matchSnapshot(printLogs(tarballContents, false))
        @@ -44,36 +44,36 @@ test('should log tarball contents', async (t) => {
         
         test('should log tarball contents with unicode', async (t) => {
           const { logTar } = requireInject('../../../lib/utils/tar.js', {
        -    'npmlog': {
        -      'notice': (str) => {
        +    npmlog: {
        +      notice: (str) => {
                 t.ok(true, 'defaults to npmlog')
                 return str
        -      }
        -    }
        +      },
        +    },
           })
        -  
        -  logTar({ 
        -    files: [], 
        +
        +  logTar({
        +    files: [],
             bundled: [],
        -    integrity: '' 
        +    integrity: '',
           }, { unicode: true })
           t.end()
         })
         
         test('should default to npmlog', async (t) => {
           const { logTar } = requireInject('../../../lib/utils/tar.js', {
        -    'npmlog': {
        -      'notice': (str) => {
        +    npmlog: {
        +      notice: (str) => {
                 t.ok(true, 'defaults to npmlog')
                 return str
        -      }
        -    }
        +      },
        +    },
           })
         
           logTar({
             files: [],
             bundled: [],
        -    integrity: ''
        +    integrity: '',
           })
           t.end()
         })
        @@ -82,19 +82,19 @@ test('should getContents of a tarball', async (t) => {
           const testDir = t.testdir({
             'package.json': JSON.stringify({
               name: 'my-cool-pkg',
        -      version: '1.0.0'
        -    }, null, 2)
        +      version: '1.0.0',
        +    }, null, 2),
           })
         
           const tarball = await pack(testDir)
         
           const tarballContents = await getContents({
             name: 'my-cool-pkg',
        -    version: '1.0.0'
        +    version: '1.0.0',
           }, tarball)
         
           const integrity = await ssri.fromData(tarball, {
        -    algorithms: ['sha1', 'sha512']
        +    algorithms: ['sha1', 'sha512'],
           })
         
           t.strictSame(tarballContents, {
        @@ -106,10 +106,9 @@ test('should getContents of a tarball', async (t) => {
             shasum: 'c0bfd67a5142104e429afda09119eedd6a30d2fc',
             integrity: ssri.parse(integrity.sha512[0]),
             filename: 'my-cool-pkg-1.0.0.tgz',
        -    files: [ { path: 'package.json', size: 49, mode: 420 } ],
        +    files: [{ path: 'package.json', size: 49, mode: 420 }],
             entryCount: 1,
        -    bundled: []
        +    bundled: [],
           }, 'contents are correct')
           t.end()
        -
         })
        diff --git a/deps/npm/test/lib/utils/unsupported.js b/deps/npm/test/lib/utils/unsupported.js
        index 89ee6af2321d7d..f14cba9b744adb 100644
        --- a/deps/npm/test/lib/utils/unsupported.js
        +++ b/deps/npm/test/lib/utils/unsupported.js
        @@ -30,7 +30,7 @@ const versions = [
           ['v10.0.0-0', false, false],
           ['v11.0.0-0', false, false],
           ['v12.0.0-0', false, false],
        -  ['v13.0.0-0', false, false]
        +  ['v13.0.0-0', false, false],
         ]
         
         test('versions', function (t) {
        @@ -71,7 +71,7 @@ test('checkForBrokenNode', t => {
           const expectLogs = [
             'ERROR: npm is known not to run on Node.js 1.2.3',
             "You'll need to upgrade to a newer Node.js version in order to use this",
        -    'version of npm. You can find the latest version at https://nodejs.org/'
        +    'version of npm. You can find the latest version at https://nodejs.org/',
           ]
           console.error = msg => logs.push(msg)
           unsupported.checkForBrokenNode()
        @@ -92,7 +92,7 @@ test('checkForUnsupportedNode', t => {
             'npm does not support Node.js 8.0.0',
             'You should probably upgrade to a newer version of node as we',
             "can't make any promises that npm will work with this version.",
        -    'You can find the latest version at https://nodejs.org/'
        +    'You can find the latest version at https://nodejs.org/',
           ]
           npmlog.warn = (section, msg) => logs.push(msg)
         
        diff --git a/deps/npm/test/lib/utils/update-notifier.js b/deps/npm/test/lib/utils/update-notifier.js
        index 903e888a5e0f7d..99c9dfc26626f1 100644
        --- a/deps/npm/test/lib/utils/update-notifier.js
        +++ b/deps/npm/test/lib/utils/update-notifier.js
        @@ -22,15 +22,15 @@ const pacote = {
               process.exit(1)
             }
             MANIFEST_REQUEST.push(spec)
        -    if (PACOTE_ERROR) {
        +    if (PACOTE_ERROR)
               throw PACOTE_ERROR
        -    }
        +
             return {
               version: spec === 'npm@latest' ? CURRENT_VERSION
        -        : /-/.test(spec) ? CURRENT_BETA
        -        : NEXT_VERSION
        +      : /-/.test(spec) ? CURRENT_BETA
        +      : NEXT_VERSION,
             }
        -  }
        +  },
         }
         
         const npm = {
        @@ -38,13 +38,12 @@ const npm = {
           log: { useColor: () => true },
           version: CURRENT_VERSION,
           config: { get: (k) => k !== 'global' },
        -  flatOptions,
           command: 'view',
        -  argv: ['npm']
        +  argv: ['npm'],
         }
         const npmNoColor = {
           ...npm,
        -  log: { useColor: () => false }
        +  log: { useColor: () => false },
         }
         
         const { basename } = require('path')
        @@ -70,17 +69,15 @@ const fs = {
               process.exit(1)
             }
             process.nextTick(() => cb(WRITE_ERROR))
        -  }
        +  },
         }
         
         const updateNotifier = requireInject('../../../lib/utils/update-notifier.js', {
           '@npmcli/ci-detect': () => ciMock,
           pacote,
        -  fs
        +  fs,
         })
         
        -const semver = require('semver')
        -
         t.afterEach(cb => {
           MANIFEST_REQUEST.length = 0
           STAT_ERROR = null
        @@ -94,7 +91,7 @@ t.test('situations in which we do not notify', t => {
           t.test('nothing to do if notifier disabled', async t => {
             t.equal(await updateNotifier({
               ...npm,
        -      config: { get: (k) => k === 'update-notifier' ? false : true }
        +      config: { get: (k) => k !== 'update-notifier' },
             }), null)
             t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
           })
        @@ -104,7 +101,7 @@ t.test('situations in which we do not notify', t => {
               ...npm,
               flatOptions: { ...flatOptions, global: true },
               command: 'install',
        -      argv: ['npm']
        +      argv: ['npm'],
             }), null)
             t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
           })
        @@ -140,7 +137,9 @@ t.test('situations in which we do not notify', t => {
           })
         
           t.test('do not update in CI', async t => {
        -    t.teardown(() => { ciMock = null })
        +    t.teardown(() => {
        +      ciMock = null
        +    })
             ciMock = 'something'
             t.equal(await updateNotifier(npm), null)
             t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
        @@ -148,14 +147,14 @@ t.test('situations in which we do not notify', t => {
         
           t.test('only check weekly for GA releases', async t => {
             // the 10 is fuzz factor for test environment
        -    STAT_MTIME = Date.now() - (1000*60*60*24*7) + 10
        +    STAT_MTIME = Date.now() - (1000 * 60 * 60 * 24 * 7) + 10
             t.equal(await updateNotifier(npm), null)
             t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
           })
         
           t.test('only check daily for betas', async t => {
             // the 10 is fuzz factor for test environment
        -    STAT_MTIME = Date.now() - (1000*60*60*24) + 10
        +    STAT_MTIME = Date.now() - (1000 * 60 * 60 * 24) + 10
             t.equal(await updateNotifier({ ...npm, version: HAVE_BETA }), null)
             t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
           })
        diff --git a/deps/npm/test/lib/version.js b/deps/npm/test/lib/version.js
        new file mode 100644
        index 00000000000000..f36132253fa321
        --- /dev/null
        +++ b/deps/npm/test/lib/version.js
        @@ -0,0 +1,160 @@
        +const t = require('tap')
        +const requireInject = require('require-inject')
        +
        +let result = []
        +
        +const noop = () => null
        +const npm = {
        +  flatOptions: {
        +    json: false,
        +  },
        +  prefix: '',
        +  version: '1.0.0',
        +}
        +const mocks = {
        +  libnpmversion: noop,
        +  '../../lib/npm.js': npm,
        +  '../../lib/utils/output.js': (...msg) => {
        +    for (const m of msg)
        +      result.push(m)
        +  },
        +  '../../lib/utils/usage.js': () => 'usage instructions',
        +}
        +
        +const version = requireInject('../../lib/version.js', mocks)
        +
        +const _processVersions = process.versions
        +t.afterEach(cb => {
        +  npm.flatOptions.json = false
        +  npm.prefix = ''
        +  process.versions = _processVersions
        +  result = []
        +  cb()
        +})
        +
        +t.test('no args', t => {
        +  const prefix = t.testdir({
        +    'package.json': JSON.stringify({
        +      name: 'test-version-no-args',
        +      version: '3.2.1',
        +    }),
        +  })
        +  npm.prefix = prefix
        +  Object.defineProperty(process, 'versions', { value: { node: '1.0.0' } })
        +
        +  version([], err => {
        +    if (err)
        +      throw err
        +
        +    t.deepEqual(
        +      result,
        +      [{
        +        'test-version-no-args': '3.2.1',
        +        node: '1.0.0',
        +        npm: '1.0.0',
        +      }],
        +      'should output expected values for various versions in npm'
        +    )
        +
        +    t.end()
        +  })
        +})
        +
        +t.test('too many args', t => {
        +  version(['foo', 'bar'], err => {
        +    t.match(
        +      err,
        +      'usage instructions',
        +      'should throw usage instructions error'
        +    )
        +
        +    t.end()
        +  })
        +})
        +
        +t.test('completion', t => {
        +  const { completion } = version
        +
        +  const testComp = (argv, expect) => {
        +    completion({ conf: { argv: { remain: argv } } }, (err, res) => {
        +      t.ifError(err)
        +      t.strictSame(res, expect, argv.join(' '))
        +    })
        +  }
        +
        +  testComp(['npm', 'version'], [
        +    'major',
        +    'minor',
        +    'patch',
        +    'premajor',
        +    'preminor',
        +    'prepatch',
        +    'prerelease',
        +    'from-git',
        +  ])
        +  testComp(['npm', 'version', 'major'], [])
        +
        +  t.end()
        +})
        +
        +t.test('failure reading package.json', t => {
        +  const prefix = t.testdir({})
        +  npm.prefix = prefix
        +
        +  version([], err => {
        +    if (err)
        +      throw err
        +
        +    t.deepEqual(
        +      result,
        +      [{
        +        npm: '1.0.0',
        +        node: '1.0.0',
        +      }],
        +      'should not have package name on returning object'
        +    )
        +
        +    t.end()
        +  })
        +})
        +
        +t.test('--json option', t => {
        +  const prefix = t.testdir({})
        +  npm.flatOptions.json = true
        +  npm.prefix = prefix
        +  Object.defineProperty(process, 'versions', { value: {} })
        +
        +  version([], err => {
        +    if (err)
        +      throw err
        +    t.deepEqual(
        +      result,
        +      ['{\n  "npm": "1.0.0"\n}'],
        +      'should return json stringified result'
        +    )
        +    t.end()
        +  })
        +})
        +
        +t.test('with one arg', t => {
        +  const version = requireInject('../../lib/version.js', {
        +    ...mocks,
        +    libnpmversion: (arg, opts) => {
        +      t.equal(arg, 'major', 'should forward expected value')
        +      t.deepEqual(
        +        opts,
        +        {
        +          json: false,
        +          path: '',
        +        },
        +        'should forward expected options'
        +      )
        +      t.end()
        +    },
        +  })
        +
        +  version(['major'], err => {
        +    if (err)
        +      throw err
        +  })
        +})
        diff --git a/deps/npm/test/lib/view.js b/deps/npm/test/lib/view.js
        index 88b2769a058990..f3e5d97f333605 100644
        --- a/deps/npm/test/lib/view.js
        +++ b/deps/npm/test/lib/view.js
        @@ -13,227 +13,225 @@ const cleanLogs = (done) => {
         }
         
         const packument = (nv, opts) => {
        -  if (!opts.fullMetadata) {
        +  if (!opts.fullMetadata)
             throw new Error('must fetch fullMetadata')
        -  }
         
        -  if (!opts.preferOnline) {
        +  if (!opts.preferOnline)
             throw new Error('must fetch with preferOnline')
        -  }
         
           const mocks = {
        -    'red': {
        -      'name' : 'red',
        +    red: {
        +      name: 'red',
               'dist-tags': {
        -        '1.0.1': {}
        +        '1.0.1': {},
        +      },
        +      time: {
        +        unpublished: new Date(),
               },
        -      'time': {
        -        'unpublished': new Date()
        -      }
             },
        -    'blue': {
        -      'name': 'blue',
        +    blue: {
        +      name: 'blue',
               'dist-tags': {},
        -      'time': {
        -        '1.0.0': '2019-08-06T16:21:09.842Z'
        +      time: {
        +        '1.0.0': '2019-08-06T16:21:09.842Z',
               },
        -      'versions': {
        +      versions: {
                 '1.0.0': {
        -          'name': 'blue',
        -          'version': '1.0.0',
        -          'dist': {
        -            'shasum': '123',
        -            'tarball': 'http://hm.blue.com/1.0.0.tgz',
        -            'integrity': '---',
        -            'fileCount': 1,
        -            'unpackedSize': 1              
        -          }
        +          name: 'blue',
        +          version: '1.0.0',
        +          dist: {
        +            shasum: '123',
        +            tarball: 'http://hm.blue.com/1.0.0.tgz',
        +            integrity: '---',
        +            fileCount: 1,
        +            unpackedSize: 1,
        +          },
                 },
        -        '1.0.1': {}
        -      }
        +        '1.0.1': {},
        +      },
             },
        -    'cyan': {
        -      '_npmUser': {
        -        'name': 'claudia',
        -        'email': 'claudia@cyan.com'
        -      } ,
        -      'name': 'cyan',
        +    cyan: {
        +      _npmUser: {
        +        name: 'claudia',
        +        email: 'claudia@cyan.com',
        +      },
        +      name: 'cyan',
               'dist-tags': {},
        -      'versions': {
        +      versions: {
                 '1.0.0': {
        -          'version': '1.0.0',
        -          'name': 'cyan',
        -          'dist': {
        -            'shasum': '123',
        -            'tarball': 'http://hm.cyan.com/1.0.0.tgz',
        -            'integrity': '---',
        -            'fileCount': 1,
        -            'unpackedSize': 1
        -          }
        +          version: '1.0.0',
        +          name: 'cyan',
        +          dist: {
        +            shasum: '123',
        +            tarball: 'http://hm.cyan.com/1.0.0.tgz',
        +            integrity: '---',
        +            fileCount: 1,
        +            unpackedSize: 1,
        +          },
                 },
        -        '1.0.1': {}
        -      }
        +        '1.0.1': {},
        +      },
             },
        -    'brown': {
        -      'name': 'brown'
        +    brown: {
        +      name: 'brown',
             },
        -    'yellow': {
        -      '_id': 'yellow',
        -      'name': 'yellow',
        -      'author': {
        -        'name': 'foo',
        -        'email': 'foo@yellow.com',
        -        'twitter': 'foo'
        +    yellow: {
        +      _id: 'yellow',
        +      name: 'yellow',
        +      author: {
        +        name: 'foo',
        +        email: 'foo@yellow.com',
        +        twitter: 'foo',
               },
        -      'readme': 'a very useful readme',
        -      'versions': {
        +      readme: 'a very useful readme',
        +      versions: {
                 '1.0.0': {
        -          'version': '1.0.0',
        -          'author': 'claudia',
        -          'readme': 'a very useful readme',
        -          'maintainers': [
        -            { 'name': 'claudia', 'email': 'c@yellow.com', 'twitter': 'cyellow' },
        -            { 'name': 'isaacs', 'email': 'i@yellow.com', 'twitter': 'iyellow' }
        -          ]
        +          version: '1.0.0',
        +          author: 'claudia',
        +          readme: 'a very useful readme',
        +          maintainers: [
        +            { name: 'claudia', email: 'c@yellow.com', twitter: 'cyellow' },
        +            { name: 'isaacs', email: 'i@yellow.com', twitter: 'iyellow' },
        +          ],
                 },
                 '1.0.1': {
        -          'version': '1.0.1',
        -          'author': 'claudia'
        +          version: '1.0.1',
        +          author: 'claudia',
                 },
                 '1.0.2': {
        -          'version': '1.0.2',
        -          'author': 'claudia'
        -        }
        -      }
        +          version: '1.0.2',
        +          author: 'claudia',
        +        },
        +      },
             },
        -    'purple': {
        -      'name': 'purple',
        -      'versions': {
        +    purple: {
        +      name: 'purple',
        +      versions: {
                 '1.0.0': {
        -          'foo': 1,
        -          'maintainers': [
        -            { 'name': 'claudia' }
        -          ]
        +          foo: 1,
        +          maintainers: [
        +            { name: 'claudia' },
        +          ],
                 },
        -        '1.0.1': {}
        -      }
        +        '1.0.1': {},
        +      },
             },
        -    'green': {
        -      '_id': 'green',
        -      'name': 'green',
        +    green: {
        +      _id: 'green',
        +      name: 'green',
               'dist-tags': {
        -        'latest': '1.0.0'
        +        latest: '1.0.0',
               },
        -      'maintainers': [
        -        { 'name': 'claudia', 'email': 'c@yellow.com', 'twitter': 'cyellow' },
        -        { 'name': 'isaacs', 'email': 'i@yellow.com', 'twitter': 'iyellow' }
        +      maintainers: [
        +        { name: 'claudia', email: 'c@yellow.com', twitter: 'cyellow' },
        +        { name: 'isaacs', email: 'i@yellow.com', twitter: 'iyellow' },
               ],
        -      'keywords': ['colors', 'green', 'crayola'],
        -      'versions': {
        +      keywords: ['colors', 'green', 'crayola'],
        +      versions: {
                 '1.0.0': {
        -          '_id': 'green',
        -          'version': '1.0.0',
        -          'description': 'green is a very important color',
        -          'bugs': {
        -            'url': 'http://bugs.green.com'
        +          _id: 'green',
        +          version: '1.0.0',
        +          description: 'green is a very important color',
        +          bugs: {
        +            url: 'http://bugs.green.com',
        +          },
        +          deprecated: true,
        +          repository: {
        +            url: 'http://repository.green.com',
                   },
        -          'deprecated': true,
        -          'repository': {
        -            'url': 'http://repository.green.com'
        +          license: { type: 'ACME' },
        +          bin: {
        +            green: 'bin/green.js',
                   },
        -          'license': { type: 'ACME' },
        -          'bin': {
        -            'green': 'bin/green.js'
        +          dependencies: {
        +            red: '1.0.0',
        +            yellow: '1.0.0',
                   },
        -          'dependencies': {
        -            'red': '1.0.0',
        -            'yellow': '1.0.0'
        +          dist: {
        +            shasum: '123',
        +            tarball: 'http://hm.green.com/1.0.0.tgz',
        +            integrity: '---',
        +            fileCount: 1,
        +            unpackedSize: 1,
                   },
        -          'dist': {
        -            'shasum': '123',
        -            'tarball': 'http://hm.green.com/1.0.0.tgz',
        -            'integrity': '---',
        -            'fileCount': 1,
        -            'unpackedSize': 1
        -          }
                 },
        -        '1.0.1': {}
        -      }
        +        '1.0.1': {},
        +      },
             },
        -    'black': {
        -      'name': 'black',
        +    black: {
        +      name: 'black',
               'dist-tags': {
        -        'latest': '1.0.0'
        +        latest: '1.0.0',
               },
        -      'versions': {
        +      versions: {
                 '1.0.0': {
        -          'version': '1.0.0',
        -          'bugs': 'http://bugs.black.com',
        -          'license': {},
        -          'dependencies': (() => {
        +          version: '1.0.0',
        +          bugs: 'http://bugs.black.com',
        +          license: {},
        +          dependencies: (() => {
                     const deps = {}
        -            for (i = 0; i < 25; i++) {
        +            for (let i = 0; i < 25; i++)
                       deps[i] = '1.0.0'
        -            }
        +
                     return deps
                   })(),
        -          'dist': {
        -            'shasum': '123',
        -            'tarball': 'http://hm.black.com/1.0.0.tgz',
        -            'integrity': '---',
        -            'fileCount': 1,
        -            'unpackedSize': 1
        -          }
        +          dist: {
        +            shasum: '123',
        +            tarball: 'http://hm.black.com/1.0.0.tgz',
        +            integrity: '---',
        +            fileCount: 1,
        +            unpackedSize: 1,
        +          },
                 },
        -        '1.0.1': {}
        -      }
        +        '1.0.1': {},
        +      },
             },
        -    'pink': {
        -      'name': 'pink',
        +    pink: {
        +      name: 'pink',
               'dist-tags': {
        -        'latest': '1.0.0'
        +        latest: '1.0.0',
               },
        -      'versions': {
        +      versions: {
                 '1.0.0': {
        -          'version': '1.0.0',
        -          'maintainers': [
        -            { 'name': 'claudia', 'url': 'http://c.pink.com' },
        -            { 'name': 'isaacs', 'url': 'http://i.pink.com'  }
        +          version: '1.0.0',
        +          maintainers: [
        +            { name: 'claudia', url: 'http://c.pink.com' },
        +            { name: 'isaacs', url: 'http://i.pink.com' },
                   ],
        -          'repository': 'http://repository.pink.com',
        -          'license': {},
        -          'dist': {
        -            'shasum': '123',
        -            'tarball': 'http://hm.pink.com/1.0.0.tgz',
        -            'integrity': '---',
        -            'fileCount': 1,
        -            'unpackedSize': 1
        -          }
        +          repository: 'http://repository.pink.com',
        +          license: {},
        +          dist: {
        +            shasum: '123',
        +            tarball: 'http://hm.pink.com/1.0.0.tgz',
        +            integrity: '---',
        +            fileCount: 1,
        +            unpackedSize: 1,
        +          },
                 },
        -        '1.0.1': {}
        -      }
        +        '1.0.1': {},
        +      },
             },
        -    'orange': {
        -      'name': 'orange',
        +    orange: {
        +      name: 'orange',
               'dist-tags': {
        -        'latest': '1.0.0'
        +        latest: '1.0.0',
               },
        -      'versions': {
        +      versions: {
                 '1.0.0': {
        -          'version': '1.0.0',
        -          'homepage': 'http://hm.orange.com',
        -          'license': {},
        -          'dist': {
        -            'shasum': '123',
        -            'tarball': 'http://hm.orange.com/1.0.0.tgz',
        -            'integrity': '---',
        -            'fileCount': 1,
        -            'unpackedSize': 1
        -          }
        +          version: '1.0.0',
        +          homepage: 'http://hm.orange.com',
        +          license: {},
        +          dist: {
        +            shasum: '123',
        +            tarball: 'http://hm.orange.com/1.0.0.tgz',
        +            integrity: '---',
        +            fileCount: 1,
        +            unpackedSize: 1,
        +          },
                 },
        -        '1.0.1': {}
        -      }
        -    }
        +        '1.0.1': {},
        +      },
        +    },
           }
           return mocks[nv.name]
         }
        @@ -244,34 +242,34 @@ t.test('should log package info', t => {
             '../../lib/npm.js': {
               flatOptions: {
                 global: false,
        -      }
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
         
           const viewJson = requireInject('../../lib/view.js', {
             '../../lib/npm.js': {
               flatOptions: {
        -        json: true
        -      }
        +        json: true,
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
         
           const viewUnicode = requireInject('../../lib/view.js', {
             '../../lib/npm.js': {
               flatOptions: {
                 global: false,
        -        unicode: true
        -      }
        +        unicode: true,
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
         
           t.test('package with license, bugs, repository and other fields', t => {
        @@ -344,8 +342,8 @@ t.test('should log info of package in current working dir', t => {
           const testDir = t.testdir({
             'package.json': JSON.stringify({
               name: 'blue',
        -      version: '1.0.0'
        -    }, null, 2)
        +      version: '1.0.0',
        +    }, null, 2),
           })
         
           const view = requireInject('../../lib/view.js', {
        @@ -353,12 +351,12 @@ t.test('should log info of package in current working dir', t => {
               prefix: testDir,
               flatOptions: {
                 defaultTag: '1.0.0',
        -        global: false
        -      }
        +        global: false,
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
         
           t.test('specific version', t => {
        @@ -383,23 +381,23 @@ t.test('should log info by field name', t => {
             '../../lib/npm.js': {
               flatOptions: {
                 json: true,
        -        global: false
        -      }
        +        global: false,
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
         
           const view = requireInject('../../lib/view.js', {
             '../../lib/npm.js': {
               flatOptions: {
        -        global: false
        -      }
        +        global: false,
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
         
           t.test('readme', t => {
        @@ -452,14 +450,14 @@ t.test('should log info by field name', t => {
           })
         
           t.test('array field - 1 element', t => {
        -    view(['purple@1.0.0',  'maintainers.name'], () => {
        +    view(['purple@1.0.0', 'maintainers.name'], () => {
               t.matchSnapshot(logs)
               t.end()
             })
           })
         
           t.test('array field - 2 elements', t => {
        -    view(['yellow@1.x.x',  'maintainers.name'], () => {
        +    view(['yellow@1.x.x', 'maintainers.name'], () => {
               t.matchSnapshot(logs)
               t.end()
             })
        @@ -472,9 +470,9 @@ t.test('throw error if global mode', (t) => {
           const view = requireInject('../../lib/view.js', {
             '../../lib/npm.js': {
               flatOptions: {
        -        global: true
        -      }
        -    }
        +        global: true,
        +      },
        +    },
           })
           view([], (err) => {
             t.equals(err.message, 'Cannot use view command in global mode.')
        @@ -489,9 +487,9 @@ t.test('throw ENOENT error if package.json misisng', (t) => {
             '../../lib/npm.js': {
               prefix: testDir,
               flatOptions: {
        -        global: false
        -      }
        -    }
        +        global: false,
        +      },
        +    },
           })
           view([], (err) => {
             t.match(err, { code: 'ENOENT' })
        @@ -501,16 +499,16 @@ t.test('throw ENOENT error if package.json misisng', (t) => {
         
         t.test('throw EJSONPARSE error if package.json not json', (t) => {
           const testDir = t.testdir({
        -    'package.json': 'not json, nope, not even a little bit!'
        +    'package.json': 'not json, nope, not even a little bit!',
           })
         
           const view = requireInject('../../lib/view.js', {
             '../../lib/npm.js': {
               prefix: testDir,
               flatOptions: {
        -        global: false
        -      }
        -    }
        +        global: false,
        +      },
        +    },
           })
           view([], (err) => {
             t.match(err, { code: 'EJSONPARSE' })
        @@ -520,16 +518,16 @@ t.test('throw EJSONPARSE error if package.json not json', (t) => {
         
         t.test('throw error if package.json has no name', (t) => {
           const testDir = t.testdir({
        -    'package.json': '{}'
        +    'package.json': '{}',
           })
         
           const view = requireInject('../../lib/view.js', {
             '../../lib/npm.js': {
               prefix: testDir,
               flatOptions: {
        -        global: false
        -      }
        -    }
        +        global: false,
        +      },
        +    },
           })
           view([], (err) => {
             t.equals(err.message, 'Invalid package.json, no "name" field')
        @@ -542,12 +540,12 @@ t.test('throws when unpublished', (t) => {
             '../../lib/npm.js': {
               flatOptions: {
                 defaultTag: '1.0.1',
        -        global: false
        -      }
        +        global: false,
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
           view(['red'], (err) => {
             t.equals(err.code, 'E404')
        @@ -560,16 +558,18 @@ t.test('completion', (t) => {
             '../../lib/npm.js': {
               flatOptions: {
                 defaultTag: '1.0.1',
        -        global: false
        -      }
        +        global: false,
        +      },
        +    },
        +    pacote: {
        +      packument,
             },
        -    'pacote': {
        -      packument
        -    }
           })
           view.completion({
        -    conf: { argv: { remain: ['npm', 'view', 'green@1.0.0'] } }
        +    conf: { argv: { remain: ['npm', 'view', 'green@1.0.0'] } },
           }, (err, res) => {
        +    if (err)
        +      throw err
             t.ok(res, 'returns back fields')
             t.end()
           })
        @@ -580,14 +580,13 @@ t.test('no registry completion', (t) => {
             '../../lib/npm.js': {
               flatOptions: {
                 defaultTag: '1.0.1',
        -      }
        -    }
        +      },
        +    },
           })
           view.completion({
        -    conf: { argv: { remain: ['npm', 'view'] } }
        +    conf: { argv: { remain: ['npm', 'view'] } },
           }, (err) => {
             t.notOk(err, 'there is no package completion')
             t.end()
           })
         })
        -
        diff --git a/deps/npm/test/lib/whoami.js b/deps/npm/test/lib/whoami.js
        index dc9dbdfd570ff2..d54814db365e7f 100644
        --- a/deps/npm/test/lib/whoami.js
        +++ b/deps/npm/test/lib/whoami.js
        @@ -8,7 +8,7 @@ test('whoami', (t) => {
             '../../lib/npm.js': { flatOptions: {} },
             '../../lib/utils/output.js': (output) => {
               t.equal(output, 'foo', 'should output the username')
        -    }
        +    },
           })
         
           whoami([], (err) => {
        @@ -24,7 +24,7 @@ test('whoami json', (t) => {
             '../../lib/npm.js': { flatOptions: { json: true } },
             '../../lib/utils/output.js': (output) => {
               t.equal(output, '"foo"', 'should output the username as json')
        -    }
        +    },
           })
         
           whoami([], (err) => {
        diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn
        index bda33c185fe683..219837ff45e9e3 100644
        --- a/deps/v8/BUILD.gn
        +++ b/deps/v8/BUILD.gn
        @@ -3237,6 +3237,7 @@ v8_source_set("v8_base_without_compiler") {
             "src/wasm/baseline/liftoff-compiler.cc",
             "src/wasm/baseline/liftoff-compiler.h",
             "src/wasm/baseline/liftoff-register.h",
        +    "src/wasm/code-space-access.h",
             "src/wasm/compilation-environment.h",
             "src/wasm/decoder.h",
             "src/wasm/function-body-decoder-impl.h",
        diff --git a/deps/v8/include/v8-platform.h b/deps/v8/include/v8-platform.h
        index aae381b080617f..1bf75a1d42fc78 100644
        --- a/deps/v8/include/v8-platform.h
        +++ b/deps/v8/include/v8-platform.h
        @@ -384,7 +384,13 @@ class PageAllocator {
             kReadWrite,
             // TODO(hpayer): Remove this flag. Memory should never be rwx.
             kReadWriteExecute,
        -    kReadExecute
        +    kReadExecute,
        +    // Set this when reserving memory that will later require kReadWriteExecute
        +    // permissions. The resulting behavior is platform-specific, currently
        +    // this is used to set the MAP_JIT flag on Apple Silicon.
        +    // TODO(jkummerow): Remove this when Wasm has a platform-independent
        +    // w^x implementation.
        +    kNoAccessWillJitLater
           };
         
           /**
        diff --git a/deps/v8/src/base/page-allocator.cc b/deps/v8/src/base/page-allocator.cc
        index 98b2c690960336..9f48ee79fe5424 100644
        --- a/deps/v8/src/base/page-allocator.cc
        +++ b/deps/v8/src/base/page-allocator.cc
        @@ -6,6 +6,10 @@
         
         #include "src/base/platform/platform.h"
         
        +#if V8_OS_MACOSX
        +#include   // For MAP_JIT.
        +#endif
        +
         namespace v8 {
         namespace base {
         
        @@ -21,6 +25,8 @@ STATIC_ASSERT_ENUM(PageAllocator::kReadWriteExecute,
                            base::OS::MemoryPermission::kReadWriteExecute);
         STATIC_ASSERT_ENUM(PageAllocator::kReadExecute,
                            base::OS::MemoryPermission::kReadExecute);
        +STATIC_ASSERT_ENUM(PageAllocator::kNoAccessWillJitLater,
        +                   base::OS::MemoryPermission::kNoAccessWillJitLater);
         
         #undef STATIC_ASSERT_ENUM
         
        @@ -38,6 +44,14 @@ void* PageAllocator::GetRandomMmapAddr() {
         
         void* PageAllocator::AllocatePages(void* hint, size_t size, size_t alignment,
                                            PageAllocator::Permission access) {
        +#if !(V8_OS_MACOSX && V8_HOST_ARCH_ARM64 && defined(MAP_JIT))
        +  // kNoAccessWillJitLater is only used on Apple Silicon. Map it to regular
        +  // kNoAccess on other platforms, so code doesn't have to handle both enum
        +  // values.
        +  if (access == PageAllocator::kNoAccessWillJitLater) {
        +    access = PageAllocator::kNoAccess;
        +  }
        +#endif
           return base::OS::Allocate(hint, size, alignment,
                                     static_cast(access));
         }
        diff --git a/deps/v8/src/base/platform/platform-cygwin.cc b/deps/v8/src/base/platform/platform-cygwin.cc
        index 92a5fbe490f4c3..b9da2f1cd592db 100644
        --- a/deps/v8/src/base/platform/platform-cygwin.cc
        +++ b/deps/v8/src/base/platform/platform-cygwin.cc
        @@ -33,6 +33,7 @@ namespace {
         DWORD GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
           switch (access) {
             case OS::MemoryPermission::kNoAccess:
        +    case OS::MemoryPermission::kNoAccessWillJitLater:
               return PAGE_NOACCESS;
             case OS::MemoryPermission::kRead:
               return PAGE_READONLY;
        diff --git a/deps/v8/src/base/platform/platform-fuchsia.cc b/deps/v8/src/base/platform/platform-fuchsia.cc
        index fa175c39177aea..35a508a140ebd7 100644
        --- a/deps/v8/src/base/platform/platform-fuchsia.cc
        +++ b/deps/v8/src/base/platform/platform-fuchsia.cc
        @@ -18,6 +18,7 @@ namespace {
         uint32_t GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
           switch (access) {
             case OS::MemoryPermission::kNoAccess:
        +    case OS::MemoryPermission::kNoAccessWillJitLater:
               return 0;  // no permissions
             case OS::MemoryPermission::kRead:
               return ZX_VM_PERM_READ;
        diff --git a/deps/v8/src/base/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc
        index 14294019d90dd0..4b49968baa053f 100644
        --- a/deps/v8/src/base/platform/platform-posix.cc
        +++ b/deps/v8/src/base/platform/platform-posix.cc
        @@ -125,6 +125,7 @@ const int kMmapFdOffset = 0;
         int GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
           switch (access) {
             case OS::MemoryPermission::kNoAccess:
        +    case OS::MemoryPermission::kNoAccessWillJitLater:
               return PROT_NONE;
             case OS::MemoryPermission::kRead:
               return PROT_READ;
        @@ -152,6 +153,11 @@ int GetFlagsForMemoryPermission(OS::MemoryPermission access,
             flags |= MAP_LAZY;
         #endif  // V8_OS_QNX
           }
        +#if V8_OS_MACOSX && V8_HOST_ARCH_ARM64 && defined(MAP_JIT)
        +  if (access == OS::MemoryPermission::kNoAccessWillJitLater) {
        +    flags |= MAP_JIT;
        +  }
        +#endif
           return flags;
         }
         
        diff --git a/deps/v8/src/base/platform/platform-win32.cc b/deps/v8/src/base/platform/platform-win32.cc
        index 5db3e343103dd0..6be63dee137a81 100644
        --- a/deps/v8/src/base/platform/platform-win32.cc
        +++ b/deps/v8/src/base/platform/platform-win32.cc
        @@ -753,6 +753,7 @@ namespace {
         DWORD GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
           switch (access) {
             case OS::MemoryPermission::kNoAccess:
        +    case OS::MemoryPermission::kNoAccessWillJitLater:
               return PAGE_NOACCESS;
             case OS::MemoryPermission::kRead:
               return PAGE_READONLY;
        diff --git a/deps/v8/src/base/platform/platform.h b/deps/v8/src/base/platform/platform.h
        index d5f59d1d7a8d8a..c4895a5b274374 100644
        --- a/deps/v8/src/base/platform/platform.h
        +++ b/deps/v8/src/base/platform/platform.h
        @@ -167,7 +167,10 @@ class V8_BASE_EXPORT OS {
             kReadWrite,
             // TODO(hpayer): Remove this flag. Memory should never be rwx.
             kReadWriteExecute,
        -    kReadExecute
        +    kReadExecute,
        +    // TODO(jkummerow): Remove this when Wasm has a platform-independent
        +    // w^x implementation.
        +    kNoAccessWillJitLater
           };
         
           static bool HasLazyCommits();
        diff --git a/deps/v8/src/utils/allocation.cc b/deps/v8/src/utils/allocation.cc
        index 6169acbfd6687a..022ac82ea6fa28 100644
        --- a/deps/v8/src/utils/allocation.cc
        +++ b/deps/v8/src/utils/allocation.cc
        @@ -213,15 +213,17 @@ bool OnCriticalMemoryPressure(size_t length) {
         VirtualMemory::VirtualMemory() = default;
         
         VirtualMemory::VirtualMemory(v8::PageAllocator* page_allocator, size_t size,
        -                             void* hint, size_t alignment)
        +                             void* hint, size_t alignment, JitPermission jit)
             : page_allocator_(page_allocator) {
           DCHECK_NOT_NULL(page_allocator);
           DCHECK(IsAligned(size, page_allocator_->CommitPageSize()));
           size_t page_size = page_allocator_->AllocatePageSize();
           alignment = RoundUp(alignment, page_size);
        -  Address address = reinterpret_cast
        ( - AllocatePages(page_allocator_, hint, RoundUp(size, page_size), alignment, - PageAllocator::kNoAccess)); + PageAllocator::Permission permissions = + jit == kMapAsJittable ? PageAllocator::kNoAccessWillJitLater + : PageAllocator::kNoAccess; + Address address = reinterpret_cast
        (AllocatePages( + page_allocator_, hint, RoundUp(size, page_size), alignment, permissions)); if (address != kNullAddress) { DCHECK(IsAligned(address, alignment)); region_ = base::AddressRegion(address, size); diff --git a/deps/v8/src/utils/allocation.h b/deps/v8/src/utils/allocation.h index 7106b1c749a893..a82012310b8efe 100644 --- a/deps/v8/src/utils/allocation.h +++ b/deps/v8/src/utils/allocation.h @@ -156,6 +156,8 @@ V8_EXPORT_PRIVATE bool OnCriticalMemoryPressure(size_t length); // Represents and controls an area of reserved memory. class VirtualMemory final { public: + enum JitPermission { kNoJit, kMapAsJittable }; + // Empty VirtualMemory object, controlling no reserved memory. V8_EXPORT_PRIVATE VirtualMemory(); @@ -164,8 +166,8 @@ class VirtualMemory final { // size. The |size| must be aligned with |page_allocator|'s commit page size. // This may not be at the position returned by address(). V8_EXPORT_PRIVATE VirtualMemory(v8::PageAllocator* page_allocator, - size_t size, void* hint, - size_t alignment = 1); + size_t size, void* hint, size_t alignment = 1, + JitPermission jit = kNoJit); // Construct a virtual memory by assigning it some already mapped address // and size. diff --git a/deps/v8/src/wasm/code-space-access.h b/deps/v8/src/wasm/code-space-access.h new file mode 100644 index 00000000000000..5eeb980e17eddc --- /dev/null +++ b/deps/v8/src/wasm/code-space-access.h @@ -0,0 +1,69 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_WASM_CODE_SPACE_ACCESS_H_ +#define V8_WASM_CODE_SPACE_ACCESS_H_ + +#include "src/base/build_config.h" +#include "src/base/macros.h" +#include "src/common/globals.h" + +namespace v8 { +namespace internal { + +#if defined(V8_OS_MACOSX) && defined(V8_HOST_ARCH_ARM64) + +// Ignoring this warning is considered better than relying on +// __builtin_available. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" +inline void SwitchMemoryPermissionsToWritable() { + pthread_jit_write_protect_np(0); +} +inline void SwitchMemoryPermissionsToExecutable() { + pthread_jit_write_protect_np(1); +} +#pragma clang diagnostic pop + +namespace wasm { + +class CodeSpaceWriteScope { + public: + // TODO(jkummerow): Background threads could permanently stay in + // writable mode; only the main thread has to switch back and forth. + CodeSpaceWriteScope() { + if (code_space_write_nesting_level_ == 0) { + SwitchMemoryPermissionsToWritable(); + } + code_space_write_nesting_level_++; + } + ~CodeSpaceWriteScope() { + code_space_write_nesting_level_--; + if (code_space_write_nesting_level_ == 0) { + SwitchMemoryPermissionsToExecutable(); + } + } + + private: + static thread_local int code_space_write_nesting_level_; +}; + +#define CODE_SPACE_WRITE_SCOPE CodeSpaceWriteScope _write_access_; + +} // namespace wasm + +#else // Not Mac-on-arm64. + +// Nothing to do, we map code memory with rwx permissions. +inline void SwitchMemoryPermissionsToWritable() {} +inline void SwitchMemoryPermissionsToExecutable() {} + +#define CODE_SPACE_WRITE_SCOPE + +#endif // V8_OS_MACOSX && V8_HOST_ARCH_ARM64 + +} // namespace internal +} // namespace v8 + +#endif // V8_WASM_CODE_SPACE_ACCESS_H_ diff --git a/deps/v8/src/wasm/wasm-code-manager.cc b/deps/v8/src/wasm/wasm-code-manager.cc index 2f5a3f479b2475..fc657d634dba7c 100644 --- a/deps/v8/src/wasm/wasm-code-manager.cc +++ b/deps/v8/src/wasm/wasm-code-manager.cc @@ -6,6 +6,7 @@ #include +#include "src/base/build_config.h" #include "src/base/iterator.h" #include "src/base/macros.h" #include "src/base/platform/platform.h" @@ -21,6 +22,7 @@ #include "src/snapshot/embedded/embedded-data.h" #include "src/utils/ostreams.h" #include "src/utils/vector.h" +#include "src/wasm/code-space-access.h" #include "src/wasm/compilation-environment.h" #include "src/wasm/function-compiler.h" #include "src/wasm/jump-table-assembler.h" @@ -47,6 +49,10 @@ namespace wasm { using trap_handler::ProtectedInstructionData; +#if defined(V8_OS_MACOSX) && defined(V8_HOST_ARCH_ARM64) +thread_local int CodeSpaceWriteScope::code_space_write_nesting_level_ = 0; +#endif + base::AddressRegion DisjointAllocationPool::Merge( base::AddressRegion new_region) { // Find the possible insertion position by identifying the first region whose @@ -731,6 +737,7 @@ void WasmCodeAllocator::FreeCode(Vector codes) { // Zap code area and collect freed code regions. DisjointAllocationPool freed_regions; size_t code_size = 0; + CODE_SPACE_WRITE_SCOPE for (WasmCode* code : codes) { ZapCode(code->instruction_start(), code->instructions().size()); FlushInstructionCache(code->instruction_start(), @@ -847,6 +854,7 @@ CompilationEnv NativeModule::CreateCompilationEnv() const { } WasmCode* NativeModule::AddCodeForTesting(Handle code) { + CODE_SPACE_WRITE_SCOPE // For off-heap builtins, we create a copy of the off-heap instruction stream // instead of the on-heap code object containing the trampoline. Ensure that // we do not apply the on-heap reloc info to the off-heap instructions. @@ -942,6 +950,7 @@ void NativeModule::UseLazyStub(uint32_t func_index) { if (!lazy_compile_table_) { uint32_t num_slots = module_->num_declared_functions; WasmCodeRefScope code_ref_scope; + CODE_SPACE_WRITE_SCOPE base::AddressRegion single_code_space_region; { base::MutexGuard guard(&allocation_mutex_); @@ -1003,6 +1012,7 @@ std::unique_ptr NativeModule::AddCodeWithCodeSpace( const int code_comments_offset = desc.code_comments_offset; const int instr_size = desc.instr_size; + CODE_SPACE_WRITE_SCOPE memcpy(dst_code_bytes.begin(), desc.buffer, static_cast(desc.instr_size)); @@ -1138,6 +1148,7 @@ WasmCode* NativeModule::AddDeserializedCode( Vector protected_instructions_data, Vector reloc_info, Vector source_position_table, WasmCode::Kind kind, ExecutionTier tier) { + // CodeSpaceWriteScope is provided by the caller. Vector dst_code_bytes = code_allocator_.AllocateForCode(this, instructions.size()); memcpy(dst_code_bytes.begin(), instructions.begin(), instructions.size()); @@ -1196,6 +1207,7 @@ WasmCode* NativeModule::CreateEmptyJumpTableInRegion( Vector code_space = code_allocator_.AllocateForCodeInRegion( this, jump_table_size, region, allocator_lock); DCHECK(!code_space.empty()); + CODE_SPACE_WRITE_SCOPE ZapCode(reinterpret_cast
        (code_space.begin()), code_space.size()); std::unique_ptr code{ new WasmCode{this, // native_module @@ -1221,6 +1233,7 @@ void NativeModule::PatchJumpTablesLocked(uint32_t slot_index, Address target) { // The caller must hold the {allocation_mutex_}, thus we fail to lock it here. DCHECK(!allocation_mutex_.TryLock()); + CODE_SPACE_WRITE_SCOPE for (auto& code_space_data : code_space_data_) { DCHECK_IMPLIES(code_space_data.jump_table, code_space_data.far_jump_table); if (!code_space_data.jump_table) continue; @@ -1283,6 +1296,7 @@ void NativeModule::AddCodeSpace( #endif // V8_OS_WIN64 WasmCodeRefScope code_ref_scope; + CODE_SPACE_WRITE_SCOPE WasmCode* jump_table = nullptr; WasmCode* far_jump_table = nullptr; const uint32_t num_wasm_functions = module_->num_declared_functions; @@ -1596,7 +1610,11 @@ VirtualMemory WasmCodeManager::TryAllocate(size_t size, void* hint) { if (!BackingStore::ReserveAddressSpace(size)) return {}; if (hint == nullptr) hint = page_allocator->GetRandomMmapAddr(); - VirtualMemory mem(page_allocator, size, hint, allocate_page_size); + // When we start exposing Wasm in jitless mode, then the jitless flag + // will have to determine whether we set kMapAsJittable or not. + DCHECK(!FLAG_jitless); + VirtualMemory mem(page_allocator, size, hint, allocate_page_size, + VirtualMemory::kMapAsJittable); if (!mem.IsReserved()) { BackingStore::ReleaseReservation(size); return {}; @@ -1843,6 +1861,7 @@ std::vector> NativeModule::AddCompiledCode( generated_code.reserve(results.size()); // Now copy the generated code into the code space and relocate it. + CODE_SPACE_WRITE_SCOPE for (auto& result : results) { DCHECK_EQ(result.code_desc.buffer, result.instr_buffer.get()); size_t code_size = RoundUp(result.code_desc.instr_size); diff --git a/deps/v8/src/wasm/wasm-serialization.cc b/deps/v8/src/wasm/wasm-serialization.cc index e5bab7e2cdc57c..f4f5f992682a06 100644 --- a/deps/v8/src/wasm/wasm-serialization.cc +++ b/deps/v8/src/wasm/wasm-serialization.cc @@ -13,6 +13,7 @@ #include "src/utils/ostreams.h" #include "src/utils/utils.h" #include "src/utils/version.h" +#include "src/wasm/code-space-access.h" #include "src/wasm/function-compiler.h" #include "src/wasm/module-compiler.h" #include "src/wasm/module-decoder.h" @@ -534,6 +535,7 @@ void NativeModuleDeserializer::ReadCode(int fn_index, Reader* reader) { auto protected_instructions = reader->ReadVector(protected_instructions_size); + CODE_SPACE_WRITE_SCOPE WasmCode* code = native_module_->AddDeserializedCode( fn_index, code_buffer, stack_slot_count, tagged_parameter_slots, safepoint_table_offset, handler_table_offset, constant_pool_offset, diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 21db27c5d3d4e4..1f93ec28c299ff 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -176,6 +176,13 @@ 'test-debug/DebugBreakStackTrace': [PASS, SLOW], }], # 'arch == arm64 and simulator_run' +['arch == arm64 and system == macos and not simulator_run', { + # printf, being a variadic function, has a different, stack-based ABI on + # Apple silicon. See: + # https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html + 'test-assembler-arm64/printf_no_preserve': [SKIP], +}], # arch == arm64 and system == macos and not simulator_run + ############################################################################## ['variant == nooptimization and (arch == arm or arch == arm64) and simulator_run', { # Slow tests: https://crbug.com/v8/7783 @@ -489,6 +496,7 @@ 'test-jump-table-assembler/*': [SKIP], 'test-gc/*': [SKIP], 'test-grow-memory/*': [SKIP], + 'test-liftoff-inspection/*': [SKIP], 'test-run-wasm-64/*': [SKIP], 'test-run-wasm-asmjs/*': [SKIP], 'test-run-wasm-atomics64/*': [SKIP], diff --git a/deps/v8/test/cctest/test-assembler-arm64.cc b/deps/v8/test/cctest/test-assembler-arm64.cc index 19da59e1727f80..52aaf3162b1991 100644 --- a/deps/v8/test/cctest/test-assembler-arm64.cc +++ b/deps/v8/test/cctest/test-assembler-arm64.cc @@ -11720,9 +11720,9 @@ TEST(system_msr) { const uint64_t fpcr_core = 0x07C00000; // All FPCR fields (including fields which may be read-as-zero): - // Stride, Len + // Stride, FZ16, Len // IDE, IXE, UFE, OFE, DZE, IOE - const uint64_t fpcr_all = fpcr_core | 0x00379F00; + const uint64_t fpcr_all = fpcr_core | 0x003F9F00; SETUP(); diff --git a/deps/v8/test/cctest/test-code-stub-assembler.cc b/deps/v8/test/cctest/test-code-stub-assembler.cc index 263951b573fd04..f79b848dc1b581 100644 --- a/deps/v8/test/cctest/test-code-stub-assembler.cc +++ b/deps/v8/test/cctest/test-code-stub-assembler.cc @@ -41,8 +41,9 @@ template using TVariable = TypedCodeAssemblerVariable; using PromiseResolvingFunctions = TorqueStructPromiseResolvingFunctions; -int sum10(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, - int a8, int a9) { +intptr_t sum10(intptr_t a0, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4, + intptr_t a5, intptr_t a6, intptr_t a7, intptr_t a8, + intptr_t a9) { return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; } diff --git a/deps/v8/test/cctest/test-icache.cc b/deps/v8/test/cctest/test-icache.cc index e8c89b7232b3b0..82baa9fe96212d 100644 --- a/deps/v8/test/cctest/test-icache.cc +++ b/deps/v8/test/cctest/test-icache.cc @@ -6,6 +6,7 @@ #include "src/codegen/macro-assembler-inl.h" #include "src/execution/simulator.h" #include "src/handles/handles-inl.h" +#include "src/wasm/code-space-access.h" #include "test/cctest/cctest.h" #include "test/common/assembler-tester.h" @@ -179,11 +180,15 @@ TEST(TestFlushICacheOfWritableAndExecutable) { CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(), buffer->size(), v8::PageAllocator::kReadWriteExecute)); + SwitchMemoryPermissionsToWritable(); FloodWithInc(isolate, buffer.get()); FlushInstructionCache(buffer->start(), buffer->size()); + SwitchMemoryPermissionsToExecutable(); CHECK_EQ(23 + kNumInstr, f.Call(23)); // Call into generated code. + SwitchMemoryPermissionsToWritable(); FloodWithNop(isolate, buffer.get()); FlushInstructionCache(buffer->start(), buffer->size()); + SwitchMemoryPermissionsToExecutable(); CHECK_EQ(23, f.Call(23)); // Call into generated code. } } diff --git a/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc b/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc index 99ec7d25ab457c..a0dd4cc33be301 100644 --- a/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc +++ b/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc @@ -8,6 +8,7 @@ #include "src/codegen/macro-assembler-inl.h" #include "src/execution/simulator.h" #include "src/utils/utils.h" +#include "src/wasm/code-space-access.h" #include "src/wasm/jump-table-assembler.h" #include "test/cctest/cctest.h" #include "test/common/assembler-tester.h" @@ -33,7 +34,12 @@ constexpr uint32_t kJumpTableSize = JumpTableAssembler::SizeForNumberOfSlots(kJumpTableSlotCount); // Must be a safe commit page size. +#if V8_OS_MACOSX && V8_HOST_ARCH_ARM64 +// See kAppleArmPageSize in platform-posix.cc. +constexpr size_t kThunkBufferSize = 1 << 14; +#else constexpr size_t kThunkBufferSize = 4 * KB; +#endif #if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_X64 constexpr uint32_t kAvailableBufferSlots = @@ -154,6 +160,7 @@ class JumpTableRunner : public v8::base::Thread { void Run() override { TRACE("Runner #%d is starting ...\n", runner_id_); + SwitchMemoryPermissionsToExecutable(); GeneratedCode::FromAddress(CcTest::i_isolate(), slot_address_).Call(); TRACE("Runner #%d is stopping ...\n", runner_id_); USE(runner_id_); @@ -176,6 +183,7 @@ class JumpTablePatcher : public v8::base::Thread { void Run() override { TRACE("Patcher %p is starting ...\n", this); + SwitchMemoryPermissionsToWritable(); Address slot_address = slot_start_ + JumpTableAssembler::JumpSlotIndexToOffset(slot_index_); // First, emit code to the two thunks. @@ -235,6 +243,7 @@ TEST(JumpTablePatchingStress) { std::bitset used_thunk_slots; buffer->MakeWritableAndExecutable(); + SwitchMemoryPermissionsToWritable(); // Iterate through jump-table slots to hammer at different alignments within // the jump-table, thereby increasing stress for variable-length ISAs. diff --git a/deps/v8/test/unittests/heap/unmapper-unittest.cc b/deps/v8/test/unittests/heap/unmapper-unittest.cc index bd476cd1ec1682..a919945d3f4ee7 100644 --- a/deps/v8/test/unittests/heap/unmapper-unittest.cc +++ b/deps/v8/test/unittests/heap/unmapper-unittest.cc @@ -170,6 +170,7 @@ class TrackingPageAllocator : public ::v8::PageAllocator { os << " page: [" << start << ", " << end << "), access: "; switch (access) { case PageAllocator::kNoAccess: + case PageAllocator::kNoAccessWillJitLater: os << "--"; break; case PageAllocator::kRead: diff --git a/deps/v8/test/unittests/unittests.status b/deps/v8/test/unittests/unittests.status index 20406242778652..96dd893db20568 100644 --- a/deps/v8/test/unittests/unittests.status +++ b/deps/v8/test/unittests/unittests.status @@ -17,6 +17,27 @@ 'RandomNumberGenerator.NextSampleSlowInvalidParam2': [SKIP], }], # system == macos and asan +['system == macos and arch == arm64 and not simulator_run', { + # Throwing C++ exceptions doesn't work; probably because the unittests + # binary is built with -fno-exceptions? + 'LanguageServerJson.LexerError': [SKIP], + 'LanguageServerJson.ParserError': [SKIP], + 'Torque.DoubleUnderScorePrefixIllegalForIdentifiers': [SKIP], + 'Torque.Enums': [SKIP], + 'Torque.ImportNonExistentFile': [SKIP], + + # Test uses fancy signal handling. Needs investigation. + 'MemoryAllocationPermissionsTest.DoTest': [SKIP], + + # cppgc::internal::kGuardPageSize is smaller than kAppleArmPageSize. + 'PageMemoryRegionTest.PlatformUsesGuardPages': [FAIL], + + # Time tick resolution appears to be ~42 microseconds. Tests expect 1 us. + 'TimeTicks.NowResolution': [FAIL], + 'RuntimeCallStatsTest.BasicJavaScript': [SKIP], + 'RuntimeCallStatsTest.FunctionLengthGetter': [SKIP], +}], # system == macos and arch == arm64 and not simulator_run + ############################################################################## ['lite_mode or variant == jitless', { # TODO(v8:7777): Re-enable once wasm is supported in jitless mode. diff --git a/doc/abi_version_registry.json b/doc/abi_version_registry.json index ec76e74aaf1bf6..80e45b1403ad15 100644 --- a/doc/abi_version_registry.json +++ b/doc/abi_version_registry.json @@ -1,5 +1,6 @@ { "NODE_MODULE_VERSION": [ + { "modules": 89, "runtime": "electron", "variant": "electron", "versions": "13" }, { "modules": 88, "runtime": "node", "variant": "v8_8.6", "versions": "15.0.0" }, { "modules": 87, "runtime": "electron", "variant": "electron", "versions": "12" }, { "modules": 86, "runtime": "node", "variant": "v8_8.4", "versions": "15.0.0-pre" }, diff --git a/doc/api/addons.md b/doc/api/addons.md index 0d8261d7c66275..796e32248f8aed 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -154,25 +154,26 @@ they were created. The context-aware addon can be structured to avoid global static data by performing the following steps: + * Define a class which will hold per-addon-instance data and which has a static -member of the form + member of the form ```cpp static void DeleteInstance(void* data) { // Cast `data` to an instance of the class and delete it. } ``` * Heap-allocate an instance of this class in the addon initializer. This can be -accomplished using the `new` keyword. + accomplished using the `new` keyword. * Call `node::AddEnvironmentCleanupHook()`, passing it the above-created -instance and a pointer to `DeleteInstance()`. This will ensure the instance is -deleted when the environment is torn down. + instance and a pointer to `DeleteInstance()`. This will ensure the instance is + deleted when the environment is torn down. * Store the instance of the class in a `v8::External`, and * Pass the `v8::External` to all methods exposed to JavaScript by passing it -to `v8::FunctionTemplate::New()` or `v8::Function::New()` which creates the -native-backed JavaScript functions. The third parameter of -`v8::FunctionTemplate::New()` or `v8::Function::New()` accepts the -`v8::External` and makes it available in the native callback using the -`v8::FunctionCallbackInfo::Data()` method. + to `v8::FunctionTemplate::New()` or `v8::Function::New()` which creates the + native-backed JavaScript functions. The third parameter of + `v8::FunctionTemplate::New()` or `v8::Function::New()` accepts the + `v8::External` and makes it available in the native callback using the + `v8::FunctionCallbackInfo::Data()` method. This will ensure that the per-addon-instance data reaches each binding that can be called from JavaScript. The per-addon-instance data must also be passed into @@ -397,14 +398,14 @@ the appropriate headers automatically. However, there are a few caveats to be aware of: * When `node-gyp` runs, it will detect the specific release version of Node.js -and download either the full source tarball or just the headers. If the full -source is downloaded, addons will have complete access to the full set of -Node.js dependencies. However, if only the Node.js headers are downloaded, then -only the symbols exported by Node.js will be available. + and download either the full source tarball or just the headers. If the full + source is downloaded, addons will have complete access to the full set of + Node.js dependencies. However, if only the Node.js headers are downloaded, + then only the symbols exported by Node.js will be available. * `node-gyp` can be run using the `--nodedir` flag pointing at a local Node.js -source image. Using this option, the addon will have access to the full set of -dependencies. + source image. Using this option, the addon will have access to the full set of + dependencies. ### Loading addons using `require()` diff --git a/doc/api/assert.md b/doc/api/assert.md index 54e4bc172ab34a..f32d11c6edad3b 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -237,7 +237,7 @@ added: --> * Returns: {Array} of objects containing information about the wrapper functions -returned by [`tracker.calls()`][]. + returned by [`tracker.calls()`][]. * Object {Object} * `message` {string} * `actual` {number} The actual number of times the function was called. diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index f54e82ee46b909..08111b67a8507e 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -699,14 +699,14 @@ asyncResource.triggerAsyncId(); * `type` {string} The type of async event. * `options` {Object} * `triggerAsyncId` {number} The ID of the execution context that created this - async event. **Default:** `executionAsyncId()`. + async event. **Default:** `executionAsyncId()`. * `requireManualDestroy` {boolean} If set to `true`, disables `emitDestroy` - when the object is garbage collected. This usually does not need to be set - (even if `emitDestroy` is called manually), unless the resource's `asyncId` - is retrieved and the sensitive API's `emitDestroy` is called with it. - When set to `false`, the `emitDestroy` call on garbage collection - will only take place if there is at least one active `destroy` hook. - **Default:** `false`. + when the object is garbage collected. This usually does not need to be set + (even if `emitDestroy` is called manually), unless the resource's `asyncId` + is retrieved and the sensitive API's `emitDestroy` is called with it. + When set to `false`, the `emitDestroy` call on garbage collection + will only take place if there is at least one active `destroy` hook. + **Default:** `false`. Example usage: @@ -791,7 +791,7 @@ never be called. #### `asyncResource.triggerAsyncId()` * Returns: {number} The same `triggerAsyncId` that is passed to the -`AsyncResource` constructor. + `AsyncResource` constructor. ### Using `AsyncResource` for a `Worker` thread pool diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 2d39bd2d109327..81e843355c9f97 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -469,7 +469,10 @@ const defaults = { ``` Use `cwd` to specify the working directory from which the process is spawned. -If not given, the default is to inherit the current working directory. +If not given, the default is to inherit the current working directory. If given, +but the path does not exist, the child process emits an `ENOENT` error +and exits immediately. `ENOENT` is also emitted when the command +does not exist. Use `env` to specify environment variables that will be visible to the new process, the default is [`process.env`][]. diff --git a/doc/api/cli.md b/doc/api/cli.md index 484695a347428d..0cab81d64cac12 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -234,7 +234,7 @@ Enable experimental JSON support for the ES Module loader. added: v9.0.0 --> -Specify the `module` of a custom [experimental ECMAScript Module loader][]. +Specify the `module` of a custom experimental [ECMAScript Module loader][]. `module` may be either a path to a file, or an ECMAScript Module name. ### `--experimental-modules` @@ -1642,6 +1642,7 @@ $ node --max-old-space-size=1536 index.js ``` [Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/ +[ECMAScript Module loader]: esm.md#esm_loaders [REPL]: repl.md [ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage [Source Map]: https://sourcemaps.info/spec.html @@ -1662,7 +1663,6 @@ $ node --max-old-space-size=1536 index.js [debugger]: debugger.md [debugging security implications]: https://nodejs.org/en/docs/guides/debugging-getting-started/#security-implications [emit_warning]: process.md#process_process_emitwarning_warning_type_code_ctor -[experimental ECMAScript Module loader]: esm.md#esm_experimental_loaders [jitless]: https://v8.dev/blog/jitless [libuv threadpool documentation]: https://docs.libuv.org/en/latest/threadpool.html [remote code execution]: https://www.owasp.org/index.php/Code_Injection diff --git a/doc/api/debugger.md b/doc/api/debugger.md index 89980cfbd4a06f..f17750ac116302 100644 --- a/doc/api/debugger.md +++ b/doc/api/debugger.md @@ -115,14 +115,14 @@ To begin watching an expression, type `watch('my_expression')`. The command * `setBreakpoint()`, `sb()`: Set breakpoint on current line * `setBreakpoint(line)`, `sb(line)`: Set breakpoint on specific line * `setBreakpoint('fn()')`, `sb(...)`: Set breakpoint on a first statement in -functions body + function's body * `setBreakpoint('script.js', 1)`, `sb(...)`: Set breakpoint on first line of -`script.js` + `script.js` * `setBreakpoint('script.js', 1, 'num < 4')`, `sb(...)`: Set conditional -breakpoint on first line of `script.js` that only breaks when `num < 4` -evaluates to `true` + breakpoint on first line of `script.js` that only breaks when `num < 4` + evaluates to `true` * `clearBreakpoint('script.js', 1)`, `cb(...)`: Clear breakpoint in `script.js` -on line 1 + on line 1 It is also possible to set a breakpoint in a file (module) that is not loaded yet: @@ -188,11 +188,11 @@ debug> * `backtrace`, `bt`: Print backtrace of current execution frame * `list(5)`: List scripts source code with 5 line context (5 lines before and -after) + after) * `watch(expr)`: Add expression to watch list * `unwatch(expr)`: Remove expression from watch list * `watchers`: List all watchers and their values (automatically listed on each -breakpoint) + breakpoint) * `repl`: Open debugger's repl for evaluation in debugging script's context * `exec expr`: Execute an expression in debugging script's context diff --git a/doc/api/dns.md b/doc/api/dns.md index a284c9d0c57bd5..baa8b8bfde4eb3 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -250,13 +250,13 @@ changes: The following flags can be passed as hints to [`dns.lookup()`][]. * `dns.ADDRCONFIG`: Limits returned address types to the types of non-loopback -addresses configured on the system. For example, IPv4 addresses are only -returned if the current system has at least one IPv4 address configured. + addresses configured on the system. For example, IPv4 addresses are only + returned if the current system has at least one IPv4 address configured. * `dns.V4MAPPED`: If the IPv6 family was specified, but no IPv6 addresses were -found, then return IPv4 mapped IPv6 addresses. It is not supported -on some operating systems (e.g FreeBSD 10.1). + found, then return IPv4 mapped IPv6 addresses. It is not supported + on some operating systems (e.g FreeBSD 10.1). * `dns.ALL`: If `dns.V4MAPPED` is specified, return resolved IPv6 addresses as -well as IPv4 mapped IPv6 addresses. + well as IPv4 mapped IPv6 addresses. ## `dns.lookupService(address, port, callback)` + +Cancel all outstanding DNS queries made by this resolver. The corresponding +promises will be rejected with an error with code `ECANCELLED`. + ### `dnsPromises.getServers()` -> Stability: 1 - Experimental +> Stability: 2 - Stable ## Introduction @@ -61,19 +65,13 @@ console.log(addTwo(4)); ``` Node.js fully supports ECMAScript modules as they are currently specified and -provides limited interoperability between them and the existing module format, +provides interoperability between them and its original module format, [CommonJS][]. -Node.js contains support for ES Modules based upon the -[Node.js EP for ES Modules][] and the [ECMAScript-modules implementation][]. - -Expect major changes in the implementation including interoperability support, -specifier resolution, and default behavior. - - - - + + + ## Enabling @@ -114,44 +112,65 @@ The _specifier_ of an `import` statement is the string after the `from` keyword, e.g. `'path'` in `import { sep } from 'path'`. Specifiers are also used in `export from` statements, and as the argument to an `import()` expression. -There are four types of specifiers: - -* _Bare specifiers_ like `'some-package'`. They refer to an entry point of a - package by the package name. - -* _Deep import specifiers_ like `'some-package/lib/shuffle.mjs'`. They refer to - a path within a package prefixed by the package name. +There are three types of specifiers: * _Relative specifiers_ like `'./startup.js'` or `'../config.mjs'`. They refer - to a path relative to the location of the importing file. + to a path relative to the location of the importing file. _The file extension + is always necessary for these._ + +* _Bare specifiers_ like `'some-package'` or `'some-package/shuffle'`. They can + refer to the main entry point of a package by the package name, or a + specific feature module within a package prefixed by the package name as per + the examples respectively. _Including the file extension is only necessary + for packages without an [`"exports"`][] field._ * _Absolute specifiers_ like `'file:///opt/nodejs/config.js'`. They refer directly and explicitly to a full path. -Bare specifiers, and the bare specifier portion of deep import specifiers, are -strings; but everything else in a specifier is a URL. +Bare specifier resolutions are handled by the [Node.js module resolution +algorithm][]. All other specifier resolutions are always only resolved with +the standard relative [URL][] resolution semantics. -`file:`, `node:`, and `data:` URLs are supported. A specifier like -`'https://example.com/app.js'` may be supported by browsers but it is not -supported in Node.js. +Like in CommonJS, module files within packages can be accessed by appending a +path to the package name unless the package’s [`package.json`][] contains an +[`"exports"`][] field, in which case files within packages can only be accessed +via the paths defined in [`"exports"`][]. -Specifiers may not begin with `/` or `//`. These are reserved for potential -future use. The root of the current volume may be referenced via `file:///`. +For details on these package resolution rules that apply to bare specifiers in +the Node.js module resolution, see the [packages documentation](packages.md). -#### `node:` Imports +### Mandatory file extensions - +A file extension must be provided when using the `import` keyword to resolve +relative or absolute specifiers. Directory indexes (e.g. `'./startup/index.js'`) +must also be fully specified. + +This behavior matches how `import` behaves in browser environments, assuming a +typically configured server. + +### URLs -`node:` URLs are supported as a means to load Node.js builtin modules. This -URL scheme allows for builtin modules to be referenced by valid absolute URL -strings. +ES modules are resolved and cached as URLs. This means that files containing +special characters such as `#` and `?` need to be escaped. + +`file:`, `node:`, and `data:` URL schemes are supported. A specifier like +`'https://example.com/app.js'` is not supported natively in Node.js unless using +a [custom HTTPS loader][]. + +#### `file:` URLs + +Modules are loaded multiple times if the `import` specifier used to resolve +them has a different query or fragment. ```js -import fs from 'node:fs/promises'; +import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1" +import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2" ``` +The volume root may be referenced via `/`, `//` or `file:///`. Given the +differences between [URL][] and path resolution (such as percent encoding +details), it is recommended to use [url.pathToFileURL][] when importing a path. + #### `data:` Imports -The `import.meta` metaproperty is an `Object` that contains the following -property: +`node:` URLs are supported as an alternative means to load Node.js builtin +modules. This URL scheme allows for builtin modules to be referenced by valid +absolute URL strings. -* `url` {string} The absolute `file:` URL of the module. +```js +import fs from 'node:fs/promises'; +``` -## Differences between ES modules and CommonJS +## Builtin modules -### Mandatory file extensions +[Core modules][] provide named exports of their public API. A +default export is also provided which is the value of the CommonJS exports. +The default export can be used for, among other things, modifying the named +exports. Named exports of builtin modules are updated only by calling +[`module.syncBuiltinESMExports()`][]. -A file extension must be provided when using the `import` keyword. Directory -indexes (e.g. `'./startup/index.js'`) must also be fully specified. +```js +import EventEmitter from 'events'; +const e = new EventEmitter(); +``` -This behavior matches how `import` behaves in browser environments, assuming a -typically configured server. +```js +import { readFile } from 'fs'; +readFile('./foo.txt', (err, source) => { + if (err) { + console.error(err); + } else { + console.log(source); + } +}); +``` -### No `NODE_PATH` +```js +import fs, { readFileSync } from 'fs'; +import { syncBuiltinESMExports } from 'module'; -`NODE_PATH` is not part of resolving `import` specifiers. Please use symlinks -if this behavior is desired. +fs.readFileSync = () => Buffer.from('Hello, ESM'); +syncBuiltinESMExports(); -### No `require`, `exports`, `module.exports`, `__filename`, `__dirname` +fs.readFileSync === readFileSync; +``` -These CommonJS variables are not available in ES modules. +## `import()` expressions -`require` can be imported into an ES module using [`module.createRequire()`][]. +[Dynamic `import()`][] is supported in both CommonJS and ES modules. In CommonJS +modules it can be used to load ES modules. -Equivalents of `__filename` and `__dirname` can be created inside of each file -via [`import.meta.url`][]. +## `import.meta` -```js -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; +* {Object} -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -``` +The `import.meta` meta property is an `Object` that contains the following +properties. -### No `require.resolve` +### `import.meta.url` -Former use cases relying on `require.resolve` to determine the resolved path -of a module can be supported via `import.meta.resolve`, which is experimental -and supported via the `--experimental-import-meta-resolve` flag: +* {string} The absolute `file:` URL of the module. -```js -(async () => { - const dependencyAsset = await import.meta.resolve('component-lib/asset.css'); -})(); -``` +This is defined exactly the same as it is in browsers providing the URL of the +current module file. -`import.meta.resolve` also accepts a second argument which is the parent module -from which to resolve from: +This enables useful patterns such as relative file loading: ```js -(async () => { - // Equivalent to import.meta.resolve('./dep') - await import.meta.resolve('./dep', import.meta.url); -})(); +import { readFileSync } from 'fs'; +const buffer = readFileSync(new URL('./data.proto', import.meta.url)); ``` -This function is asynchronous because the ES module resolver in Node.js is -asynchronous. With the introduction of [Top-Level Await][], these use cases -will be easier as they won't require an async function wrapper. - -### No `require.extensions` +### `import.meta.resolve(specifier[, parent])` -`require.extensions` is not used by `import`. The expectation is that loader -hooks can provide this workflow in the future. - -### No `require.cache` +> Stability: 1 - Experimental -`require.cache` is not used by `import`. It has a separate cache. +* `specifier` {string} The module specifier to resolve relative to `parent`. +* `parent` {string|URL} The absolute parent module URL to resolve from. If none + is specified, the value of `import.meta.url` is used as the default. +* Returns: {Promise} -### URL-based paths +Provides a module-relative resolution function scoped to each module, returning +the URL string. -ES modules are resolved and cached based upon -[URL](https://url.spec.whatwg.org/) semantics. This means that files containing -special characters such as `#` and `?` need to be escaped. + +```js +const dependencyAsset = await import.meta.resolve('component-lib/asset.css'); +``` -Modules are loaded multiple times if the `import` specifier used to resolve -them has a different query or fragment. +`import.meta.resolve` also accepts a second argument which is the parent module +from which to resolve from: + ```js -import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1" -import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2" +await import.meta.resolve('./dep', import.meta.url); ``` -For now, only modules using the `file:` protocol can be loaded. +This function is asynchronous because the ES module resolver in Node.js is +allowed to be asynchronous. ## Interoperability with CommonJS -### `require` - -`require` always treats the files it references as CommonJS. This applies -whether `require` is used the traditional way within a CommonJS environment, or -in an ES module environment using [`module.createRequire()`][]. - -To include an ES module into CommonJS, use [`import()`][]. - ### `import` statements An `import` statement can reference an ES module or a CommonJS module. -`import` statements are permitted only in ES modules. For similar functionality -in CommonJS, see [`import()`][]. +`import` statements are permitted only in ES modules, but dynamic [`import()`][] +expressions are supported in CommonJS for loading ES modules. When importing [CommonJS modules](#esm_commonjs_namespaces), the `module.exports` object is provided as the default export. Named exports may be available, provided by static analysis as a convenience for better ecosystem compatibility. -Additional experimental flags are available for importing -[Wasm modules](#esm_experimental_wasm_modules) or -[JSON modules](#esm_experimental_json_modules). For importing native modules or -JSON modules unflagged, see [`module.createRequire()`][]. - -The _specifier_ of an `import` statement (the string after the `from` keyword) -can either be an URL-style relative path like `'./file.mjs'` or a package name -like `'fs'`. - -Like in CommonJS, files within packages can be accessed by appending a path to -the package name; unless the package’s [`package.json`][] contains an -[`"exports"`][] field, in which case files within packages need to be accessed -via the path defined in [`"exports"`][]. - -```js -import { sin, cos } from 'geometry/trigonometry-functions.mjs'; -``` +### `require` -### `import()` expressions +The CommonJS module `require` always treats the files it references as CommonJS. -[Dynamic `import()`][] is supported in both CommonJS and ES modules. It can be -used to include ES module files from CommonJS code. +Using `require` to load an ES module is not supported because ES modules have +asynchronous execution. Instead, use use [`import()`][] to load an ES module +from a CommonJS module. -## CommonJS Namespaces +### CommonJS Namespaces CommonJS modules consist of a `module.exports` object which can be of any type. @@ -396,59 +402,73 @@ Named exports detection covers many common export patterns, reexport patterns and build tool and transpiler outputs. See [cjs-module-lexer][] for the exact semantics implemented. -## Builtin modules +### Differences between ES modules and CommonJS -[Core modules][] provide named exports of their public API. A -default export is also provided which is the value of the CommonJS exports. -The default export can be used for, among other things, modifying the named -exports. Named exports of builtin modules are updated only by calling -[`module.syncBuiltinESMExports()`][]. +#### No `require`, `exports` or `module.exports` -```js -import EventEmitter from 'events'; -const e = new EventEmitter(); -``` +In most cases, the ES module `import` can be used to load CommonJS modules. +If needed, a `require` function can be constructed within an ES module using +[`module.createRequire()`][]. + +#### No `__filename` or `__dirname` + +These CommonJS variables are not available in ES modules. + +`__filename` and `__dirname` use cases can be replicated via +[`import.meta.url`][]. + +#### No JSON Module Loading + +JSON imports are still experimental and only supported via the +`--experimental-json-modules` flag. + +Local JSON files can be loaded relative to `import.meta.url` with `fs` directly: + + ```js -import { readFile } from 'fs'; -readFile('./foo.txt', (err, source) => { - if (err) { - console.error(err); - } else { - console.log(source); - } -}); +import { readFile } from 'fs/promises'; +const json = JSON.parse(await readFile(new URL('./dat.json', import.meta.url))); ``` -```js -import fs, { readFileSync } from 'fs'; -import { syncBuiltinESMExports } from 'module'; +Alterantively `module.createRequire()` can be used. -fs.readFileSync = () => Buffer.from('Hello, ESM'); -syncBuiltinESMExports(); +#### No Native Module Loading -fs.readFileSync === readFileSync; -``` +Native modules are not currently supported with ES module imports. -## CommonJS, JSON, and native modules +The can instead be loaded with [`module.createRequire()`][] or +[`process.dlopen`][]. -CommonJS, JSON, and native modules can be used with -[`module.createRequire()`][]. +#### No `require.resolve` -```js -// cjs.cjs -module.exports = 'cjs'; +Relative resolution can be handled via `new URL('./local', import.meta.url)`. -// esm.mjs -import { createRequire } from 'module'; +For a complete `require.resolve` replacement, there is a flagged experimental +[`import.meta.resolve`][] API. -const require = createRequire(import.meta.url); +Alternatively `module.createRequire()` can be used. -const cjs = require('./cjs.cjs'); -cjs === 'cjs'; // true -``` +#### No `NODE_PATH` + +`NODE_PATH` is not part of resolving `import` specifiers. Please use symlinks +if this behavior is desired. -## Experimental JSON modules +#### No `require.extensions` + +`require.extensions` is not used by `import`. The expectation is that loader +hooks can provide this workflow in the future. + +#### No `require.cache` + +`require.cache` is not used by `import` as the ES module loader has its own +separate cache. + + + +## JSON modules + +> Stability: 1 - Experimental Currently importing JSON modules are only supported in the `commonjs` mode and are loaded using the CJS loader. [WHATWG JSON modules specification][] are @@ -478,7 +498,11 @@ node index.mjs # fails node --experimental-json-modules index.mjs # works ``` -## Experimental Wasm modules + + +## Wasm modules + +> Stability: 1 - Experimental Importing Web Assembly modules is supported under the `--experimental-wasm-modules` flag, allowing any `.wasm` files to be @@ -502,7 +526,11 @@ node --experimental-wasm-modules index.mjs would provide the exports interface for the instantiation of `module.wasm`. -## Experimental top-level `await` + + +## Top-level `await` + +> Stability: 1 - Experimental The `await` keyword may be used in the top level (outside of async functions) within modules as per the [ECMAScript Top-Level `await` proposal][]. @@ -526,7 +554,11 @@ console.log(five); // Logs `5` node b.mjs # works ``` -## Experimental loaders + + +## Loaders + +> Stability: 1 - Experimental **Note: This API is currently being redesigned and will still change.** @@ -1237,6 +1269,8 @@ _internal_, _conditions_) ### Customizing ESM specifier resolution algorithm +> Stability: 1 - Experimental + The current specifier resolution does not support all default behavior of the CommonJS loader. One of the behavior differences is automatic resolution of file extensions and the ability to import directories that have an index @@ -1264,11 +1298,10 @@ success! [Core modules]: modules.md#modules_core_modules [Dynamic `import()`]: https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports [ECMAScript Top-Level `await` proposal]: https://github.com/tc39/proposal-top-level-await/ -[ECMAScript-modules implementation]: https://github.com/nodejs/modules/blob/master/doc/plan-for-new-modules-implementation.md [ES Module Integration Proposal for Web Assembly]: https://github.com/webassembly/esm-integration -[Node.js EP for ES Modules]: https://github.com/nodejs/node-eps/blob/master/002-es-modules.md +[Node.js Module Resolution Algorithm]: #esm_resolver_algorithm_specification [Terminology]: #esm_terminology -[Top-Level Await]: https://github.com/tc39/proposal-top-level-await +[URL]: https://url.spec.whatwg.org/ [WHATWG JSON modules specification]: https://html.spec.whatwg.org/#creating-a-json-module-script [`"exports"`]: packages.md#packages_exports [`"type"`]: packages.md#packages_type @@ -1279,15 +1312,19 @@ success! [`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs [`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export [`import()`]: #esm_import_expressions -[`import.meta.url`]: #esm_import_meta +[`import.meta.url`]: #esm_import_meta_url +[`import.meta.resolve`]: #esm_import_meta_resolve_specifier_parent [`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import [`module.createRequire()`]: module.md#module_module_createrequire_filename [`module.syncBuiltinESMExports()`]: module.md#module_module_syncbuiltinesmexports [`package.json`]: packages.md#packages_node_js_package_json_field_definitions +[`process.dlopen`]: process.md#process_process_dlopen_module_filename_flags [`transformSource` hook]: #esm_transformsource_source_context_defaulttransformsource [`string`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String [`util.TextDecoder`]: util.md#util_class_util_textdecoder [cjs-module-lexer]: https://github.com/guybedford/cjs-module-lexer/tree/1.0.0 +[custom https loader]: #esm_https_loader [special scheme]: https://url.spec.whatwg.org/#special-scheme [the official standard format]: https://tc39.github.io/ecma262/#sec-modules [transpiler loader example]: #esm_transpiler_loader +[url.pathToFileURL]: url.md#url_url_pathtofileurl_path diff --git a/doc/api/events.md b/doc/api/events.md index 5c6b058123ca57..4115c762655040 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -383,6 +383,29 @@ Installing a listener using this symbol does not change the behavior once an `'error'` event is emitted, therefore the process will still crash if no regular `'error'` listener is installed. +### `EventEmitter.setMaxListeners(n[, ...eventTargets])` + + +* `n` {number} A non-negative number. The maximum number of listeners per + `EventTarget` event. +* `...eventsTargets` {EventTarget[]|EventEmitter[]} Zero or more {EventTarget} + or {EventEmitter} instances. If none are specified, `n` is set as the default + max for all newly created {EventTarget} and {EventEmitter} objects. + +```js +const { + setMaxListeners, + EventEmitter +} = require('events'); + +const target = new EventTarget(); +const emitter = new EventEmitter(); + +setMaxListeners(5, target, emitter); +``` + ### `emitter.addListener(eventName, listener)` -> Stability: 1 - Recursive removal is experimental. - * `path` {string|Buffer|URL} * `options` {Object} * `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or @@ -6133,7 +6137,7 @@ string. * `'wx'`: Like `'w'` but fails if the path exists. * `'w+'`: Open file for reading and writing. -The file is created (if it does not exist) or truncated (if it exists). + The file is created (if it does not exist) or truncated (if it exists). * `'wx+'`: Like `'w+'` but fails if the path exists. diff --git a/doc/api/http.md b/doc/api/http.md index 4ce2c9251a2c16..8e7056114bee8f 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -253,8 +253,8 @@ Destroy any sockets that are currently in use by the agent. It is usually not necessary to do this. However, if using an agent with `keepAlive` enabled, then it is best to explicitly shut down -the agent when it will no longer be used. Otherwise, -sockets may hang open for quite a long time before the server +the agent when it is no longer needed. Otherwise, +sockets might stay open for quite a long time before the server terminates them. ### `agent.freeSockets` @@ -1997,9 +1997,9 @@ Duplicates in raw headers are handled in the following ways, depending on the header name: * Duplicates of `age`, `authorization`, `content-length`, `content-type`, -`etag`, `expires`, `from`, `host`, `if-modified-since`, `if-unmodified-since`, -`last-modified`, `location`, `max-forwards`, `proxy-authorization`, `referer`, -`retry-after`, `server`, or `user-agent` are discarded. + `etag`, `expires`, `from`, `host`, `if-modified-since`, `if-unmodified-since`, + `last-modified`, `location`, `max-forwards`, `proxy-authorization`, `referer`, + `retry-after`, `server`, or `user-agent` are discarded. * `set-cookie` is always an array. Duplicates are added to the array. * For duplicate `cookie` headers, the values are joined together with '; '. * For all other headers, the values are joined together with ', '. @@ -2336,6 +2336,9 @@ This can be overridden for servers and client requests by passing the + +* `windowSize` {number} + +Sets the local endpoint's window size. +The `windowSize` is the total window size to set, not +the delta. + +```js +const http2 = require('http2'); + +const server = http2.createServer(); +const expectedWindowSize = 2 ** 20; +server.on('connect', (session) => { + + // Set local window size to be 2 ** 20 + session.setLocalWindowSize(expectedWindowSize); +}); +``` + #### `http2session.setTimeout(msecs, callback)` -* `buf` {Buffer|Uint8Array} The packed settings. +* `buf` {Buffer|TypedArray} The packed settings. * Returns: {HTTP/2 Settings Object} Returns a [HTTP/2 Settings Object][] containing the deserialized settings from diff --git a/doc/api/https.md b/doc/api/https.md index d8906868a34f43..b322c3ee147909 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -161,7 +161,7 @@ added: v0.3.4 --> * `options` {Object} Accepts `options` from [`tls.createServer()`][], - [`tls.createSecureContext()`][] and [`http.createServer()`][]. + [`tls.createSecureContext()`][] and [`http.createServer()`][]. * `requestListener` {Function} A listener to be added to the `'request'` event. * Returns: {https.Server} diff --git a/doc/api/modules.md b/doc/api/modules.md index 03d919f37fd9b3..8648ec3ee79182 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -503,7 +503,7 @@ wrapper that looks like the following: By doing this, Node.js achieves a few things: * It keeps top-level variables (defined with `var`, `const` or `let`) scoped to -the module rather than the global object. + the module rather than the global object. * It helps to provide some global-looking variables that are actually specific to the module, such as: * The `module` and `exports` objects that the implementor can use to export diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 9f16d2d2933b90..9ad15223f11da7 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -864,8 +864,8 @@ typedef void (*napi_async_cleanup_hook)(napi_async_cleanup_hook_handle handle, ``` * `[in] handle`: The handle that must be passed to -[`napi_remove_async_cleanup_hook`][] after completion of the asynchronous -cleanup. + [`napi_remove_async_cleanup_hook`][] after completion of the asynchronous + cleanup. * `[in] data`: The data that was passed to [`napi_add_async_cleanup_hook`][]. The body of the function should initiate the asynchronous cleanup actions at the @@ -945,7 +945,7 @@ napi_get_last_error_info(napi_env env, * `[in] env`: The environment that the API is invoked under. * `[out] result`: The `napi_extended_error_info` structure with more -information about the error. + information about the error. Returns `napi_ok` if the API succeeded. @@ -1725,7 +1725,7 @@ NAPI_EXTERN napi_status napi_add_async_cleanup_hook( * `[in] hook`: The function pointer to call at environment teardown. * `[in] arg`: The pointer to pass to `hook` when it gets called. * `[out] remove_handle`: Optional handle that refers to the asynchronous cleanup -hook. + hook. Registers `hook`, which is a function of type [`napi_async_cleanup_hook`][], as a function to be run with the `remove_handle` and `arg` parameters once the @@ -1762,7 +1762,7 @@ NAPI_EXTERN napi_status napi_remove_async_cleanup_hook( ``` * `[in] remove_handle`: The handle to an asynchronous cleanup hook that was -created with [`napi_add_async_cleanup_hook`][]. + created with [`napi_add_async_cleanup_hook`][]. Unregisters the cleanup hook corresponding to `remove_handle`. This will prevent the hook from being executed, unless it has already started executing. @@ -3372,7 +3372,7 @@ napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result) Returns `napi_ok` if the API succeeded. * `napi_invalid_arg` if the type of `value` is not a known ECMAScript type and - `value` is not an External value. + `value` is not an External value. This API represents behavior similar to invoking the `typeof` Operator on the object as defined in [Section 12.5.5][] of the ECMAScript Language @@ -3902,11 +3902,11 @@ napi_get_all_property_names(napi_env env, * `[in] object`: The object from which to retrieve the properties. * `[in] key_mode`: Whether to retrieve prototype properties as well. * `[in] key_filter`: Which properties to retrieve -(enumerable/readable/writable). + (enumerable/readable/writable). * `[in] key_conversion`: Whether to convert numbered property keys to strings. * `[out] result`: A `napi_value` representing an array of JavaScript values -that represent the property names of the object. [`napi_get_array_length`][] and -[`napi_get_element`][] can be used to iterate over `result`. + that represent the property names of the object. [`napi_get_array_length`][] + and [`napi_get_element`][] can be used to iterate over `result`. Returns `napi_ok` if the API succeeded. @@ -4738,14 +4738,15 @@ napi_status napi_define_class(napi_env env, ``` * `[in] env`: The environment that the API is invoked under. -* `[in] utf8name`: Name of the JavaScript constructor function; this is - not required to be the same as the C++ class name, though it is recommended - for clarity. +* `[in] utf8name`: Name of the JavaScript constructor function; When wrapping a + C++ class, we recommend for clarity that this name be the same as that of + the C++ class. * `[in] length`: The length of the `utf8name` in bytes, or `NAPI_AUTO_LENGTH` if it is null-terminated. * `[in] constructor`: Callback function that handles constructing instances - of the class. This should be a static method on the class, not an actual - C++ constructor function. [`napi_callback`][] provides more details. + of the class. When wrapping a C++ class, this method must be a static member + with the [`napi_callback`][] signature. A C++ class constructor cannot be + used. [`napi_callback`][] provides more details. * `[in] data`: Optional data to be passed to the constructor callback as the `data` property of the callback info. * `[in] property_count`: Number of items in the `properties` array argument. @@ -4757,27 +4758,33 @@ napi_status napi_define_class(napi_env env, Returns `napi_ok` if the API succeeded. -Defines a JavaScript class that corresponds to a C++ class, including: - -* A JavaScript constructor function that has the class name and invokes the - provided C++ constructor callback. -* Properties on the constructor function corresponding to _static_ data - properties, accessors, and methods of the C++ class (defined by - property descriptors with the `napi_static` attribute). -* Properties on the constructor function's `prototype` object corresponding to - _non-static_ data properties, accessors, and methods of the C++ class - (defined by property descriptors without the `napi_static` attribute). - -The C++ constructor callback should be a static method on the class that calls -the actual class constructor, then wraps the new C++ instance in a JavaScript -object, and returns the wrapper object. See `napi_wrap()` for details. +Defines a JavaScript class, including: + +* A JavaScript constructor function that has the class name. When wrapping a + corresponding C++ class, the callback passed via `constructor` can be used to + instantiate a new C++ class instance, which can then be placed inside the + JavaScript object instance being constructed using [`napi_wrap`][]. +* Properties on the constructor function whose implementation can call + corresponding _static_ data properties, accessors, and methods of the C++ + class (defined by property descriptors with the `napi_static` attribute). +* Properties on the constructor function's `prototype` object. When wrapping a + C++ class, _non-static_ data properties, accessors, and methods of the C++ + class can be called from the static functions given in the property + descriptors without the `napi_static` attribute after retrieving the C++ class + instance placed inside the JavaScript object instance by using + [`napi_unwrap`][]. + +When wrapping a C++ class, the C++ constructor callback passed via `constructor` +should be a static method on the class that calls the actual class constructor, +then wraps the new C++ instance in a JavaScript object, and returns the wrapper +object. See [`napi_wrap`][] for details. The JavaScript constructor function returned from [`napi_define_class`][] is -often saved and used later, to construct new instances of the class from native -code, and/or check whether provided values are instances of the class. In that -case, to prevent the function value from being garbage-collected, create a -persistent reference to it using [`napi_create_reference`][] and ensure the -reference count is kept >= 1. +often saved and used later to construct new instances of the class from native +code, and/or to check whether provided values are instances of the class. In +that case, to prevent the function value from being garbage-collected, a +strong persistent reference to it can be created using +[`napi_create_reference`][], ensuring that the reference count is kept >= 1. Any non-`NULL` data which is passed to this API via the `data` parameter or via the `data` field of the `napi_property_descriptor` array items can be associated @@ -4942,7 +4949,7 @@ napi_status napi_check_object_type_tag(napi_env env, * `[in] js_object`: The JavaScript object whose type tag to examine. * `[in] type_tag`: The tag with which to compare any tag found on the object. * `[out] result`: Whether the type tag given matched the type tag on the -object. `false` is also returned if no type tag was found on the object. + object. `false` is also returned if no type tag was found on the object. Returns `napi_ok` if the API succeeded. diff --git a/doc/api/path.md b/doc/api/path.md index c26a98e59c9d6d..ca62e2f3628bfe 100644 --- a/doc/api/path.md +++ b/doc/api/path.md @@ -434,6 +434,10 @@ A [`TypeError`][] is thrown if `path` is not a string. ## `path.posix` * {Object} @@ -441,6 +445,8 @@ added: v0.11.15 The `path.posix` property provides access to POSIX specific implementations of the `path` methods. +The API is accessible via `require('path').posix` or `require('path/posix')`. + ## `path.relative(from, to)` * {Object} @@ -575,6 +585,8 @@ added: v0.11.15 The `path.win32` property provides access to Windows-specific implementations of the `path` methods. +The API is accessible via `require('path').win32` or `require('path/win32')`. + [MSDN-Rel-Path]: https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#fully-qualified-vs-relative-paths [`TypeError`]: errors.md#errors_class_typeerror [`path.parse()`]: #path_path_parse_path diff --git a/doc/api/process.md b/doc/api/process.md index f2dd0c18d5cc00..5665deab898573 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -525,10 +525,8 @@ process.on('SIGTERM', handle); * `'SIGSTOP'` cannot have a listener installed. * `'SIGBUS'`, `'SIGFPE'`, `'SIGSEGV'` and `'SIGILL'`, when not raised artificially using kill(2), inherently leave the process in a state from - which it is not safe to attempt to call JS listeners. Doing so might lead to - the process hanging in an endless loop, since listeners attached using - `process.on()` are called asynchronously and therefore unable to correct the - underlying problem. + which it is not safe to call JS listeners. Doing so might cause the process + to stop responding. * `0` can be sent to test for the existence of a process, it has no effect if the process exists, but will throw an error if the process does not exist. @@ -885,31 +883,29 @@ changes: * `filename` {string} * `flags` {os.constants.dlopen} **Default:** `os.constants.dlopen.RTLD_LAZY` -The `process.dlopen()` method allows to dynamically load shared -objects. It is primarily used by `require()` to load -C++ Addons, and should not be used directly, except in special -cases. In other words, [`require()`][] should be preferred over -`process.dlopen()`, unless there are specific reasons. +The `process.dlopen()` method allows dynamically loading shared objects. It is +primarily used by `require()` to load C++ Addons, and should not be used +directly, except in special cases. In other words, [`require()`][] should be +preferred over `process.dlopen()` unless there are specific reasons such as +custom dlopen flags or loading from ES modules. The `flags` argument is an integer that allows to specify dlopen behavior. See the [`os.constants.dlopen`][] documentation for details. -If there are specific reasons to use `process.dlopen()` (for instance, -to specify dlopen flags), it's often useful to use [`require.resolve()`][] -to look up the module's path. +An important requirement when calling `process.dlopen()` is that the `module` +instance must be passed. Functions exported by the C++ Addon are then +accessible via `module.exports`. -An important drawback when calling `process.dlopen()` is that the `module` -instance must be passed. Functions exported by the C++ Addon will be accessible -via `module.exports`. - -The example below shows how to load a C++ Addon, named as `binding`, -that exports a `foo` function. All the symbols will be loaded before +The example below shows how to load a C++ Addon, named `local.node`, +that exports a `foo` function. All the symbols are loaded before the call returns, by passing the `RTLD_NOW` constant. In this example the constant is assumed to be available. ```js const os = require('os'); -process.dlopen(module, require.resolve('binding'), +const path = require('path'); +const module = { exports: {} }; +process.dlopen(module, path.join(__dirname, 'local.node'), os.constants.dlopen.RTLD_NOW); module.exports.foo(); ``` @@ -2678,7 +2674,6 @@ cases: [`readable.read()`]: stream.md#stream_readable_read_size [`require()`]: globals.md#globals_require [`require.main`]: modules.md#modules_accessing_the_main_module -[`require.resolve()`]: modules.md#modules_require_resolve_request_options [`subprocess.kill()`]: child_process.md#child_process_subprocess_kill_signal [`v8.setFlagsFromString()`]: v8.md#v8_v8_setflagsfromstring_flags [debugger]: debugger.md diff --git a/doc/api/readline.md b/doc/api/readline.md index 14b416b1e8045b..7ea2a1d5a60552 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -283,6 +283,15 @@ added: v0.1.98 The `rl.setPrompt()` method sets the prompt that will be written to `output` whenever `rl.prompt()` is called. +### `rl.getPrompt()` + + +* Returns: {string} the current prompt string + +The `rl.getPrompt()` method returns the current prompt used by `rl.prompt()`. + ### `rl.write(data[, key])` * `buffer` {Buffer|TypedArray|DataView} A `Buffer`, or `TypedArray`, or - `DataView` containing the bytes to decode. + `DataView` containing the bytes to decode. * Returns: {string} Returns any remaining input stored in the internal buffer as a string. Bytes @@ -84,7 +84,7 @@ changes: --> * `buffer` {Buffer|TypedArray|DataView} A `Buffer`, or `TypedArray`, or - `DataView` containing the bytes to decode. + `DataView` containing the bytes to decode. * Returns: {string} Returns a decoded string, ensuring that any incomplete multibyte characters at diff --git a/doc/api/tls.md b/doc/api/tls.md index 128fac46064653..bedf4e28e7bc04 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -644,7 +644,7 @@ added: v0.3.2 --> * `callback` {Function} A listener callback that will be registered to listen -for the server instance's `'close'` event. + for the server instance's `'close'` event. * Returns: {tls.Server} The `server.close()` method stops the server from accepting new connections. @@ -975,8 +975,8 @@ added: v9.9.0 --> * Returns: {Buffer|undefined} The latest `Finished` message that has been -sent to the socket as part of a SSL/TLS handshake, or `undefined` if -no `Finished` message has been sent yet. + sent to the socket as part of a SSL/TLS handshake, or `undefined` if + no `Finished` message has been sent yet. As the `Finished` messages are message digests of the complete handshake (with a total of 192 bits for TLS 1.0 and more for SSL 3.0), they can @@ -1033,7 +1033,7 @@ certificate. `'2A:7A:C2:DD:...'`. * `ext_key_usage` {Array} (Optional) The extended key usage, a set of OIDs. * `subjectaltname` {string} (Optional) A string containing concatenated names - for the subject, an alternative to the `subject` names. + for the subject, an alternative to the `subject` names. * `infoAccess` {Array} (Optional) An array describing the AuthorityInfoAccess, used with OCSP. * `issuerCertificate` {Object} (Optional) The issuer certificate object. For @@ -1099,8 +1099,8 @@ added: v9.9.0 --> * Returns: {Buffer|undefined} The latest `Finished` message that is expected -or has actually been received from the socket as part of a SSL/TLS handshake, -or `undefined` if there is no `Finished` message so far. + or has actually been received from the socket as part of a SSL/TLS handshake, + or `undefined` if there is no `Finished` message so far. As the `Finished` messages are message digests of the complete handshake (with a total of 192 bits for TLS 1.0 and more for SSL 3.0), they can @@ -1155,7 +1155,7 @@ added: v12.11.0 --> * Returns: {Array} List of signature algorithms shared between the server and -the client in the order of decreasing preference. + the client in the order of decreasing preference. See [SSL_get_shared_sigalgs](https://www.openssl.org/docs/man1.1.1/man3/SSL_get_shared_sigalgs.html) @@ -1170,8 +1170,8 @@ added: * `length` {number} number of bytes to retrieve from keying material * `label` {string} an application specific label, typically this will be a -value from the -[IANA Exporter Label Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#exporter-labels). + value from the + [IANA Exporter Label Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#exporter-labels). * `context` {Buffer} Optionally provide a context. * Returns: {Buffer} requested bytes of the keying material diff --git a/doc/api/url.md b/doc/api/url.md index e3f1adba94fc86..3d4500aa385969 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -210,9 +210,15 @@ const myURL = new URL('https://example.org:81/foo'); console.log(myURL.hostname); // Prints example.org +// Setting the hostname does not change the port myURL.hostname = 'example.com:82'; console.log(myURL.href); // Prints https://example.com:81/foo + +// Use myURL.host to change the hostname and port +myURL.host = 'example.org:82'; +console.log(myURL.href); +// Prints https://example.org:82/foo ``` Invalid host name values assigned to the `hostname` property are ignored. diff --git a/doc/api/util.md b/doc/api/util.md index a5daf2cb240bfb..d6be620b42c56d 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -78,7 +78,7 @@ added: v0.11.3 * `section` {string} A string identifying the portion of the application for which the `debuglog` function is being created. * `callback` {Function} A callback invoked the first time the logging function -is called with a function argument that is a more optimized logging function. + is called with a function argument that is a more optimized logging function. * Returns: {Function} The logging function The `util.debuglog()` method is used to create a function that conditionally @@ -1073,7 +1073,7 @@ changes: --> * {symbol} that can be used to declare custom promisified variants of functions, -see [Custom promisified functions][]. + see [Custom promisified functions][]. In addition to being accessible through `util.promisify.custom`, this symbol is [registered globally][global symbol registry] and can be @@ -1290,6 +1290,10 @@ The encoding supported by the `TextEncoder` instance. Always set to `'utf-8'`. ## `util.types` `util.types` provides type checks for different kinds of built-in objects. @@ -1301,6 +1305,8 @@ The result generally does not make any guarantees about what kinds of properties or behavior a value exposes in JavaScript. They are primarily useful for addon developers who prefer to do type checking in JavaScript. +The API is accessible via `require('util').types` or `require('util/types')`. + ### `util.types.isAnyArrayBuffer(value)` /gms, ''); const gtocHTML = unified() .use(markdown) + .use(gfm) .use(remark2rehype, { allowDangerousHtml: true }) .use(raw) .use(navClasses) @@ -283,6 +285,7 @@ function parseYAML(text) { meta.changes.forEach((change) => { const description = unified() .use(markdown) + .use(gfm) .use(remark2rehype, { allowDangerousHtml: true }) .use(raw) .use(htmlStringify) @@ -381,6 +384,7 @@ function buildToc({ filename, apilinks }) { file.toc = unified() .use(markdown) + .use(gfm) .use(remark2rehype, { allowDangerousHtml: true }) .use(raw) .use(htmlStringify) diff --git a/tools/doc/package-lock.json b/tools/doc/package-lock.json index 36514e5989c7b7..9586fa494483a2 100644 --- a/tools/doc/package-lock.json +++ b/tools/doc/package-lock.json @@ -1,8 +1,949 @@ { "name": "node-doc-generator", "version": "0.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "node-doc-generator", + "version": "0.0.0", + "bin": { + "node-doc-generator": "generate.js" + }, + "devDependencies": { + "highlight.js": "10.1.0", + "js-yaml": "3.14.0", + "rehype-raw": "4.0.2", + "rehype-stringify": "8.0.0", + "remark-gfm": "^1.0.0", + "remark-html": "12.0.0", + "remark-parse": "^9.0.0", + "remark-rehype": "7.0.0", + "to-vfile": "6.1.0", + "unified": "9.2.0", + "unist-util-find": "^1.0.2", + "unist-util-select": "3.0.1", + "unist-util-visit": "2.0.3" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@types/mdast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz", + "integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/ccount": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz", + "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==", + "dev": true + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "dev": true + }, + "node_modules/character-entities-html4": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz", + "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==", + "dev": true + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "dev": true + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "dev": true + }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "dev": true + }, + "node_modules/css-selector-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz", + "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==", + "dev": true + }, + "node_modules/debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/hast-to-hyperscript": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-7.0.4.tgz", + "integrity": "sha512-vmwriQ2H0RPS9ho4Kkbf3n3lY436QKLq6VaGA1pzBh36hBi3tm1DO9bR+kaJIbpT10UqaANDkMjxvjVfr+cnOA==", + "dev": true, + "dependencies": { + "comma-separated-tokens": "^1.0.0", + "property-information": "^5.3.0", + "space-separated-tokens": "^1.0.0", + "style-to-object": "^0.2.1", + "unist-util-is": "^3.0.0", + "web-namespaces": "^1.1.2" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz", + "integrity": "sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA==", + "dev": true, + "dependencies": { + "ccount": "^1.0.3", + "hastscript": "^5.0.0", + "property-information": "^5.0.0", + "web-namespaces": "^1.1.2", + "xtend": "^4.0.1" + } + }, + "node_modules/hast-util-is-element": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz", + "integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==", + "dev": true + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.4.tgz", + "integrity": "sha512-gW3sxfynIvZApL4L07wryYF4+C9VvH3AUi7LAnVXV4MneGEgwOByXvFo18BgmTWnm7oHAe874jKbIB1YhHSIzA==", + "dev": true + }, + "node_modules/hast-util-raw": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-5.0.2.tgz", + "integrity": "sha512-3ReYQcIHmzSgMq8UrDZHFL0oGlbuVGdLKs8s/Fe8BfHFAyZDrdv1fy/AGn+Fim8ZuvAHcJ61NQhVMtyfHviT/g==", + "dev": true, + "dependencies": { + "hast-util-from-parse5": "^5.0.0", + "hast-util-to-parse5": "^5.0.0", + "html-void-elements": "^1.0.0", + "parse5": "^5.0.0", + "unist-util-position": "^3.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + } + }, + "node_modules/hast-util-sanitize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-3.0.0.tgz", + "integrity": "sha512-gxsM24ARtuulsrWEj8QtVM6FNeAEHklF/t7TEIWvX1wuQcoAQtJtEUcT8t0os4uxCUqh1epX/gTi8fp8gNKvCA==", + "dev": true, + "dependencies": { + "xtend": "^4.0.0" + } + }, + "node_modules/hast-util-to-html": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-7.1.1.tgz", + "integrity": "sha512-Ujqj0hGuo3dIQKilkbauAv5teOqPvhaSLEgs1lgApFT0812e114KiffV8XfE4ttR8dRPqxNOIJOMu6SKOVOGlg==", + "dev": true, + "dependencies": { + "ccount": "^1.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-is-element": "^1.0.0", + "hast-util-whitespace": "^1.0.0", + "html-void-elements": "^1.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0", + "stringify-entities": "^3.0.1", + "unist-util-is": "^4.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/hast-util-to-html/node_modules/unist-util-is": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz", + "integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==", + "dev": true + }, + "node_modules/hast-util-to-parse5": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-5.1.2.tgz", + "integrity": "sha512-ZgYLJu9lYknMfsBY0rBV4TJn2xiwF1fXFFjbP6EE7S0s5mS8LIKBVWzhA1MeIs1SWW6GnnE4In6c3kPb+CWhog==", + "dev": true, + "dependencies": { + "hast-to-hyperscript": "^7.0.0", + "property-information": "^5.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + } + }, + "node_modules/hast-util-whitespace": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz", + "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==", + "dev": true + }, + "node_modules/hastscript": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz", + "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==", + "dev": true, + "dependencies": { + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + } + }, + "node_modules/highlight.js": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.0.tgz", + "integrity": "sha512-e8aO/LUHDoxW4ntyKQf0/T3OtIZPhsfTr8XRuOq+FW5VdWEg/UDAeArzKF/22BaNZp6hPi/Zu/XQlTLOGLix3Q==", + "dev": true + }, + "node_modules/html-void-elements": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", + "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "dev": true + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "dev": true + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "dev": true + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dev": true, + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "node_modules/is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "dev": true + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "dev": true + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "node_modules/lodash.iteratee": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.iteratee/-/lodash.iteratee-4.7.0.tgz", + "integrity": "sha1-vkF32yiajMw8CZDx2ya1si/BVUw=", + "dev": true + }, + "node_modules/mdast-util-definitions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-3.0.1.tgz", + "integrity": "sha512-BAv2iUm/e6IK/b2/t+Fx69EL/AGcq/IG2S+HxHjDJGfLJtd6i9SZUS76aC9cig+IEucsqxKTR0ot3m933R3iuA==", + "dev": true, + "dependencies": { + "unist-util-visit": "^2.0.0" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.1.tgz", + "integrity": "sha512-qJXNcFcuCSPqUF0Tb0uYcFDIq67qwB3sxo9RPdf9vG8T90ViKnksFqdB/Coq2a7sTnxL/Ify2y7aIQXDkQFH0w==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^1.0.0", + "micromark": "~2.10.0", + "parse-entities": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.0.tgz", + "integrity": "sha512-HLfygQL6HdhJhFbLta4Ki9hClrzyAxRjyRvpm5caN65QZL+NyHPmqFlnF9vm1Rn58JT2+AbLwNcEDY4MEvkk8Q==", + "dev": true, + "dependencies": { + "mdast-util-gfm-autolink-literal": "^0.1.0", + "mdast-util-gfm-strikethrough": "^0.2.0", + "mdast-util-gfm-table": "^0.1.0", + "mdast-util-gfm-task-list-item": "^0.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.1.tgz", + "integrity": "sha512-gJ2xSpqKCetSr22GEWpZH3f5ffb4pPn/72m4piY0v7T/S+O7n7rw+sfoPLhb2b4O7WdnERoYdALRcmD68FMtlw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.2.tgz", + "integrity": "sha512-T37ZbaokJcRbHROXmoVAieWnesPD5N21tv2ifYzaGRLbkh1gknItUGhZzHefUn5Zc/eaO/iTDSAFOBrn/E8kWw==", + "dev": true, + "dependencies": { + "mdast-util-to-markdown": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.4.tgz", + "integrity": "sha512-T4xFSON9kUb/IpYA5N+KGWcsdGczAvILvKiXQwUGind6V9fvjPCR9yhZnIeaLdBWXaz3m/Gq77ZtuLMjtFR4IQ==", + "dev": true, + "dependencies": { + "markdown-table": "^2.0.0", + "mdast-util-to-markdown": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.5.tgz", + "integrity": "sha512-6O0bt34r+e7kYjeSwedhjDPYraspKIYKbhvhQEEioL7gSmXDxhN7WQW2KoxhVMpNzjNc03yC7K5KH6NHlz2jOA==", + "dev": true, + "dependencies": { + "mdast-util-to-markdown": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-9.1.1.tgz", + "integrity": "sha512-vpMWKFKM2mnle+YbNgDXxx95vv0CoLU0v/l3F5oFAG5DV7qwkZVWA206LsAdOnEVyf5vQcLnb3cWJywu7mUxsQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.3", + "mdast-util-definitions": "^3.0.0", + "mdurl": "^1.0.0", + "unist-builder": "^2.0.0", + "unist-util-generated": "^1.0.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^2.0.0" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.5.3.tgz", + "integrity": "sha512-sr8q7fQJ1xoCqZSXW6dO/MYu2Md+a4Hfk9uO+XHCfiBhVM0EgWtfAV7BuN+ff6otUeu2xDyt1o7vhZGwOG3+BA==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^1.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown/node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-to-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz", + "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "node_modules/micromark": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.10.1.tgz", + "integrity": "sha512-fUuVF8sC1X7wsCS29SYQ2ZfIZYbTymp0EYr6sab3idFjigFFjGa5UwoniPlV9tAgntjuapW1t9U+S0yDYeGKHQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.1.tgz", + "integrity": "sha512-lJlhcOqzoJdjQg+LMumVHdUQ61LjtqGdmZtrAdfvatRUnJTqZlRwXXHdLQgNDYlFw4mycZ4NSTKlya5QcQXl1A==", + "dev": true, + "dependencies": { + "micromark": "~2.10.0", + "micromark-extension-gfm-autolink-literal": "~0.5.0", + "micromark-extension-gfm-strikethrough": "~0.6.0", + "micromark-extension-gfm-table": "~0.4.0", + "micromark-extension-gfm-tagfilter": "~0.3.0", + "micromark-extension-gfm-task-list-item": "~0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.1.tgz", + "integrity": "sha512-j30923tDp0faCNDjwqe4cMi+slegbGfc3VEAExEU8d54Q/F6pR6YxCVH+6xV0ItRoj3lCn1XkUWcy6FC3S9BOw==", + "dev": true, + "dependencies": { + "micromark": "~2.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.2.tgz", + "integrity": "sha512-aehEEqtTn3JekJNwZZxa7ZJVfzmuaWp4ew6x6sl3VAKIwdDZdqYeYSQIrNKwNgH7hX0g56fAwnSDLusJggjlCQ==", + "dev": true, + "dependencies": { + "micromark": "~2.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.1.tgz", + "integrity": "sha512-xVpqOnfFaa2OtC/Y7rlt4tdVFlUHdoLH3RXAZgb/KP3DDyKsAOx6BRS3UxiiyvmD/p2l6VUpD4bMIniuP4o4JA==", + "dev": true, + "dependencies": { + "micromark": "~2.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz", + "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.2.tgz", + "integrity": "sha512-cm8lYS10YAqeXE9B27TK3u1Ihumo3H9p/3XumT+jp8vSuSbSpFIJe0bDi2kq4YAAIxtcTzUOxhEH4ko2/NYDkQ==", + "dev": true, + "dependencies": { + "micromark": "~2.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/not": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz", + "integrity": "sha1-yWkcF0bFXc++VMvYvU/wQbwrUZ0=", + "dev": true + }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dev": true, + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/property-information": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.5.0.tgz", + "integrity": "sha512-RgEbCx2HLa1chNgvChcx+rrCWD0ctBmGSE0M7lVm1yyv4UbvbrWoXp/BkVLZefzjrRBGW8/Js6uh/BnlHXFyjA==", + "dev": true, + "dependencies": { + "xtend": "^4.0.0" + } + }, + "node_modules/rehype-raw": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-4.0.2.tgz", + "integrity": "sha512-xQt94oXfDaO7sK9mJBtsZXkjW/jm6kArCoYN+HqKZ51O19AFHlp3Xa5UfZZ2tJkbpAZzKtgVUYvnconk9IsFuA==", + "dev": true, + "dependencies": { + "hast-util-raw": "^5.0.0" + } + }, + "node_modules/rehype-stringify": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-8.0.0.tgz", + "integrity": "sha512-VkIs18G0pj2xklyllrPSvdShAV36Ff3yE5PUO9u36f6+2qJFnn22Z5gKwBOwgXviux4UC7K+/j13AnZfPICi/g==", + "dev": true, + "dependencies": { + "hast-util-to-html": "^7.1.1" + } + }, + "node_modules/remark-gfm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz", + "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==", + "dev": true, + "dependencies": { + "mdast-util-gfm": "^0.1.0", + "micromark-extension-gfm": "^0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-html": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/remark-html/-/remark-html-12.0.0.tgz", + "integrity": "sha512-M104NMHs48+uswChJkCDXCdabzxAinpHikpt6kS3gmGMyIvPZ5kn53tB9shFsL2O4HUJ9DIEsah1SX1Ve5FXHA==", + "dev": true, + "dependencies": { + "hast-util-sanitize": "^3.0.0", + "hast-util-to-html": "^7.0.0", + "mdast-util-to-hast": "^9.0.0", + "xtend": "^4.0.1" + } + }, + "node_modules/remark-parse": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", + "dev": true, + "dependencies": { + "mdast-util-from-markdown": "^0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-7.0.0.tgz", + "integrity": "sha512-uqQ/VbaTdxyu/da6npHAso6hA00cMqhA3a59RziQdOLN2KEIkPykAVy52IcmZEVTuauXO0VtpxkyCey4phtHzQ==", + "dev": true, + "dependencies": { + "mdast-util-to-hast": "^9.1.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "node_modules/replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stringify-entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.0.1.tgz", + "integrity": "sha512-Lsk3ISA2++eJYqBMPKcr/8eby1I6L0gP0NlxF8Zja6c05yr/yCYyb2c9PwXjd08Ib3If1vn1rbs1H5ZtVuOfvQ==", + "dev": true, + "dependencies": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.2", + "is-hexadecimal": "^1.0.0" + } + }, + "node_modules/style-to-object": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.2.3.tgz", + "integrity": "sha512-1d/k4EY2N7jVLOqf2j04dTc37TPOv/hHxZmvpg8Pdh8UYydxeu/C1W1U4vD8alzf5V2Gt7rLsmkr4dxAlDm9ng==", + "dev": true, + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/to-vfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz", + "integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==", + "dev": true, + "dependencies": { + "is-buffer": "^2.0.0", + "vfile": "^4.0.0" + } + }, + "node_modules/trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "dev": true + }, + "node_modules/unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "dev": true, + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + } + }, + "node_modules/unist-builder": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", + "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==", + "dev": true + }, + "node_modules/unist-util-find": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unist-util-find/-/unist-util-find-1.0.2.tgz", + "integrity": "sha512-ft06UDYzqi9o9RmGP0sZWI/zvLLQiBW2/MD+rW6mDqbOWDcmknGX9orQPspfuGRYWr8eSJAmfsBcvOpfGRJseA==", + "dev": true, + "dependencies": { + "lodash.iteratee": "^4.5.0", + "unist-util-visit": "^1.1.0" + } + }, + "node_modules/unist-util-find/node_modules/unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "dev": true, + "dependencies": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "node_modules/unist-util-find/node_modules/unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "dev": true, + "dependencies": { + "unist-util-is": "^3.0.0" + } + }, + "node_modules/unist-util-generated": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.5.tgz", + "integrity": "sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw==", + "dev": true + }, + "node_modules/unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", + "dev": true + }, + "node_modules/unist-util-position": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", + "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", + "dev": true + }, + "node_modules/unist-util-select": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/unist-util-select/-/unist-util-select-3.0.1.tgz", + "integrity": "sha512-VQpTuqZVJlRbosQdnLdTPIIqwZeU70YZ5aMBOqtFNGeeCdYn6ORZt/9RiaVlbl06ocuf58SVMoFa7a13CSGPMA==", + "dev": true, + "dependencies": { + "css-selector-parser": "^1.0.0", + "not": "^0.1.0", + "nth-check": "^1.0.0", + "unist-util-is": "^4.0.0", + "zwitch": "^1.0.0" + } + }, + "node_modules/unist-util-select/node_modules/unist-util-is": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz", + "integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==", + "dev": true + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.2" + } + }, + "node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.0.tgz", + "integrity": "sha512-0g4wbluTF93npyPrp/ymd3tCDTMnP0yo2akFD2FIBAYXq/Sga3lwaU1D8OYKbtpioaI6CkDcQ6fsMnmtzt7htw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + } + }, + "node_modules/unist-util-visit-parents/node_modules/unist-util-is": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz", + "integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==", + "dev": true + }, + "node_modules/unist-util-visit/node_modules/unist-util-is": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz", + "integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==", + "dev": true + }, + "node_modules/vfile": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.0.tgz", + "integrity": "sha512-a/alcwCvtuc8OX92rqqo7PflxiCgXRFjdyoGVuYV+qbgCb0GgZJRvIgCD4+U/Kl1yhaRsaTwksF88xbPyGsgpw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "replace-ext": "1.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", + "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true + } + }, "dependencies": { "@types/mdast": { "version": "3.0.3", @@ -70,12 +1011,6 @@ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", "dev": true }, - "collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", - "dev": true - }, "comma-separated-tokens": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", @@ -88,6 +1023,15 @@ "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==", "dev": true }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -100,21 +1044,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "hast-to-hyperscript": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-7.0.4.tgz", @@ -248,12 +1177,6 @@ "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", "dev": true }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "inline-style-parser": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", @@ -300,18 +1223,6 @@ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, - "is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", - "dev": true - }, - "is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "dev": true - }, "js-yaml": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", @@ -328,24 +1239,6 @@ "integrity": "sha1-vkF32yiajMw8CZDx2ya1si/BVUw=", "dev": true }, - "longest-streak": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-1.0.0.tgz", - "integrity": "sha1-0GWXxNTDG1LMsfXY+P5xSOr9aWU=", - "dev": true - }, - "markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", - "dev": true - }, - "markdown-table": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-0.4.0.tgz", - "integrity": "sha1-iQwsGzv+g/sA5BKbjkz+ZFJw+dE=", - "dev": true - }, "mdast-util-definitions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-3.0.1.tgz", @@ -355,6 +1248,75 @@ "unist-util-visit": "^2.0.0" } }, + "mdast-util-from-markdown": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.1.tgz", + "integrity": "sha512-qJXNcFcuCSPqUF0Tb0uYcFDIq67qwB3sxo9RPdf9vG8T90ViKnksFqdB/Coq2a7sTnxL/Ify2y7aIQXDkQFH0w==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^1.0.0", + "micromark": "~2.10.0", + "parse-entities": "^2.0.0" + } + }, + "mdast-util-gfm": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.0.tgz", + "integrity": "sha512-HLfygQL6HdhJhFbLta4Ki9hClrzyAxRjyRvpm5caN65QZL+NyHPmqFlnF9vm1Rn58JT2+AbLwNcEDY4MEvkk8Q==", + "dev": true, + "requires": { + "mdast-util-gfm-autolink-literal": "^0.1.0", + "mdast-util-gfm-strikethrough": "^0.2.0", + "mdast-util-gfm-table": "^0.1.0", + "mdast-util-gfm-task-list-item": "^0.1.0" + } + }, + "mdast-util-gfm-autolink-literal": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.1.tgz", + "integrity": "sha512-gJ2xSpqKCetSr22GEWpZH3f5ffb4pPn/72m4piY0v7T/S+O7n7rw+sfoPLhb2b4O7WdnERoYdALRcmD68FMtlw==", + "dev": true + }, + "mdast-util-gfm-strikethrough": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.2.tgz", + "integrity": "sha512-T37ZbaokJcRbHROXmoVAieWnesPD5N21tv2ifYzaGRLbkh1gknItUGhZzHefUn5Zc/eaO/iTDSAFOBrn/E8kWw==", + "dev": true, + "requires": { + "mdast-util-to-markdown": "^0.5.0" + } + }, + "mdast-util-gfm-table": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.4.tgz", + "integrity": "sha512-T4xFSON9kUb/IpYA5N+KGWcsdGczAvILvKiXQwUGind6V9fvjPCR9yhZnIeaLdBWXaz3m/Gq77ZtuLMjtFR4IQ==", + "dev": true, + "requires": { + "markdown-table": "^2.0.0", + "mdast-util-to-markdown": "^0.5.0" + }, + "dependencies": { + "markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "requires": { + "repeat-string": "^1.0.0" + } + } + } + }, + "mdast-util-gfm-task-list-item": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.5.tgz", + "integrity": "sha512-6O0bt34r+e7kYjeSwedhjDPYraspKIYKbhvhQEEioL7gSmXDxhN7WQW2KoxhVMpNzjNc03yC7K5KH6NHlz2jOA==", + "dev": true, + "requires": { + "mdast-util-to-markdown": "^0.5.0" + } + }, "mdast-util-to-hast": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-9.1.1.tgz", @@ -371,12 +1333,112 @@ "unist-util-visit": "^2.0.0" } }, + "mdast-util-to-markdown": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.5.3.tgz", + "integrity": "sha512-sr8q7fQJ1xoCqZSXW6dO/MYu2Md+a4Hfk9uO+XHCfiBhVM0EgWtfAV7BuN+ff6otUeu2xDyt1o7vhZGwOG3+BA==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^1.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "dependencies": { + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true + } + } + }, + "mdast-util-to-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz", + "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==", + "dev": true + }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", "dev": true }, + "micromark": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.10.1.tgz", + "integrity": "sha512-fUuVF8sC1X7wsCS29SYQ2ZfIZYbTymp0EYr6sab3idFjigFFjGa5UwoniPlV9tAgntjuapW1t9U+S0yDYeGKHQ==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "micromark-extension-gfm": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.1.tgz", + "integrity": "sha512-lJlhcOqzoJdjQg+LMumVHdUQ61LjtqGdmZtrAdfvatRUnJTqZlRwXXHdLQgNDYlFw4mycZ4NSTKlya5QcQXl1A==", + "dev": true, + "requires": { + "micromark": "~2.10.0", + "micromark-extension-gfm-autolink-literal": "~0.5.0", + "micromark-extension-gfm-strikethrough": "~0.6.0", + "micromark-extension-gfm-table": "~0.4.0", + "micromark-extension-gfm-tagfilter": "~0.3.0", + "micromark-extension-gfm-task-list-item": "~0.3.0" + } + }, + "micromark-extension-gfm-autolink-literal": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.1.tgz", + "integrity": "sha512-j30923tDp0faCNDjwqe4cMi+slegbGfc3VEAExEU8d54Q/F6pR6YxCVH+6xV0ItRoj3lCn1XkUWcy6FC3S9BOw==", + "dev": true, + "requires": { + "micromark": "~2.10.0" + } + }, + "micromark-extension-gfm-strikethrough": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.2.tgz", + "integrity": "sha512-aehEEqtTn3JekJNwZZxa7ZJVfzmuaWp4ew6x6sl3VAKIwdDZdqYeYSQIrNKwNgH7hX0g56fAwnSDLusJggjlCQ==", + "dev": true, + "requires": { + "micromark": "~2.10.0" + } + }, + "micromark-extension-gfm-table": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.1.tgz", + "integrity": "sha512-xVpqOnfFaa2OtC/Y7rlt4tdVFlUHdoLH3RXAZgb/KP3DDyKsAOx6BRS3UxiiyvmD/p2l6VUpD4bMIniuP4o4JA==", + "dev": true, + "requires": { + "micromark": "~2.10.0" + } + }, + "micromark-extension-gfm-tagfilter": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz", + "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==", + "dev": true + }, + "micromark-extension-gfm-task-list-item": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.2.tgz", + "integrity": "sha512-cm8lYS10YAqeXE9B27TK3u1Ihumo3H9p/3XumT+jp8vSuSbSpFIJe0bDi2kq4YAAIxtcTzUOxhEH4ko2/NYDkQ==", + "dev": true, + "requires": { + "micromark": "~2.10.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "not": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz", @@ -392,15 +1454,6 @@ "boolbase": "~1.0.0" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, "parse-entities": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", @@ -448,101 +1501,14 @@ "hast-util-to-html": "^7.1.1" } }, - "remark": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/remark/-/remark-5.1.0.tgz", - "integrity": "sha1-y0Y709vLS5l5STXu4c9x16jjBow=", + "remark-gfm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz", + "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==", "dev": true, "requires": { - "remark-parse": "^1.1.0", - "remark-stringify": "^1.1.0", - "unified": "^4.1.1" - }, - "dependencies": { - "parse-entities": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", - "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", - "dev": true, - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "remark-parse": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-1.1.0.tgz", - "integrity": "sha1-w8oQ+ajaBGFcKPCapOMEUQUm7CE=", - "dev": true, - "requires": { - "collapse-white-space": "^1.0.0", - "extend": "^3.0.0", - "parse-entities": "^1.0.2", - "repeat-string": "^1.5.4", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^1.0.0", - "vfile-location": "^2.0.0" - } - }, - "unified": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/unified/-/unified-4.2.1.tgz", - "integrity": "sha1-dv9Dqo2kMPbn5KVchOusKtLPzS4=", - "dev": true, - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "has": "^1.0.1", - "once": "^1.3.3", - "trough": "^1.0.0", - "vfile": "^1.0.0" - } - }, - "unist-util-remove-position": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz", - "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==", - "dev": true, - "requires": { - "unist-util-visit": "^1.1.0" - } - }, - "unist-util-visit": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", - "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", - "dev": true, - "requires": { - "unist-util-visit-parents": "^2.0.0" - } - }, - "unist-util-visit-parents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", - "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", - "dev": true, - "requires": { - "unist-util-is": "^3.0.0" - } - }, - "vfile": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-1.4.0.tgz", - "integrity": "sha1-wP1vpIT43r23cfaMMe112I2pf+c=", - "dev": true - }, - "vfile-location": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz", - "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==", - "dev": true - } + "mdast-util-gfm": "^0.1.0", + "micromark-extension-gfm": "^0.3.0" } }, "remark-html": { @@ -558,27 +1524,12 @@ } }, "remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", "dev": true, "requires": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" + "mdast-util-from-markdown": "^0.8.0" } }, "remark-rehype": { @@ -590,50 +1541,6 @@ "mdast-util-to-hast": "^9.1.0" } }, - "remark-stringify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-1.1.0.tgz", - "integrity": "sha1-pxBeJbnuK/mkm3XSxCPxGwauIJI=", - "dev": true, - "requires": { - "ccount": "^1.0.0", - "extend": "^3.0.0", - "longest-streak": "^1.0.0", - "markdown-table": "^0.4.0", - "parse-entities": "^1.0.2", - "repeat-string": "^1.5.4", - "stringify-entities": "^1.0.1", - "unherit": "^1.0.4" - }, - "dependencies": { - "parse-entities": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", - "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", - "dev": true, - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "stringify-entities": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz", - "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", - "dev": true, - "requires": { - "character-entities-html4": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - } - } - }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -658,12 +1565,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", - "dev": true - }, "stringify-entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.0.1.tgz", @@ -696,34 +1597,12 @@ "vfile": "^4.0.0" } }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", - "dev": true - }, - "trim-trailing-lines": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz", - "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==", - "dev": true - }, "trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", "dev": true }, - "unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "dev": true, - "requires": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - } - }, "unified": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", @@ -745,13 +1624,12 @@ "dev": true }, "unist-util-find": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unist-util-find/-/unist-util-find-1.0.1.tgz", - "integrity": "sha1-EGK7tpKMepfGrcibU3RdTEbCIqI=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unist-util-find/-/unist-util-find-1.0.2.tgz", + "integrity": "sha512-ft06UDYzqi9o9RmGP0sZWI/zvLLQiBW2/MD+rW6mDqbOWDcmknGX9orQPspfuGRYWr8eSJAmfsBcvOpfGRJseA==", "dev": true, "requires": { "lodash.iteratee": "^4.5.0", - "remark": "^5.0.1", "unist-util-visit": "^1.1.0" }, "dependencies": { @@ -793,15 +1671,6 @@ "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", "dev": true }, - "unist-util-remove-position": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", - "dev": true, - "requires": { - "unist-util-visit": "^2.0.0" - } - }, "unist-util-select": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/unist-util-select/-/unist-util-select-3.0.1.tgz", @@ -882,12 +1751,6 @@ "vfile-message": "^2.0.0" } }, - "vfile-location": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.1.0.tgz", - "integrity": "sha512-FCZ4AN9xMcjFIG1oGmZKo61PjwJHRVA+0/tPUP2ul4uIwjGGndIxavEMRpWn5p4xwm/ZsdXp9YNygf1ZyE4x8g==", - "dev": true - }, "vfile-message": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", @@ -904,12 +1767,6 @@ "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", "dev": true }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/tools/doc/package.json b/tools/doc/package.json index e3e60831a85e57..3a5d9c0139d56b 100644 --- a/tools/doc/package.json +++ b/tools/doc/package.json @@ -11,15 +11,17 @@ "js-yaml": "3.14.0", "rehype-raw": "4.0.2", "rehype-stringify": "8.0.0", + "remark-gfm": "^1.0.0", "remark-html": "12.0.0", - "remark-parse": "8.0.3", + "remark-parse": "^9.0.0", "remark-rehype": "7.0.0", "to-vfile": "6.1.0", "unified": "9.2.0", - "unist-util-find": "1.0.1", + "unist-util-find": "^1.0.2", "unist-util-select": "3.0.1", "unist-util-visit": "2.0.3" }, - "optionalDependencies": {}, - "bin": "./generate.js" + "bin": { + "node-doc-generator": "generate.js" + } } diff --git a/tools/eslint-rules/prefer-primordials.js b/tools/eslint-rules/prefer-primordials.js index ffbb1e6e308c95..51fb6ab8c2ad44 100644 --- a/tools/eslint-rules/prefer-primordials.js +++ b/tools/eslint-rules/prefer-primordials.js @@ -75,7 +75,6 @@ module.exports = { acc.set( option.name, (option.ignore || []) - .concat(['prototype']) .reduce((acc, name) => acc.set(name, { ignored: true }), new Map()) diff --git a/tools/js2c.py b/tools/js2c.py index 195e6a6189a989..0f073e182bdb28 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -163,9 +163,11 @@ def handle_config_gypi(config_filename): def jsonify(config): # 1. string comments config = re.sub(r'#.*?\n', '', config) + # 2. join multiline strings + config = re.sub(r"'$\s+'", '', config, flags=re.M) # 3. normalize string literals from ' into " config = re.sub('\'', '"', config) - # 2. turn pseudo-booleans strings into Booleans + # 4. turn pseudo-booleans strings into Booleans config = re.sub('"true"', 'true', config) config = re.sub('"false"', 'false', config) return config diff --git a/tools/license-builder.sh b/tools/license-builder.sh index e6d66a037704bc..899f9de99c0610 100755 --- a/tools/license-builder.sh +++ b/tools/license-builder.sh @@ -1,23 +1,23 @@ -#!/usr/bin/env bash +#!/bin/sh set -e -rootdir="$(CDPATH= cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +rootdir="$(CDPATH='' cd "$(dirname "$0")/.." && pwd)" licensefile="${rootdir}/LICENSE" -licensehead="$(sed '/^- /,$d' ${licensefile})" +licensehead="$(sed '/^- /,$d' "${licensefile}")" tmplicense="${rootdir}/~LICENSE.$$" -echo -e "$licensehead" > $tmplicense +echo "$licensehead" > "$tmplicense" # addlicense -function addlicense { +addlicense() { echo " - ${1}, located at ${2}, is licensed as follows: \"\"\" -$(echo -e "$3" | sed -e 's/^/ /' -e 's/^ $//' -e 's/ *$//' | sed -e '/./,$!d' | sed -e '/^$/N;/^\n$/D') +$(echo "$3" | sed -e 's/^/ /' -e 's/^ $//' -e 's/ *$//' | sed -e '/./,$!d' | sed -e '/^$/N;/^\n$/D') \"\"\"\ -" >> $tmplicense +" >> "$tmplicense" } @@ -29,85 +29,85 @@ fi # Dependencies bundled in distributions -addlicense "Acorn" "deps/acorn" "$(cat ${rootdir}/deps/acorn/acorn/LICENSE)" -addlicense "Acorn plugins" "deps/acorn-plugins" "$(cat ${rootdir}/deps/acorn-plugins/acorn-class-fields/LICENSE)" -addlicense "c-ares" "deps/cares" "$(tail -n +3 ${rootdir}/deps/cares/LICENSE.md)" -addlicense "cjs-module-lexer" "deps/cjs-module-lexer" "$(cat ${rootdir}/deps/cjs-module-lexer/LICENSE)" +addlicense "Acorn" "deps/acorn" "$(cat "${rootdir}"/deps/acorn/acorn/LICENSE)" +addlicense "Acorn plugins" "deps/acorn-plugins" "$(cat "${rootdir}"/deps/acorn-plugins/acorn-class-fields/LICENSE)" +addlicense "c-ares" "deps/cares" "$(tail -n +3 "${rootdir}"/deps/cares/LICENSE.md)" +addlicense "cjs-module-lexer" "deps/cjs-module-lexer" "$(cat "${rootdir}"/deps/cjs-module-lexer/LICENSE)" if [ -f "${rootdir}/deps/icu/LICENSE" ]; then # ICU 57 and following. Drop the BOM addlicense "ICU" "deps/icu" \ "$(sed -e '1s/^[^a-zA-Z ]*ICU/ICU/' -e :a \ - -e 's/<[^>]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/Code of Conduct -ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct). +ESLint adheres to the [JS Foundation Code of Conduct](https://eslint.org/conduct). ## Filing Issues @@ -267,7 +267,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

        Automattic

        Gold Sponsors

        Shopify Salesforce Airbnb Microsoft FOSS Fund Sponsorships

        Silver Sponsors

        Liftoff AMP Project

        Bronze Sponsors

        -

        Writers Per Hour 2021 calendar Buy.Fineproxy.Org Veikkaajat.com Anagram Solver Bugsnag Stability Monitoring Mixpanel VPS Server Icons8: free icons, photos, illustrations, and music Discord ThemeIsle Marfeel Fire Stick Tricks

        +

        Writers Per Hour 2021 calendar Buy.Fineproxy.Org Veikkaajat.com Anagram Solver Bugsnag Stability Monitoring Mixpanel VPS Server Icons8: free icons, photos, illustrations, and music Discord ThemeIsle Fire Stick Tricks

        ## Technology Sponsors diff --git a/tools/node_modules/eslint/lib/linter/timing.js b/tools/node_modules/eslint/lib/linter/timing.js index 8396d9215b54dc..58230306855abe 100644 --- a/tools/node_modules/eslint/lib/linter/timing.js +++ b/tools/node_modules/eslint/lib/linter/timing.js @@ -44,6 +44,26 @@ const enabled = !!process.env.TIMING; const HEADERS = ["Rule", "Time (ms)", "Relative"]; const ALIGN = [alignLeft, alignRight, alignRight]; +/** + * Decide how many rules to show in the output list. + * @returns {number} the number of rules to show + */ +function getListSize() { + const MINIMUM_SIZE = 10; + + if (typeof process.env.TIMING !== "string") { + return MINIMUM_SIZE; + } + + if (process.env.TIMING.toLowerCase() === "all") { + return Number.POSITIVE_INFINITY; + } + + const TIMING_ENV_VAR_AS_INTEGER = Number.parseInt(process.env.TIMING, 10); + + return TIMING_ENV_VAR_AS_INTEGER > 10 ? TIMING_ENV_VAR_AS_INTEGER : MINIMUM_SIZE; +} + /* istanbul ignore next */ /** * display the data @@ -61,7 +81,7 @@ function display(data) { return [key, time]; }) .sort((a, b) => b[1] - a[1]) - .slice(0, 10); + .slice(0, getListSize()); rows.forEach(row => { row.push(`${(row[1] * 100 / total).toFixed(1)}%`); @@ -133,7 +153,8 @@ module.exports = (function() { return { time, - enabled + enabled, + getListSize }; }()); diff --git a/tools/node_modules/eslint/node_modules/import-fresh/index.js b/tools/node_modules/eslint/node_modules/import-fresh/index.js index 425ed98c42f68e..0a4c5d52f6d322 100644 --- a/tools/node_modules/eslint/node_modules/import-fresh/index.js +++ b/tools/node_modules/eslint/node_modules/import-fresh/index.js @@ -10,7 +10,8 @@ module.exports = moduleId => { const parentPath = parentModule(__filename); - const filePath = resolveFrom(path.dirname(parentPath), moduleId); + const cwd = parentPath ? path.dirname(parentPath) : __dirname; + const filePath = resolveFrom(cwd, moduleId); const oldModule = require.cache[filePath]; // Delete itself from module parent diff --git a/tools/node_modules/eslint/node_modules/import-fresh/package.json b/tools/node_modules/eslint/node_modules/import-fresh/package.json index 38892a62e43136..893bb4a523fbca 100644 --- a/tools/node_modules/eslint/node_modules/import-fresh/package.json +++ b/tools/node_modules/eslint/node_modules/import-fresh/package.json @@ -47,5 +47,5 @@ "heapdump": "node heapdump.js", "test": "xo && ava && tsd" }, - "version": "3.2.1" + "version": "3.2.2" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/trim-trailing-lines/index.js b/tools/node_modules/eslint/node_modules/trim-trailing-lines/index.js index 0f2d48b52fc567..eff85c6baedffb 100644 --- a/tools/node_modules/eslint/node_modules/trim-trailing-lines/index.js +++ b/tools/node_modules/eslint/node_modules/trim-trailing-lines/index.js @@ -2,16 +2,7 @@ module.exports = trimTrailingLines -var line = '\n' - // Remove final newline characters from `value`. function trimTrailingLines(value) { - var val = String(value) - var index = val.length - - while (val.charAt(--index) === line) { - // Empty - } - - return val.slice(0, index + 1) + return String(value).replace(/\n+$/, '') } diff --git a/tools/node_modules/eslint/node_modules/trim-trailing-lines/package.json b/tools/node_modules/eslint/node_modules/trim-trailing-lines/package.json index bbf4660f41bdda..c0242dc1299bdc 100644 --- a/tools/node_modules/eslint/node_modules/trim-trailing-lines/package.json +++ b/tools/node_modules/eslint/node_modules/trim-trailing-lines/package.json @@ -19,14 +19,14 @@ "deprecated": false, "description": "Remove final line feeds from a string", "devDependencies": { - "browserify": "^16.0.0", + "browserify": "^17.0.0", "nyc": "^15.0.0", - "prettier": "^1.0.0", - "remark-cli": "^7.0.0", - "remark-preset-wooorm": "^6.0.0", - "tape": "^4.0.0", - "tinyify": "^2.0.0", - "xo": "^0.25.0" + "prettier": "^2.0.0", + "remark-cli": "^9.0.0", + "remark-preset-wooorm": "^8.0.0", + "tape": "^5.0.0", + "tinyify": "^3.0.0", + "xo": "^0.34.0" }, "files": [ "index.js" @@ -72,12 +72,12 @@ "build": "npm run build-bundle && npm run build-mangle", "build-bundle": "browserify . -s trimTrailingLines -o trim-trailing-lines.js", "build-mangle": "browserify . -s trimTrailingLines -p tinyify -o trim-trailing-lines.min.js", - "format": "remark . -qfo && prettier --write \"**/*.js\" && xo --fix", + "format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", "test": "npm run format && npm run build && npm run test-coverage", "test-api": "node test", "test-coverage": "nyc --reporter lcov tape test.js" }, - "version": "1.1.3", + "version": "1.1.4", "xo": { "prettier": true, "esnext": false, diff --git a/tools/node_modules/eslint/node_modules/v8-compile-cache/README.md b/tools/node_modules/eslint/node_modules/v8-compile-cache/README.md index 9580f6943205e1..6e0b99fbaa6304 100644 --- a/tools/node_modules/eslint/node_modules/v8-compile-cache/README.md +++ b/tools/node_modules/eslint/node_modules/v8-compile-cache/README.md @@ -26,9 +26,11 @@ The ability to tap into V8 to produce/consume this cache was introduced in [Node Set the environment variable `DISABLE_V8_COMPILE_CACHE=1` to disable the cache. +Cache directory is defined by environment variable `V8_COMPILE_CACHE_CACHE_DIR` or defaults to `/v8-compile-cache-`. + ## Internals -The caches are stored in `$TMP/v8-compile-cache/V8_VERSION`, where there are `.BLOB` and `.MAP` files corresponding to the entry module that required `v8-compile-cache`. The cache is _entry module specific_ because it is faster to load the entire code cache into memory at once, than it is to read it from disk on a file-by-file basis. +Cache files are suffixed `.BLOB` and `.MAP` corresponding to the entry module that required `v8-compile-cache`. The cache is _entry module specific_ because it is faster to load the entire code cache into memory at once, than it is to read it from disk on a file-by-file basis. ## Benchmarks diff --git a/tools/node_modules/eslint/node_modules/v8-compile-cache/package.json b/tools/node_modules/eslint/node_modules/v8-compile-cache/package.json index 83d66522f04c29..25540b730159b7 100644 --- a/tools/node_modules/eslint/node_modules/v8-compile-cache/package.json +++ b/tools/node_modules/eslint/node_modules/v8-compile-cache/package.json @@ -11,15 +11,15 @@ "deprecated": false, "description": "Require hook for automatic V8 compile cache persistence", "devDependencies": { - "babel-core": "6.23.1", - "eslint": "^3.15.0", - "flow-parser": "0.38.0", + "babel-core": "6.26.3", + "eslint": "^7.12.1", + "flow-parser": "0.136.0", "rimraf": "^2.5.4", - "rxjs": "5.2.0", + "rxjs": "6.6.3", "semver": "^5.3.0", "tap": "^10.1.1", "temp": "^0.8.3", - "yarn": "0.20.3" + "yarn": "1.22.10" }, "files": [ "v8-compile-cache.js" @@ -34,9 +34,10 @@ }, "scripts": { "bench": "bench/run.sh", - "lint": "eslint --max-warnings=0 .", - "posttest": "npm run lint", - "test": "tap test/*-test.js" + "eslint": "eslint --max-warnings=0 .", + "posttest": "npm run eslint", + "tap": "tap test/*-test.js", + "test": "npm run tap" }, - "version": "2.1.1" + "version": "2.2.0" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/v8-compile-cache/v8-compile-cache.js b/tools/node_modules/eslint/node_modules/v8-compile-cache/v8-compile-cache.js index 69f053667046ca..b9c09288cb310b 100644 --- a/tools/node_modules/eslint/node_modules/v8-compile-cache/v8-compile-cache.js +++ b/tools/node_modules/eslint/node_modules/v8-compile-cache/v8-compile-cache.js @@ -86,8 +86,6 @@ class FileSystemBlobStore { try { fs.writeFileSync(this._blobFilename, blobToStore); fs.writeFileSync(this._mapFilename, mapToStore); - } catch (error) { - throw error; } finally { fs.unlinkSync(this._lockFilename); } @@ -301,7 +299,8 @@ function slashEscape(str) { '\x00': 'z0', 'z': 'zZ', }; - return str.replace(/[\\:\/\x00z]/g, match => (ESCAPE_LOOKUP[match])); + const ESCAPE_REGEX = /[\\:/\x00z]/g; // eslint-disable-line no-control-regex + return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]); } function supportsCachedData() { @@ -311,6 +310,11 @@ function supportsCachedData() { } function getCacheDir() { + const v8_compile_cache_cache_dir = process.env.V8_COMPILE_CACHE_CACHE_DIR; + if (v8_compile_cache_cache_dir) { + return v8_compile_cache_cache_dir; + } + // Avoid cache ownership issues on POSIX systems. const dirname = typeof process.getuid === 'function' ? 'v8-compile-cache-' + process.getuid() @@ -348,7 +352,7 @@ if (!process.env.DISABLE_V8_COMPILE_CACHE && supportsCachedData()) { nativeCompileCache.setCacheStore(blobStore); nativeCompileCache.install(); - process.once('exit', code => { + process.once('exit', () => { if (blobStore.isDirty()) { blobStore.save(); } diff --git a/tools/node_modules/eslint/package.json b/tools/node_modules/eslint/package.json index a5f0c57b98a18d..53d055bc094d51 100644 --- a/tools/node_modules/eslint/package.json +++ b/tools/node_modules/eslint/package.json @@ -154,5 +154,5 @@ "test:cli": "mocha", "webpack": "node Makefile.js webpack" }, - "version": "7.12.1" + "version": "7.13.0" } \ No newline at end of file diff --git a/vcbuild.bat b/vcbuild.bat index 86a986b3dec2f3..777842de209d11 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -249,8 +249,8 @@ echo Looking for Visual Studio 2019 @rem VCINSTALLDIR may be set if run from a VS Command Prompt and needs to be @rem cleared first as vswhere_usability_wrapper.cmd doesn't when it fails to @rem detect the version searched for -set "VCINSTALLDIR=" -call tools\msvs\vswhere_usability_wrapper.cmd "[16.0,17.0)" +if not defined target_env set "VCINSTALLDIR=" +call tools\msvs\vswhere_usability_wrapper.cmd "[16.0,17.0)" "prerelease" if "_%VCINSTALLDIR%_" == "__" goto msbuild-not-found set "WIXSDKDIR=%WIX%\SDK\VS2017" if defined msi (